カテゴリー: WordPress/php

  • All in One WP Migrationでコピーしたら下層ページが404になったときの対処方

    All in One WP Migrationを使って既存サイトを新規サーバーにコピーしたら、コピー先のサイトの下層ページが404になってしまった。

    パーマリンクを更新してみたけど直らないし、.htaccessを編集してみたけど全ページがトップページになってしまう!

     

    そんなときは、設定→パーマリンクの「パーマリンク構造」がコピー元と同じになっているか見てみましょう。

    どうもここの設定はコピーされないようです。違っていれば同じにしてみてください。

     

    以上、現場からでした。

  • All in One SEOのパンくず構造化データを削除

    All in One SEOのパンくず構造化データを削除

    WordPressのAll in One SEOは自動でパンくずの構造化データを出力してくれる。

    大変ありがたいんだけど、自前でプログラムを用意する場合や、他のプラグインを使いたくてちょっと邪魔になる場合もある。

    しかし管理画面から構造化データの出力をオフにすることはできないので、プログラムで書いてやる必要があるのであった。。

     

    実装

    こう!

    add_filter( 'aioseo_schema_output', 'aioseo_filter_schema_output' );
    
    function aioseo_filter_schema_output( $graphs ) {
        foreach ( $graphs as $index => $graph ) {
    		if ( 'BreadcrumbList' === $graph['@type'] ) {
    			unset( $graphs[ $index ] );
    		}
    
    		foreach ( $graph as $key => $value ) {
    			if ( 'breadcrumb' === $key ) {
    				unset( $graphs[ $index ][ $key ] );
    			}
    		}
    	}
    	return $graphs;
    }

     

    なお、All in One SEOが吐き出す構造化データを全部消したいときは、こう!

    add_filter( 'aioseo_schema_disable', 'aioseo_disable_schema_products' );
    
    function aioseo_disable_schema_products( $disabled ) {
       if ( is_singular( 'product' ) && aioseo()->helpers->isWooCommerceActive() ) {
          return true;
       }
       return $disabled;
    }

     

    以上、現場からでした。

  • WordPress – wp_queryでtermを選択していない記事のみ表示させる

    WordPress – wp_queryでtermを選択していない記事のみ表示させる

    wp_queryで、特定のtermを選択している記事を表示させるのはリファレンスに書いてあるとおり、

    $args = array(
    	'post_type' => 'post',
    	'tax_query' => array(
    		array(
    			'taxonomy' => 'people',
    			'field'    => 'slug',
    			'terms'    => 'bob',
    		),
    	),
    );
    $query = new WP_Query( $args );

    これでオッケー。

     

    じゃあ、termを何も選択していない記事だけ表示したいときはどうすんのということですが、ググったけどわからずChatGPTに聞いたら教えてくれたので、ググってこの記事にたどり着いてしまった人に共有しておきます。

    $args = array(
    	'post_type' => 'post',
    	'tax_query' => array(
    		array(
    			'taxonomy' => 'people',
    			'operator'    => 'NOT EXISTS'
    		),
    	),
    );
    $query = new WP_Query( $args );

    こうです!

     

    以上、現場からでした。

  • ローカルでメールを送信せずにMW WP Formのデバッグを行う

    ローカルでメールを送信せずにMW WP Formのデバッグを行う

    ローカルでXAMPPとかを使ってWordPressの開発を行っている際、MW WP Formの確認→完了の遷移や、メール本文の中身もテストしたい。

    そんなご要望にばっちりお応えする機能が、MW WP Formにはあります。




    実装

    wp-config.phpに、以下のように書きます。場所は define(‘WP_DEBUG’, false); の直下にでも。

    define('WP_DEBUG', false); // ←元からあるやつ
    define('MWFORM_DEBUG', true); // ←追加

    これだけで、MW WP Formのデバッグモードが有効になります。

    デバッグモード中は、送信ボタンを押してもメールは送信されませんが、メールが機能していなくても確認→完了画面の遷移が機能します。

    また、wp-content > uploads > mw-wp-form_uploads フォルダ内に、メール送信時のログが出力されます!

    これにより、メールを送信することなく、メールの中身を見ることが可能。公開されているサイトでも、メール送信なしで動作確認したい場合にも使えますね。

     

    現場からは以上です。

  • wp_get_archivesのリンクが404になるときの対処法

    wp_get_archivesのリンクが404になるときの対処法

    wp_get_archives()でカスタム投稿タイプの月ごとのアーカイブのリストを表示させたのに、リンク先が404になってしまう…

    そんなときの対策です。




    なぜ404になるんだい

    月別アーカイブページのURLって、デフォルトだと例えばnewsという投稿タイプであれば’/news/2021/08’みたいな感じだと思うんですけど、投稿タイプのパーマリンクを’/news/%post_id%’にしてしまっている場合、記事の詳細ページのURLが’/news/2021’って感じで、アーカイブのURLとかぶるんですよね。

    つまり、「‘/news/2021/08’ という記事はありませんよ」と誤って認識されちゃうみたいです。

    アーカイブページじゃなくて、記事ページとして認識されてしまっている。

     

    ということは記事のパーマリンク構造を変えればいけるのでは?ってなると思うんですが、記事のパーマリンク構造を変えるのはまぁいろいろきついです。

    ここは、もっと簡単なプランBでいきましょう。

    実装

    実は、月別アーカイブページには「/news/2021/08」ではなく「/news/date/2021/08」でもアクセスできることがあります。これはアクセスできないときもあるので、おそらく、パーマリンクを’/news/%post_id%’にしているとき限定で特別に用意されるパーマリンクなのかなと。

    これは実際この辺の仕組みを完全に理解しているわけではないので推測ではありますが、先ほどこのブログでも試しに記事のパーマリンクを’/%post_id%’にしたところ、「/date/2021/08」にアクセスできました。なので、間違ってはないと思います。

    というわけで、wp_get_archives()のリンクの文字列を無理やり書き換えちゃいましょう。

    wp_get_archives(); を書く場所を、以下のように変更。

    $args = array(
      'show_post_count' => true,
      'echo' => false,
      'post_type' => 'news'
    );
    
    $monthly_list = wp_get_archives( $args );
    $monthly_list = str_replace('/news/', '/news/date/', $monthly_list);
    echo $monthly_list;

    wp_get_archives()はそのままでは出力までしてしまうのですが、‘echo’ => falseを設定することで、文字列として変数に代入できます。
    さらに文字列を置換する関数str_replaceで、リンクの’/news/’を’/news/date/’に書き換えているわけですね。

    ちなみにですが、デフォルトの投稿(post)では、この処理はwp_get_archives()で自動でやってくれるみたいなので、やらなきゃいけないのはカスタム投稿タイプのときだけのようです。

    現場からは以上です。

  • WordPress 現在のページURLのややこしくない取得方法

    WordPress 現在のページURLのややこしくない取得方法

    WordPressの現在のURLを取得する方法を調べていたところ、get_the_permalink();を使う方法がよく紹介されていたのですが、なんか難しかったのでもっと簡単な方法がないかと、自分なりにシンプルにできる方法を考えてみました。




    実装

    get_the_permalink();ではなく、get_permalink(); を使用します。
    これは、引数に記事IDを入れることで、その記事のURLを取得することができる関数。

    つまり、今の記事のIDを取得して、get_permalink(); に入れればいいわけです。

    $current_url = get_permalink( $post->ID );

     
    以上、現場からでした。

  • WordPress カスタムフィールドをフリーワード検索に含める方法

    WordPress カスタムフィールドをフリーワード検索に含める方法

    WordPressの検索、便利なんですがカスタムフィールドには対応していません。

    というわけで、対応させましょう。




    実装

    デフォルトのフリーワード検索を使う場合。通常のフリーワード検索はタイトル、本文、カテゴリー、タグあたりを検索しますが、そこにカスタムフィールドも追加で検索できるようにするイメージです。

    functions.phpに以下のように書きます

    function cf_search_join( $join ) {
    	global $wpdb;
    	if ( is_search() ) {
    		$join .= ' LEFT JOIN ' . $wpdb->postmeta . ' ON ' . $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
    	}
    	return $join;
    }
    add_filter( 'posts_join', 'cf_search_join' );
    
    function cf_search_where( $where ) {
    	global $wpdb;
    	if ( is_search() ) {
    		$where = preg_replace(
    			"/\(\s*" . $wpdb->posts . ".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
    			"(" . $wpdb->posts . ".post_title LIKE $1) OR (" . $wpdb->postmeta . ".meta_value LIKE $1)", $where );
    
    		// 特定のカスタムフィールドを検索対象から外す
    //		$where .= " AND (" . $wpdb->postmeta . ".meta_key NOT LIKE 'number')";
    //		$where .= " AND (" . $wpdb->postmeta . ".meta_key NOT LIKE 'zip')";
    //		$where .= " AND (" . $wpdb->postmeta . ".meta_key NOT LIKE 'access')";
    	}
    	return $where;
    }
    add_filter( 'posts_where', 'cf_search_where' );
    
    function cf_search_distinct( $where ) {
    	global $wpdb;
    	if ( is_search() ) {
    		return "DISTINCT";
    	}
    	return $where;
    }
    add_filter( 'posts_distinct', 'cf_search_distinct' );

    特定のカスタムフィールドを検索対象からはずすこともできます。

    こちらの記事を参考にさせていただきました。ありがとうございます。
    WordPress内の検索対象にカスタムフィールドも適用する

     

    現場からは以上です。

    WordPress functions.phpを関数ごとに分割して管理しやすくする話

  • WordPress 一覧に「NEW」マークを表示させる

    WordPress 一覧に「NEW」マークを表示させる

    WordPressの記事一覧でよくある、公開して一週間の間は「NEW」を表示させるやつ。

    毎回テンプレートに直接プログラムを書くのは大変なので、関数を作って、表示させる日付も簡単に変更できるようにしましょう。




    実装

    functions.phpに、以下のように書きます

    function get_my_new( $limit = 7 ) {
      $days = $limit;
      $today = date_i18n('U');
      $entry = get_the_time('U');
      $kiji = date('U',($today - $entry)) / 86400;
    
      // 出力部分
      if( $days > $kiji ){
        $html = ' class="new"';
      } else {
        $html = '';
      }
      return $html;
    }

    $html = ‘ class=”new”‘;の部分を、表示させるNEWマークに合わせて変更してください。この場合は、newというclassをくっつける処理ですね。画像を出したり、テキストを出したり、なんでもできます。

    $limit = 7の部分で、デフォルトで何日表示させるかを設定できます。

    ※functions.phpは、以下の記事のように関数ごとにファイルを分けると、使いやすくなります。

    WordPress functions.phpを関数ごとに分割して管理しやすくする話

     

    あとはテーマ内でNEWマークを表示させたい部分に、

    <?php echo get_my_new(); ?>

    と書くだけです。

    ここで、

    <?php echo get_my_new(10); ?>

    のように引数を指定してやると、デフォルトでは7日だけど、この部分だけ10日表示させるといったことも可能です。

     

    以上、現場からでした。

  • WordPress、テーマ内で使う値が本番とテストで違う場合の対処法

    WordPress、テーマ内で使う値が本番とテストで違う場合の対処法

    WordPressを構築していたら、本番環境とテスト環境で違う値にしなきゃいけないことがあると思います。

    例えばMW WP Formをfnctions.phpでカスタマイズする場合、フックにフォームIDを使う必要があるわけですが、テストと本番ではIDが違う場合が多いです。

    そんなとき、テストから本番にアップする際は値を変えてアップする…なんてことをしていると、テストでは動かなくなるし、また違う日に違うカスタマイズを誰かがやらなきゃいけなくなったときに、その値を正しく変えてくれる保証はありません。いつの間にか動かなくなってるとか怖いですよね。そしてめんどくさい。そんなことを考えなきゃいけないのが何よりめんどくさい。

    というわけで、いい感じに解決しましょう。




    wp-config.phpに定数を定義する

    テスト環境と本番環境でほぼ間違いなく違っていて、そしてそう触ることのないファイル。
    それがwp-config.phpです。

    wp-config.phpには各環境のデータベース情報が書かれていますので、つまりその環境ごとに固有の設定が書かれているわけです。wp-config.phpは、テストで修正したものを本番にアップする際に、そのまま一緒にアップするということはまずないと思います。

    そんなwp-config.phpに定数を定義してあげれば万事解決。

    例えばテストでは

    /** MW WP Form ID Settings. */
    define('MW_WP_FORM_ID', 2222);

    とし、本番では

    /** MW WP Form ID Settings. */
    define('MW_WP_FORM_ID', 3333);

    こうしとく。

    ちなみにですが、この定数はwp-config.phpにもともと書かれている「/* 編集が必要なのはここまでです ! WordPress でブログをお楽しみください。 */」より上に書いてください。つまり「define(‘WP_DEBUG’, false);」の真下ですね。じゃないとうまく動かないです。

     

    そしてfunctions.phpのフック内では

    add_filter( 'mwform_choices_mw-wp-form-'.MW_WP_FORM_ID, 'mwform_add_birthday_options', 10, 2 );

    こうやって定数を呼び出してやれば、同じfunctions.phpをテスト/本番で使っていても、値はそれぞれ別になっていることになります。

     

    これで安心!いろんな面倒なことから解放されます。環境が他にもあったとしても使えますしね。

    以上、現場からでした。

  • WordPress 表示設定で「投稿ページ」に指定した固定ページのID取得

    WordPress 表示設定で「投稿ページ」に指定した固定ページのID取得

    WordPressの表示設定で、「投稿ページ」に固定ページを指定した場合の、指定された固定ページのIDを取得する方法。

    調べてもなかなか出てこなかったのでメモ




    実装

    取得するタグは以下

    get_option('page_for_posts')

    これで、投稿ページのIDを取得できます。
    IDさえ取得すればあとはなんとでもなる。

    例えば、投稿ページのURLを出力したい場合は

    the_permalink( get_option('page_for_posts') );

    と書けばOK。

     

    以上、現場からでした。

  • Advanced Custom Fieldsで「真/偽」を使ったときのmeta_queryの指定

    Advanced Custom Fieldsで「真/偽」を使ったときのmeta_queryの指定

    WordPressのカスタムフィールドを作れるプラグインAdvanced Custom Fieldsの「真/偽」を使って、「チェックした記事は一覧に表示させない(meta_queryで除外する)」方法を調べるのにけっこう時間がかかったので、備忘録として。




    その答えは、こうだ!!!

    $param = array(
    	'posts_per_page' => '3',
    	'post_type' => 'news',
    	'meta_query' => [
    		[
    			'key' => 'check_flag',
    			'value' => '0',
    			'compare' => '='
    		],
    	],
    );

    これで、「”check_flag”にチェックが入っていない記事」だけが表示されます。

    しかし、ここで要注意なんですが、既にある程度記事がある段階で真/偽フィールドを追加した場合、このままだとうまく除外できません

    なぜかというと、上記は具体的には「値がfalse(0)である記事のみ表示させる」という意味なんですが、なんと真/偽フィールドを追加する前から存在している記事は、チェックをしていない場合に入ってる値はfalseではなくNULLだからなんですね。
    そもそも値が入っていないのです。

    だから、そういった場合は上記に加え「NULLのやつも表示」って書く必要があります。

    $param = array(
    	'posts_per_page' => '3',
    	'post_type' => 'news',
    	'meta_query' => [
    		'relation' => 'OR',
    		[
    			'key' => 'check_flag',
    			'value' => '0',
    			'compare' => '='
    		],
    		[
    			'key' => 'check_flag',
    			'compare' => 'NOT EXISTS'
    		]
    	],
    );

    これでよし。

     

    おまけで、「”check_flag”にチェックが入っている記事」だけ表示したい場合はこう。

    $param = array(
    	'posts_per_page' => '3',
    	'post_type' => 'news',
    	'meta_query' => [
    		[
    			'key' => 'check_flag',
    			'value' => '1',
    			'compare' => '='
    		]
    	],
    );

    まぁ、こっちは公式に書いてるんですけどね。

     

    ついでにもう一つ、ちょっと応用編。

    例えばindex.phpとかarchive-news.phpで、WP_QUERYを使っていない場合。(条件なしで普通にループさせている場合。)
    こうなると、もし上記を実装するとなるとWP_QUERYを書かなきゃいけなくなって、カテゴリーページとか年別アーカイブも作って同じように実装して…ってやらなきゃいけないので、めちゃくちゃめんどくさいですよね。

    そんなときは、functions.phpで以下のようにやっちゃいましょう。

    add_filter( 'parse_query', 'custom_parse_query' );
    function custom_parse_query( $query ) {
      if ( is_admin() || is_singular() ) { // 管理画面とsingleは除く
        return false;
      }
    
      $check_flag_array = array(
        'relation' => 'OR',
        array(
          'key' => 'check_flag',
          'value' => '0',
          'compare' => '='
        ),
        array(
          'key' => 'check_flag',
          'compare' => 'NOT EXISTS'
        )
      );
      if ( get_query_var( 'post_type' ) == 'news' ) { //post_typeを指定
          $query->set( 'meta_query', $check_flag_array );
      }
    }

    これで、「post_typeがnewsの一覧(query)」で、同様の条件を指定することができます。

    もしnews以外も同じ条件を指定したい場合は、post_typeを増やすだけです。
    ※$query->is_main_query()も入れないと、index.phpで適応されないみたいです。

    add_filter( 'parse_query', 'custom_parse_query' );
    function custom_parse_query( $query ) {
      if ( is_admin() || is_singular() ) { // 管理画面とsingleは除く
        return false;
      }
    
      $check_flag_array = array(
        'relation' => 'OR',
        array(
          'key' => 'check_flag',
          'value' => '0',
          'compare' => '='
        ),
        array(
          'key' => 'check_flag',
          'compare' => 'NOT EXISTS'
        )
      );
      if ( get_query_var( 'post_type' ) == 'news' || get_query_var( 'post_type' ) == 'post' || get_query_var( 'post_type' ) == 'seminar' || get_query_var( 'post_type' ) == 'business' || $query->is_main_query() )
    }

    これでぐっと楽になりました。
    しかもなんと、RSSフィードにも表示されないみたいです!

     

    以上、現場からでした。

     

    よかったらこっちもどうぞ

    WordPress functions.phpを関数ごとに分割して管理しやすくする話

  • 「WordPress Popular Posts」でランキングを好きなように表示させるシンプルなやり方

    「WordPress Popular Posts」でランキングを好きなように表示させるシンプルなやり方

    WordPressで、記事の閲覧数ランキングを表示させるときに便利なプラグイン「WordPress Popular Posts(以下WPP)」。

    そのままウィジェットに突っ込めばランキング表示できるし、設定もいろいろできるしすごく良いですよね。

    ところが、表示の仕方をカスタマイズしたり、もっと好きな場所に好きなように表示させたいとなった場合、何やら関数を作ったりフックを使ったりしなきゃいけないようで初心者にはちょっとつらい。

    というわけで、初心者向けに超シンプルにフルカスタマイズできる方法をご紹介します。




    実装

    考え方は至ってシンプル。

    ①ランク順に「記事ID」を取得
    ②記事IDをもとに、WP_Queryで普通にまわす

    めっちゃ簡単にできそうでしょ!?

    できます。
    やっていきましょう。

    記事IDを取得

    <?php
    if ( function_exists( 'wpp_get_mostpopular' ) ){
      $wpp_option = array( // 表示オプションの設定
        'range' => 'weekly',
        'post_type' => 'post',
        'order_by' => 'views',
        'limit' => 5
      );
      $wpp_query = new WPP_Query( $wpp_option );
      $wpp_query_ids = array_map(
        function( $wppost ){
          return (int)$wppost->id;
        }, $wpp_query->get_posts()
      );
    }

    こんな感じです。

    $wpp_optionでは、表示オプションを配列にしてやります。

    WPPで使えるオプションは、「設定→WordPress Popular Posts→パラメーター」から確認できます。

    これで、”$wpp_query_ids”に、1~5位までの記事のIDが配列で格納されました。

    あとは、この配列を使って、WP_Queryで記事を表示させます。

     

    普通にループ

    おなじみのやつですが、“orderby => post__in”の部分がポイント。

    <?php
    $wp_query = new WP_Query();
    $param = array(
      'posts_per_page' => '5',
      'post_type' => 'post',
      'post__in' => $wpp_query_ids, // ここで記事IDの配列を使う
      'orderby' => 'post__in' // 配列に入ってる順番に表示
    );
    $wp_query->query($param);
    if($wp_query->have_posts()):
      while($wp_query->have_posts()) : $wp_query->the_post();
    ?>
    <p><a href="<?php the_permalink();"><?php the_title(); ?></a></p>
    <?php
      endwhile;
    endif; wp_reset_query();
    ?>

     

    ランクとか、閲覧数も表示させたい!

    WPPを仕様通り表示させると、簡単に閲覧数やランクを表示させることができますが、今回はIDだけ拾ってあとは普通のループに任せちゃってるので、表示させられないじゃん…

    しかしご安心ください。いけます。

    閲覧数の表示

    wpp_get_views()という関数を使います。

    ループ内で以下のように書けば、閲覧数を表示させることができます。

    <?php echo wpp_get_views($post->ID, 'weekly'); ?>

    上の例と合わせるなら、こんな感じ

    <?php
    $wp_query = new WP_Query();
    $param = array(
      'posts_per_page' => '5',
      'post_type' => 'post',
      'post__in' => $wpp_query_ids, // ここで記事IDの配列を使う
      'orderby' => 'post__in' // 配列に入ってる順番に表示
    );
    $wp_query->query($param);
    if($wp_query->have_posts()):
      while($wp_query->have_posts()) : $wp_query->the_post();
    ?>
    <p><a href="<?php the_permalink();"><?php the_title(); ?></a>(閲覧数:<?php echo wpp_get_views($post->ID, 'weekly'); ?>)</p>
    <?php
      endwhile;
    endif; wp_reset_query();
    ?>

    ランクの表示

    こっちはプログラミングでやっちゃいましょう。

    基礎中の基礎、「変数$iをループごとに1ずつ増やして表示させる」だけですね。

    <?php
    $wp_query = new WP_Query();
    $param = array(
      'posts_per_page' => '5',
      'post_type' => 'post',
      'post__in' => $wpp_query_ids, // ここで記事IDの配列を使う
      'orderby' => 'post__in' // 配列に入ってる順番に表示
    );
    $wp_query->query($param);
    if($wp_query->have_posts()):
      $i = 1; // 変数"$i"を定義
      while($wp_query->have_posts()) : $wp_query->the_post();
    ?>
    <p><?php echo $i; ?>位</p>
    <p><a href="<?php the_permalink();"><?php the_title(); ?></a>(閲覧数:<?php echo wpp_get_views($post->ID, 'weekly'); ?>)</p>
    <?php
      endwhile;
      $i++; // $iを1増やす
    endif; wp_reset_query();
    ?>

     

    おわり

    こんな感じで、難しく考えなくても、シンプルにランキングが実装できます。
    クライアントワークでも使えますね!

    僕は頭がよろしくないので、いつも難しいコードとか読むと発狂しそうになるんですが、だいたいは「IDさえゲットできればなんとかなる」と思っていて、とにかくまずはIDを取得することを考えるようにしています。

     

    ではでは、エクセレントなランキング表示を!

  • 「My WP Customize」で、特定の権限だけに設定を反映させる方法

    「My WP Customize」で、特定の権限だけに設定を反映させる方法

    WordPressで、クライアントに納品するとき、管理画面上で無駄な部分を非表示にするために今まで使っていた「WP Admin UI Customize」。

    すごく便利だったんですが、新しいプラグインに移行するため開発が終了するとのことで、今後使えなくなりそうです。

    その新しいプラグインが、「My WP Customize」。

    こちらは「WP Admin UI Customize」の上位種のようなものですが、どこをどう見ても、我々が一番ほしいであろう「特定の権限だけに設定を反映させる」設定画面が見当たらない

    これじゃ管理者にまで反映されちゃうじゃん、できないの?と思っていたのですが、できました。アドオンを使うみたいです。




    アドオンのダウンロード・インストール

    下記公式サイトにアクセスし、

    https://mywpcustomize.com/add-ons/

    「Select User Roles」を選択。

    飛んだページの下の方に、「Download」という項目があり、リンクがあるので、飛ぶ。

    するとgithubにたどり着きます。右上の「Clone or Download」→「Download ZIP」を選択すると、zipファイルがダウンロードできます。

    ファイルをダウンロードしたら解凍します。このzipのまま管理画面からアップロードはできませんので、注意してください。

    解凍したら、フォルダの中にある「mywp-select-user-roles」というフォルダを、FTPで「wp-content/plugins」の中にアップします。

    アップしたら管理画面を開き、「プラグイン」から「My WP Add-on Select User Roles」を有効にしましょう。

    これでようやくアドオンをインストールできました。

    設定

    アドオンを有効化したら、管理画面のメニュー「My WP」の子メニューに「ユーザー権限グループ」が追加されていると思いますので、見てみましょう

    こんな感じで、設定を反映させる権限を選択できるようになりました。

    やったね。

     

  • WordPress 固定ページ内でページネーションを使ったら404になる原因と対策

    WordPress 固定ページ内でページネーションを使ったら404になる原因と対策

    あんまりやりたくないパターンだけど、WordPressの固定ページテンプレート内で記事一覧を表示させ、あまつさえページネーションもつけたいというときがある。

    このページネーションの2ページ目以降が404になってはまったけど、動かない原因と対策がわかったのでメモ。




    なぜ404となるのか

    固定ページ内でページネーションを使うと404になる原因についてですが、たぶん以下のような感じだと思います。

    • ページネーションの仕様上、2ページ目とかのURLに、/page/2/とかがつく
    • 例えば/hoge/page/2/のようなパーマリンクになる
    • そんな固定ページはないので、404になる。

    まぁ、固定ページでそもそもページネーションできるようになっていないんでしょうね。そりゃそうよ。

    解決策

    /page/2/みたいにならなければいいんじゃないか。

    WordPressでは、上記のようなURL構造でなくとも、?page=2みたいなパラメータでもページネーションになります。

    ただし、デフォルトだと?page=2にアクセスしても、/page/2/にリダイレクトされてしまう。

    よって、ページネーションのURLの形式を?page=2にして、なおかつ勝手にリダイレクトさせないようにすればOK

    実装

    functions.phpに以下を記述

    add_filter('redirect_canonical','my_disable_redirect_canonical');
    function my_disable_redirect_canonical( $redirect_url ) {
    
        if ( is_archive() ){
            $subject = $redirect_url;
            $pattern = '/\/page\//'; // URLに「/page/」があるかチェック
            preg_match($pattern, $subject, $matches);
    
            if ($matches){
            //リクエストURLに「/page/」があれば、リダイレクトしない。
            $redirect_url = false;
            return $redirect_url;
            }
        }
    
    }

    続いて、ページネーションのほうは以下のようにする。

    <?php
    $paged = (int) get_query_var('paged'); // $pagedを定義。これがないとページネーションが動かないっぽい
    $wp_query = new WP_Query();
    $param = array(
      'post_type' => 'hoge',
      'paged' => $paged
    );
    $wp_query->query($param);
    if($wp_query->have_posts()):
    while($wp_query->have_posts()) : $wp_query->the_post();
    ?>
    ここで記事をループさせる
    <?php endwhile; endif; ?>
    
    <?php
    if ($wp_query->max_num_pages > 1): // ここからページネーション
    echo '<div class="new-pagenation">';
    echo paginate_links(array(
      'base' => get_pagenum_link(1) . '%_%',
      'format' => '?paged=%#%',
      'current' => max(1, $paged),
      'total' => $wp_query->max_num_pages,
      'next_text' => '次へ',
      'prev_text' => '前へ'
    ));
    echo '</div>';
    endif;
    ?>

    paginate_links()というナイスな関数を使うのが肝で、パラメータでURLのフォーマットを設定することができる。他にもいろいろパラメータを設定できる優れもので、僕もこんな関数があることを初めて知りました。具体的な使用方法はWordPress Codexを参照してください。

    次回以降普通のページネーションでもこれ使おう…

    あとは、paginate_links()で出力されるhtmlに合わせ、スタイリングしてやりましょう。

     

    以上、現場からでした。

    これでも動かない場合は、こっちも見てみてね。

    WordPress カスタム投稿でページネーションが404になる原因と解決法

  • WP-Membersの閲覧制限で、カスタムフィールドも非表示にする方法

    WP-Membersの閲覧制限で、カスタムフィールドも非表示にする方法

    WordPressで会員制サイトを作るためのプラグイン「WP-Members」、めっちゃ便利ですねこれ。

    会員登録機能も簡単に作れて、記事に閲覧制限もかけられる。

    ただし、閲覧制限で非表示になる部分は投稿コンテンツ(the_content();)のみなので、カスタムフィールドを使っている場合、カスタムフィールドにも閲覧制限設定を実装する必要があります。

    そんなに難しくないので、サクッとやっちゃいましょう。




    実装

    まず、「記事に閲覧制限をかけているかどうか」を取得します。下記を記事用テンプレートに記述。

    $block_flag = get_post_meta($post->ID, '_wpmem_block', true); // 閲覧制限のチェック

    閲覧制限がかかっていると、”$block_flag”に”1″が、かかっていないと”0″が入ります。

     

    続いて、カスタムフィールドの出力を制御します。

    if( !$block_flag || is_user_logged_in() ) {
      // ここに書かれたものは、「閲覧制限がない」または「ログインしているとき」に表示される
    }

    ややこしい言い回しになってしまいましたが、要するに「閲覧制限をかけていない場合か、ログインしている場合に表示される」というわけで、この中に書いたものは、閲覧制限で非表示になります。

    これを、カスタムフィールドが出力される場所ごとに書いてもいいんですが、面倒だし見づらくなるので、まとめちゃいましょう。

    例えばこんな感じ

    $block_flag = get_post_meta($post->ID, '_wpmem_block', true); // 閲覧制限のチェック
    
    if( !$block_flag || is_user_logged_in() ) {
      // カスタムフィールドの値を先に全部取得しとく
      $custom_url = get_field('custom_url');
      $custom_client = get_field('custom_client');
      $custom_editor = get_field('custom_editor');
    }
    
    // 以下、出力部分
    if( $custom_url ) {
      echo $custom_url;
    }
    if( $custom_client ) {
      echo $custom_editor;
    }
    if( $custom_editor ) {
      echo $custom_editor;
    }

    これで、「ログインしていないとそもそもカスタムフィールドの値を取得しない。カスタムフィールドの値がなければ、出力もされない」というロジックになりますので、コード量を大幅に削減でき、見やすくなります。

    この方法がまかり通らない場合(リピーターフィールド等)は、仕方ないので別個対応してあげましょう。

     

    以上、現場からでした。

  • WP_Queryで「タイトルもしくはカスタムフィールドに一致したら」という条件で検索

    WP_Queryで「タイトルもしくはカスタムフィールドに一致したら」という条件で検索

    WP_Queryでループの検索条件を文字列で絞り込むとき、だいたい以下のように書くと思います。

    <?php
    $wp_query = new WP_Query();
    $param = array(
      'posts_per_page' => '5',
      'post_type' => 'post',
      's' => '検索用テキスト',
      'post_status' => 'publish',
    );
    $wp_query->query($param); if($wp_query->have_posts()):
    // ここに出力を書く
    endwhile; endif; wp_reset_query();
    ?>

    普通は’s’のところに、検索のための文字列を入れますよね。

    ただ、これはデフォルトだとタイトルと投稿内容しか対象にならない。「カスタムフィールドも検索対象にしたいんじゃ!」ってこと、あると思います。

    ここで’s’も’meta_query’も普通に使っちゃうと、AND検索になります。なので、例えば「東京駅」で検索かけたときに、カスタムフィールドには入ってるけどタイトルには入ってないから検索結果に出ないということになっちゃうんですよね。それじゃ困る。

    「タイトルか、もしくはカスタムフィールドにあれば表示する」というOR検索にしたいわけです。

    そんなときは、こうしましょう。




    実装

    以下コードをfunctions.phpに記述

    add_action( 'pre_get_posts', function( $q )
    {
        if( $title = $q->get( '_meta_or_title' ) )
        {
            add_filter( 'get_meta_sql', function( $sql ) use ( $title )
            {
                global $wpdb;
    
                // Only run once:
                static $nr = 0; 
                if( 0 != $nr++ ) return $sql;
    
                // Modify WHERE part:
                $sql['where'] = sprintf(
                    " AND ( %s OR %s ) ",
                    $wpdb->prepare( "{$wpdb->posts}.post_title = '%s'", $title ),
                    mb_substr( $sql['where'], 5, mb_strlen( $sql['where'] ) )
                );
                return $sql;
            });
        }
    });

    そしてループの条件を以下のようにします。これは、カスタムフィールド「station」もしくはタイトルで、「東京駅」という単語でOR検索をかけるときの例。

    <?php
    $wp_query = new WP_Query();
    $param = array(
      'posts_per_page' => '5',
      'post_type' => 'post',
      'post_status' => 'publish',
      '_meta_or_title' => '東京駅',
      'meta_query' => array(
        array(
          'key' => 'station', // 検索をかけるカスタムフィールドのkey
          'value' => '東京駅',
          'compare' => 'LIKE'
        )
      )
    );
    $wp_query->query($param); if($wp_query->have_posts()):
    // ここに出力を書く
    endwhile; endif; wp_reset_query();
    ?>

    これでヨシ!

    以上、現場からでした。

  • WordPress カスタム投稿でページネーションが404になる原因と解決法

    WordPress カスタム投稿でページネーションが404になる原因と解決法

    WordPressで、「カスタム投稿タイプのページネーション2ページ目以降(2ページ目以降じゃなくても、nページ目以降で)が404になる」という現象にちょいちょい陥ったことがあるものの、いつもその場しのぎの応急処置しかしていなかったけど、今回それじゃだめな仕様を実装しなければいけなくなったので、その原因とちゃんとした解決法を調べた。




    現象が発生する条件

    この現象が発生するのは以下のとき。

    1. カスタム投稿タイプの一覧ページで、
    2. WP_Queryによる定義を行っており、
    3. ‘posts_per_page’で1ページの記事表示数を指定していて、
    4. 管理画面の「設定→表示→1ページに表示する最大投稿数」で設定した数値より3の数値のほうが小さいとき。

    つまり、管理画面で「1ページに表示する最大投稿数」を10にしていて、カスタム投稿タイプ”shop”の表示数を5とかにしたい場合、ページネーションがうまく機能しなくなる。

     

    原因

    この原因は、かいつまんで言うと

    WordPressさんが、表示させるテンプレートを決定する前に、管理画面から設定した値を参照する。このときはまだそのテンプレートに書かれたquery_postsは読まれていない。

    そして、テンプレートが読まれquery_postsが読まれた段階でも管理画面から設定した値は参照されたままになっており、2つの値がぶつかり合う

    という感じのようです。

    つまり、例えば

    • デフォルト投稿記事数が20
    • 管理画面からの設定数が10

    だった場合、デフォルト投稿は2ページ目まで表示されます。

    そしてなんと、カスタム投稿タイプもこれに合わせて2ページ目までしか表示されないということらしいです。

    カスタム投稿の記事数が30,管理画面の設定数が5だとしても、どんな値でもデフォルト投稿のページ数になってしまう。

    そういうことか。。。一見ほとんどバグじゃないかと思いますが、WordPressの仕様らしいのでしょうがないですね。

    しょうがないので、解決してみましょう。

     

    応急処置

    ググったらよく出てくるやつ。

    管理画面の最大投稿数を1にする

    シンプルでいいです。確かにこれなら理論上いけますね。

    簡単なテーマやサイトであればこれでいいと思いますが、「いや、それじゃ困る。なぜならデフォルト投稿の表示数も管理画面から設定できるようにしないといけないから」というパターン、あると思います。

    というわけで、もっと自然に解決する方法がこちら。

    自然に解決

    functions.phpに以下を記述

    <?php
    add_filter( 'parse_query', 'custom_per_page' );
    function custom_per_page( $query ) {
      if ( is_admin() || is_singular() || !is_main_query() ) { // 管理画面とsingleとメインループじゃない部分は除く
        return false;
      }
    
      if ( get_query_var( 'post_type' ) == 'event' ) {
          $query->set( 'posts_per_page', '6' );
      }
    }

    そして、テンプレート側では’posts_per_page’を指定しない

    カスタム投稿ごとに表示数を設定したい場合は、単純に増やせばOK

    <?php
    add_filter( 'parse_query', 'custom_per_page' );
    function custom_per_page( $query ) {
      if ( is_admin() || is_singular() || !is_main_query() ) { // 管理画面とsingleとメインループじゃない部分は除く
        return false;
      }
    
      if ( get_query_var( 'post_type' ) == 'event' ) {
          $query->set( 'posts_per_page', '6' );
      }
    
      if ( get_query_var( 'post_type' ) == 'blog' ) {
        $query->set( 'posts_per_page', '5' );
      }
    }

     

    以上、現場からでした。

    こっちの記事もどうぞ

    WordPress 固定ページ内でページネーションを使ったら404になる原因と対策

  • WordPress 「カスタマイズ」内のメニューを非表示にする方法

    WordPress 「カスタマイズ」内のメニューを非表示にする方法

    WordPressの管理画面、「外観→カスタマイズ」内にデフォルトで表示されているメニューたちを非表示にする方法。テーマによって追加で表示されている項目を非表示にする方法も添えて。

    なんだか苦戦しがちな「メニュー」項目も非表示にできました。




    実装

    functions.phpに以下を記述

    // カスタマイズからメニューを削除
    function my_custom_customizer( $wp_customize ) {
      $wp_customize->remove_section( 'add_menu' ); // メニュー
      $wp_customize->remove_panel( 'widgets' ); // ウィジェット
      $wp_customize->remove_section( 'colors' ); // 色
      $wp_customize->remove_section( 'static_front_page' ); // 固定フロントページ
      $wp_customize->remove_section( 'title_tagline' ); // サイト基本情報
      $wp_customize->remove_section( 'custom_css' ); // 追加CSS
    }
    add_action( 'customize_register', 'my_custom_customizer', 20 );

     

    テーマによっては他のメニューもあるかもしれないですね。そんなときは、以下のような流れで実装しましょう。

    カスタマイズ画面でコンソールを開く

    カスタマイズ画面でF12を押して、コンソールを開きます(Chrome)。

    ①非表示にしたい項目にカーソルを合わせ、
    ②<li>のソースを見てみましょう。

    例えば以下のようになってると思います。

    <li id="accordion-section-skin_section" class="...">
    

    この<li>のidが重要。

    今回の場合、

    accordion-section_skin_section

    黄色マーカーの部分”skin_section”を抜粋しremove_section()の引数とします。

    $wp_customize->remove_section( 'skin_section' );

    ちなみに、赤の部分がsectionではなくpanelだった場合、こうなります。

    $wp_customize->remove_panel( 'skin_section' );

     

    これでだいたいどんな項目も非表示にできますね!

    現場からは以上です。

  • WordPress ajaxがスマホで動かないとき、原因は全然違うところにあった

    WordPress ajaxがスマホで動かないとき、原因は全然違うところにあった

    WordPressでajax実装したのはいいけど、スマホで実機確認したら動いてない!読み込みに失敗してる!

    PCで動いてスマホで動かないってどういうことやねん…ajaxやぞ…そんなことあんのか…

    と長い間悩んでましたが、全然違うところに原因があってしんどかったという話です。




     

    管理画面にログインしているかどうかが問題だった

    スマホで動いてないのではなく、管理画面にログインしてないときに動いてなかったのです。なんてこった…ずっとログインしたまま作業してたからね…

     

    というわけで、管理画面にログインしてないときに動かない場合に見る部分はこちらです。

    /**
     * Ajax実装部分
     */
    function my_ajax_scroll() {
      // ここに処理を書く
    }
    add_action('wp_ajax_my_ajax_scroll', 'my_ajax_scroll');
    add_action('wp_ajax_nopriv_my_ajax_scroll', 'my_ajax_scroll');

    WordPressでAjaxを使うとき、functionsにこんな感じで関数を書き、add_actionしますね。
    この”wp_ajax_nopriv”のほうは「ログインしていないとき」に有効なadd_actionで、ここを忘れてたり間違えてたりすると、ログインしていない状態でうまくajax通信ができないということでした。

    以上、現場からでした。

  • Advanced Custom Fieldsで、チェックボックスの値を全部取得したい

    Advanced Custom Fieldsで、チェックボックスの値を全部取得したい

    WordPressのプラグイン「Advanced Custom Fields」で、チェックボックス(セレクトボックス)の値を、選択してないやつも含めて全部取得したい。

    例えば、「月火水木金土日」という選択肢があって、「火水」しか選択してなくても、とりあえずリストとして全部表示させたいわけである。

    これはけっこう長いこと悩んでいて、あれこれややこしい方法で実装してみては「ほんまにこれしかないんか…」と調査しまくっていたが、ついにめっちゃ簡単な方法を見つけたので備忘録。




    実装

    関数”get_field_object()”を使う。

    例えば、”custom_week”というカスタムフィールドに、「月~日」の選択肢を用意しており、更に土日を選択しているとき、値は以下のようになる。

    $week = get_field_object('custom_week');
    echo '<pre>';
    var_dump($week);
    echo '</pre>';
    
    // 以下、出力部分
    array(15) {
      ["key"]=>
      string(19) "field_59b111613d05f"
      ["label"]=>
      string(9) "営業日"
      ["name"]=>
      string(14) "custom_week"
      ["_name"]=>
      string(14) "custom_week"
      ["type"]=>
      string(8) "checkbox"
      ["order_no"]=>
      int(1)
      ["instructions"]=>
      string(0) ""
      ["required"]=>
      int(0)
      ["id"]=>
      string(24) "acf-field-custom_week"
      ["class"]=>
      string(8) "checkbox"
      ["conditional_logic"]=>
      array(3) {
        ["status"]=>
        int(0)
        ["allorany"]=>
        string(3) "all"
        ["rules"]=>
        int(0)
      }
      ["choices"]=>
      array(7) {
        ["月"]=>
        string(3) "月"
        ["火"]=>
        string(3) "火"
        ["水"]=>
        string(3) "水"
        ["木"]=>
        string(3) "木"
        ["金"]=>
        string(3) "金"
        ["土"]=>
        string(3) "土"
        ["日"]=>
        string(3) "日"
      }
      ["default_value"]=>
      string(0) ""
      ["layout"]=>
      string(10) "horizontal"
      ["value"]=>
      array(2) {
        [0]=>
        string(3) "土"
        [1]=>
        string(3) "日"
      }
    }

    “var_dump()”でデバッグしてしまえばだいたいわかるけど、この場合

    “$week[‘choices’]”

    で選択肢を配列で全部取得できる。あとはforeachで回すなりなんなり好きにしちゃいましょう!

    繰り返しフィールドだろうとなんだろうと、get_field_object()で全値をとって、var_dump()で中身を見てしまえばなんだってできるね。

     

    以上、現場からでした。