どんな記事が安定して読まれているのか把握するために、平均PVを調べたいと思いました。前回作った月別ページビュー集計の自作プラグインに追加します。
1. 管理ページにサブメニューを追加する(add_submenu_page)
最終的に出来上がったのがこちら。

ブログの勢いを将棋の駒でランク付けしています。

書いた記事が、駒得で変換されるのでモチベーションが上がります。

野球が好きなら、ヒットやホームランでもいいんだろうね。
まずは、メニューに項目を追加します。
WordPressプラグインでは、add_submenu_page
関数1を使います。

/ Register the admin menu for the plugin
function chiilabo_stats_admin_menu() {
add_menu_page(
'chiilabo-stats' // ページのタイトル
, 'ちいラボ統計' // 左メニュー
, 'edit_posts' // 必要な権限
, 'chiilabo-stats' // スラッグ名
, '' // ページの表示関数
, 'dashicons-admin-users' // メニューのアイコン
, 0 // メニューが表示位置のインデックス
);
add_submenu_page(
'chiilabo-stats',// 親メニューのスラッグ
'記事分析',
'記事分析',
'edit_posts',
'chiilabo-stats',
'posts_stats_display',
1
);
add_submenu_page(
'chiilabo-stats', // 親メニューのスラッグ
'月別集計',
'月別集計',
'edit_posts',
'monthly-pageview-totals',
'monthly_pageview_totals_display',
2
);
add_submenu_page(
'chiilabo-stats', // 親メニューのスラッグ
'グリッド集計',
'グリッド集計',
'edit_posts',
'grid-stats',
'grid_stats_display',
3
);
}
add_action( 'admin_menu', 'chiilabo_stats_admin_menu' );
2. 投稿データの集計
まずは、記事ごとの文字数とPV/日の表を作りました。

前回は手探りで集計しましたが、今回はもう少しきちんと見てみます。
➤ 投稿のデータベースは get_posts()
で、
➤ アクセス数のデータベースは $wpdb->get_results($query)
で
取得しています。
get_posts()
の返り値は、WP_Post
クラスのオブジェクトの配列です2。
WP_Post
にはいくつかの属性があります。
今回 使えそうなのは、 ID, post_title, post_date, post_content, post_name
3。
この2つのデータベースを投稿IDで結びつけることで、投稿情報とアクセス数の表を作ることができます。
2-1. 投稿の本文の文字数を数える(post_content)
記事の本文は、WP_Post->post_content で取得できます。
文字数は、strip_tags()
でタグ部分を除去してから、mb_strlen()
で数えます4。
echo mb_strlen(strip_tags($post->post_content));
2-2. 一日あたりの平均PVを求める(strtotime)
一日あたりの平均PVは、合計PV ÷ 投稿時から経過した日数で計算します。
投稿時から経過した日数は、strtotime
を使って計算します5。
$days[$log->post_id] = (strtotime("now") - strtotime($log->date)) / 86400;
合計PVは、MySQLのクエリ結果の pv
を使っています。
データベースの count
を post_id
でグループ化して集計(SUM
)しています。
$query = "
SELECT post_id, SUM(count) as pv, date
FROM $table_name
GROUP BY post_id
ORDER BY date DESC
";
$logs = $wpdb->get_results($query);
ゼロ除算を防ぐために 切り上げ(ceil
)で整数値にしています。
$pv_ave = ceil($log->pv / ceil($days[$log->post_id]));
あとは、PVが少ない(2以下)記事をスキップしています。
/**
* 記事ごとの分析
*
*/
function posts_stats_display() {
global $wpdb;
// Retrieve all the posts and their permalinks
$posts = get_posts( array(
'post_type' => 'post',
'post_status' => 'publish',
'numberposts' => -1
) );
$post_id2obj = array();
$post_words = array();
foreach ( $posts as $post ) {
$post_id2obj[$post->ID] = $post;
$post_words[$post->ID] = mb_strlen($post->post_content);
}
$table_name = ACCESSES_TABLE_NAME;
$query = "
SELECT post_id, SUM(count) as pv, date
FROM $table_name
GROUP BY post_id
ORDER BY date DESC
";
// Retrieve the access logs
$logs = $wpdb->get_results($query);
$pvs = array();
foreach ( $logs as $log ) {
$days[$log->post_id] = (strtotime("now") - strtotime($log->date)) / 86400;
}
// Initialize the table
echo '<style>.widefat.stats td, .widefat.stats th { padding: 2px 10px !IMPORTANT; } </style>';
echo '<table class="widefat stats">';
echo '<thead><tr>';
echo '<th>投稿日</th>';
echo '<th>文字数</th>';
echo '<th>PV/日</th>';
echo '<th>タイトル</th>';
echo '<th>星</th>';
echo '</tr></thead>';
// Populate the table
echo '<tbody>';
echo '<tr>';
echo '<td>';
foreach ( $logs as $log ) {
$post = $post_id2obj[$log->post_id];
$pv_ave = ceil($log->pv / ceil($days[$log->post_id]));
if ($pv_ave > 2) {
echo '</td>';
echo '</tr>';
echo '<tr>';
echo '<td>';
echo $log->date;
echo '</td>';
echo '<td align="right">';
echo mb_strlen(strip_tags($post->post_content));
echo '</td>';
echo '<td align="right">';
echo $pv_ave;
echo '</td>';
echo '<td>';
echo '<a href="'. get_permalink($post) . '">';
echo mb_substr($post->post_title, 0, 50) .' ... ('. $log->pv .') ';
echo '</a>';
echo '</td>';
echo '<td>';
echo '<a href="'. get_permalink($post) . '">';
echo '○';
echo '</a>';
} else {
echo '<a href="'. get_permalink($post) . '">';
echo '✕';
echo '</a>';
}
}
echo '</tbody>';
echo '</table>';
}
3. アイキャッチをグリッド表示
表を眺めても、PVの多い記事の傾向がつかめなかったので、アイキャッチ画像を並べることにしました。

