WordPress:プラグインなしでカスタムフィールドを追加する

WordPress:プラグインなしでカスタムフィールドを追加する

テーマをゼロから作ってみる(8)です。基本的な構造ができましたので SEO 関連に進みます。このプロジェクトのデモサイトを下のリンクで立ち上げています。

  • ゼロから作るWordPressテーマ(現在停止中)

01SEO 対策に必要なこと

SEO 対策に必要なことは何かといろいろ読んでみますと、どの記事もほぼ同じで次の項目をあげています。

  1. title の最適化と meta description の活用
  2. noindex, canonical で低品質なページをインデックスさせない
  3. JSON-LD による構造化データ出力
  4. SNS シェア用データの OGP 出力
  5. Google Analytics, search console 導入
  6. Google XML Sitemaps でサイトマップ出力
  7. サイト内の回遊率を上げる
    1. パンくずリスト
    2. 目次
    3. SNS連携機能
    4. 関連記事、人気記事の内部リンク
  8. サイト表示速度の最適化
    1. キャッシュの導入
    2. AMP の導入

これを順番にやっていこうと思います。

02title, meta description 用カスタムフィールド

まず、タイトルの最適化とメタディスクリプションです。

なお、ここでやっているのは最適化の方法などの話ではありません。最適化するためのツールといいますか、たとえば記事のタイトル(通常 h1 タグ)とは別にタイトルタグを設定したり、メタディスクリプションを出力するためにカスタムフィールドを利用する方法です。

add_meta_boxes でメタボックスの定義

まず、add_meta_boxes フックでメタボックスを登録します。メタボックスの定義は、admin_menu ではなく add_meta_boxes フックを使うことが推奨されています。

(Android 上の Chrome 限定の注意)
コードブロックをタップしますと数秒固まる場合があります。スクロール等他の操作に支障はありません。Chrome のバグとの報告が上がっています。詳細は「AndroidのChromeだけ固まる(止まる)ってどういうこと?!」をご覧ください。

// メタボックスの定義
function adding_custom_meta_boxes( $post ) {
    add_meta_box( 
        'imz-meta-box', // ID
        'IMUZA 拡張設定', // 表示タイトル
        'render_imz_meta_box', // HTML出力関数
        'post', // ページの種類
        'normal', // 表示位置
        'default' // 表示される優先度
    );
}
add_action( 'add_meta_boxes_post', 'adding_custom_meta_boxes' ); 

上から、ID, 表示タイトル, HTML 出力関数名, ページの種類, 表示位置, 表示される優先度となっています。ただ、表示位置(normal, advanced, side)と表示される優先度(high, core, low)は変更しても変化しませんでしたので今のところよくわかりません。とりあえずはドキュメントのまま使っています。

上は投稿ページのみの場合です。固定ページにも必要な場合は、

// メタボックスの定義
function adding_custom_meta_boxes( $post_type, $post ) {
    $types = ['post', 'page'];
    foreach( $types as $type){
        add_meta_box( 
            'imz-meta-box',
            'IMUZA 拡張設定',
            'render_imz_meta_box',
            $type,
            'normal',
            'default'
        );    
    }
}
add_action( 'add_meta_boxes', 'adding_custom_meta_boxes', 10, 2 ); 

こうですね。

HTML 出力関数

上に指定した関数 render_imz_meta_box() にカスタムフィールド入力用の HTML 出力コードを書いていきます。

// カスタムフィールドの入力エリア
function render_imz_meta_box() {
    global $post;
    $custom_fields = get_post_custom($post->ID);

    echo <<<EOM
<table class="form-table"><tbody>
<tr>
<th><label for="imz_keywords">タイトル</label></th>
<td><input class="large-text" type="text" name="imz_title" id="imz_title" value="{$custom_fields['_imz_title'][0]}"></td>
</tr>
<tr>
<th><label for="imz_description">メタ・ディスクリプション</label></th>
<td><textarea class="widefat" name="imz_description" id="imz_description" rows="4" cols="4">{$custom_fields['_imz_description'][0]}</textarea></td>
</tr>
<tr>
<th><label for="imz_keywords">メタ・キーワード</label></th>
<td><input class="large-text" type="text" name="imz_keywords" id="imz_keywords" value="{$custom_fields['_imz_keywords'][0]}"></td>
</tr>
</tbody></table>
EOM;
}

これで投稿ページに次のようなカスタムフィールドが出現します。get_post_custom() は次の項目で保存するデータを読み込んで初期値として出力しています。get_post_meta() で個別に取り出しても同じです。

「head スクリプト」以下は上のコードには含まれていませんがテーブルに追加していくだけです。

03save_post フックでカスタムフィールドの保存

// カスタムフィールドの値を保存
function save_imz_custom_fields( $post_id ) {
    if(!empty($_POST['imz_title'])){
	update_post_meta($post_id, '_imz_title', $_POST['imz_title'] );
    }else{
        delete_post_meta($post_id, '_imz_title');
    }
    if(!empty($_POST['imz_description'])){
        update_post_meta($post_id, '_imz_description', $_POST['imz_description'] );
    }else{
        delete_post_meta($post_id, '_imz_description');
    }
    if(!empty($_POST['imz_keywords'])){
	update_post_meta($post_id, '_imz_keywords', $_POST['imz_keywords'] );
    }else{
        delete_post_meta($post_id, '_imz_keywords');
    }
}
add_action('save_post', 'save_imz_custom_fields');

update_post_meta() は指定したキーがなければ add_post_meta() を呼び出しますので初回の登録でも問題ありません。

04title タグ, meta description タグを出力する

通常タイトルタグは functions.php に add_theme_support( ‘title-tag’ ) を書いておけば自動でページに応じたタイトルタグを出力してくれます(4.1以降)。記事ページでは記事のタイトルがそのままタイトルタグに利用されます。カスタムフィールドのタイトルはそれを変更して最適化するために使います。

たとえば、この「テーマをゼロから作ってみる」の目標である映画レビューサイト「そんなには褒めないよ。映画評」では、記事のタイトルは映画名ですが、それでは検索ワードが入りませんのでカスタムフィールドを使ってタイトルタグを差し替えます。

フィルターフック pre_get_document_title

pre_get_document_title を使います。

このフィルターは戻り値に空文字以外を返しますとそれがタイトルタグに使われます。

function custom_change_title( $title ) {
    if( is_single() ){
        $title = get_post_meta( get_the_ID(), '_imz_title', true );
        $title = esc_html( $title );
    }
    return $title;
}
add_filter( 'pre_get_document_title', 'custom_change_title' );

これを functions.php に書いておきます。カスタムフィールドにデータがあればそのデータがタイトルタグに使われ、空であればデフォルトのタイトルが使われます。

meta description タグを出力

メタディスクリプション、メタキーワードは、single.php の head タグ内に直書きします。

直書きではなく関数にしました。functions.php に書いておきます。

function get_imz_meta_description($id){
    $description = get_post_meta($id, '_imz_description', true);
    $keywords = get_post_meta($id, '_imz_keywords', true);
    if($description){
        echo '<meta name="description" content="' . esc_attr($description) . '" />' . PHP_EOL;   
    }
    if($keywords){
        echo '<meta name="keywords" content="' . esc_attr($keywords) . '" />' . PHP_EOL;
    }        
}

HTML出力は、

<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>" />
<?php get_imz_meta_description(get_the_ID()); ?>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<?php wp_head(); ?>
</head>
(略)

です。これで次のように出力されます。

SEO のやるべき対策の2の「noindex, canonical で低品質なページをインデックスさせない」も書こうと思いましたが長くなりましたので次回です。