カスタム投稿タイプをタイプを用いてCSS/JavaScriptを一括を管理する方法

Cocoonカスタマイズ集
この記事は約12分で読めます。
記事内に広告が含まれています。

はじめに

Cocoonには、「カスタムHTML」ブロックとは別に、投稿ごと・固定ページごとにCSSやJavaScriptを直接記述できる機能が標準で用意されています。

ページ単位で細かな調整ができる点は便利ですが、実運用では次のような問題に直面することが少なくありません。

  • どのページにCSSやJavaScriptを設定したのか、管理画面から分からない
  • 同じCSSやJavaScriptを複数ページで使いたい場合、各ページに同じコードをコピーする必要がある
  • 修正が入った際、全てのページを探して更新しなければならない

これらは、サイト規模が大きくなるほど管理コストやミスの原因になります。

そこで、CSS・JavaScriptを専用の管理画面で一覧管理し、投稿ID・固定ページID・カテゴリー・タグ条件に応じて自動出力する仕組みを追加します。
この方法を使えば、どのコードがどのページで使われているかを一目で把握でき、同一のCSSやJavaScriptを複数ページで安全に再利用できるようになります。

この記事では、この方法について説明します。

完成イメージ

一覧
エディター

実装手順

以下のコードをfunctions.phpに追加します。

// カスタム投稿タイプを追加
add_action('init', function () {
  register_post_type('my_asset_snippet', [
    'label'     => 'JS・CSS管理',
    'public'    => false,
    'show_ui'   => true,
    'menu_icon' => 'dashicons-media-code',
    'supports'  => ['title'],
  ]);
});


// メタボックスを追加
add_action('add_meta_boxes', function () {
  add_meta_box(
    'asset_snippet',
    'JS / CSS 設定',
    'render_asset_snippet',
    'my_asset_snippet',
    'normal',
    'high'
  );
});


/**
 * メタボックスの入力フォームを出力
 *
 * @param WP_Post $post 投稿オブジェクト
 * @return void
 */
if (!function_exists('render_asset_snippet')):
function render_asset_snippet($post) {
  // nonceフィールドを出力
  wp_nonce_field('asset_snippet_action', 'asset_snippet_nonce');

  // 設定を取得
  $type   = get_post_meta($post->ID, 'my_asset_snippet_type', true) ?: 'css';
  $code   = get_post_meta($post->ID, 'my_asset_snippet_code', true);
  $pages  = get_post_meta($post->ID, 'my_asset_snippet_pages', true);
  $cats   = get_post_meta($post->ID, 'my_asset_snippet_cats', true);
  $tags   = get_post_meta($post->ID, 'my_asset_snippet_tags', true);
  $enable = get_post_meta($post->ID, 'my_asset_snippet_enable', true);

  ?>
  <p>
    <strong>種別</strong><br>
    <label>
      <input type="radio" name="asset-type" value="css" <?php checked($type, 'css'); ?>>
      CSS(head出力)
    </label>
    &nbsp;
    <label>
      <input type="radio" name="asset-type" value="js" <?php checked($type, 'js'); ?>>
      JavaScript(footer出力)
    </label>
  </p>

  <p>
    <strong>コード</strong>
    <textarea name="asset-code" style="width:100%;height:200px;"><?= esc_textarea($code); ?></textarea>
  </p>

  <p>
    <strong>投稿・固定ページID(カンマ区切り)</strong><br>
    <input type="text" name="asset-pages" value="<?= esc_attr($pages); ?>" style="width:100%;">
  </p>

  <p>
    <strong>カテゴリーID(カンマ区切り)</strong><br>
    <input type="text" name="asset-cats" value="<?= esc_attr($cats); ?>" style="width:100%;">
  </p>

  <p>
    <strong>タグID(カンマ区切り)</strong><br>
    <input type="text" name="asset-tags" value="<?= esc_attr($tags); ?>" style="width:100%;">
  </p>

  <p>
    <label>
      <input type="checkbox" name="asset-enable" value="1" <?php checked($enable, '1'); ?>>
      有効にする
    </label>
  </p>

  <?php
}
endif;


// 投稿データを保存
add_action('save_post_my_asset_snippet', function ($post_id) {
  // nonceチェック
  if (!isset($_POST['asset_snippet_nonce']) || !wp_verify_nonce($_POST['asset_snippet_nonce'], 'asset_snippet_action')) {
    return;
  }

  // 自動保存チェック
  if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
    return;
  }

  // リビジョンは除外
  if (wp_is_post_revision($post_id)) {
    return;
  }

  // 権限チェック
  if (!current_user_can('edit_post', $post_id)) {
    return;
  }

  // 値を保存
  update_post_meta($post_id, 'my_asset_snippet_type', sanitize_text_field($_POST['asset-type'] ?? 'css'));
  update_post_meta($post_id, 'my_asset_snippet_code', $_POST['asset-code'] ?? '');
  update_post_meta($post_id, 'my_asset_snippet_pages', sanitize_text_field($_POST['asset-pages'] ?? ''));
  update_post_meta($post_id, 'my_asset_snippet_cats', sanitize_text_field($_POST['asset-cats'] ?? ''));
  update_post_meta($post_id, 'my_asset_snippet_tags', sanitize_text_field($_POST['asset-tags'] ?? ''));
  update_post_meta($post_id, 'my_asset_snippet_enable', isset($_POST['asset-enable']) ? '1' : '0');
});


