愛と涙のWordPress無理やり
カスタマイズ事例集
やろうと思えば何でも出来る
名古屋で株式会社ベクトルという
ウェブ制作会社をしています。
設⽴して7期⽬。
⽯川栄和 @kurudrive
テーマやプラグイン作ってます
ウェブ制作の知識が無くても
⾼品質なホームページが作れるテンプレート
今⽇伝えたい事
• WordPressはブログや企業サイトだけじゃない
アプリケーションプラットフォーム。
• プラグインでもいろいろ出来るけど、
PHPの基本がわかればなんでも出来る。
どんな関数を使ってどんな処理が出来るか
ヒントになれば幸いです。
本⽇紹介する事例
1. 伝票管理システム
2. GPSスタンプラリー
3. ⼤企業の社内イントラ
3-1.多⾔語対応
3-2.カスタム投稿タイプを管理画⾯から制御
3-3.ユーザー権限グループを管理画⾯から制御
3-4.承認フローシステム
4. 請求書管理システム
CSV出⼒
はじめに
途中ソースコードを紹介する場⾯があります。
限られたスペースの中で⾒やすく紹介するため、
本来必要なエスケープ処理や翻訳関数などは
省略しています。
1.伝票管理システム
WordPressはブログや企業サイトだけじゃない
詳しい資料・ソースコード
ホームページだけじゃない!
管理システムとしてのWordPress
http://tech.hi-works.com/webcreative/wordpress/769
クライアントと業務の問題点
• 紙の伝票で処理していた
→ 数が多い / 営業拠点によって伝票がない
• 取引先からの問い合わせもスタッフが
都度ファイルから探して確認・返答
していたので⼈的コストも多い
海外への輸出代⾏業者
クライアント
問題点
• ⼀つの伝票を投稿
• 各情報をカスタムフィールド
に登録
• 伝票番号等で簡単検索
• 紙の伝票が不要に
• レスポンシブ対応でどこから
でもデータを確認
• PCに疎い依頼者には印刷し
てFAX送信すればOK!
輸出コンテナの伝票情報をWordPressで管理
ログインユーザーで表⽰情報を切り分け
輸送依頼者が⾃分で
コンテナの状況を閲覧出来る。
• クライアント毎にユーザーを発⾏
• 伝票(投稿)の「投稿者」には
該当クライアントのユーザーアカ
ウントを割り当てる
• クライアントが直接ログインする
と、そのアカウントの
伝票(投稿)しか⾒れないように
しておく
伝票毎にクライアントにメール送信
• データ登録通知
• 請求通知
ContactForm7を応⽤
2.GPSスタンプラリー
データの保存先にカスタム投稿タイプを利⽤
お城めぐりGPSスタンプラリー
kojoki.jp
お城に⾏ってスマホからチェックイン
⾃分の⾏ったお城の履歴
詳しい資料・ソースコード
WordFes 2014
WordPressと外部APIとの連携
https://www.slideshare.net/kurudrive/wordpressapi
主な処理
• 投稿にお城のデータを⼊⼒
• サービス利⽤者はWordPressのユーザーに
登録・ログインして利⽤
• GPSで位置情報の判定に成功したら、
チェックイン情報をカスタム投稿タイプに保存
チェックイン情報の保存
カスタム投稿タイプにデータを保存する
ユーザーがチェックインした情報を保存したい
最低限保存する情報
• チェックインしたユーザーは誰か?
ログイン中のユーザーID
• チェックインしたお城はどこか?
お城ページの投稿ID
ログイン中のユーザーIDと
チェックインしたお城のIDを取得
ログインしているユーザーID
// ログインしているユーザー情報を取得
$user = wp_get_current_user();
// ユーザーID
$user_id = $user->ID;
クッキーなどからチェックインした城のIDを取得
If ( isset( $_COOKIE["checkin_spot_id"] ) ) {
$checkin_id = $_COOKIE["checkin_spot_id"];
}
チェックイン成功ページでの処理
チェックイン情報の保存先と保存情報
チェックイン情報 保存⽤の
カスタム投稿タイプに投稿していく
最低限保存する情報
• チェックインしたユーザーIDの保存先
投稿者に設定
• チェックインしたお城ID(投稿ID)の保存先
タイトル⼜はカスタムフィールドに保存
投稿を⾃動で追加する
$checkin_post = array();
// 投稿タイプ
$checkin_post['post_type'] = 'checkin';
// 投稿の状態
$checkin_post['post_status'] = 'publish';
// 投稿のタイトル
$checkin_post['post_title'] = get_the_title($checkin_id);
// 投稿の作成者
$checkin_post['post_author'] = $user_id;
タイトルはチェックインした城の名前
$posted_id = wp_insert_post( $checkin_post );
新規投稿する関数 新規投稿する情報
投稿に成功した時に、成功した投稿のIDが返ってくる
カスタムフィールドにお城のIDを保存
add_post_meta($posted_id, 'checkin_spot_id', $checkin_id);
上記で成功したチェックイン情報の投稿ID
保存先のカスタムフィールドのキー チェックインしたお城ID
保存結果
保存したチェックインデータの引き出し例
$posts = get_posts(array(
'post_type' => 'checkin',
'posts_per_page' => -1,
'author' => $user_id,
));
ログイン中のユーザーのチェックイン履歴
投稿タイプがʼcheckinʼ
作成者が $user_id
ログイン中のユーザーの投稿
結果出⼒応⽤例
その他の 投稿・削除⽤関数
• 既存投稿の更新
wp_update_post();
• 既存投稿の削除
wp_delete_post();
• カスタムフィールドの値の更新
update_post_meta();
• カスタムフィールドの値の削除
delete_post_meta();
3.社内イントラ
多⾔語多機能サイト
最初の主な要望
• 多⾔語対応(英語 / ⽇本語)
• 編集権限制御
部署毎の担当者が⾃部署のコンテンツだけ変更可能に
部署毎のコンテンツ : 固定ページと部署毎のニュース
• MicrosoftのActive Directoryとユーザーアカウントを連携
部署⽤のWordPressユーザーを発⾏して〜という運⽤ではない
• 閲覧制御
• イベントカレンダー
• 電話帳機能(CSVインポート・エクスポート)
• 他多数
基本構成検討
→ マルチサイトは多⾔語対応の為に使った
(終わりのはじまり...)
要望 : ⾃分の部署コンテンツだけ編集出来る出来るように
→ マルチサイトにして⾃分のサイトだけ編集させれば...
だがしかし・・・
• 将来的に⾔語毎に違う情報配置要望の可能性
• 部署によっては親部署・⼦部署がある
(必ず並列じゃない)
3-1.多⾔語対応
当初の多⾔語対応想定
• マルチサイトで1⾔語1サイト
• ⼀つの記事毎に他の⾔語(⼦サイト)で
どの記事に該当するのかを指定して紐付ける
Multi language switcher とは
プラグイン「Multi language switcher」の利⽤を想定。
(と⾔うかそれが前提条件で初期構築…)
Multi language switcher の⻑所と短所
• ⾔語毎のサイトの編集画⾯にログインして記事を書いて紐付け
• ⽇本語の翻訳が存在しないページでは英語を表⽰すれば良いという
場合でも⼿動で英語コンテンツを登録する必要がある。
⻑所
• シンプル(⼦サイトの記事同⼠を紐づけているだけ)
• このプラグインを停⽌しても⼤きな不具合は発⽣しない
(⾔語毎に別々の⼦サイトになるだけ)
• サイト(⾔語)毎に全然違うデザインやレイアウトにしやすい。
短所
先⽅で関係各位が集まる中、多⾔語の表⽰・編集を実演
( ゚д゚) こんな感じっす!
ちょっとこれは⾯倒くさいなぁ...
⼀つの画⾯で出来ないの?
/ ̄ ̄\
/ノ( _ノ \
| ⌒(( ●)(●)
.| (__人__) /⌒l
| ` ⌒´ノ |`'''|
/ ⌒ヽ } | | __________て
/ へ \ }__/ / | | ̄ ̄ ̄ ̄ ̄ ̄ ̄| | |(
/ / | ノ ノ | | \ / | | |’, ・
( _ ノ | \´ _ | | \ ノ( / | | | , ’
| \_,, -‐ ''"  ̄ ゙̄''―---└'´ ̄`ヽ | | | て
.| __ ノ _| | | (
ヽ _,, -‐ ''" ̄|_ ̄_o o o___|_|r'"
( ディレクションに関するセッションではないので詳細は割愛 )
Multi language switcher を諦め独⾃実装
1画⾯で英語と⽇本語を⼊⼒する独⾃カスタマイズ...。
• 副⾔語(⽇本語)のタイトルと本⽂欄をカスタムフィールドで作成
• ⽇本語表⽰の場合はカスタムフィールドに保存されている情報を表⽰
• ⾔語の判別はURLにパラメーターをつける事で実施する
( 検索システム対策 )
基本的な構造案
主な処理
1.サイト内のリンクURLを、⾔語判別⽤
パラメーター付きのURLに置換する(検索対策)
2.⾔語パラメータを取得して英語か⽇本語か判別
3.⽇本語表⽰の場合はタイトルと本⽂を
カスタムフィールドの内容に差し替えて表⽰する
URLに⾔語判定⽤パラメーターをつける
サイト内のリンク先URLを差し替えないといけない。
例)
通常(英語)http://○○○.com/abc
⽇本語 http://○○○.com/abc?lang=ja
function change_url( $permalink ){
// 差し替えたいURL
$permalink = 'https://www.google.co.jp';
// 戻す
return $permalink;
}
add_filter( 'the_permalink', 'change_url' );
the_permalink() タグを使ってある所のリンク先が
全部 google.co.jp になります。
フィルターフックの例
add_filter( 'the_permalink', 差し替える関数名 );
function lang_switch_link_url( $permalink ){
if ( !is_admin() ){
// 現在の⾔語を取得
$locale = get_locale();
// URLに⾔語パラメーターを追加
$permalink = add_query_arg( 'lang', $locale, $permalink );
}
return $permalink;
}
add_filter( 'the_permalink', 'lang_switch_link_url' ,10,2 );
※補⾜
• get_locale() で取得する現在の表⽰⾔語の値は別の箇所でフィルターで書き換え済みの想定
• 実際には外部リンクへの差し替えが⾏われている場合の処理、
及び the_permalink 以外で出⼒されるURLの書き換え処理なども必要になってきます。
フィルターでURLを置換
元のURL
パラメーター名 パラメーターの値
タイトルや本⽂を差し替える
function lang_switch_title( $title ){
if ( get_locale() == "ja" && !is_admin() ){
// ⽇本語表⽰で管理画⾯以外の場合に差し替え
$title = get_post_meta( $post->ID, 'lang_title_ja', true );
}
return $title;
}
add_filter( 'the_title', 'lang_switch_title', 10, 2 );
⽇本語のタイトルが保存された
カスタムフィールド
3-2.部署毎のニュースコンテンツ
要望
→ 部署毎のカスタム投稿タイプで実装
部署(のカスタム投稿タイプ)は定期的に
再編が予想される
⾃部署以外の記事は編集できないように
懸念事項
管理画⾯からニュース⽤投稿タイプを管理
• 各部署のニュース⽤カスタム投稿タイプを
管理画⾯から追加・削除出来るように
• 通常独⾃の設定項⽬を保存する場合
専⽤のオプション項⽬設定画⾯を1ページ作って
そこに設定項⽬のフォームを設置する
→ フォームを作るのも⾯倒
→ ⼊⼒項⽬が増減するので余計⼿間がかかりそう
ニュース⽤のカスタム投稿タイプ⾃体を
『NEWS設定』というカスタム投稿タイプで制御する
管理画⾯での表⽰例
NEWS設定の概要
1. カスタム投稿タイプ「NEWS設定」に、どんな名前の
NEWS⽤カスタム投稿タイプを作るか
「タイトル/スラッグ」を⼊⼒して投稿する
2. カスタム投稿タイプ「NEWS設定」に投稿された投稿を
get_posts()などで取得してループする
3. ループの中で カスタム投稿タイプを作成する
register_post_type() を書くと、NEWS設定に投稿した
分だけ新しくニュース⽤の投稿タイプが作成される。
NEWS設定を取得
// NEWS設定に投稿されている情報を取得する関数
function news_manage_news_settings(){
$args = array(
'posts_per_page' => -1,
'post_type' => 'news_setting',
);
$news_settings = get_posts($args);
return $news_settings;
}
予めカスタム投稿タイプ『NEWS設定( post_type = news_setting )』を
作成して複数投稿されている前提
NEWS⽤投稿タイプを⽣成
function news_manage_add_post_type_news() {
// NEWS設定に投稿されている投稿データを取得
$news_settings = news_settings();
// NEWS設定の情報をループしてカスタム投稿タイプを作る
foreach ($news_settings as $key => $news_setting) {
$labels = array(
'name' => $news_setting->post_title,
'singular_name' => $news_setting->post_title,
'menu_name' => 'NEWS [ '.$news_setting->post_title.' ]',
);
$args = array(
'labels' => $labels,
// 中略
);
register_post_type( $news_setting->post_name.'_news', $args );
}
}
add_action( 'init', 'news_manage_add_post_type_news' );
ポイント
• プラグイン Contact Form 7
• プラグイン Smart Custom Fields
• プラグイン VK All in one Expansion Unit の
カスタム投稿タイプマネージャー
カスタム投稿タイプを実際に表⽰するページ
情報ではなく、管理⽤の項⽬として使う
3-3.編集権限の設定
NEWSを編集出来る権限の設定
NEWS設定で作成されたカスタム投稿タイプ
→ 特定の部署のメンバーしか投稿できないように
記事を投稿・編集・削除出来る権限を設定しておく
$args = array(
// 中略
'capability_type' => array(
$news_setting->post_name.'_news',
$news_setting->post_name.'_newss'
),
'map_meta_cap' => true,
//中略
);
register_post_type( $news_setting->post_name.'_news', $args );
ユーザー権限の管理をどうするか?
プラグイン User Role editor ?
• 細かく設定できすぎる
→ 設定が⾯等
→ クライアントが使いこなせない
• 要望がイレギュラーすぎて既存のプラグインでは
存在すると思えない
⾃作しましょう!
ユーザー権限グループ管理機能
ユーザー権限管理⽤カスタム投稿タイプ追加
カスタム投稿タイプ「ユーザー権限グループ」を作成する
NEWS設定 で投稿されている情報
チェックボックスの⽣成
// NEWS設定に投稿されている情報を取得する関数
$news_settings = news_settings();
// NEWS投稿タイプをループしてチェックボックスを⽣成
echo '<ul>';
foreach ($news_settings as $key => $value) {
$news_post_type = $value->post_name;
$news_label = $value->post_title;
// チェックボックス出⼒
echo '<li><label><input type="checkbox"
name="edit_post_type_items[]" value="'.$news_post_type.ʼ”>'.
$value->post_title.'</label></li>';
}
echo '</ul>';
参考
/*-------------------------------------------*/
/* 権限グループ編集画⾯ _ 投稿タイプ別の⼊⼒フィールドの⽣成
/*-------------------------------------------*/
add_action('user_group_setting_meta_box', 'eam_user_edit_post_type_items',9);
function eam_user_edit_post_type_items(){
global $post;
wp_nonce_field( wp_create_nonce(__FILE__), 'noncename__edit_post_type_items' );
// 現在保存されている編集可能投稿タイプの値を取得
$edit_post_type_items = get_post_meta( $post->ID, 'edit_post_type_items', true );
// NEWS投稿タイプの情報を取得
$args = array(
ʻpost_typeʼ => ʻnews_settingʼ, // NEWS設定の投稿タイプ
ʻposts_per_pageʼ => -1, // 投稿を全件取得
);
$news_settings = get_posts($args);
// NEWS投稿タイプをループしてチェックボックスを⽣成
if ( $news_settings ){
echo '<ul>';
foreach ($news_settings as $key => $value) {
$news_post_type = esc_attr( $value->post_name );
$news_label = esc_html( $value->post_title );
// 既にチェックが保存されているものはチェックをつける
$checked = '';
if ( $edit_post_type_items && in_array($value->post_name, $edit_post_type_items) ) {
$checked = " checked";
}
// チェックボックス出⼒
echo '<li><label><input type="checkbox" name="edit_post_type_items[]" value="'.$news_post_type.'"'.$checked.'>'.$news_label.'</label></li>';
} // foreach ($news_settings as $key => $value) {
echo '</ul>';
} // if ( $news_settings ){
}
ここまでの状況
• カスタム投稿タイプ「ユーザー権限グループ」に
権限グループ情報が投稿されている
• 各権限グループには
編集可能なニュース⽤カスタム投稿タイプの情報が
カスタムフィールドに配列で保存されている
実際にユーザー権限を作成
WordPressのユーザー権限を発⾏する
権限を作成・更新するタイミング
カスタムフィールドを保存処理時
権限作成・更新⽤の関数を作成して実⾏させる。
ユーザー権限グループのロールを発⾏
function eam_update_role( $post_id ){
// 変更のあったユーザー権限グループの投稿
$post = get_post( $post_id );
$role_slug = $post->post_name;
$role_label = $post->post_title;
// 変更のあったロールだけ⼀旦削除
remove_role( $role_slug );
// ロールを再度作成
add_role( $role_slug, $role_label, array('read'=> true) );
}
ユーザーの権限グループに追加される
ユーザー権限グループに権限を設定
// 作成した各権限グループのロールを取得
$role = get_role( $role_slug );
// グループが編集可能に設定されている情報を取得
$edit_post_types = get_post_meta(・・・);
foreach ($edit_post_types as $key => $edit_post_type ) {
// チェックされている投稿タイプの権限を付与する
$role->add_cap( 'add_'.$edit_post_type' );
$role->add_cap( ʼedit_'.$edit_post_type' );
$role->add_cap( ʼdelete_'.$edit_post_type' );
(中略)
}
特定部署のユーザーでのログインイメージ
先⽅で編集権限の動作確認
____
/ \ /\ キリッ
. / (ー) (ー)\
/ ⌒(__人__)⌒ \ できたお
| |r┬-| |
\ `ー'´ /
ノ \
/´ ヽ
確認・承認はどうやるの?
/ ̄ ̄ ̄\
/ ─ ─ \
/ <○> <○> \.
| (__人__) |
\ ` ⌒´ /
/ \
は?
/ ̄ ̄\
/ノ( _ノ \
| ⌒(( ●)(●)
.| (__人__) /⌒l
| ` ⌒´ノ |`'''|
/ ⌒ヽ } | | __________て
/ へ \ }__/ / | | ̄ ̄ ̄ ̄ ̄ ̄ ̄| | |(
/ / | ノ ノ | | \ / | | |’, ・
( _ ノ | \´ _ | | \ ノ( / | | | , ’
| \_,, -‐ ''"  ̄ ゙̄''―---└'´ ̄`ヽ | | | て
.| __ ノ _| | | (
ヽ _,, -‐ ''" ̄|_ ̄_o o o___|_|r'"
( ディレクションに関するセッションではないので詳細は割愛 )
3-4.承認フロー実装します!
この部分のソースについて
処理が複雑でスライドでは紹介できないので、
スライドでは概念の説明のみとなります。
参考ソースコードを確認したい場合は
以下のURLにアップしてあります。
https://github.com/kurudrive/wc-kyoto-2017
承認フローの機能
• 公開権限を持つ/持たないユーザーグループ
• 下位権限のユーザーは新規投稿時に承認依頼をする
(公開権限を持たない)
• 下位権限のユーザーから承認依頼があって、
公開権限を持つユーザーが公開処理を⾏うと公開
• 下位権限ユーザーは公開中の記事も直接編集不可
公開権限の有無のグループ分け
公開権限の有無の設定
公開権限の有無の処理
// 作成した各権限グループのロールを取得
$role = get_role( $role_slug );
// 公開可能かどうかの情報を取得
$publish_role = get_post_meta(・・・);
// 公開権限があるユーザー
if ( $publish_role ){
$role->add_cap( 'publish_'.$edit_post_type.'s' );
$role->add_cap( 'publish_others_'.$edit_post_type.'s' );
$role->add_cap( 'edit_published_'.$edit_post_type.'s' );
$role->add_cap( 'delete_others_'.$edit_post_type.'s' );
$role-
>add_cap( 'delete_published_'.$edit_post_type.'s' );
}
下位権限のユーザーは承認依頼をさせる
1. この位置に
2. 公開権限を持つ
ユーザーのプルダウン
3. 承認依頼ボタン
// この位置に処理を追加
add_action( 'post_submitbox_start', '◯◯');
// 権限グループを取得
$roles = wp_roles()->roles;
承認依頼メールの送信
// 承認依頼ボタン
<input type="submit" name="send_review_mail" value="承認依頼">
function edit_flow__send_review_mail(){
// 承認依頼のボタンが押されたら
if ( isset($_POST['send_review_mail']) ){
// メール送信処理を書く
}
}
add_action('save_post', 'edit_flow__send_review_mail');
レビュー依頼メールの処理と内容
wp_mail()
→ メールを送信する事ができる
メールの本⽂に確認するURLを貼り付けておく
admin_url().'post.php?post='.$_POST['ID'].'&action=edit'
承認依頼のあった記事の公開・⾮承認
公開
⾮承認のメール送信
公開済の記事の編集(複製1)
「複製して編集」のリンクを追加
$links = admin_url().'post-new.php?post_type='.$post_type;
$links .= '&master_id='.$post->ID;
コピー元の投稿ID
公開済の記事の編集(複製2)
/*-------------------------------------------*/
/* 新規複製 _ 複製を実⾏
/*-------------------------------------------*/
function edit_flow__create_copy(){
// 管理画⾯のURLに複製識別⽤のURLが含まれていたら
if ( isset($_GET['master_id']) ){
$master_id = esc_html($_GET['master_id']);
// 記事の複製を実⾏
$copy_post_id = edit_flow__copy_post( $master_id );
// 複製した記事の編集画⾯へリダイレクト
$url = admin_url().'post.php?post='.$copy_post_id.'&action=edit';
header("Location: {$url}");
}
}
add_action('admin_init', 'edit_flow__create_copy');
公開済の記事の編集(複製3)
wp_insert_post() / add_post_meta()
を使って複製
POINT
複製元の記事(現在公開中の記事)IDを
カスタムフィールドに保存しておく。
公開承認処理
更新記事 公開記事
更新内容で上書き
更新記事を削除
4.請求書・⾒積書管理システム
主な機能
• 投稿に請求データを登録して請求書を発⾏
• 同様にカスタム投稿タイプで⾒積書も発⾏
• ⾒積書を wp_insert_post() で複製したり、
請求書のカスタム投稿タイプに複製
• クラウド会計ソフト⽤にCSV出⼒
CSVへの出⼒
実際のソースコード
https://github.com/vektor-inc/bill-vektor/blob/master/inc/export/class.csv-export.php
https://goo.gl/H3yKJc
CSV出⼒部分のソースは下記にあります
CSVダウンロードボタンに送信するvalueを指定
<button type="submit" name="action" value="csv_mf">
CSVエクスポート
</button>
CSVダウンロードを受け取ったらCSVを発⾏
function export_csv(){
// CSVダウンロードを押されたかどうか
if ( $_GET['action'] == 'csv_mf' ){
// 変数 $csv に 出⼒するCSVを成形
// httpヘッダーを記載
}
// CSVを出⼒
echo $csv;
// 終了
die();
}
add_action( 'init', export_csv );
httpヘッダーにcsvである事と⽂字コードを記載
header("Content-Type: text/csv; charset=utf-8");
utf-8の場合
header("Content-Type: text/csv; charset=shift_jis");
$full_csv = mb_convert_encoding( $full_csv, "SJIS" );
shift-jisの場合(エクセルなどで開く場合)
まとめ
カスタム投稿タイプ / カスタムフィールド
wp_insert_post() / add_post_meta()
wp_mail()
使い⽅次第でWordPressはなんでも出来る!
けれども
仕様はしっかり固めよう
Thank you.

愛と涙のWordPress無理やりカスタマイズ事例集