WordPressで特定の投稿や固定ページにスタイルやスクリプトを挿入するカスタマイズ

WordPressのテーマ制作時に絶対といってよいほど加えるべき機能がこれです。

運用が始まる前はコンテンツ内容は固まっていますが運用段階が始まってしばらくたつと例外処理が発生します。

そんなときこの機能を用意しておくとテーマのcssファイルやjsファイルを変更する必要がなく、かつ本番系、開発系で処理をわけることが簡単になります。

内容的にはカスタムフィールドを使います。

今回のコードではカスタムフィールド「custom_header」を作成してコードを書くとheadタグ内にここに書いたコードが吐き出されます。

また、カスタムフィールド「custom_footer」を作成してコードを書くとbodyタグの一番下のほうにここに書いたコードが吐き出されます。

カスタムフィールドを設定したらfunctions.phpに以下のコードを記入します。

if ( ! function_exists( 'custom_header_css' ) ) :
function custom_header_css() {
    global $post;
    $field = 'custom_header';
    if ( is_singular() ) {
        $custom_block = get_post_meta( $post->ID, $field, true );
        if ( $custom_block ) {
            echo $custom_block;
        }
    }
}
add_action( 'wp_head', 'custom_header_css', $priority = 100 );
endif;

if ( ! function_exists( 'custom_footer_script' ) ) :
function custom_footer_script() {
    global $post;
    $field = 'custom_footer';
    if ( is_singular() ) {
        $custom_block = get_post_meta( $post->ID, $field, true );
        if ( $custom_block ) {
            echo $custom_block;
        }
    }
}
add_action( 'wp_head', 'custom_header_css', $priority = 100 );
endif;

これでいざとなった時に即座にスタイルとスクリプトを挿入できるようになります。

WordPressで直近1年分の記事を取得する方法

WordPressで過去1年分の記事を取得したい場合、テンプレートで以下のコードを描くと取得できます。

<?php 

$args = array(
    'post_type' => 'custom_post_type', // ここは取得したい投稿タイプを指定します
    'posts_per_page' => -1,
    'orderby' => 'date',
    'order' => 'DESC',
    'date_query' => array(
        array(
            'before' => 'now',
            'after' => '1 year ago',
            'inclusive' => true, // その日を含めるか真偽値で設定します
        )
    )
);
$my_query = new WP_Query( $args );

if ( $my_query->have_posts() ) :
    while ( $my_query->have_posts() ) : $my_query->the_post; ?>

        <!-- ここのコードはお好みで -->
        <article>
            <h1><?php the_title(); ?></h1>
            <?php the_content(); ?>
        </article>

    <?php
    endwhile; 
endif;
wp_reset_postdata();

ポイントはWP_Queryの引数内のdate_queryです。

date_query内のbeforeは戻る前の基準となる日付です。

コードではnowという文字列を記入することで現在を基準としています。

afterの値は過去のある時点をさします。

コードでは「1 year ago」という文字列を記入しています。1年前の今日を指定しています

これで直近1年分の投稿を取得することができました。

Nunjucksテンプレート内でjavascriptの関数を使用する

テンプレートエンジンnunjucksでテンプレートファイルにjavascript関数を使用することはできません。

例えば次のようなコードはコンパイラエラーになります。

{%- set currentTime = new Date() -%}

nunjucks使用の際はテンプレート内で関数を使うことはできません。

Nunjucksとは何なのか

Nunjucksはjavascript製テンプレートエンジンの一つです。

Firefoxで有名なMozillaによって開発されています。

Nunjucksで良い機能

  • 他のテンプレートエンジンpugやPHPのtwigのようにblock機能がついている。
  • pugもよいが普通のタグ構造がわからなくなる。
  • gulpを使わずともnpm-scriptで処理を記入することができる。

npmでNunjucksを使うまで

下記のようにコマンドを実行します。

mkdir projects

cd projects

npm init -y

npm i nunjucks-cli -D

npm init で生成されたpackage.jsonに下記コードを追加します

"scripts": {
    "build:html": "nunjucks ./src/templates/**/*.njk -p ./src/templates/ -o ./dist/" 
}

ここまで描いてsrcコードからdistコードに正しい書き方で保存されます

