サイトマップをツリー表示する方法

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

完成イメージ

固定ページ

投稿

使用方法

以下にショートコードを示します。

[my_sitemap_tree]

実装手順

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

/**
 * 固定ページを階層構造で再帰的に表示
 *
 * @param WP_Post[] $pages 固定ページの配列
 * @param int $parent_id 親ページID(初期値0)
 * @return string 生成されたHTML
 */
if (!function_exists('sitemap_tree_render_pages')):
function sitemap_tree_render_pages($pages, $parent_id = 0) {
  ob_start();

  foreach ($pages as $page) {
    if ($page->post_parent == $parent_id) {
      $permalink = esc_url(get_permalink($page));
      $title     = esc_html($page->post_title);
      $children  = sitemap_tree_render_pages($pages, $page->ID);
      ?>
      <li class="sitemap-tree__item">
        <a href="<?= $permalink; ?>" class="sitemap-tree__link"><?= $title; ?></a>
        <?php if ($children): ?>
          <ul class="sitemap-tree__children"><?= $children; ?></ul>
        <?php endif; ?>
      </li>
      <?php
    }
  }

  return ob_get_clean();
}
endif;


/**
 * カテゴリーと投稿を階層構造で再帰的に表示
 *
 * @param array $cat_tree 親IDごとのカテゴリーマップ
 * @param array $post_map カテゴリーIDごとの投稿マップ
 * @param int $parent_id 親カテゴリーID
 * @return string 生成されたHTML
 */
if (!function_exists('sitemap_tree_render_categories')):
function sitemap_tree_render_categories($cat_tree, $post_map, $parent_id = 0) {
  if (empty($cat_tree[$parent_id])) {
    return '';
  }

  ob_start();

  foreach ($cat_tree[$parent_id] as $category) {
    $cat_id = $category->term_id;

    // 子カテゴリー群のHTMLを再帰取得
    $subcats_html = sitemap_tree_render_categories($cat_tree, $post_map, $cat_id);

    // このカテゴリーに属する投稿
    $posts = !empty($post_map[$cat_id]) ? $post_map[$cat_id] : [];

    // 子要素(子カテゴリまたは記事)が存在するか判定
    $has_children  = !empty($subcats_html) || !empty($posts);
    $li_class = $has_children ? 'sitemap-tree__category-item sitemap-tree__category-item--has-children' : 'sitemap-tree__category-item';
    $category_name = esc_html($category->name);
    ?>
    <li class="<?= esc_attr($li_class); ?>">
      <span class="sitemap-tree__category-name"><?= $category_name; ?></span>
      <?php if ($has_children): ?>
        <ul class="sitemap-tree__subcategory-list">
          <?php foreach ($posts as $post): ?>
            <li class="sitemap-tree__post-item">
              <a href="<?= esc_url(get_permalink($post)); ?>" class="sitemap-tree__post-link">
                <?= esc_html($post->post_title); ?>
              </a>
            </li>
          <?php endforeach; ?>

          <?= $subcats_html; ?>
        </ul>
      <?php endif; ?>
    </li>
    <?php
  }

  return ob_get_clean();
}
endif;


// ショートコードを追加
add_shortcode('my_sitemap_tree', function () {
  // 固定ページを一括取得
  $pages = get_pages(['sort_column' => 'menu_order']);

  // 全カテゴリーを一括取得
  $all_categories = get_terms([
    'taxonomy'   => 'category',
    'hide_empty' => false,
  ]);

  // 全公開投稿を一括取得
  $all_posts = get_posts([
    'post_type'   => 'post',
    'post_status' => 'publish',
    'numberposts' => -1,
    'orderby'     => 'title',
    'order'       => 'ASC',
  ]);

  // カテゴリーの階層マップを作成
  $cat_tree = [];
  if (!is_wp_error($all_categories)) {
    foreach ($all_categories as $cat) {
      $cat_tree[$cat->parent][] = $cat;
    }
  }

  // 投稿を所属カテゴリーに分類
  $post_map = [];
  foreach ($all_posts as $post) {
    $cats = wp_get_post_categories($post->ID);

    foreach ($cats as $cat_id) {
      $post_map[$cat_id][] = $post;
    }
  }

  ob_start();
  ?>
  <div class="sitemap-tree">
    <h2 class="sitemap-tree__heading">固定ページ</h2>
    <ul class="sitemap-tree__list">
      <?= sitemap_tree_render_pages($pages); ?>
    </ul>

    <h2 class="sitemap-tree__heading">投稿</h2>
    <ul class="sitemap-tree__list">
      <?= sitemap_tree_render_categories($cat_tree, $post_map, 0); ?>
    </ul>
  </div>
  <?php
  return ob_get_clean();
});


// フロント用JS・CSSを追加
add_action('wp_enqueue_scripts', function () {
  ob_start();
  ?>
  .sitemap-tree__category-item--has-children {
    > .sitemap-tree__subcategory-list {
      display: none;
    }

    &.sitemap-tree__category-item--active {
      > .sitemap-tree__subcategory-list {
        display: block;
      }

      > .sitemap-tree__category-name::before {
        content: '\f07c';
      }
    }

    > .sitemap-tree__category-name {
      cursor: pointer;
      padding-left: 1.5em;
      position: relative;

      &::before {
        content: '\f07b';
        font-family: 'Font Awesome 5 Free';
        font-weight: 900;
        left: 0;
        position: absolute;
      }
    }
  }

  .article .sitemap-tree {
    overflow-x: auto;
    white-space: nowrap;

    .sitemap-tree__list {
      li {
        list-style: none;
        margin: 0;
        padding-left: 1em;
        position: relative;
      }

      li {
        &::before {
          background-color: #333;
          content: '';
          height: 1px;
          left: -0.5em;
          margin: auto;
          position: absolute;
          top: 0.75em;
          width: 1em;
        }

        &::after {
          background-color: #333;
          bottom: 0;
          content: '';
          height: 100%;
          left: -0.5em;
          position: absolute;
          top: 0;
          width: 1px;
        }

        &:last-child::after {
          height: 0.75em;
        }
      }
    }
  }
  <?php

  $handle = 'sitemap-tree';

  wp_register_style($handle, false);
  wp_enqueue_style($handle);
  wp_add_inline_style($handle, ob_get_clean());

  ob_start();
  ?>
  jQuery(function ($) {
    $('.sitemap-tree__category-item--has-children > .sitemap-tree__category-name').click(function () {
      $(this).parent('.sitemap-tree__category-item--has-children').toggleClass('sitemap-tree__category-item--active');
    });
  });
  <?php
  wp_add_inline_script('jquery', ob_get_clean());
});

さいごに

今回紹介した方法を使えば、でサイトマップをLuxeritasのように階層表示できます。
固定ページや投稿を整理して表示できるため、訪問者が目的のページにアクセスしやすくなります。
また、カテゴリーごとに折りたたみ表示できるため、サイト構造が複雑でも見やすくなります。

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