/**
 * 表示対象を判定
 *
 * @param int $snippet_id スニペットの投稿ID
 * @return bool
 */
if (!function_exists('asset_snippet_is_target')):
function asset_snippet_is_target($snippet_id) {
  // 設定を取得
  $pages = array_filter(array_map('intval', explode(',', get_post_meta($snippet_id, 'my_asset_snippet_pages', true))));
  $cats  = array_filter(array_map('intval', explode(',', get_post_meta($snippet_id, 'my_asset_snippet_cats', true))));
  $tags  = array_filter(array_map('intval', explode(',', get_post_meta($snippet_id, 'my_asset_snippet_tags', true))));

  // 指定なしは終了
  if (empty($pages) && empty($cats) && empty($tags)) {
    return true;
  }

  // 現在のページIDを取得
  $current_id = get_queried_object_id();

  // 投稿・固定ページ単位を確認
  if (!empty($pages) && in_array($current_id, $pages, true)) {
    return true;
  }

  // カテゴリー単位を確認
  if (is_category() && !empty($cats) && in_array($current_id, $cats, true)) {
    return true;
  }

  // タグ単位を確認
  if (is_tag() && !empty($tags) && in_array($current_id, $tags, true)) {
    return true;
  }

  return false;
}
endif;


/**
 * スニペットを出力
 *
 * @param string $type css|js
 * @return void
 */
if (!function_exists('render_asset_snippets')):
function render_asset_snippets($type) {
  if (is_admin()) {
    return;
  }

  // 有効かつ指定種別を取得
  $snippets = get_posts([
    'post_type'      => 'my_asset_snippet',
    'posts_per_page' => -1,
    'meta_query'     => [
      ['key' => 'my_asset_snippet_type', 'value' => $type],
      ['key' => 'my_asset_snippet_enable', 'value' => '1'],
    ],
  ]);

  foreach ($snippets as $snippet) {
    // 表示対象外は処理対象外
    if (!asset_snippet_is_target($snippet->ID)) {
      continue;
    }

    // コードを取得
    $code = get_post_meta($snippet->ID, 'my_asset_snippet_code', true);

    if (!$code) {
      continue;
    }

    // 種別に応じたタグを設定
    $tag = ($type === 'css') ? 'style' : 'script';

    echo "\n\n<{$tag}>\n{$code}\n</{$tag}>\n";
  }
}
endif;


// headタグ内でCSSを出力
add_action('wp_head', function () {
  render_asset_snippets('css');
}, 100);


// footerタグ内でJSを出力
add_action('wp_footer', function () {
  render_asset_snippets('js');
}, 100);


// 管理画面一覧にカラムを追加
add_filter('manage_my_asset_snippet_posts_columns', function ($columns) {
  $new = [];

  foreach ($columns as $key => $label) {
    $new[$key] = $label;

    if ($key === 'title') {
      $new['asset_enable'] = '有効 / 無効';
      $new['asset_type'] = '種別';
    }
  }

  return $new;
});


// 管理画面一覧のカラムにデータを表示
add_action('manage_my_asset_snippet_posts_custom_column', function ($column, $post_id) {
  switch ($column) {
    // 有効・無効を表示
    case 'asset_enable':
      echo get_post_meta($post_id, 'my_asset_snippet_enable', true) === '1' ? '有効' : '無効';
      break;

    // 種別を表示
    case 'asset_type':
      echo strtoupper(get_post_meta($post_id, 'my_asset_snippet_type', true) ?: 'css');
      break;
  }

}, 10, 2);

さいごに

今回紹介した方法を使えば、投稿や固定ページごとに分散しがちなCSS・JavaScriptを、専用の管理画面で一元的に把握・制御できるようになります。
どのコードがどのページで使われているのかが明確になり、同じCSSやJavaScriptを何度も書き直す必要もありません。
Cocoon標準機能やカスタムHTMLブロックの弱点を補いながら、保守性と安全性を高められる点が、この仕組みの最大のメリットです。
サイト規模が大きくなってきた場合や、将来的な修正コストを減らしたい場合に、特に効果を発揮するでしょう。

タイトルとURLをコピーしました