【WordPress】ファイルアップロード時にファイル名を自動で英数字に変換するコード

WordPressのメディアアップローダーで日本語のファイルをアップロードするとファイルがエンコードされます。

これを防ぐためにfunctions.phpに以下のコードを追加します。

if ( ! function_exists( 'my_rename_mediafile' ) ):

function my_rename_mediafile( $filename ) {
    $info = pathinfo( $filename );
    $ext = empty( $info['extension'] ) ? '' : '.' . $info['extension'];

    if ( $info['filename'] !== 'sitemap' ) {
        $filename = md5( time() . $ext );
    }
    return strlower( $filename );
}
add_filter( 'sanitize_file_name', 'my_rename_mediafile', 10 );

endif;

プラグインでも解決できる

日本語用プラグイン「WP Multibyte Patch」を一番最初に有効化しておけば上記のコードは必要ありませんでした…。

日本語のファイル名の画像は自動で英数字に変換されます。

日本語名ファイル名で起こる問題

なぜ日本語名ファイルがまずいのかというと…

  • 単純にエンコードされたファイル名が長すぎる
  • サーバー移行などの際にエラーが発生する可能性がある

などなど。

サーバー移行で失敗して最初から入れ直すとなったらとても辛いですね。
ボタン一つ二つの操作で綺麗に移行したいものです。

WordPressのdebugログの肥大化を防ぐ方法 安定運用のためにエラーに敏感になる

WordPressでは設定によってデバッグログをファイルに書き出してくれる機能があります。サイトが重くなったり処理が意図通りになっていない場合にこのデバッグログの内容を確認します。

デバッグログ出力設定方法

wp-config.phpファイルに定数を設定します。
運用環境と開発環境(ステージング環境)は若干処理を変更します。

▽開発環境

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );

▽本番環境

define( 'WP_DEBUG', true );
if ( WP_DEBUG ) {
    define( 'WP_DEBUG_LOG', true );
    define( 'WP_DEBUG_DISPLAY', false );
    @ini_set( 'display_errors', 0 );
}

このように書くと「wp-content」フォルダ内に「debug.log」というファイルが作成されます。
その後はログが発生した場合、このdebug.logに上書きされます。

debug.logの時間帯の注意

debug.logに書き込まれる時間はwp-settings.phpのtimezone設定に従うためデフォルトでUTC(協定世界時間)設定になるようです。
日本時間との差は9時間あるので気をつけてください。

date_default_timezone_set( 'Asia/Tokyo' );

強引に上記の記述で変更可能ですがWordPressの基準の日付が日本時間になってしまいすべて9時間未来になってしまうためdebu.logの時間変更のためだけに行うにはデメリットが多すぎるのでやめておきましょう。

debug.logはほっとくと肥大化する

debug.logファイルは上書きが基本なのでエラーがあるとファイルサイズが増えていきます。
気が付くとGBまで行ってしまいファイル操作も大変になります。

テキストファイルであってもGBもあればメモ帳アプリが開くことができない場合もあり調整が困難になります。

ログファイル肥大化の防止策

生成するログファイルを日別に生成するように変更できたら肥大化を避けられます。
具体的には下記のようにコードを修正します。