パッと見でどの記事のPVが多いかわかるように、将棋の駒でランク分けしました。
スタイルで画像・文字が重なるようにしています6。
なし | 歩 | 香 | 桂 | 銀 | 金 | 角 | 飛 |
---|---|---|---|---|---|---|---|
0 | 2.5 | 6 | 9 | 12 | 15 | 40 | 100 |
3-1. アイキャッチ画像を表示する(get_the_post_thumbnail_url)
記事ごとのアイキャッチ画像のURLは、get_the_post_thumbnail_url で取得します7。
$img = get_the_post_thumbnail_url( $log->post_id, 'thumbnail' );
ただし、そのまま表示すると画像データが重くなるので、「thumbnail」サイズにします8。
アイキャッチ画像を正方形に揃えます。
table.widefat.stats img{
width: 100%;
height: 100%;
object-fit:cover;
aspect-ratio: 100/100;
opacity: 0.6;
}
3-2. モバイル表示の列数を少なく(wp_is_mobile)
パソコン画面では 9列、スマホ画面では 4列にしました。wp_is_mobile
で条件分けします9。
$row = 9;
if (wp_is_mobile()) {
$row = 4;
}
3-3. 未投稿と「書きかけ」カテゴリーの記事の色を赤にした
投稿一覧に下書きの投稿も含めました10。
$posts = get_posts( array(
'post_type' => 'post',
'post_status' => array( 'publish', 'pending', 'draft', 'future'),
'numberposts' => -1
) );
未完成の記事かどうかをチェックして、CSSクラスをセットするようにしました。
IDからカテゴリーも確認しました11。
$is_todo_post = 0;
if ($post->post_status == "publish") {
$categories = get_the_category($post->ID);
foreach ( $categories as $category) {
if ($category->term_id == 2458) {
$is_todo_post = 1;
}
}
} else {
$is_todo_post = 1;
}
if ($is_todo_post == 1) {
echo '<td class="container todo_post">';
} else {
echo '<td class="container">';
}
function grid_stats_display() {
global $wpdb;
// Retrieve all the posts and their permalinks
$posts = get_posts( array(
'post_type' => 'post',
'post_status' => array( 'publish', 'pending', 'draft', 'future'),
'numberposts' => -1
) );
$post_id2obj = array();
$post_words = array();
foreach ( $posts as $post ) {
$post_id2obj[$post->ID] = $post;
$post_words[$post->ID] = mb_strlen($post->post_content);
}
$table_name = ACCESSES_TABLE_NAME;
$query = "
SELECT post_id, SUM(count) as pv, date
FROM $table_name
GROUP BY post_id
ORDER BY date DESC
";
// Retrieve the access logs
$logs = $wpdb->get_results($query);
$post_id2log = array();
$days = array();
foreach ( $logs as $log ) {
$post_id2log[$log->post_id] = $log;
$days[$log->post_id] = (strtotime("now") - strtotime($log->date)) / 86400;
}
foreach ( $logs as $log ) {
}
// Initialize the table
$row = 9;
if (wp_is_mobile()) {
$row = 4;
}
echo '<style>
table.widefat.stats{
width: 100%;
}
.widefat.stats td, .widefat.stats th {
border: 1px solid black;
padding: 0px 0px !IMPORTANT;
width: calc(100%/'.$row.');
}
.container{
position: relative;
width:calc(100%/'.$row.');
}
.widefat.stats img{
width: 100%;
height: 100%;
object-fit:cover;
aspect-ratio: 100/100;
opacity: 0.6;
}
.container p{
position: absolute;
padding: 5px;
font-size: 7px;
margin:0;
}
.container .date{
top: 5px;
left: 5px;
text-align: center;
background-color: brown;
font-weight: bold;
color: #fff;
}
.container .tag {
background-color: #fff;
left: 5px;
bottom: -5px;
font-weight: 900;
}
.container .pv {
background-color: #fff;
right: 5px;
bottom: -5px;
font-weight: 900;
}
.container .rank {
position: absolute;
font-size: 300%;
font-weight: 900;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
text-shadow: var(--cocoon-white-color) 3px 0px 0px, var(--cocoon-white-color) 2px 1px 0px, var(--cocoon-white-color) 2px 2px 0px, var(--cocoon-white-color) 2px 3px 0px, var(--cocoon-white-color) 1px 3px 0px, var(--cocoon-white-color) 0px 3px 0px, var(--cocoon-white-color) -1px 3px 0px, var(--cocoon-white-color) -2px 2px 0px, var(--cocoon-white-color) -3px 1px 0px, var(--cocoon-white-color) -3px 0px 0px, var(--cocoon-white-color) -3px -1px 0px, var(--cocoon-white-color) -3px -2px 0px, var(--cocoon-white-color) -2px -2px 0px, var(--cocoon-white-color) -1px -3px 0px, var(--cocoon-white-color) 0px -3px 0px, var(--cocoon-white-color) 1px -3px 0px, var(--cocoon-white-color) 2px -2px 0px, var(--cocoon-white-color) 2px -2px 0px, var(--cocoon-white-color) 3px -1px 0px;
}
.container.todo_post .rank, .container.todo_post .tag {
color: red;
}
</style>
';
echo '<table class="widefat stats">';
// Populate the table
echo '<tbody>';
$count = 0;
$last_date = "";
foreach ( $posts as $post ) {
if($count == 0) {
echo '<tr>';
}
$log = $post_id2log[$post->ID];
$pv_ave = ($log->pv / ceil($days[$post->ID]));
if (is_nan($pv_ave)) {
$pv_ave = 0;
}
$is_todo_post = 0;
if ($post->post_status == "publish") {
$categories = get_the_category($post->ID);
foreach ( $categories as $category) {
if ($category->term_id == 2458) {
$is_todo_post = 1;
}
}
} else {
$is_todo_post = 1;
}
if ($is_todo_post == 1) {
echo '<td class="container todo_post">';
} else {
echo '<td class="container">';
}
echo '<a href="'. get_permalink($post) . '" title="'. mb_substr($post->post_title, 0, 50) .'">';
$img = get_the_post_thumbnail_url($post->ID, 'thumbnail' );
echo '<img src="' .$img. '" alt="' . mb_substr($post->post_title, 0, 50) . '">';
$date = $log->date;
if ($date != $last_date) {
echo '<p class="date">'.$log->date.'</p>';
$last_date = $date;
}
echo '<p class="tag">'.mb_strlen(strip_tags($post->post_content)).'</p>';
echo '<p class="pv">'. floor($pv_ave).'</p>';
$pv_rank = "";
if ($pv_ave >= 100) {
$pv_rank = "飛";
} else if ($pv_ave >= 40) {
$pv_rank = "角";
} else if ($pv_ave >= 15) {
$pv_rank = "金";
} else if ($pv_ave >= 12) {
$pv_rank = "銀";
} else if ($pv_ave >= 9) {
$pv_rank = "桂";
} else if ($pv_ave >= 6) {
$pv_rank = "香";
} else if ($pv_ave >= 2.5) {
$pv_rank = "歩";
} else {
$pv_rank = "";
}
echo '<p class="rank">'.$pv_rank.'</p>';
echo '</a>';
echo '</td>';
$count = $count+1;
if ($count == $row) {
echo '</tr>';
$count = 0;
}
}
echo '</tbody>';
echo '</table>';
}
4. 全部合わせたファイル
プラグインのPHP全体を残しておきます。
<?php
/**
* Plugin Name: ちいラボ統計
* Plugin URI: chiilabo.com
* Author: chiilabo
* Author URI: chiilabo.com
* Description: 投稿月ごとの月別ページビュー集計表を表示する。
* Version: 1.0.0
*/
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
define( 'ACCESSES_TABLE_NAME', $wpdb->prefix . 'cocoon' . '_accesses' );
// Register the admin menu for the plugin
function chiilabo_stats_admin_menu() {
add_menu_page(
'chiilabo-stats' // ページのタイトルタグ<title>に表示されるテキスト
, 'ちいラボ統計' // 左メニューとして表示されるテキスト
, 'edit_posts' // 必要な権限 manage_options は通常
, 'chiilabo-stats' // 左メニューのスラッグ名
, '' // メニューページを表示する際に実行される関数
, 'dashicons-admin-users' // メニューのアイコンを指定 https
, 0 // メニューが表示される位置のインデックス(0が先頭) 5=投稿,10=メディア,20=固定ページ,25=コメント,60=テーマ,65=プラグイン,70=ユーザー,75=ツール,80=設定
);
add_submenu_page(
'chiilabo-stats', // 親メニューのスラッグ
'記事分析',
'記事分析',
'edit_posts',
'chiilabo-stats',
'posts_stats_display',
1
);
add_submenu_page(
'chiilabo-stats', // 親メニューのスラッグ
'月別集計',
'月別集計',
'edit_posts',
'monthly-pageview-totals',
'monthly_pageview_totals_display',
2
);
add_submenu_page(
'chiilabo-stats', // 親メニューのスラッグ
'グリッド集計',
'グリッド集計',
'edit_posts',
'grid-stats',
'grid_stats_display',
3
);
}
add_action( 'admin_menu', 'chiilabo_stats_admin_menu' );
// Callback to display the page content
function monthly_pageview_totals_display() {
global $wpdb;
// Use the Transients API to cache the page view data for 12 hours
// Retrieve all the posts and their permalinks
$posts = get_posts( array(
'post_type' => 'post',
'post_status' => 'publish',
'numberposts' => -1
) );
$urls = array();
$post_ms = array();
$results = array();
foreach ( $posts as $post ) {
$url = parse_url( get_permalink( $post ) );
$urls[$post->ID] = substr( $url['path'], 1 );
$post_m = substr($urls[$post->ID], 0,7);
$post_ms[$post_m]=$post_m;
$results[$post_m]=array();
}
$table_name = ACCESSES_TABLE_NAME;
$query = "
SELECT post_id, SUM(count) as pv, YEAR(date) as year, MONTH(date) as month, date
FROM $table_name
GROUP BY post_id, year, month
ORDER BY date DESC
";
// Retrieve the access logs
$logs = $wpdb->get_results($query);
$months = array();
foreach ( $logs as $log ) {
$post_m = substr($urls[$log->post_id], 0,7);
$access_m = $log->year.sprintf('%02d', $log->month);
$pv = $results[$post_m][$access_m];
if (!$pv) {
$pv =0;
}
$results[$post_m][$access_m] = $pv + $log->pv;
$months[ $access_m ] = $log->year.'年'.$log->month.'月';
}
// Initialize the table
echo '<table class="widefat">';
echo '<thead><tr>';
echo '<th width="40%">投稿月</th>';
foreach ( $months as $month ) {
echo '<th>' . esc_html( $month ) . '</th>';
}
echo '</tr></thead>';
// Populate the table
echo '<tbody>';
foreach ( $results as $m => $row ) {
echo '<tr>';
echo '<td>' . $m . '</td>';
foreach ( $months as $key => $month ) {
$pv = 0;
foreach ( $row as $mm => $mpv ) {
if ( $mm == $key ) {
$pv = $mpv;
break;
}
}
echo '<td align="right">' . ( $pv ? number_format_i18n( $pv ) : '' ) . '</td>';
}
echo '</tr>';
}
echo '</tbody>';
echo '</table>';
}
/**
* 記事ごとの分析
*
*/
function posts_stats_display() {
global $wpdb;
// Retrieve all the posts and their permalinks
$posts = get_posts( array(
'post_type' => 'post',
'post_status' => 'publish',
'numberposts' => -1
) );
$post_id2obj = array();
$post_words = array();
foreach ( $posts as $post ) {
$post_id2obj[$post->ID] = $post;
$post_words[$post->ID] = mb_strlen($post->post_content);
}
$table_name = ACCESSES_TABLE_NAME;
$query = "
SELECT post_id, SUM(count) as pv, date
FROM $table_name
GROUP BY post_id
ORDER BY date DESC
";
// Retrieve the access logs
$logs = $wpdb->get_results($query);
$pvs = array();
foreach ( $logs as $log ) {
$days[$log->post_id] = (strtotime("now") - strtotime($log->date)) / 86400;
}
// Initialize the table
echo '<style>.widefat.stats td, .widefat.stats th { padding: 2px 10px !IMPORTANT; } </style>';
echo '<table class="widefat stats">';
echo '<thead><tr>';
echo '<th>投稿日</th>';
echo '<th>文字数</th>';
echo '<th>PV/日</th>';
echo '<th>タイトル</th>';
echo '<th>星</th>';
echo '</tr></thead>';
// Populate the table
echo '<tbody>';
echo '<tr>';
echo '<td>';
foreach ( $logs as $log ) {
$post = $post_id2obj[$log->post_id];
$pv_ave = ceil($log->pv / ceil($days[$log->post_id]));
if ($pv_ave > 2) {
echo '</td>';
echo '</tr>';
echo '<tr>';
echo '<td>';
echo $log->date;
echo '</td>';
echo '<td align="right">';
echo mb_strlen(strip_tags($post->post_content));
echo '</td>';
echo '<td align="right">';
echo $pv_ave;
echo '</td>';
echo '<td>';
echo '<a href="'. get_permalink($post) . '">';
echo mb_substr($post->post_title, 0, 50) .' ... ('. $log->pv .') ';
echo '</a>';
echo '</td>';
echo '<td>';
echo '<a href="'. get_permalink($post) . '">';
echo '○';
echo '</a>';
} else {
echo '<a href="'. get_permalink($post) . '">';
echo '✕';
echo '</a>';
}
}
echo '</tbody>';
echo '</table>';
}
/**
*
*
*/
function grid_stats_display() {
global $wpdb;
// Retrieve all the posts and their permalinks
$posts = get_posts( array(
'post_type' => 'post',
'post_status' => array( 'publish', 'pending', 'draft', 'future'),
'numberposts' => -1
) );
$post_id2obj = array();
$post_words = array();
foreach ( $posts as $post ) {
$post_id2obj[$post->ID] = $post;
$post_words[$post->ID] = mb_strlen($post->post_content);
}
$table_name = ACCESSES_TABLE_NAME;
$query = "
SELECT post_id, SUM(count) as pv, date
FROM $table_name
GROUP BY post_id
ORDER BY date DESC
";
// Retrieve the access logs
$logs = $wpdb->get_results($query);
$post_id2log = array();
$days = array();
foreach ( $logs as $log ) {
$post_id2log[$log->post_id] = $log;
$days[$log->post_id] = (strtotime("now") - strtotime($log->date)) / 86400;
}
foreach ( $logs as $log ) {
}
// Initialize the table
$row = 9;
if (wp_is_mobile()) {
$row = 4;
}
echo '<style>
table.widefat.stats{
width: 100%;
}
.widefat.stats td, .widefat.stats th {
border: 1px solid black;
padding: 0px 0px !IMPORTANT;
width: calc(100%/'.$row.');
}
.container{
position: relative;
width:calc(100%/'.$row.');
}
.widefat.stats img{
width: 100%;
height: 100%;
object-fit:cover;
aspect-ratio: 100/100;
opacity: 0.6;
}
.container p{
position: absolute;
padding: 5px;
font-size: 7px;
margin:0;
}
.container .date{
top: 5px;
left: 5px;
text-align: center;
background-color: brown;
font-weight: bold;
color: #fff;
}
.container .chars {
background-color: #fff;
left: 5px;
bottom: -5px;
font-weight: 900;
}
.container .pv {
background-color: #fff;
right: 5px;
bottom: -5px;
font-weight: 900;
}
.container .rank {
position: absolute;
font-size: 300%;
font-weight: 900;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
text-shadow: var(--cocoon-white-color) 3px 0px 0px, var(--cocoon-white-color) 2px 1px 0px, var(--cocoon-white-color) 2px 2px 0px, var(--cocoon-white-color) 2px 3px 0px, var(--cocoon-white-color) 1px 3px 0px, var(--cocoon-white-color) 0px 3px 0px, var(--cocoon-white-color) -1px 3px 0px, var(--cocoon-white-color) -2px 2px 0px, var(--cocoon-white-color) -3px 1px 0px, var(--cocoon-white-color) -3px 0px 0px, var(--cocoon-white-color) -3px -1px 0px, var(--cocoon-white-color) -3px -2px 0px, var(--cocoon-white-color) -2px -2px 0px, var(--cocoon-white-color) -1px -3px 0px, var(--cocoon-white-color) 0px -3px 0px, var(--cocoon-white-color) 1px -3px 0px, var(--cocoon-white-color) 2px -2px 0px, var(--cocoon-white-color) 2px -2px 0px, var(--cocoon-white-color) 3px -1px 0px;
}
.container.todo_post .rank, .container.todo_post .chars {
color: red;
}
</style>
';
echo '<table class="widefat stats">';
// Populate the table
echo '<tbody>';
$count = 0;
$last_date = "tomorrow";
foreach ( $posts as $post ) {
if($count == 0) {
echo '<tr>';
}
$log = $post_id2log[$post->ID];
$pv_ave = ($log->pv / ceil($days[$post->ID]));
if (is_nan($pv_ave)) {
$pv_ave = 0;
}
$is_todo_post = 0;
if ($post->post_status == "publish") {
$categories = get_the_category($post->ID);
foreach ( $categories as $category) {
if ($category->term_id == 2458) {
$is_todo_post = 1;
}
}
} else {
$is_todo_post = 1;
}
if ($is_todo_post == 1) {
echo '<td class="container todo_post">';
} else {
echo '<td class="container">';
}
echo '<a href="'. get_permalink($post) . '" title="'. mb_substr($post->post_title, 0, 50) .'">';
$img = get_the_post_thumbnail_url($post->ID, 'thumbnail' );
echo '<img src="' .$img. '" alt="' . mb_substr($post->post_title, 0, 50) . '">';
$date = substr($post->post_date, 0, 10);
if (strtotime($date) != false && floor(strtotime($date)/86400) < floor( strtotime($last_date)/86400)) {
echo '<p class="date">'.$date.'</p>';
$last_date = $date;
}
echo '<p class="chars">'.mb_strlen(strip_tags($post->post_content)).'</p>';
echo '<p class="pv">'. floor($pv_ave).'</p>';
$pv_rank = "";
if ($pv_ave >= 100) {
$pv_rank = "飛";
} else if ($pv_ave >= 40) {
$pv_rank = "角";
} else if ($pv_ave >= 15) {
$pv_rank = "金";
} else if ($pv_ave >= 12) {
$pv_rank = "銀";
} else if ($pv_ave >= 9) {
$pv_rank = "桂";
} else if ($pv_ave >= 6) {
$pv_rank = "香";
} else if ($pv_ave >= 2.5) {
$pv_rank = "歩";
} else {
$pv_rank = "";
}
echo '<p class="rank">'.$pv_rank.'</p>';
echo '</a>';
echo '</td>';
$count = $count+1;
if ($count == $row) {
echo '</tr>';
$count = 0;
}
}
echo '</tbody>';
echo '</table>';
}
こちらもどうぞ。
![[WordPress] 投稿月でグループ分けした月別PV集計表を見るためのカスタムプラグインを作った【ChatGPTと】](https://chiilabo.com/wp-content/uploads/2023/03/image-23-26-320x198.jpg)
![[WordPress] テーマの更新があったので実行した](https://chiilabo.com/wp-content/uploads/2023/03/image-35-8-320x198.jpg)

(補足)
- add_submenu_page – 【初心者】自作のWordPressプラグインを作成する ~コピペで開発できる作り方で解説 | ゼロからわかるホームページの作り方
- get_posts – テンプレートタグ/get posts – WordPress Codex 日本語版
- WP_Post – クラスリファレンス/WP Post – WordPress Codex 日本語版
- mb_strlen, strip_tags 【WordPress】タイトル、本文の文字数制限について解説 | SHU BLOG
- strtotime – PHP 日付 を比較する | WEPICKS!
- position absolute – 【HTML】画像の上に文字を表示する方法について徹底解説! – WEBCAMP MEDIA
- get_the_post_thumbnail_url – アイキャッチ画像の表示・取得関連【Wordpress】 – Sensitivitiy
- get_the_post_thumbnail_url WordPress: アイキャッチ画像URLの取得は get_the_post_thumbnail_url | WWWクリエイターズ
- wp_is_mobile – 表示デバイスと画面サイズの両方を使った判断方法 | ホームNW研究所ホームNW研究所
- post_status ‘draft’ – テンプレートタグ/get posts – WordPress Codex 日本語版
- get_the_category テンプレートタグ/get the category – WordPress Codex 日本語版