自分だけのクイズ作成 - Quipha公開中

【WP】【Cocoon】固定ページの子ページ一覧表示

Wordpress
スポンサーリンク

はじめに

今回は、固定ページの子ページ一覧を表示するカスタマイズを行います。
ウィジェットで使用できるようにしてみました。

例えばコーポレートサイトや、マニュアルサイトでも便利に使えると思います。
このように、サイドバーに固定ページの子ページの一覧を表示するようにしてみます。

イメージとしては、Cliborのサイトをご覧ください。

Cliborのサイトは、厳密には今回の対応とは別なカスタマイズをしていますが、雰囲気は同じです。

本記事は、functions.phpの修正を含みます。修正前にバックアップを行いましょう。
修正については、自己責任でお願いします。

子ページリスト仕様

固定ページにて、子ページの一覧を表示するウィジェットを作成します。
まずは、以下のように親子の固定ページを作成したとします。

子ページは一階層のみ対応しました。二階層目以降は想定していません。

ウィジェットでは以下のように、子ページの表示を設定できるようにします。(ナビカードと同様)

子ページを持つ固定ページを表示した場合、サイドバーに子ページ一覧が表示されます。(または親ページを持つ子ページを表示した場合)
ウィジェットのタイトルは、親ページのタイトルが設定されます。

子ページを開いている場合、現在開いているページのカードをハイライトします。

Cocoonのインストールについて

Cocoonのインストールについては、以下の記事を参考にして下さい。

必ず子テーマを有効にします。

スポンサーリンク

参考ウィジェットの確認

Cocoonの既存のソースで、参考になるものがないか探します。
今回は「ナビカード」を参考にしました。

該当のソースは以下です。
今回は、このソースを参考にしながら進めていきたいと思います。

\cocoon-master\lib\widgets\navi-entries.php

一から作る前に一度、既存のソースを確認することをオススメします。
参考にできるもの、流用できるものなどあれば、活用しましょう。

それでは早速、オリジナルのウィジェットを作成していきましょう。

子ページ一覧ウィジェットの作成

ソースの全容は最後に再掲しますが、順番にソースを見ていきましょう。

子テーマのfunctions.phpを開きます。
これ以降のソースコードは、全てfunctions.phpに追記していきます。

\cocoon-child-master\functions.php

必ず子テーマのソースを修正しましょう。親テーマの修正はNGです。

ウィジェットの作成

まずは管理画面で配置できるウィジェットを作成しましょう。

ウィジェット名は、「ChildPageWidgetItem」としました。

まずは最低限のウィジェットのコードを記述します。

add_action('widgets_init', function () {
  register_widget('ChildPageWidgetItem');
});
class ChildPageWidgetItem extends WP_Widget
{

  // ウィジェット名などを設定
  function __construct()
  {
    parent::__construct(
      'child_pages',
      WIDGET_NAME_PREFIX . __('子ページカード', THEME_NAME),
      array('description' => __('子ページリストを表示するウィジェットです。', THEME_NAME)),
      array('width' => 400, 'height' => 350)
    ); //ウイジェット名
  }

  // ウィジェットの内容を出力
  function widget($args, $instance)
  {
  }

  // ウィジェットオプションの保存処理
  function update($new_instance, $old_instance)
  {
  }

  // 管理用のオプションのフォームを出力
  function form($instance)
  {
  }
}

このコードを記述した状態で、管理画面の外観→ウィジェットを確認してみましょう。

「子ページカード」というウィジェットが新たに表示されていると思います。

WordPressの独自ウィジェットの作成方法は、以下をご覧ください。

WordPress ウィジェット API - WordPress Codex 日本語版

続いて、ウィジェットオプションのフォームを作成します。

オプション項目
  • 表示タイプ
  • タイトルを太字にする
  • 矢印表示