function wp_debug_mode() {
    /**
     * Filters whether to allow the debug mode check to occur.
     *
     * This filter runs before it can be used by plugins. It is designed for
     * non-web runtimes. Returning false causes the `WP_DEBUG` and related
     * constants to not be checked and the default PHP values for errors
     * will be used unless you take care to update them yourself.
     *
     * To use this filter you must define a `$wp_filter` global before
     * WordPress loads, usually in `wp-config.php`.
     *
     * Example:
     *
     *     $GLOBALS['wp_filter'] = array(
     *         'enable_wp_debug_mode_checks' => array(
     *             10 => array(
     *                 array(
     *                     'accepted_args' => 0,
     *                     'function'      => function() {
     *                         return false;
     *                     },
     *                 ),
     *             ),
     *         ),
     *     );
     *
     * @since 4.6.0
     *
     * @param bool $enable_debug_mode Whether to enable debug mode checks to occur. Default true.
     */
    if ( ! apply_filters( 'enable_wp_debug_mode_checks', true ) ) {
        return;
    }

    if ( WP_DEBUG ) {
        error_reporting( E_ALL );

        if ( WP_DEBUG_DISPLAY ) {
            ini_set( 'display_errors', 1 );
        } elseif ( null !== WP_DEBUG_DISPLAY ) {
            ini_set( 'display_errors', 0 );
        }

        if ( in_array( strtolower( (string) WP_DEBUG_LOG ), array( 'true', '1' ), true ) ) {
            $log_path = WP_CONTENT_DIR . '/debug.log';
        } elseif ( is_string( WP_DEBUG_LOG ) ) {
            $log_path = WP_DEBUG_LOG;
        } else {
            $log_path = false;
        }

        if ( $log_path ) {
            ini_set( 'log_errors', 1 );

          // ここで変数$log_pathに日付を追加すれば各日でログファイルを分けられる
          // ※コアファイルなのでWordPressをアップデートすると効かなくなる
            $log_path = WP_CONTENT_DIR . '/debug-' . date('Ymd') . 'log';

            ini_set( 'error_log', $log_path );
        }
    } else {
        error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR );
    }

    if (
        defined( 'XMLRPC_REQUEST' ) || defined( 'REST_REQUEST' ) || defined( 'MS_FILES_REQUEST' ) ||
        ( defined( 'WP_INSTALLING' ) && WP_INSTALLING ) ||
        wp_doing_ajax() || wp_is_json_request() ) {
        ini_set( 'display_errors', 0 );
    }
}

どうしても自動化したい場合こちらのコードで一時的に対応できます。
もしくはサーバー管理者に相談できるのなら差し替えプログラムを書いてもらいタイマー処理を用意してもらうことも考えられます。

自動処理はアップデートに対応できないので1週間、1か月などのスパンを決めてデバッグファイルをローカルもしくはクラウドに保存、確認しておくのが結局のところ良いのかもしれません。

【WordPress】テーマ開発-ブロックパターンの追加方法

WordPressのエディタがGutenbergに変わってしばらく経ちますがブロックエディタは進化してきて馴染んできたと思います。

特にブロックパターン機能はHTMLを書けない不慣れなユーザーにも扱いやすくするとても親切なツールです。

管理画面を扱うユーザーにとって一度わかってしまえばとても便利なのでブロックパターンは多用してなるべく多くのことを管理者自身にやってもらうことが良いと思います。

ブロッパターンの登録方法

まず下記のようなコードをfunctions.phpにかきます。

if ( ! function_exists() ):

function hoge_register_block_patterns() {
    register_block_pattern(
        $block_pattern_name, // ブロックパターンの名前
        array(
            'title' => "", // ブロックパターンのタイトル※こちらが表示されるタイトル
            'categories' => array('text'), // カテゴリを指定textは適当
            'description' => '', // パターンの説明。ここに指定してある文言が紹介文になる
            'content' => "", // ★ここにコンテンツ内容を入れる
            'keywords' => [], // キーワード検索でひっかけたい文字を指定する
            'viewportWidth' => 'ブロックパターンプレビュー時の想定幅'
        )
    )
}
add_action('init', 'hoge_register_block_patterns');
// @XXX hoge部分は適宜変更してください
endif;

functions.phpに用意が出来たら実際の投稿からパターンを作成

  1. 始めに実際の投稿画面で作成したいブロックパターンの素(もと)を作成する
  2. ビジュアルエディタ画面でCtrl+Shift+Alt+Mを同時押ししてビジュアルエディタからHTMLへブロックエディタの表示を変更する
  3. 1で作成した箇所をコピーする
  4. functions.php内のコードregiter_block_patternの’content’の値にコピーしたものを貼り付ける
  5. 貼りつけたコピーを汎用性の高いものに変更(例えば画像はplacehold.jpなどに変更したり)
  6. 管理画面からブロックパターンに追加されているか確認する

これでブロックパターンは気軽に登録することができます。

可能なかぎり管理画面を使いやすくして管理者に自信をもって操作してもらえるようにしましょう。

WordPressで投稿スラッグ(パーマリンク)を自動的に英数字に変更する方法とコード説明

WordPressの投稿を新規作成したとき、タイトルをつけると同時に投稿スラッグには日本語が入ります。

