【目的別】WordPressの簡単カスタマイズ方法
ひらりんです。お久しぶりです。 今回はWordPressのカスタマイズ方法を目的別に書いてみようかと思います。
初級編から上級編まで。 ではいってみましょー!
目次
もくじ
初級編
中級編
上級編
( ˘ω˘)スヤァ
初級編
まずは簡単な初級編から
wp_list_categories()の記事数を<a>タグに含める
カテゴリ一覧を表示するために、WordPressがデフォルトで用意している関数。 いくつか引数を渡すことができ、show_count=1を指定するとカテゴリに紐づく記事数を一緒に表示してくれます。 その際、通常だとカテゴリページへリンクする<a>タグに記事数は含まれません。 例えばこんな感じ:
1 2 3 4 5 6 |
[sourcecode lang="html"] <ul> <li><a href="#">カテゴリ1</a> (10)</li> <li><a href="#">カテゴリ2</a> (7)</li> </ul> [/sourcecode] |
これを
1 2 3 4 5 6 |
[sourcecode lang="html"] <ul> <li><a href="#">カテゴリ1 (10)</a></li> <li><a href="#">カテゴリ2 (7)</a></li> </ul> [/sourcecode] |
こうしたい場合、wp_list_categoriesフィルターにフックします。 functions.phpなどに下記を追記してみてください。
1 2 3 4 5 6 7 |
[sourcecode lang="php"] function hoge($output) { $output = preg_replace('@</a>\s+?([0-9(),]+)@', ' $1</a>', $output); return $output; } add_filter('wp_list_categories', 'hoge'); [/sourcecode] |
※よい子のみんなはちゃんとしたメソッド名にしましょう。
ここでポイントなのは、記事数が1000を超えるとカンマがつくということ。 なので正規表現が\d+とかになってると無視されちゃいます。
投稿画面のカテゴリから”新規追加”と”よく使うもの”を非表示
使わないなら、いらないよね。 いらないなら、消しちゃおう。 ということで:
1 2 3 4 5 6 7 8 9 |
[sourcecode lang="php"] function hoge() { echo '<style type="text/css">' . '#category-adder { display: none; }' . '#category-tabs { display: none; }' . '</style>'; } add_action('admin_head', 'hoge'); [/sourcecode] |
※よい子のみんなは(ry
( ˘ω˘)スヤァ
中級編
お次はちょろっとプログラミングな中級編
ログイン画面のURLを変更
対クライアントでWordPressを使ったWEBサイトを制作したりしていると、 セキュリティ面をいろいろ考慮しなければいけない点があったりすると思いますが、 そんなひとつに”ログイン画面のURLを変更する”なんてのがあります。
WordPressセキュリティあるあるなので、その手の素晴らしいプラグインで ボタンひとつでできたりしますが、大人の事情によりプラグインが導入できない場合など こんな方法がありますよという紹介がてら:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
[sourcecode lang="php"] if (!defined('LOGIN_CHANGE_PAGE')) define('LOGIN_CHANGE_PAGE', 'naisyo.php'); add_action('login_init', 'login_init_hook'); add_action('site_url', 'action_site_url_hook', 10, 2); add_action('wp_redirect', 'action_wp_redirect_hook', 10, 1); /** * 指定以外のログインURLは403エラーにする */ function login_init_hook() { if ( !defined('LOGIN_CHANGE') || sha1('password') !== LOGIN_CHANGE ) { status_header(403); exit; } } /** * ログイン済か新設のログインURLの場合はwp-login.phpを置き換える */ function site_url_hook($url, $path) { if ( ($path === 'wp-login.php' || preg_match('/wp-login\.php\?action=\w+/', $path)) && (is_user_logged_in() || false !== strpos($_SERVER['REQUEST_URI'], LOGIN_CHANGE_PAGE)) ) { $url = str_replace('wp-login.php', LOGIN_CHANGE_PAGE, $url); } return $url; } /** * ログアウト時のリダイレクト先の変更 */ function wp_redirect_hook($location) { if (false !== strpos($_SERVER['REQUEST_URI'], LOGIN_CHANGE_PAGE)) $location = str_replace('wp-login.php', LOGIN_CHANGE_PAGE, $location); return $location; } [/sourcecode] |
上記をfunctions.phpなどに書いておきつつ、 変更した名前でwp-config.phpと同階層にファイルを作成します。 ここであれば”naisyo.php”という名前ですね:
1 2 3 4 5 |
[sourcecode lang="php"] <?php define('LOGIN_CHANGE', sha1('password')); require_once('./wp-login.php'); [/sourcecode] |
実際に変更するURLやハッシュ値などは適宜変更してください。 絶対にこのまま使わないでください。 絶対使うなよ? 絶対だぞ?
複数のカスタムフィールドでソート
カスタムフィールドでのソートといえば”meta_key”と”orderby=meta_value”を使ったおなじみの形が有名ですが、 WordPress 4.2から複数のカスタムフィールドでソートできるようになりました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
[sourcecode lang="php"] $the_query = new WP_Query(array( 'meta_query' => array( 'pickup' => array( 'key' => 'cf_item_is_pickup', 'value' => array(0, 1), 'type' => 'NUMERIC', 'compare' => 'IN' ), 'new' => array( 'key' => 'cf_item_is_new', 'value' => array("0", "1"), 'type' => 'CHAR', 'compare' => 'IN' ) ), 'orderby' => array( 'pickup' => 'DESC', 'new' => 'DESC', 'date' => 'DESC' ) )); [/sourcecode] |
上記のコードは”cf_item_is_pickup”というカスタムフィールドと、 “cf_item_is_new”というカスタムフィールド、更に記事の公開日によって 降順に並び替えが行われます。
ちなみに、WP_Queryの引数については下記がとっっっっっっっっっっても便利です!!!!!!
WP_Queryの使い方をPHPコードにまとめた便利なコード・スニペット
( ˘ω˘)スヤァ
上級編
ここからは上級編!
投稿画面の親カテゴリのチェックボックスを非表示
簡単な方法としては初級編でやった管理画面にCSSを追加する感じで非表示にしてしまえばいいのですが、 ここではwalkerクラスを拡張する形で実装してみます。 同じような方法でリスト系の挙動を自由に変更できるので、覚えておくと◎
まずはfilterを定義しましょう:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[sourcecode lang="php"] add_filter('wp_terms_checklist_args', 'wp_terms_checklist_args_hook'); function wp_terms_checklist_args_hook($args) { if ($args['taxonomy'] === 'category') { /** * 投稿画面再表示時にチェックされているカテゴリが一番上にくる挙動をキャンセル */ $args['checked_ontop'] = false; $args['walker'] = $GLOBALS['smv_walker_category_checklist']; } return $args; } [/sourcecode] |
ここではカテゴリチェックリストを表示するためのwalkerクラスを独自クラスへ変更しています。
次に独自クラスの実装:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
[sourcecode lang="php"] if (false === class_exists('Walker_Category_Checklist')) require_once(ABSPATH . '/wp-admin/includes/template.php'); /** * Class SmvWalkerCategoryChecklist */ class SmvWalkerCategoryChecklist extends Walker_Category_Checklist { function start_el(&$output, $category, $depth = 0, $args = array(), $id = 0) { if (empty($args['taxonomy'])) { $taxonomy = 'category'; } else { $taxonomy = $args['taxonomy']; } if ($taxonomy === 'category') { $name = 'post_category'; } else { $name = "tax_input[$taxonomy]"; } $args['popular_cats'] = empty($args['popular_cats']) ? array() : $args['popular_cats']; $class = in_array($category->term_id, $args['popular_cats']) ? ' class="popular-category"' : ''; $args['selected_cats'] = empty( $args['selected_cats'] ) ? array() : $args['selected_cats']; /** * 親カテゴリの場合はチェックボックスを表示しない */ if ($category->parent == 0) { $output .= "\n<li id='{$taxonomy}-{$category->term_id}'$class>" . '<label class="selectit"> ' . esc_html( apply_filters( 'the_category', $category->name ) ) . '</label>'; } else { $output .= "\n<li id='{$taxonomy}-{$category->term_id}'$class>" . '<label class="selectit"><input value="' . $category->term_id . '" type="checkbox" name="'.$name.'[]" id="in-'.$taxonomy.'-' . $category->term_id . '"' . checked( in_array( $category->term_id, $args['selected_cats'] ), true, false ) . disabled( empty( $args['disabled'] ), false, false ) . ' /> ' . esc_html( apply_filters( 'the_category', $category->name ) ) . '</label>'; } } } [/sourcecode] |
Walker_Category_Checklistを継承しつつ、start_el()のみオーバーライドしています。 また、念のため冒頭で親クラスが見つからなければrequire_once()で読み込んでいます。
あとはfunctions.phpなどで独自クラスをGLOBAL変数に突っ込むだけ!
1 2 3 4 5 6 |
[sourcecode lang="php"] if (false === class_exists('SmvWalkerCategoryChecklist')) { require_once('smv_walker_category_checklist.class.php'); $GLOBALS['smv_walker_category_checklist'] = new SmvWalkerCategoryChecklist(); } [/sourcecode] |
これで管理画面のカテゴリリストから親カテゴリのチェックボックスが消えると思います。 独自クラスの内容を書き換えれば他にもいろんなことができるのでお試しあれ。
独自パーマリンク設定の追加
WordPressといえばパーマリンクですが、案件によっては既存のルールから逸脱した独自パーマリンクが必用になるケースもありますよね。 例えばWordPressにAPIのエンドポイントを実装して、外部から特定の記事情報をjson形式で取得したい・・・なんて場合:
※下記コードはあくまでサンプルです。実際に使う場合はパラメータのサニタイズなどを行い、 SQLインジェクションなどを考慮して実装してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
[sourcecode lang="php"] <?php add_filter('query_vars', 'query_vars_hook'); add_action('parse_request', 'parse_request_hook'); add_action('init', 'init_hook'); /** * __apiパラメータを許可 */ function query_vars_hook($vars) { $vars[] = '__api'; return $vars; } /** * __apiがパラメータに含まれていた場合の処理 */ function parse_request() { if (get_query_var('__api', false)) { handle_request(); } } /** * リライトルールの追加 */ function init_hook() { add_rewrite_rule('^api/category/([^/]+)/?$', 'index.php?__api=1&filter=$matches[1]') } /** * 実際の処理 */ function handle_request() { $results = array(); $the_query = new WP_Query(array( 'post_type' => 'post', 'post_status' => 'publish', 'posts_per_page' => 10, 'tax_query' => array( 'taxonomy' => 'category', 'field' => 'slug', 'terms' => get_query_var('filter') ) )); if ($the_query->have_posts()) { while ($the_query->have_posts()) { $the_query->the_post(); $results[get_the_ID()] = array( 'title' => get_the_title(), 'excerpt' => get_the_excerpt(), 'date' => get_the_date() ); } } wp_send_json($results); die(); } [/sourcecode] |
こんな感じで追加できます。 あくまでサンプルなのでご容赦くださいませ。APIという視点から見てもいろいろ足りないコードです。 また、パーマリンク周りはコアロジックに関わる部分ですので、十分理解してから実装するようにしましょう。
参考1:Rewrite API « WordPress Codex 参考2:Rewrite APIその2 WordPressでアプリを作る基本(WordPressプラグイン開発のバイブルのボツ原稿から) | Shinichi Nishikawa’s
Advanced Custom Fieldsのrelationshipフィールドを特定の条件で絞り込む
カスタムフィールドといえば同じみのプラグイン、Advanced Custom Field。 弊社で扱うWordPress制のサイトには100%といっても過言ではないほどの勢いで入ってます。とりあえず入れとけ的な。 そんなACFのカスタマイズをご紹介します。
ACFで使いできるカスタムフィールドはいくつか種類がありますが、 その中でrelationshipフィールドというものがあります。
ここで候補にあがってくる記事や画像はACFの設定画面である程度制御することが可能ですが、 独自のルールを追加する場合はフィルターフックを用いて行います:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
[sourcecode lang="php"] add_filter('acf/fields/relationship/query', array($this, 'acf_fields_relationship_query'), 10, 3); public function acf_fields_relationship_query($options, $field, $the_post) { // 編集中の記事に設定されているカスタム分類を取得 $genre = get_the_terms($the_post->ID, 'genre'); if (!$genre || is_wp_error($genre)) // 取得できなかった場合は何もしない return $options; // 既にacfによってルールが形成されていることを考慮して初期化 $options['tax_query'] = array(); // 返された配列をforeachで処理 foreach ($genre as $v) { // 設定されているカスタム分類で絞り込みを行う為の条件を追加 $options['tax_query'][] = array( 'taxonomy' => 'genre', 'field' => 'id', 'terms' => $v->term_id ); } return $options; } [/sourcecode] |
こんな感じで編集中の記事に設定されているカスタム分類に紐づく記事を 候補として絞り込むことができます。
※編集中の記事には予めカスタム分類が割り当てられており、かつ一旦保存されている必用があります。
ACFには要所々で処理を変更するためのフックが用意されているので、 仕組みさえ分かってしまえば、要件にあわせてカスタマイズすることもそこまで難しくないかと思います。
( ˘ω˘)スヤァ
あとがき
普段文章を書かないので、なかなかに時間がかかりました。 やってることは過去に自分が作ったソースコードやらからコピペしてるだけなんですけどね・・・
と、いうことで、 いかがでしたでしょうか? フィルターフックやアクションフック、ウィジェットAPIなどを使えば やりたかったあんなことやこんなことが意外と簡単に実装できたりするかもしれません。 まずはどんなフックやAPIがあるか調べてみるところから初めてみましょうーーー
エンジニア募集!
ソニックムーブではエンジニアを募集しております! PHPによるWEB制作に興味のある方は下記応募リンクから気軽にご応募くださいませ! 女子歓迎(`・ω・´)シャキーン