公開済みの記事パーツをスラッグで呼び出すコード例です。
通常の投稿ではなく、カスタム投稿タイプblogpartsの記事パーツを対象にします。
SWELL標準のblog_partsとは別の機能です。
準備と貼付先
子テーマのfunctions.phpをバックアップし、PHP領域へ追加します。
後述の「本文とテキストフィールドを分けて表示する」のコードには先頭に<?phpがありますが、既存のPHP領域へ追記するときはこの開始タグを重ねず、functionから貼り付けてください。
旧motoki_show_custom_post_type・replace_shortcodeと対応するショートコード登録は外して置き換えます。
以前の記事では同名関数を複数掲載していましたが、複数の例を同時に入れると関数名が重複します。
blogpartsが未登録の場合は、同じfunctions.phpへ次も追加します。
管理画面の「記事パーツ」で本文とスラッグを設定して公開します。公開するパーツには閲覧者へ見せてよい内容だけを保存してください。このコードは会員制のアクセス制御ではなく、投稿タイプのpublicがfalseでも秘密情報の保護を保証しません。
既に登録済みの投稿タイプの設定は変更しません。
ACFを使う場合は記事パーツに適用するフィールドグループを作り、naraをテキスト型、改行を使うosakaをテキストエリア(textarea)型として登録してください。
add_action('init', function () {
if (!post_type_exists('blogparts')) {
register_post_type('blogparts', [
'label' => '記事パーツ', 'public' => false,
'show_ui' => true, 'show_in_rest' => true,
'supports' => ['title', 'editor'],
]);
}
});本文とテキストフィールドを分けて表示する
<?php
function waza_blogpart_post($slug) {
$slug = sanitize_title($slug);
if ($slug === '') return null;
$posts = get_posts(['name'=>$slug, 'post_type'=>'blogparts', 'post_status'=>'publish', 'numberposts'=>1]);
$post = $posts[0] ?? null;
return $post && $post->post_type === 'blogparts' && $post->post_status === 'publish' && $post->post_password === '' ? $post : null;
}
function waza_blogpart_content($atts) {
static $active = [];
$a = shortcode_atts(['slug'=>''], $atts, 'blogparts');
$post = waza_blogpart_post($a['slug']);
if (!$post || isset($active[$post->ID]) || count($active) >= 8) return '';
$active[$post->ID] = true;
$previous_post = $GLOBALS['post'] ?? null;
try {
// 本文フィルターが投稿情報を変更しても呼出し前の状態へ戻す。
return apply_filters('the_content', $post->post_content);
} finally {
$GLOBALS['post'] = $previous_post;
if ($previous_post instanceof WP_Post) {
setup_postdata($previous_post);
}
unset($active[$post->ID]);
}
}
add_shortcode('blogparts', 'waza_blogpart_content');
function waza_blogpart_field($atts) {
$a = shortcode_atts(['slug'=>'', 'field'=>'', 'find'=>'', 'replace'=>''], $atts, 'blogparts_field');
if (!function_exists('get_field') || !in_array($a['field'], ['nara', 'osaka'], true)) return '';
$post = waza_blogpart_post($a['slug']);
if (!$post) return '';
$value = get_field($a['field'], $post->ID, false);
if (!is_scalar($value)) return '';
$value = (string) $value;
if ($a['find'] !== '') $value = str_replace($a['find'], $a['replace'], $value);
return nl2br(esc_html($value));
}
add_shortcode('blogparts_field', 'waza_blogpart_field');
本文を表示する
[blogparts slug="test"]testは公開済みblogparts記事のスラッグへ置き換えます。
パスワード付き・下書き・存在しない記事は表示しません。
同じパーツへの循環参照は停止し、最大8階層までとしています。
埋め込み先のグローバル記事は入れ替えないため、動的な処理が参照先の記事IDを必要とする場合は明示的にIDを渡す設計が必要です。
ACFのテキストを表示・置換する
[blogparts_field slug="test" field="nara"]
[blogparts_field slug="test" field="osaka" find="醤油ラーメン" replace="塩ラーメン"]fieldはコード内で許可したnara・osakaだけを読みます。
実際に公開してよいテキストフィールド名へ変更してください。
ACFが無効なら空文字です。
文字列の置換はHTMLへ変換する前に行い、値をエスケープして表示します。ACFのget_field()の第3引数をfalseにして未整形値を取得し、文字として表示するためにesc_html()を通しています。
配列や繰り返しフィールド、HTMLをそのまま出す用途には対応していません。
旧例の本文HTML全体に対するstr_replaceや、未エスケープのACF値の連結は撤去しました。
ACF繰り返しとプレースホルダー埋め込みの旧コードは、そのまま混在させず別途データ構造を定義して実装する必要があります。
記事パーツの編集保存から表示まで確認する
ACF 6.8.10の編集画面で、naraをテキスト型、osakaをtextarea型として登録した公開blogpartsを更新しました。
再表示でnaraの文字列0とosakaの改行を保持し、参照ページにパーツ本文と両フィールドが表示されることを確認しました。
osakaに「醤油ラーメン」とHTMLタグを含む文字列を保存したところ、呼び出し側の指定で「塩ラーメン」へ置換され、HTMLタグは文字として表示されました。
改行は残り、script要素は生成されませんでした。
スマホ幅385pxでも0・置換後の文字列・二行目を表示し、横にはみ出しませんでした。
確認するときは、パーツの本文を呼ぶblogpartsと、ACF値を読むblogparts_fieldを分けて試してください。
本文が表示されてもフィールド欄が空なら、フィールドグループの適用先、許可名、保存した型を確認します。
配列を返す型はこのコードの対象外です。

