投稿を保存したときに、本文から読む時間の目安を計算してreadtimeへ保存します。1分600文字という仮定の概算で、実際の読了時間を測定するものではありません。ACFを使わず、WordPress標準の投稿メタだけで動かせます。
保存時に計算するコード
子テーマのfunctions.phpのPHP領域へ追加します。旧get_time_to_content_read・save_read_timeと旧save_postフックは外してください。対象は通常投稿のみで、固定ページ・リビジョン・自動下書きは対象外です。
<?php
function waza_read_minutes($content) {
$text = html_entity_decode(wp_strip_all_tags(strip_shortcodes($content)), ENT_QUOTES, 'UTF-8');
$text = preg_replace('/\s+/u', '', $text);
return (int) ceil(mb_strlen($text, 'UTF-8') / 600);
}
function waza_save_read_minutes($id, $post) {
if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || wp_is_post_revision($id) || wp_is_post_autosave($id)) return;
if ($post->post_type !== 'post' || $post->post_status === 'auto-draft' || !current_user_can('edit_post', $id)) return;
update_post_meta($id, 'readtime', waza_read_minutes($post->post_content));
}
add_action('save_post_post', 'waza_save_read_minutes', 20, 2);
600文字の境界を確認する
0文字は0分、1〜600文字は1分、601〜1200文字は2分です。旧floor(文字数/600)+1では600文字が2分になるため、ceilで切り上げています。HTMLタグ・登録済みショートコード・空白を除いて計算します。画像、動画、外部コンテンツ、ショートコードが生成する文章を読む時間は含めません。
投稿更新と自動処理での更新を区別する
| 更新のしかた | このコードの処理 |
|---|---|
| 編集権限のある利用者が通常投稿を更新 | 保存された本文から再計算 |
| 固定ページ・リビジョン・自動下書き | 対象外 |
| 利用者を設定しない背景処理による更新 | edit_postの権限確認を通らないため再計算しない |
| 同じreadtimeを別の保存処理も更新 | 後から保存された値になるため計算専用キーを使う |
インポートや定期処理の後で値が古い場合は、今回の保存処理が実行される条件を確認します。コードを有効化しただけでは、既存記事や背景処理で変更した本文を一括再計算しません。必要な場合は対象と権限を決めた別の処理を設計してください。
実WordPressの投稿更新で、今回より前の保存フックの値を計算値へ置き換えること、後の保存フックが計算値をさらに置き換え得ることを確認しています。優先度20はすべてのプラグインより後に動くという意味ではありません。readtimeを手動入力する欄と併用せず、別の専用キーへ変更する場合は保存コードと表示コードの両方を同じ名前へ合わせます。
編集画面で更新した本文と保存値を照合する
| 編集操作 | 保存後のreadtime | 照合した内容 |
|---|---|---|
| 601文字の本文を更新 | 2 | 検証用テンプレートに2分と表示 |
| 600文字へ戻して更新 | 1 | 保存本文600文字と1分の表示 |
| 無関係のメタを登録したまま更新 | 変更なし | unrelated_keyの文字列を保持 |
今回は通常投稿の編集画面から本文を更新し、保存後のメタ値と公開表示を照合しました。スマホ幅385pxでも600文字の本文と「読む目安: 1分」が表示され、横にはみ出しませんでした。掲載コードを有効化しただけの状態と、対象投稿を更新した後の状態を区別してください。
保存直後に別タブを開いても、更新処理が終わる前なら古い表示が残ることがあります。編集画面の更新結果を確認し、その後に公開ページを再読み込みして照合します。readtimeは計算専用とし、他の手入力欄や保存処理と同じキーを使わないようにします。

HTMLを含む600文字の本文で保存値を確かめる
| 保存した本文 | 計算対象の文字数 | 保存後の目安 |
|---|---|---|
| 段落・strongタグ、空白、登録済みタグを含む本文 | 600文字 | 1分 |
| 同じ本文へ通常の文字を1文字追加 | 601文字 | 2分 |
投稿編集画面からHTMLを含む本文を更新し、保存メタreadtimeと公開表示を照合しました。
タグの属性文字列、空白、登録済みショートコードの記述は文字数に含まれず、通常の本文を1文字増やすと2分へ変わりました。
登録されていないショートコード風の文字列は、strip_shortcodes()で除去される登録済みタグと条件が違います。
プラグインを止めた後の本文や外部コンテンツを含む記事では、本文の文字数に基づく目安と実際の読み時間を分けて扱ってください。
値の確認と表示
コード追加後に対象投稿を更新すると、その記事のreadtimeが更新されます。既存記事の一括再計算は行いません。手動入力やACFの編集欄と同じキーを併用すると保存順序で値が変わるため、このキーは計算専用にしてください。
<?php
$minutes = get_post_meta(get_the_ID(), 'readtime', true);
if (is_numeric($minutes) && (int) $minutes > 0) {
echo '<p>読む目安: ' . esc_html((string) (int) $minutes) . '分</p>';
}表示コードは自作テンプレートのループ内で使います。ブロックエディターへPHPを直接貼っても動きません。保存前後のメタ値と、600文字ちょうどの文章で確認してください。取り消す場合は保存フックと表示コードを外します。保存値は残りますが自動更新されなくなります。
プレーンテキストで計算を試す
空白を除く文字数を600で割り、切り上げる部分だけをブラウザーで試せます。HTMLやショートコードの除去、WordPressへの保存を再現する見本ではありません。
0文字・0分



