前回まででプラグインの雛形を作り、必要なテストデータを作成しました。今回からプラグインのメインの開発を進めていきます。
メタボックスの分析
まずはブラウザ(Safari)でWordPress管理画面にログインしダッシュボードを開きます。Webインスペクタを開き「概要」メタボックスを選択し、要素タブを開きます。下の図のように、この部分はdiv#dashboard_right_now
という要素でできていることが分かります。

dashboard_right_nowで検索すると、wp_dashboard_right_now()
という関数にたどり着きます。この関数はwp-admin/includes/dashboard.phpで定義されていて、WordPress 6.4.2でのソースコードはMake WordPress Coreから参照できます。
n件の投稿
、n件の固定ページ
と表示されている部分は、以下のコードから出力されています。
// Posts and Pages.
foreach ( array( 'post', 'page' ) as $post_type ) {
$num_posts = wp_count_posts( $post_type );
if ( $num_posts && $num_posts->publish ) {
if ( 'post' === $post_type ) {
/* translators: %s: Number of posts. */
$text = _n( '%s Post', '%s Posts', $num_posts->publish );
} else {
/* translators: %s: Number of pages. */
$text = _n( '%s Page', '%s Pages', $num_posts->publish );
}
$text = sprintf( $text, number_format_i18n( $num_posts->publish ) );
$post_type_object = get_post_type_object( $post_type );
if ( $post_type_object && current_user_can( $post_type_object->cap->edit_posts ) ) {
printf( '<li class="%1$s-count"><a href="edit.php?post_type=%1$s">%2$s</a></li>', $post_type, $text );
} else {
printf( '<li class="%1$s-count"><span>%2$s</span></li>', $post_type, $text );
}
}
}
wp-admin/includes/dashboard.php$post_type
に'post'
または'page'
のいずれかをセットし、wp_count_posts()
で記事の件数を取得し、出力するテキストを生成します。ログインしているユーザーがその投稿タイプの編集権限を持っているかどうか確認し、権限があれば編集ページへのリンク付きで記事の件数を表示し、権限がなければ記事の件数だけを表示します。
306行のコードを以下のように変更すればカスタム投稿タイプを含めることができますが、この方法はおすすめできません。
foreach ( array( 'post', 'page', 'drnp-mycpt-a', 'drnp-mycpt-b' ) as $post_type ) {
wp-admin/includes/dashboard.phpwp-admin/includes/dashboard.php
はコアファイルであり、WordPress本体のバージョンアップで修正部分が上書きされてしまうからです。
add_filters
WordPressにはfilterという方法があります。filterとは何か、ハンドブックに説明されています。
Filters are one of the two types of Hooks.
They provide a way for functions to modify data during the execution of WordPress Core, plugins, and themes. They are the counterpart to Actions.
Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. Filters expect to have something returned back to them.
Filters – Plugin Handbook | Developer.WordPress.org
フィルタはフックの2つのタイプのうちの1つです。
WordPressコア、プラグイン、テーマの実行中に関数がデータを変更する方法を提供します。Actionと対になるものです。
Actionとは異なり、フィルタは単独で動作し、グローバル変数や出力に影響を与えるような副作用はありません。filterでは何かの値を返されることが期待されます。
WordPressコアの各所にはapply_filters
が準備されています。ここでテーマやプラグインコアの処理に干渉し、コアの変数に何かの加工をして処理を戻します。第1引数にタグ名、第2引数以降にadd_filter
に引き継ぐデータを記述します。
/**
* Filters the array of extra elements to list in the 'At a Glance'
* dashboard widget.
*
* Prior to 3.8.0, the widget was named 'Right Now'. Each element
* is wrapped in list-item tags on output.
*
* @since 3.8.0
*
* @param string[] $items Array of extra 'At a Glance' widget items.
*/
$elements = apply_filters( 'dashboard_glance_items', array() );
if ( $elements ) {
echo '<li>' . implode( "</li>\n<li>", $elements ) . "</li>\n";
}
wp-admin/includes/dashboard.php呼び出す関数を追加するには、add_filters
を使用します。プラグイン等からadd_filter( 'dashboard_glance_items', '関数名' );
と記述すると、その結果が、変数$elements
に代入されます。
wp-admin/includes/dashboard.phpを参考にし、以下のコードを追加します。
function drnp_add_my_custom_post_type_to_right_now( $elements ) {
foreach ( array( 'drnp-mycpt-a', 'drnp-mycpt-b' ) as $post_type ) {
$num_posts = wp_count_posts( $post_type );
if ( $num_posts && $num_posts->publish ) {
$post_type_object = get_post_type_object( $post_type );
$text = sprintf( '%s件の%s', number_format_i18n( $num_posts->publish ), $post_type_object->labels->name );
if ( $post_type_object && current_user_can( $post_type_object->cap->edit_posts ) ) {
$elements[] = sprintf( '<a class="%1$s-count" href="edit.php?post_type=%1$s">%2$s</a>', esc_html( $post_type ), esc_html( $text ) );
} else {
$elements[] = sprintf( '<span class="%1$s-count">%2$s</span></li>', esc_html( $post_type ), esc_html( $text ) );
}
}
}
return $elements;
}
add_filter( 'dashboard_glance_items', 'drnp_add_my_custom_post_type_to_right_now' );
dashboard-right-now-plus.phpなお、多言語化に関する部分は簡略化しました。
表示確認
管理画面にログインし、追加した2つのカスタム投稿タイプがダッシュボードの概要メタボックスに表示されていることを確認します。

コードまとめ
ここまでの処理をまとめると、以下のようになります。
<?php
/**
* Dashboard Right Now Plus
*
* @package DashboardRightNowPlus
*
* @wordpress-plugin
* Plugin Name: Dashboard Right Now Plus
* Plugin URI: https://gist.github.com/web83info/5747ac715e4544b408e91e2ec034ab05/
* Description: Add custom post type to "Right Now" meta box on WordPress dashboard
* Version: 1.0.0
* Requires at least: 6.4
* Requires PHP: 7.2
* Author: web83info
* Author URI: https://labs.web83.info/
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/
/**
* カスタム投稿タイプdrnp-mycpt-a, drnp-mycpt-b を追加
*
* @return void
*/
function drnp_add_my_custom_post_type() {
$custom_post_types = array(
'drnp-mycpt-a' => array(
'type' => 'drnp-mycpt-a',
'name' => 'マイCPT-A',
),
'drnp-mycpt-b' => array(
'type' => 'drnp-mycpt-b',
'name' => 'マイCPT-B',
),
);
foreach ( $custom_post_types as $custom_post_type ) {
register_post_type(
$custom_post_type['type'],
array(
'labels' => array(
'name' => $custom_post_type['name'],
'singular_name' => $custom_post_type['name'],
),
'public' => true,
)
);
if ( 0 === wp_count_posts( $custom_post_type['type'] )->publish ) {
for ( $i = 1; $i <= 3; $i++ ) {
wp_insert_post(
array(
'post_type' => $custom_post_type['type'],
'post_title' => $custom_post_type['name'] . ' 記事 #' . $i,
'post_status' => 'publish',
)
);
}
}
}
}
add_action( 'init', 'drnp_add_my_custom_post_type' );
/**
* アンインストール時にカスタム投稿タイプdrnp-mycpt-a, drnp-mycpt-b の記事を削除
*
* @return void
*/
function drnp_uninstall_my_custom_post_type() {
$args = array(
'post_type' => array(
'drnp-mycpt-a',
'drnp-mycpt-b',
),
'numberposts' => -1,
);
$posts = get_posts( $args );
foreach ( $posts as $post ) {
wp_delete_post( $post->ID );
}
}
register_uninstall_hook( __FILE__, 'drnp_uninstall_my_custom_post_type' );
/**
* 概要メタボックスにカスタム投稿タイプの件数を表示
*
* @param array $elements 追加表示させる内容.
* @return array 追加表示させる内容.
*/
function drnp_add_my_custom_post_type_to_right_now( $elements ) {
foreach ( array( 'drnp-mycpt-a', 'drnp-mycpt-b' ) as $post_type ) {
$num_posts = wp_count_posts( $post_type );
if ( $num_posts && $num_posts->publish ) {
$post_type_object = get_post_type_object( $post_type );
$text = sprintf( '%s件の%s', number_format_i18n( $num_posts->publish ), $post_type_object->labels->name );
if ( $post_type_object && current_user_can( $post_type_object->cap->edit_posts ) ) {
$elements[] = sprintf( '<a class="%1$s-count" href="edit.php?post_type=%1$s">%2$s</a>', esc_html( $post_type ), esc_html( $text ) );
} else {
$elements[] = sprintf( '<span class="%1$s-count">%2$s</span></li>', esc_html( $post_type ), esc_html( $text ) );
}
}
}
return $elements;
}
add_filter( 'dashboard_glance_items', 'drnp_add_my_custom_post_type_to_right_now' );
dashboard-right-now-plus.php