form関数の中に追記していきます。

  function form($instance)
  {
    if (empty($instance)) {
      $instance = array(
        'entry_type' => ET_DEFAULT,
        'is_bold' => 0,
        'is_arrow_visible' => 0,
      );
    }

    $entry_type  = ET_DEFAULT;
    if (isset($instance['entry_type']))
      $entry_type = esc_attr($instance['entry_type']);
    $is_bold = empty($instance['is_bold']) ? 0 : 1;
    $is_arrow_visible = empty($instance['is_arrow_visible']) ? 0 : 1;

    // 表示タイプ
    echo '<p>';
    generate_label_tag($this->get_field_id('entry_type'), __('表示タイプ', THEME_NAME));
    echo '<br>';
    $options = get_widget_entry_type_options();
    generate_radiobox_tag($this->get_field_name('entry_type'), $options, $entry_type);
    echo '</p>';

    // タイトルを太字にする 
    echo '<p>';
    generate_checkbox_tag($this->get_field_name('is_bold'), $is_bold, __('タイトルを太字にする', THEME_NAME));
    echo '</p>';

    //矢印表示 
    generate_checkbox_tag($this->get_field_name('is_arrow_visible'), $is_arrow_visible, __('矢印表示', THEME_NAME));
  }

設定を更新するための処理を、update関数の中に記述します。

  function update($new_instance, $old_instance)
  {
    $instance = $old_instance;
    $instance['entry_type'] = strip_tags($new_instance['entry_type']);
    $instance['is_bold'] = isset($new_instance['is_bold']) ? 1 : 0;
    $instance['is_arrow_visible'] = isset($new_instance['is_arrow_visible']) ? 1 : 0;
    return $instance;
  }

この時点で、ウィジェットを確認しましょう。
サイドバーに配置して設定フォームを確認します。このように表示されたらOKです。

表示タイプなどを変更して、保存できることを確認しましょう。

ウィジェットの表示

引き続き子ページの一覧を表示する処理を作成します。

まずはfunctions.phpに、共通関数を作成しました。

  • 表示されている固定ページが、子ページを持っているかどうか
  • 表示されている固定ページが、トップレベルの階層のページかどうか
  • 表示されている固定ページの親ページのタイトルを取得
// 子ページを持っているかどうか
function has_children()
{
  global $post;
  $pages = get_pages('child_of=' . $post->ID);
  return count($pages) > 0;
}

// トップレベルのページかどうか
function is_top_level()
{
  global $post, $wpdb;
  $current_page = $wpdb->get_var("SELECT post_parent FROM $wpdb->posts WHERE ID = " . $post->ID);
  return $current_page == 0;
}

// 親ページのタイトルを取得
function get_parent_title()
{
  global $post, $wpdb;
  $post_title = $wpdb->get_var("SELECT post_title FROM $wpdb->posts WHERE ID = " . $post->post_parent);
  return $post_title;
}

次に、ウィジェットの表示の処理を、widget関数の中に追記していきます。
まずは、ウィジェットタイトルの取得処理です。

  // ウィジェットの内容を出力
  function widget($args, $instance)
  {
  
    // 固定ページのみ表示
    if (!is_page()) {
      return;
    }

    // ウィジェットタイトルの取得
    $title = '';
    global $post;
    $is_top_level = is_top_level();
    if ($is_top_level && has_children()) {
      // 表示されているページが親ページで、さらに子ページを持っている場合
      // 表示されているページのタイトルを取得
      $title = $post->post_title;
    } else if (!$is_top_level) {
      // 子ページの場合、親ページのタイトルを取得
      $title = get_parent_title();
    } else {
      // それ以外の場合は何もしない
      return;
    }

    // タイトルの表示
    echo $args['before_widget'];
    echo $args['before_title'];
    echo $title;
    echo $args['after_title'];

..続く

  }

ウィジェットタイトルの表示後は、一覧の表示処理です。上記の「続く」の箇所に追記します。
管理画面で設定したウィジェットの設定と、リストの作成処理を呼び出します。

    // 表示タイプ
    $entry_type = apply_filters('child_pages_widget_entry_type', empty($instance['entry_type']) ? ET_DEFAULT : $instance['entry_type']);
    // タイトルの太さ
    $is_bold = apply_filters('child_pages_widget_is_bold', empty($instance['is_bold']) ? 0 : 1);
    // 矢印表示
    $is_arrow_visible = apply_filters('child_pages_widget_is_arrow_visible', empty($instance['is_arrow_visible']) ? 0 : 1);

    // 引数配列のセット
    $atts = array(
      'type' => $entry_type,
      'bold' => $is_bold,
      'arrow' => $is_arrow_visible,
    );

    // リストの作成
    echo get_child_page_list_tag($atts);

    echo $args['after_widget'];