複数パーツを呼ぶ場合は公開状態も個別に確認する
| 参照したパーツ | 本文の出力 |
|---|---|
| 別スラッグの公開パーツA・B | 両方の本文を表示 |
| 非公開のパーツ | 本文を表示しない |
| 公開状態でもパスワード付き | 本文を表示しない |
異なるスラッグの公開パーツを同じ投稿から呼び出し、両方が表示されることを確認しました。
同じ投稿から非公開・パスワード付きのパーツも参照しましたが、これらの本文は出力されませんでした。
スラッグが実在するかだけでなく、参照先の投稿タイプ、公開状態、パスワードの有無を照合します。
既存のパーツを更新するときはA・Bの本文が混ざらないことを確認し、呼び出し元の投稿IDに依存する処理は別に確認してください。
パーツ本文の処理後に投稿と著者情報を戻す
パーツ本文にはthe_contentのフィルターが適用されます。
パーツの中にSWELLのブログパーツや投稿リストを含めると、その内部処理が投稿情報を変更する場合があります。
掲載コードでは、呼出し直前のグローバル投稿を保存し、finallyで戻します。元の投稿がWP_Postの場合だけ、setup_postdata()で著者などの投稿データを再設定します。元の投稿がない場合や、フィルターが変更する任意のグローバル変数まで完全に復元する設計ではありません。
循環参照を防ぐ処理も維持します。
過去の隔離したWordPress 7.1.2とSWELL 2.19.0では、別著者の投稿ループ、投稿が設定されていない呼出し、描画中の例外を確認した記録があります。2026年10月21日の本文見直しでは、その動作試験を再実行していません。
公開中の利用先でのキャッシュ、PC・スマホ表示と操作は別に確認します。
確認と戻し方
存在するスラッグ・存在しないスラッグ・自己参照・非公開・ACF未有効・文字列0で確認します。
パーツ内のリンクや画像はPC・スマホ幅とキーボードでも確認してください。
解除時は本文から呼び出しを外し、追加した関数と登録をまとめて戻します。
パーツ本体やフィールド値は削除しません。
旧GitHub例は今回の修正と同期していません。
よくある質問:クラシックエディタで記事の中に他の記事(記事パーツ)を参照するとき
この方法では、何を呼び出せますか?
記事では、公開済みの記事パーツをスラッグで呼び出すコード例です。通常の投稿ではなく、カスタム投稿タイプblogpartsの記事パーツが対象で、SWELL標準のブログパーツとは別の機能です。
コードは、どこに追加しますか?
記事では、子テーマのfunctions.phpをバックアップし、PHP領域へ追加します。既存のPHP領域へ追記するときは、先頭のPHP開始タグを重ねません。旧版の関数と対応するショートコード登録は外して置き換えます。複数の例を同時に入れると関数名が重複します。
blogpartsが未登録のときは、どうしますか?
記事では、同じfunctions.phpへ登録用のコードも追加します。管理画面の「記事パーツ」で本文とスラッグを設定して公開します。既に登録済みの投稿タイプの設定は変更しません。
どんな記事パーツが表示されますか?
記事では、パスワード付き・下書き・存在しない記事は表示しません。同じパーツへの循環参照は停止し、最大8階層までとしています。異なるスラッグの公開パーツを同じ投稿から呼び出すと両方が表示され、非公開・パスワード付きのパーツ本文は出力されませんでした。
ACFのテキストも、表示できますか?
できます。記事では、ACFを使う場合は記事パーツに適用するフィールドグループを作り、テキスト型と、改行を使うテキストエリア型のフィールドを登録します。パーツの本文を呼ぶものと、ACF値を読むものを分けて試します。配列を返す型はこのコードの対象外です。
本文は表示されるのに、フィールド欄が空のときは?
記事では、フィールドグループの適用先、許可名、保存した型を確認します。
HTMLタグを含む文字列は、どう表示されますか?
記事では、HTMLタグを含む文字列を保存したところ、HTMLタグは文字として表示され、改行は残り、script要素は生成されませんでした。呼び出し側の指定で文字列の置換もできます。
公開前に、何を確認しますか?
記事では、存在するスラッグ・存在しないスラッグ・自己参照・非公開・ACF未有効・文字列0で確認します。パーツ内のリンクや画像は、PC・スマホ幅とキーボードでも確認します。解除時は、本文から呼び出しを外し、追加した関数と登録をまとめて戻します。パーツ本体やフィールド値は削除しません。