ブラウザがchromeなどのWEBブラウザで直接サイトを見ている場合は日本語スラッグでも一見問題ないように見えますが、
SNSなどでシェアした場合、日本語のスラッグは以下のようにエンコードされて貼り付けられてしまいます。

例えば、「日本語スラッグがよくない理由」などのタイトルをつけた場合、SNSシェア画面には設定されるスラッグは次のようになります。

▽スラッグ

%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%82%B9%E3%83%A9%E3%83%83%E3%82%B0%E3%81%8C%E3%82%88%E3%81%8F%E3%81%AA%E3%81%84%E7%90%86%E7%94%B1

※このスラッグの変換は下記のWEBサービスを利用して作成しました。

▽URLエンコード・デコード
https://tech-unlimited.com/urlencode.html

いまいちこの使い時がわかりませんでしたがデコードのほうが使う機会が多いかもしれません。

さて、日本語のスラッグをエンコードされた文字列リンクですがこれだと怪しいサイトに飛ばされる気がしてなかなかリンクをタップする気にはなりません。

SNSからの流入は大きな影響があるのでやはり日本語のスラッグはやめて英数字でスラッグを作成するべきです。

ただ、他の業務で忙しい片手間WEBサイト担当者がその都度スラッグを考えるのはかなり手間に感じることでしょう。

そんな場合は、投稿スラッグを勝手に英数字にかえてしまう処理を用意してあげると運用コストを減らせるのでよいと思われます。

functions.phpに以下のコードを書くと投稿スラッグが日本語になってしまいそうな場合に勝手に英数字に変更してくれます。

if ( ! function_exist( 'auto_post_slug' ) ) :
function auto_post_slug( $slug, $post_id, $post_status, $post_type ) {
    if ( preg_match( '/(%[0-9a-f]{2})+/', $slug ) ) {
        $slug = utf8_uri_encode( $post_type ) . '-' . $post_id;
    }
    return $slug;
}
add_filter( 'wp_unique_post_type', 'auto_post_slug', 10, 4 );
endif;

このコードの内容を説明すると

  1. 投稿スラッグが「%」から始まり次の文字が2桁の英数字に該当する文字だったら、つまりマルチバイトをエンコードした結果生成される文字だったら
  2. 投稿のpostタイプをutf8_uri_encodeという関数に適用させる
  3. それにハイフンと投稿IDをつなげる
  4. それをスラッグとして設定する

という処理になります。

これで日本語スラッグを避けて記事を投稿できるようになります。

WordPressのプラグイン「intituive custom order」の並べ替えがRestAPIで効かない場合の対処法

WordPressのプラグイン「intituive custom order」はドラッグで並び順を変更できるとても便利なプラグインです。このプラグインを有効化してクエリのorderbyに「menu_order」という値を設定するだけでドラッグで直感的に変更した並び順に値を取得できます。

しかし、RestAPIでクエリを投げた場合orderby=menu_orderが利かなくなってしまうことがあります。理由はRestAPIではデフォルトでorderbyに「menu_order」を指定することはできなくなっているからです。

そういう時はfunctions.phpに以下のコードを追加するとmenu_orderを使用できるようになります。

if ( function_exist( 'my_prefix_add_rest_orderby_param' ) ):
function my_prefix_add_rest_orderby_param($params) {
    $params['orderby']['enum'][] = 'menu_order';
    return $params;
}
add_filter('rest_{post_type}_collection_params', 'my_prefix_add_rest_orderby_params', 10, 1);
endif;
// *{post_type}はカスタム投稿であればスラッグを指定する

説明できますか?わかった気になるjavascriptのモジュール。

javascriptのimport文を使用するモジュール機能ですが、いままでNext.jsやReactのサンプルコードなどで多く使用されていたためあまり考えずに使用していましたが後輩に簡単に説明できるぐらいに知っておこうと思い調べてみました。

WEBブラウザ上では外部javascriptファイルを読み込むときにはその都度、scriptタグで読み込むしかありませんでした。しかし、WEBブラウザがjavascriptの新しいバージョンに対応していくうちにjavascriptでも外部ファイルを読み込むことができるようになり、これからはjsファイルの分割化が通常になっていくと思われます。