次に、リストを作成する処理「get_child_page_list_tag」を実装します。

// 子ページリスト ショートコード
add_shortcode('child_page_list', 'get_child_page_list_tag');
function get_child_page_list_tag($atts)
{
}

リストを表示するための関数になりますが、折角ですのでショートコードで呼べるようにしておきました。

まずは、前半部分の処理の実装です。
設定の取得と、表示されている固定ページの親ページIDを取得し、子ページの一覧を取得しています。

  extract(shortcode_atts(array(
    'type' => '',
    'bold' => 0,
    'arrow' => 0,
    'class' => null,
  ), $atts, 'child_page_list'));

  if (is_admin() && !is_admin_php_page()) {
    return;
  }

  // 固定ページのみ表示
  if (!is_page()) {
    return;
  }

  // 親ページのIDを取得
  global $post;
  $post_parent = -1;
  $is_top_level = is_top_level();
  if ($is_top_level && has_children()) {
    // 表示されているページが親ページで、さらに子ページを持っている場合
    // 表示されているページのIDを取得
    $post_parent = $post->ID;
  } else if (!$is_top_level) {
    // 子ページの場合、親ページのIDを取得
    $post_parent = $post->post_parent;
  } else {
    // それ以外の場合は何もしない
    return;
  }

  // 子ページの一覧を取得
  $children = get_posts(
    array(
      'post_parent' => $post_parent,
      'post_type'   => 'page',
      'orderby' => 'menu_order title',
      'order'   => 'ASC',
      // 件数を指定
      'posts_per_page' => 9999,
    )
  );

  if (!$children) {
    return;
  }

..続く

次に後半部分の実装です。
子ページの情報を元にリストを作成します。

表示されている固定ページと、メニュー一覧のカードが同じ場合は、ハイライトしているところがポイントです。

  $tag = null;
  foreach ($children as $child) {

    // 記事のディスクリプションを取得
    $description = get_the_page_meta_description($child->ID);

    // 画像取得用のパラメータ
    $img_obj = (object) [
      'object_id' => $child->ID,
      'object' => $child->post_type,
      'url' => get_permalink($child->ID),
    ];
    $image_attributes = get_navi_card_image_attributes($img_obj, $type);

    // 現在表示している固定ページIDとメニューが同じ場合はハイライトする
    $classes = array();
    if ($child->ID == $post->ID) {
      $classes[] = 'navi-entry-cards-link-selected';
    }

    // アイテムタグの取得
    $atts = array(
      'prefix' => WIDGET_NAVI_ENTRY_CARD_PREFIX,
      'url' => get_permalink($child->ID),
      'title' => $child->post_title,
      'snippet' => $description,
      'image_attributes' => $image_attributes,
      'type' => $type,
      'classes' => $classes,
      'object' =>  $child->post_type,
      'object_id' => $child->ID,
    );

    $tag .= get_widget_entry_card_link_tag($atts);
  }

  $atts = array(
    'tag' => $tag,
    'type' => $type,
    'bold' => $bold,
    'arrow' => $arrow,
    'class' => $class,
  );

  $tag = get_navi_card_wrap_tag($atts);
  return $tag;

最後に、style.cssに以下を追記します。(ハイライト)

\cocoon-child-master\style.css

.navi-entry-cards-link-selected {
  background-color: rgba(225, 245, 254, 0.2) !important;
  border: 2px solid #4fc3f7 !important;
}

見た目はお好みで調整してください。

結構長くなりましたが、実装はこれで完了です。

スポンサーリンク

動作確認

管理画面の固定ページより、以下のように親子ページを作成しました。

必要に応じて、アイキャッチやメタディスクリプションを設定して下さい。

ウィジェットはサイドバーに配置します。

親ページを表示してみましょう。
このように、ウィジェットに子ページの一覧が表示されました。

子ページを表示してみます。
表示されている固定ページのカードがハイライトされました。

設定はナビカードと同様ですので、カードの表示は変更することが出来ます

ショートコードで子ページ一覧を表示

今回、ついでにショートコードでも動作するように対応しました。
例えば、固定ページの本文中にショートコードを埋め込んでみます。

[child_page_list]

ショートコードの引数は、ナビカードと同じものが使えます。

固定ページの本文の中に、子ページの一覧が表示されました。

ソース全容

