WordPress 詰まったこと、使ったこと その1

最近 WordPress で詰まったこと、使ったことをメモしておきます。

f:id:jotaki:20190206105446p:plain

page.phppre_get_posts のクエリ書き換えがうまくいかない

固定ページである投稿タイプの一覧出して、ページ送りも実装して、としたかったのですが、仕様的に難しそう。

pre_get_posts は単一の固定ページのリクエスト(ページテンプレート)に対するクエリを変更するのに用いるべきではありません。なぜなら 'is_page'、'is_singular'、'pagename' および他のプロパティ(pretty パーマリンクを使っているかどうかによる)が parse_query() メソッドによってセットされた後だからです。

参考: プラグイン API/アクションフック一覧/pre get posts - WordPress Codex 日本語版

知らなかった。。また、

これと同様に、pre_get_posts はテンプレートファイル(例えば archive.php)内では動作しません。なぜならクエリが完了した後だからです。

とのことで、archive.php 等で扱う際にも注意が必要。

固定ページでページ送りを動作させる

という訳で、固定ページでページ送りを動作させる場合。
下記でうまくいきました。 参考: WordPress 小技集 – PageNavi を固定ページで使う –

page.php

<?php
  $paged = get_query_var('paged')? get_query_var('paged') : 1;
  $args = array(
    'paged' => $paged,
    'post_type' => 'post',
    'posts_per_page' => '10'
  );
?>
<?php $the_query = new WP_Query( $args ); ?>
<?php if ( $the_query->have_posts() ): ?>
  <?php while ( $the_query->have_posts() ): $the_query->the_post(); ?>
    <!-- ここにループ内容 -->
  <?php endwhile; ?>
<?php endif; ?>
<?php wp_reset_postdata(); ?>
<?php
  // ページネーション
  if(function_exists('wp_pagenavi')) {
    // サブクエリを引数で渡してあげる
    wp_pagenavi(array('query' => $the_query));
  }
?>

meta_query で複数条件

これも何度かやっている気がしますが、WP_Querymeta_query で複数条件で指定したい場合

pre_get_posts の場合

$meta_query = array(
  'relation' => 'AND',
  array(
      'relation' => 'OR',
      array(
        'key' => 'checkFlag01',
        'value' => '0',
        'compare' => '=='
      ),
      array(
        'key' => 'checkFlag01',
        'value' => '',
        'compare' => 'NOT EXISTS'
      ),
  ),
  array(
    'relation' => 'OR',
    array(
      'key' => 'checkFlag02',
      'value' => '0',
      'compare' => '=='
    ),
    array(
      'key' => 'checkFlag02',
      'value' => '',
      'compare' => 'NOT EXISTS'
    )
  )
);
$query->set( 'meta_query', $meta_query );

checkFlag01checkFlag02 というチェックボックスフィールド(meta_key)がない投稿の一覧などを表示する場合の例。

'value' => '0', 'compare' => '=='
'value' => '', 'compare' => 'NOT EXISTS' の 2 つ指定があるのは、フィールド作成前に更新した投稿と、フィールド作成した後に更新した投稿に対応するため

acf_the_content フィルター

記事投稿のデフォルトの Wysiwyg エディターから出力される内容 the_content を対象に <img><iframe> があったらそれを囲う <div> を付与するなどの対応を ACF の Wysiwyg エディターの出力内容にも反映させるには、acf_the_content を使う。

PhotoSwipe_fanc という PhotoSwipe プラグイン用の処理を加えた場合は下記のようになる。

functions.php

add_filter('the_content', 'PhotoSwipe_fanc');
add_filter('acf_the_content', 'PhotoSwipe_fanc');

WordPress で PhotoSwipe プラグインを使う

上記の例の functions の中身。これと

  • ライブラリ JS 読み込み
  • CSS 読み込み
  • フッターなどに <div class="pswp"~ のパーツ追加
  • main.js などに $('a.photo-swipe img:not("[data-size]")').each(function(){~ の追加

で動作確認。

functions.php

// PhotoSwipe 用のクラス付与
if ( !function_exists('PhotoSwipe_fanc') ) {
    function PhotoSwipe_fanc($content) {
        global $post;
        if ( $post->post_type == 'post' ) {
            $pattern = "/(<a[^>]*?href=['\"][^'\"]+?\.(?:bmp|gif|jpg|jpeg|png)(\?\S{0,}){0,1}['\"][^\>]*)>/i";
            $replacement = '$1 class="photo-swipe">';
            $content = preg_replace($pattern, $replacement, $content);
            if ( ! preg_match_all( '/<img [^>]+>/', $content, $matches ) ) {
                return $content;
            }
            $selected_images = $attachment_ids = array();
            foreach( $matches[0] as $image ) {
                if ( preg_match( '/wp-image-([0-9]+)/i', $image, $class_id ) && ( $attachment_id = absint( $class_id[1] ) ) ) {
                    $selected_images[ $image ] = $attachment_id;
                    $attachment_ids[ $attachment_id ] = true;
                }
            }
            if ( count( $attachment_ids ) > 1 ) {
                update_meta_cache( 'post', array_keys( $attachment_ids ) );
            }
            foreach ( $selected_images as $image => $attachment_id ) {
                $content = str_replace( $image, PhotoSwipe_fanc_set( $image, $attachment_id ), $content );
            }
        }
        return $content;
    }
    function PhotoSwipe_fanc_set($image, $attachment_id){
        global $post;
        if ( $post->post_type == 'post' ) {
            $image_src_full = wp_get_attachment_image_src( $attachment_id,'full' );
            if($image_src_full){
                $attr = 'data-size="'.$image_src_full[1].'x'.$image_src_full[2].'"';
                $image = preg_replace( '/<img ([^>]+?)[\/ ]*>/', '<img $1' . $attr . ' />', $image );
            }
        }
        return $image;
    }
    add_filter('the_content', 'PhotoSwipe_fanc');
    add_filter('acf_the_content', 'PhotoSwipe_fanc');
}

管理画面で権限ごとにクラス付与、要素非表示

User Role Editor や Adminimize でもできますが、軽めに非表示にだけする場合

参考: WordPress の管理画面にユーザー権限グループに応じた class を出力する – Simple Colors

// 管理画面で権限のclassをbodyに付与
function add_user_role_class( $admin_body_class ) {
    global $current_user;
    if ( ! $admin_body_class ) {
        $admin_body_class .= ' ';
    }
    $admin_body_class .= 'role-' . urlencode( $current_user->roles[0] );
    return $admin_body_class;
}
add_filter( 'admin_body_class', 'add_user_role_class' );

function my_dashboard_print_styles() {
?>
<style>
/* 編集者権限では「ツール」を表示しない */
.role-editor #menu-tools {
    display: none;
}
</style>
<?php
}
add_action( 'admin_print_styles', 'my_dashboard_print_styles' );

スマホでは管理画面バーを隠す

// スマホではアドミンバーを隠す
function hide_admin_bar_sp() {
    $output = '
    <style type="text/css">
        @media (max-width: 782px) {
            html {margin-top: 0 !important;}
            #wpadminbar {display: none;}
        }
    </style> ';
    echo $output;
}
add_action('wp_footer', 'hide_admin_bar_sp');