LIGのメルマガ、はじめました!
LIGのメルマガ、はじめました!

たまに役に立つWordPressのカスタマイズ5選

づや

こんにちは、エンジニアのづやです。

ありがたいことに、この業界で15年程度生き抜くことができまして、質問を受けたりレビューをしたりする機会が多くなってまいりました。

しょっちゅう必要ではないのですが、カスタマイズが必要になった際に解決したことを今回まとめてみました。

非公開ページを親ページにしたい

皆様はWordPressをGutenberg(グーテンベルク)で使われているでしょうか。

URLを綺麗にしたいときなど、固定ページで非公開の親ページを選びたいときがありますよね。

page_attributes_dropdown_pages_argsとかquick_edit_dropdown_pages_argsにフックしてたと思うのですが、グーテンベルクになってからは、ここもrest apiで取得しているようで効かなくなってますよね。

add_filter( 'rest_page_query', function( $args, $request ) {

        $args["post_status"] = array( 'publish', 'private' );

        return $args;
    }, 10, 2 );

上記のフックが対応してるので、post_statusを適宜更新してあげましょう。orderとかももってるので、並びを変えたい場合もここで行いましょう。

ただ、APIなので表側でもこのAPI使っている場合は、条件分岐が必要です。

アップロードした特定の画像の命名規則を変更したい

WordPressでサイトを作成したら、メディアのアップロードをしますよね。特定の投稿タイプだったり、特定のカスタムフィールドの画像の名前を変更したいことってあると思います。

そんなときは下記のsanitize_file_nameフィルターを使って解決できます。これを使うと、引数にアップロードされたファイル名がもらえるので、ファイル名を変えたいだけならこいつでOKです。

add_filter( 'sanitize_file_name', function($name){

    // $nameにアップロードされたファイル名がくるので任意の名前に変更する

    // ファイル名を小文字にする例
    $name = mb_strtolower($name);

    return $name;
});

また、wp_unique_filenameというのも存在します。こいつはディレクトリ内に同じ名前のファイルが存在した場合は、被らないように拡張子の前に「-1」など連番を自動でつける処理をしてくれたあとに呼ばれます。

そのため、こいつでファイル名だけを変えたい場合は、ちょっと気を付ける必要があります。

アップロードした特定の画像のディレクトリを変更したい

ディレクトリを変更したい場合は、下記のupload_dirフィルターを使って処理を行います。

add_filter('upload_dir', function ($uploads) {

    /**
	$uploadsにはこんな感じで、パスだったりURLやディレクトリの情報が入ってきます。
	Array
	(
		[path] => /var/www/html/wp-content/uploads
		[url] => http://localhost/wp-content/uploads
		[subdir] => 
		[basedir] => /var/www/html/wp-content/uploads
		[baseurl] => http://localhost/wp-content/uploads
		[error] => 
	)
	*/

	// 行いたい処理に応じて適宜値を変更していきます
  // 例えばuploadsの下の特定の記事ID単位にしたい場合
  if (!empty($_POST['post_id'])
        && (isset($_POST['action']) && 'upload-attachment' === $_POST['action'])
    ) {
        // Uploaded from media component of image block
        $post_id = $_POST['post_id'];
    } elseif (isset($_POST) && 1 === count($_POST) && isset($_POST['post'])) {
        // Uploaded from image block
        $post_id = $_POST['post'];
    }
	
    // post_idを取得してこんな感じに処理を変更してあげます
    if (!empty($post_id)) {
        $uploads['subdir'] = $post_id;
        $uploads['path'] .= "/{$post_id}";
        $uploads['url'] .= "/{$post_id}";
    }

	return $uploads;
}

これは特定の投稿タイプだけディレクトリを変えたいときなどに、役に立つと思います。

記事の総件数を取得したい

ページネーションを作ったりで、現在使用しているwp_queryの件数を取得したいことがあるかと思います。

たまにposts_per_pagesに-1を取得して、全件取得してからそれをcountしているのですが、件数が増えてくると、パフォーマンスが非常に悪くなるので避けましょう。

wp_queryを通してデータを取得している場合は、使っているwp_queryが件数情報も取得しています。

// 総取得件数
$wp_query->found_posts

// 現在の取得件数での最大ページ
$wp_query->max_num_pages

// 現在表示している取得件数
$wp_query->post_count

こいつらと、現在のページをget_query_var( 'paged')とかで取得してあげればだいたい対応できるはずです。

wp_queryを使ってないときに取得したい場合はwp_count_postsが便利です。

$ret = wp_count_posts("post");	

/**
こんな感じでステータス毎の投稿タイプ毎の件数の取得が可能です
    stdClass Object
(
    [publish] => 14
    [future] => 0
    [draft] => 2
    [pending] => 0
    [private] => 0
    [trash] => 0
)
*/

全件取得して、PHPのcountとかで取得していくと、件数が増えたときにout of memoryにすぐなってしまいます。適切に使っていきましょう。

Google XML Sitemapsで特定の記事を動的に除外したい

Google XML Sitemapsでサイトマップを出力することが多いのですが、他のプラグインやカスタマイズしたカスタムフィールドでnoindexを制御したりすることってないでしょうか。

管理画面から「,」区切りで記事IDを入力すると、除外する記事を指定できますよね。

しかし1個ずつ手で入力するのは、人的ミスも発生しますし運用がしんどいのではないでしょうか。

そんなときは、下記のフックで対応ができます。

add_filter("option_sm_options" , function($options){
    $options["sm_b_exclude"] = array_merge($options["sm_b_exclude"] ,[ 
        // 除外したい記事IDの配列
    ]);


    return $options;
});

例えばYoast SEOを利用していて、管理画面からnoindexを設定したIDを、自動で除外したい場合なのはこんな感じでしょうか。

add_filter("option_sm_options" , function($options){

    // YOAST SEOのnoindex記事を除外したい
    $post_ids = get_posts([
        'fields' => 'ids' ,
        'post_type' => 'post', // 複数ある場合は複数指定する
        'meta_key'    => "_yoast_wpseo_meta-robots-noindex",
        'meta_value'  => "1"
    ]);

    $options["sm_b_exclude"] = array_merge($options["sm_b_exclude"] ,$post_ids);


    return $options;
});

Yoast SEOのサイトマップ機能を使えばいいんじゃないのと思われる方もいるかもしれませんが、いろんな事情により併用したいときがありますよね。

諸事情に関しては話すと長くなると今回は触れませんが、自前でnoindexを記事単位で制御してるときとかも使えるのではないかと思います。

最後に

見た目では動いていたりするけどパフォーマンスが悪かったり、検索してみると最新のコードで動かなかったりで、簡単なカスタマイズなのに想定以上の時間をもっていかれるときがありますよね。

そんなときはプラグインとかCoreのソースを追って解決することが多いので、こちらの記事がお困りの誰かのお役に立てれば幸いです。

ではまたどこかで。

M o n g o