functions.php

<?php //子テーマ用関数
if ( !defined( 'ABSPATH' ) ) exit;

//子テーマ用のビジュアルエディタースタイルを適用
add_editor_style();

//以下に子テーマ用の関数を書く

// 子ページを持っているかどうか
function has_children()
{
  global $post;
  $pages = get_pages('child_of=' . $post->ID);
  return count($pages) > 0;
}

// トップレベルのページかどうか
function is_top_level()
{
  global $post, $wpdb;
  $current_page = $wpdb->get_var("SELECT post_parent FROM $wpdb->posts WHERE ID = " . $post->ID);
  return $current_page == 0;
}

// 親ページのタイトルを取得
function get_parent_title()
{
  global $post, $wpdb;
  $post_title = $wpdb->get_var("SELECT post_title FROM $wpdb->posts WHERE ID = " . $post->post_parent);
  return $post_title;
}

// 子ページリスト ショートコード
add_shortcode('child_page_list', 'get_child_page_list_tag');
function get_child_page_list_tag($atts)
{

  extract(shortcode_atts(array(
    'type' => '',
    'bold' => 0,
    'arrow' => 0,
    'class' => null,
  ), $atts, 'child_page_list'));

  if (is_admin() && !is_admin_php_page()) {
    return;
  }

  // 固定ページのみ表示
  if (!is_page()) {
    return;
  }

  // 親ページのIDを取得
  global $post;
  $post_parent = -1;
  $is_top_level = is_top_level();
  if ($is_top_level && has_children()) {
    // 表示されているページが親ページで、さらに子ページを持っている場合
    // 表示されているページのIDを取得
    $post_parent = $post->ID;
  } else if (!$is_top_level) {
    // 子ページの場合、親ページのIDを取得
    $post_parent = $post->post_parent;
  } else {
    // それ以外の場合は何もしない
    return;
  }

  // 子ページの一覧を取得
  $children = get_posts(
    array(
      'post_parent' => $post_parent,
      'post_type'   => 'page',
      'orderby' => 'menu_order title',
      'order'   => 'ASC',
      // 件数を指定
      'posts_per_page' => 9999,
    )
  );

  if (!$children) {
    return;
  }

  $tag = null;
  foreach ($children as $child) {

    // 記事のディスクリプションを取得
    $description = get_the_page_meta_description($child->ID);

    // 画像取得用のパラメータ
    $img_obj = (object) [
      'object_id' => $child->ID,
      'object' => $child->post_type,
      'url' => get_permalink($child->ID),
    ];
    $image_attributes = get_navi_card_image_attributes($img_obj, $type);

    // 現在表示している固定ページIDとメニューが同じ場合はハイライトする
    $classes = array();
    if ($child->ID == $post->ID) {
      $classes[] = 'navi-entry-cards-link-selected';
    }

    // アイテムタグの取得
    $atts = array(
      'prefix' => WIDGET_NAVI_ENTRY_CARD_PREFIX,
      'url' => get_permalink($child->ID),
      'title' => $child->post_title,
      'snippet' => $description,
      'image_attributes' => $image_attributes,
      'type' => $type,
      'classes' => $classes,
      'object' =>  $child->post_type,
      'object_id' => $child->ID,
    );

    $tag .= get_widget_entry_card_link_tag($atts);
  }

  $atts = array(
    'tag' => $tag,
    'type' => $type,
    'bold' => $bold,
    'arrow' => $arrow,
    'class' => $class,
  );

  $tag = get_navi_card_wrap_tag($atts);
  return $tag;
}

// 子ページリスト ウィジェット
add_action('widgets_init', function () {
  register_widget('ChildPageWidgetItem');
});
class ChildPageWidgetItem extends WP_Widget
{

  // ウィジェット名などを設定
  function __construct()
  {
    parent::__construct(
      'child_pages',
      WIDGET_NAME_PREFIX . __('子ページカード', THEME_NAME),
      array('description' => __('子ページリストを表示するウィジェットです。', THEME_NAME)),
      array('width' => 400, 'height' => 350)
    ); //ウイジェット名
  }