モジュールとはなにか?

javascriptの分割されたコードの塊のことを「モジュール」と呼びます。javascriptの一般的なブラウザ対応バージョンES5ではモジュール機能はありません。IE11を除くことで利用可能になるES5の次のバージョンES2015ではモジュール機能は標準装備されるようになりました。

モジュールパターン

ES2015ができるまではモジュールがなかったのでモジュールのように使うために「モジュールパターン」という疑似的に生み出すコードの工夫でモジュールのように使えるようにしていました。

しかし、このモジュールパターンはjavascriptによくある問題「グローバル変数の汚染」というデメリットをもっていました。

そのデメリットを解消しようとあらたに「CommonJS」「AMD」などの仕様が生まれました。

これによってモジュールは実現に近づきましたがCommonJS、AMDはECMAScript標準とは違う枠組みで策定されたのでブラウザが解釈(使用)できませんでした。

そのため、CommonJS、AMDを使用して作成されたモジュールはBrowserifyやRequireJSなどのモジュールバンドラを使用してブラウザでも解釈可能なコードに変換する必要がありました。

ES5標準のブラウザ環境時代(IE11 がはびこる時代)ではjavascriptのモジュール化はかなり面倒くさいことになっていたのです。

ES2015でモジュールが標準仕様に追加

ES5の次のバージョンES2015ではモジュール機能が標準仕様に追加されたのでブラウザでもモジュールがモジュールバンドラを使用せずに使えます。さらに2022年6月のIE11のサポート対象外化によってモジュール使用がグッと身近になってきました。

ただしモジュールを使用するにあたって注意があります。これをあらかじめ知らないとハマる可能性があるので頭の隅にいれておくかノートアプリに保存しておくとよいでしょう。

モジュール使用時の注意点

  1. scriptタグにtype=”module”属性を追加しないと動かない
  2. ローカルで呼び出すとクロスオリジン制約に引っかかってエラーになる

2を詳しくいうとデスクトップなどにフォルダを作ってindex.html、index.js、module.jsのファイルを作成してテストした場合(htmlファイルをダブルクリックでブラウザで読み込んだ場合)httpから始まっていないのでCORSに引っかかり意図しない結果になります。これはhttpからはじまるようにサーバーを立ててテストすれば解消されます。

サーバーの立て方はいろいろありますが例えば、

  • npm でbrowser-syncを使う
  • dockerでnginxもしくはapachでwebサーバーを用意する
  • xampp、mampを使う
  • 実際にサーバーにアップする

などが考えられます。 browser-syncかdockerがおすすめです。

はまると面倒!?Instagramのタイムラインをサイトに表示させる方法

「facebookのページプラグインやTwitterの埋め込みタイムラインのようにインスタグラムの投稿をサイトに表示させたい」という要望があることがあります。しかしfacebookのページプラグインやTwitterのタイムラインのように気軽に表示することができません。表示するにはひと手間、ふた手間かかるので注意が必要です。

最初の疑問「インスタグラムとfacebookの運用はお客さんがやってるんだけどホームページに埋め込めるの?」

結論から先に言えば、対象のSNSアカウントをもっている人に動いてもらえれば可能です。ただし、アカウントの持ち主に動いてもらう内容がかなり複雑になるのです。

ホームページに埋め込む前に必要なものがある

インスタグラムタイムラインを埋め込むためには以下の条件を満たす必要があります。

  • facebookアカウントを持っている
  • facebookページを持っている
  • instagramのアカウントを持っている
  • developers facebookのアカウントを持っている

最低限この条件が必要なので満たしていない場合は作成します。

developers facebookの準備が厄介

facebookアカウントとinstagramのアカウント作成、facebookページの作成は比較的簡単です。むしろfacebookとinstagramのアカウントを持っているからホームページに埋め込みたいという要望が出てくるのでしょう。

しかし、developers facebookだけは登録が厄介です。特にweb制作に詳しくないお客が作らないといけない場合は厄介です。携帯電話番号登録からのSMSアカウント認証もありますので代表電話で登録することができません。携帯電話番号は認証時に使用するだけと思われますので登録後はアカウント設定で電話番号を変更しておくとよいかもしれません。