  // ウィジェットの内容を出力
  function widget($args, $instance)
  {
  
    // 固定ページのみ表示
    if (!is_page()) {
      return;
    }

    // ウィジェットタイトルの取得
    $title = '';
    global $post;
    $is_top_level = is_top_level();
    if ($is_top_level && has_children()) {
      // 表示されているページが親ページで、さらに子ページを持っている場合
      // 表示されているページのタイトルを取得
      $title = $post->post_title;
    } else if (!$is_top_level) {
      // 子ページの場合、親ページのタイトルを取得
      $title = get_parent_title();
    } else {
      // それ以外の場合は何もしない
      return;
    }

    // タイトルの表示
    echo $args['before_widget'];
    echo $args['before_title'];
    echo $title;
    echo $args['after_title'];

    // 表示タイプ
    $entry_type = apply_filters('child_pages_widget_entry_type', empty($instance['entry_type']) ? ET_DEFAULT : $instance['entry_type']);
    // タイトルの太さ
    $is_bold = apply_filters('child_pages_widget_is_bold', empty($instance['is_bold']) ? 0 : 1);
    // 矢印表示
    $is_arrow_visible = apply_filters('child_pages_widget_is_arrow_visible', empty($instance['is_arrow_visible']) ? 0 : 1);

    // 引数配列のセット
    $atts = array(
      'type' => $entry_type,
      'bold' => $is_bold,
      'arrow' => $is_arrow_visible,
    );

    // リストの作成
    echo get_child_page_list_tag($atts);

    echo $args['after_widget'];

  }

  // ウィジェットオプションの保存処理
  function update($new_instance, $old_instance)
  {
    $instance = $old_instance;
    $instance['entry_type'] = strip_tags($new_instance['entry_type']);
    $instance['is_bold'] = isset($new_instance['is_bold']) ? 1 : 0;
    $instance['is_arrow_visible'] = isset($new_instance['is_arrow_visible']) ? 1 : 0;
    return $instance;
  }

  // 管理用のオプションのフォームを出力
  function form($instance)
  {
    if (empty($instance)) {
      $instance = array(
        'entry_type' => ET_DEFAULT,
        'is_bold' => 0,
        'is_arrow_visible' => 0,
      );
    }

    $entry_type  = ET_DEFAULT;
    if (isset($instance['entry_type']))
      $entry_type = esc_attr($instance['entry_type']);
    $is_bold = empty($instance['is_bold']) ? 0 : 1;
    $is_arrow_visible = empty($instance['is_arrow_visible']) ? 0 : 1;

    // 表示タイプ
    echo '<p>';
    generate_label_tag($this->get_field_id('entry_type'), __('表示タイプ', THEME_NAME));
    echo '<br>';
    $options = get_widget_entry_type_options();
    generate_radiobox_tag($this->get_field_name('entry_type'), $options, $entry_type);
    echo '</p>';

    // タイトルを太字にする 
    echo '<p>';
    generate_checkbox_tag($this->get_field_name('is_bold'), $is_bold, __('タイトルを太字にする', THEME_NAME));
    echo '</p>';

    //矢印表示 
    generate_checkbox_tag($this->get_field_name('is_arrow_visible'), $is_arrow_visible, __('矢印表示', THEME_NAME));
  }
}

style.css

@charset "UTF-8";

/*!
Theme Name: Cocoon Child
Description: Cocoon専用の子テーマ
Theme URI: https://wp-cocoon.com/
Author: わいひら
Author URI: https://nelog.jp/
Template:   cocoon-master
Version:    1.1.3
*/

/************************************
** 子テーマ用のスタイルを書く
************************************/
/*必要ならばここにコードを書く*/

.navi-entry-cards-link-selected {
  background-color: rgba(225, 245, 254, 0.2) !important;
  border: 2px solid #4fc3f7 !important;
}

/************************************
** レスポンシブデザイン用のメディアクエリ
************************************/
/*1023px以下*/
@media screen and (max-width: 1023px){
  /*必要ならばここにコードを書く*/
}

/*834px以下*/
@media screen and (max-width: 834px){
  /*必要ならばここにコードを書く*/
}

/*480px以下*/
@media screen and (max-width: 480px){
  /*必要ならばここにコードを書く*/
}

さいごに

Cocoonはとてもカスタマイズしやすく、スキンも沢山ありますので、様々なジャンルのサイトに対応できると思います。

本カスタマイズを追加すると、コーポレートサイトを作る際等に便利になると思います😀

コメント

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