拡張ポイント — filter リファレンス
本プラグインはテーマ・他プラグインからカスタマイズできる WordPress filter を多数提供しています。 本章では主要 11 個 + 補助 5 個の合計 16 個の filter を、関数シグネチャ・デフォルト値・上書きサンプルとともに解説します。
filter 全体一覧
本プラグインが提供する全 filter とその責務を一覧にします。
| filter 名 | 定義ファイル | 1 行説明 |
|---|---|---|
ksmd_md_scheme |
md-renderer.php |
md ホスト URL の scheme (http/https) を上書き |
ksmd_subdir_mode_md_scheme v1.0.3 |
md-subdir-mode.php |
サブディレモード root URL の scheme を上書き (reverse proxy 環境向け) |
ksmd_host |
md-renderer.php / core-functions.php |
md ホスト名を動的に取得 (multisite 対応等) |
ksmd_home_intro_markdown |
md-route-renderers.php |
md ホームの導入 Markdown を上書き |
ksmd_home_archive_links |
md-route-renderers.php |
md ホームに表示するアーカイブセクションのリンク配列 |
ksmd_home_recent_post_type |
md-route-renderers.php |
md ホームの「最近の記事」の post_type |
ksmd_archive_default_post_types |
md-route-renderers.php |
archive route で対象とする post_type 配列のデフォルト |
ksmd_term_archive_post_types |
md-route-renderers.php |
term archive で対象とする post_type |
ksmd_archive_query_args |
md-route-renderers.php |
archive 出力時の WP_Query args (posts_per_page 等) |
ksmd_schema_type |
md-schema-mapper.php / md-route-renderers.php |
post_type/route 別の Schema.org type を動的決定 |
ksmd_route_schema_header_lines |
md-route-renderers.php |
route 別の Schema.org header Markdown 行配列 |
ksmd_route_schema_footer_lines |
md-route-renderers.php |
route 別の Schema.org footer Markdown 行配列 |
ksmd_schema_header_lines |
md-schema-mapper.php |
singular post の Schema.org header Markdown 行配列 |
ksmd_schema_footer_lines |
md-schema-mapper.php |
singular post の Schema.org footer Markdown 行配列 |
ksmd_robots_txt_lines |
md-resolver.php |
md ホストの robots.txt 行配列 |
ksmd_test_renderer_sslverify |
settings-page-logic.php |
診断タブの Test renderer 内 wp_remote_get の sslverify 設定 |
ksmd_bootstrap_sslverify |
md-bootstrap-installer.php |
Bootstrap verify 内 wp_remote_get の sslverify 設定 |
📝 Note
the_content filter は WordPress core のフィルタで本プラグインの拡張点ではありませんが、
singular renderer は apply_filters('the_content', $post->post_content) 経由で本文を取得するため、
the_content に登録した Markdown 系プラグイン (Markdown 入力プラグイン等) の出力もそのまま反映されます。
📝 Note (新機能の拡張点)
includes/md-alternate-link.php (alt-link) と includes/md-favicon-proxy.php (favicon proxy) は
現状 apply_filters() 拡張点なし。設定 toggle (enable_md_alternate_link / enable_favicon_proxy) と
Content Targets 設定で挙動を制御します。将来的に「alt-link 出力対象 URI」「favicon リダイレクト先 URL」などを動的に変更したい
ニーズが生じた場合、対応する filter を追加する余地があります。
ksmd_md_scheme
md ホスト URL の scheme を決定します。
シグネチャ
apply_filters( 'ksmd_md_scheme',
string $scheme, // 'http' or 'https' (home_url から自動算出)
string $url, // 書き換え対象の元 URL
string $md_host // md ホスト名 (例: md.example.com)
);
// 期待戻り値: 'http' or 'https' (それ以外は内部で 'https' に強制矯正)
デフォルト値
home_url() の scheme をそのまま継承します。本番 https サイトは https、
ローカル http (localhost / WSL2) は http になります。
$home_scheme = wp_parse_url( $home_url, PHP_URL_SCHEME );
$scheme = ( $home_scheme === 'http' ) ? 'http' : 'https';
サンプル 1: 強制 https 化
ローカルでは http だが md ホストだけは常に https で配信したい場合 (証明書を md.* にだけ入れている等):
add_filter( 'ksmd_md_scheme', function ( $scheme, $url, $md_host ) {
return 'https';
}, 10, 3 );
サンプル 2: 開発環境だけ http に固定
add_filter( 'ksmd_md_scheme', function ( $scheme, $url, $md_host ) {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
return 'http';
}
return $scheme;
}, 10, 3 );
サンプル 3: 特定パスだけ http
(運用上推奨はしないが、参考として)
add_filter( 'ksmd_md_scheme', function ( $scheme, $url, $md_host ) {
if ( strpos( $url, '/internal-tool/' ) !== false ) {
return 'http';
}
return $scheme;
}, 10, 3 );
ksmd_subdir_mode_md_scheme v1.0.3
サブディレモード root の md ホスト URL を構築するときの scheme を上書きできる filter です。reverse proxy 環境やメインホストと md ホストで scheme が異なる場合に有効です。サブディレモード機能専用のため、サブディレモードを使っていない場合は呼ばれません。
シグネチャ
apply_filters( 'ksmd_subdir_mode_md_scheme',
string $scheme, // 'http' or 'https' (home_url から自動算出、不正値時は is_ssl() フォールバック)
string $md_host, // md ホスト名 (例: md.example.com)
array $opts // 全 ksmd_settings (subdir_mode_enabled / subdir_mode_type 等を含む)
);
// 期待戻り値: 'http' or 'https'
デフォルト値
wp_parse_url( home_url(), PHP_URL_SCHEME ) をそのまま使用。不正値 (空・想定外) のときのみ is_ssl() ベースの判定に fallback します。一般的な ksmd_md_scheme filter (個別ページの URL 用) とは独立して、subdir mode root の https://md.example.com/ 構築時にのみ呼ばれます。
サンプル 1: reverse proxy で常に https
上流 (Cloudflare 等) で TLS 終端し、内部リクエストが http で届く環境。 md ホスト root の canonical 用 URL を強制 https にしたい場合:
add_filter( 'ksmd_subdir_mode_md_scheme', function ( $scheme, $md_host, $opts ) {
return 'https';
}, 10, 3 );
サンプル 2: メインと md で scheme が異なる
メインサイトは http (社内ステージング) だが md ホストには独立して https 証明書を入れている場合、md scheme だけ強制 https にできます:
add_filter( 'ksmd_subdir_mode_md_scheme', function ( $scheme, $md_host, $opts ) {
if ( strpos( $md_host, 'md.staging.' ) === 0 ) {
return 'https'; // ステージング md だけは https
}
return $scheme;
}, 10, 3 );
呼ばれるタイミング
サブディレモードの auto モード renderer (ksmd_render_subdir_root_auto()) で md ホスト URL (https://md.example.com/) を組み立てる前。canonical pointer / parallel mirror 宣言 / 「最近の Markdown コンテンツ」リンク / sitemap.xml URL の構築に影響します。
ksmd_host
md ホスト名を動的に取得・上書きします。
シグネチャ
apply_filters( 'ksmd_host',
string $md_host // 設定値の md_host (空なら ksmd_default_md_host() 算出値)
);
// 期待戻り値: ホスト名文字列 (例: 'md.example.com')
デフォルト値
設定タブの md_host 値、または空なら ksmd_default_md_host()
(home_url() の host から www. を除去して md. を付与) が返ります。
サンプル 1: multisite で blog ID ごとに切替
add_filter( 'ksmd_host', function ( $md_host ) {
if ( ! function_exists( 'get_current_blog_id' ) ) {
return $md_host;
}
$blog_id = get_current_blog_id();
$map = array(
1 => 'md.example.com',
2 => 'md.example.jp',
3 => 'md.example.co.kr',
);
return isset( $map[ $blog_id ] ) ? $map[ $blog_id ] : $md_host;
}, 10, 1 );
サンプル 2: ステージング環境では別ホスト
add_filter( 'ksmd_host', function ( $md_host ) {
if ( defined( 'WP_ENVIRONMENT_TYPE' )
&& WP_ENVIRONMENT_TYPE === 'staging' ) {
return 'md-staging.example.com';
}
return $md_host;
}, 10, 1 );
サンプル 3: 言語別 md ホスト (Polylang/WPML 風)
add_filter( 'ksmd_host', function ( $md_host ) {
if ( function_exists( 'pll_current_language' ) ) {
$lang = pll_current_language( 'slug' );
if ( $lang === 'en' ) {
return 'md-en.example.com';
}
}
return $md_host;
}, 10, 1 );
⚠ Warning
ksmd_host を上書きする場合、その新ホストでも index.php を配置し、
DNS / バーチャルホストを設定する必要があります。Bootstrap installer は設定値の md_host を見るため、
filter で上書きしたホストには対応しません。手動 SSH 配置になります。
ksmd_home_intro_markdown
md ホームの H1/Canonical 直後に挿入する導入 Markdown を上書きします。
シグネチャ
apply_filters( 'ksmd_home_intro_markdown',
string $intro_raw, // 設定値 home_intro_markdown
array $context // home/front_page の context
);
// 期待戻り値: Markdown 文字列 (空なら blogdescription にフォールバック)
デフォルト値
設定値 home_intro_markdown の生値。空文字なら renderer 側で blogdescription
(get_bloginfo('description')) にフォールバックします。
サンプル 1: 動的に当日の記事数を埋め込む
add_filter( 'ksmd_home_intro_markdown', function ( $intro, $context ) {
$count = wp_count_posts( 'post' )->publish;
return "本サイトには現在 **{$count} 本の記事** が公開されています。\n\n"
. "AI クローラ向けの Markdown 並行版です。";
}, 10, 2 );
サンプル 2: 特定 locale だけ別 intro
add_filter( 'ksmd_home_intro_markdown', function ( $intro, $context ) {
if ( get_locale() === 'en_US' ) {
return "Welcome to the AI-optimized Markdown version of our site.";
}
return $intro; // 既存値を尊重
}, 10, 2 );
サンプル 3: テーマ functions.php からの簡易上書き
add_filter( 'ksmd_home_intro_markdown', '__return_empty_string' );
// 強制的に空にして blogdescription だけ表示させる
ksmd_home_archive_links
md ホームの「サイトのセクション」に列挙するアーカイブリンク配列を上書きします。
シグネチャ
apply_filters( 'ksmd_home_archive_links',
array $links, // [['label' => string, 'url' => string, 'pt' => string], ...]
array $context
);
// 期待戻り値: 同じ形式の配列 (label / url 必須、pt 任意)
デフォルト値
enabled_post_types ∩ has_archive=true な post_type の archive link を集めた配列。
page と attachment は除外。リンクは md_host 化済。
サンプル 1: お知らせ archive を先頭に追加
add_filter( 'ksmd_home_archive_links', function ( $links, $context ) {
array_unshift( $links, array(
'label' => 'お知らせ',
'url' => 'https://md.example.com/news/',
'pt' => 'news',
) );
return $links;
}, 10, 2 );
サンプル 2: 特定 post_type を除外
add_filter( 'ksmd_home_archive_links', function ( $links, $context ) {
return array_values( array_filter( $links, function ( $link ) {
return $link['pt'] !== 'product'; // products archive を除外
} ) );
}, 10, 2 );
サンプル 3: ラベルを日本語ローカライズ
add_filter( 'ksmd_home_archive_links', function ( $links, $context ) {
$jp_map = array(
'post' => 'ブログ記事',
'product' => '商品一覧',
'event' => 'イベント情報',
);
foreach ( $links as &$link ) {
if ( isset( $jp_map[ $link['pt'] ] ) ) {
$link['label'] = $jp_map[ $link['pt'] ];
}
}
return $links;
}, 10, 2 );
ksmd_home_recent_post_type
md ホームの「最近の記事」セクションで使う post_type を上書きします。
シグネチャ
apply_filters( 'ksmd_home_recent_post_type',
array|string $default, // 計算済 post_type 配列 (page/attachment 除外済)
array $context
);
// 期待戻り値: post_type slug の string または string[] (両対応で後方互換)
デフォルト値
enabled_post_types から page と attachment を除外した配列。
設定で enabled_post_types が空なら空配列が渡され、renderer 側で「記事がありません」表示になります。
サンプル 1: post のみに固定 (CPT を含めたくない)
add_filter( 'ksmd_home_recent_post_type', function ( $default, $context ) {
return 'post'; // string を返しても可、内部で配列化される
}, 10, 2 );
サンプル 2: お知らせ + ブログを最近の記事に
add_filter( 'ksmd_home_recent_post_type', function ( $default, $context ) {
return array( 'post', 'news' );
}, 10, 2 );
サンプル 3: 特定 CPT を除外
add_filter( 'ksmd_home_recent_post_type', function ( $default, $context ) {
if ( ! is_array( $default ) ) {
$default = array( $default );
}
return array_values( array_diff( $default, array( 'product' ) ) );
}, 10, 2 );
ksmd_archive_default_post_types
archive route (author / date / search / feed) で対象とする post_type 配列のデフォルトを上書きします。
シグネチャ
apply_filters( 'ksmd_archive_default_post_types',
array $list, // 計算済 post_type 配列 (route_type 別 exclude 適用済)
string $route_type, // 'author' | 'date' | 'search' | 'feed' | etc.
array $context
);
// 期待戻り値: post_type slug の配列
デフォルト値
enabled_post_types から以下を除外した配列:
- 常に除外:
attachment search以外で除外:page(WP デフォルトのWP_Query動作と整合)
search route だけ page を含めるのは、WP 標準の is_search() 時に
WP_Query が post_type='any' に切り替えるため、page も検索結果に出るのが WP デフォルト動作だからです。
サンプル 1: feed に CPT も含める
add_filter( 'ksmd_archive_default_post_types',
function ( $list, $route_type, $context ) {
if ( $route_type === 'feed' ) {
$list[] = 'product';
$list[] = 'event';
}
return $list;
}, 10, 3
);
サンプル 2: search から特定 CPT を除外
add_filter( 'ksmd_archive_default_post_types',
function ( $list, $route_type, $context ) {
if ( $route_type === 'search' ) {
$list = array_values( array_diff( $list, array( 'private_post' ) ) );
}
return $list;
}, 10, 3
);
サンプル 3: author 一覧は post のみ
add_filter( 'ksmd_archive_default_post_types',
function ( $list, $route_type, $context ) {
if ( $route_type === 'author' ) {
return array( 'post' );
}
return $list;
}, 10, 3
);
ksmd_term_archive_post_types
term archive (category / tag / custom taxonomy) で対象とする post_type を上書きします。
シグネチャ
apply_filters( 'ksmd_term_archive_post_types',
array $term_post_types, // 計算済配列 (taxonomy.object_type ∩ enabled_post_types)
WP_Term $term, // 当該 term オブジェクト
array $context
);
// 期待戻り値: post_type slug の配列
デフォルト値
get_taxonomy($term->taxonomy)->object_type と enabled_post_types の積集合から
attachment を除外した配列。page は WP 標準動作に合わせて含めます。
サンプル 1: 特定カテゴリは post のみ
add_filter( 'ksmd_term_archive_post_types',
function ( $list, $term, $context ) {
if ( $term->taxonomy === 'category'
&& $term->slug === 'news' ) {
return array( 'post' );
}
return $list;
}, 10, 3
);
サンプル 2: タグページから page を除外
add_filter( 'ksmd_term_archive_post_types',
function ( $list, $term, $context ) {
if ( $term->taxonomy === 'post_tag' ) {
return array_values( array_diff( $list, array( 'page' ) ) );
}
return $list;
}, 10, 3
);
サンプル 3: カスタム taxonomy で CPT を追加
add_filter( 'ksmd_term_archive_post_types',
function ( $list, $term, $context ) {
if ( $term->taxonomy === 'product_brand' ) {
$list[] = 'product_review';
return array_values( array_unique( $list ) );
}
return $list;
}, 10, 3
);
ksmd_archive_query_args
archive 出力時に内部で使う WP_Query args を直前で上書きします。
シグネチャ
apply_filters( 'ksmd_archive_query_args',
array $args, // WP_Query args (post_type, post_status, posts_per_page, paged, etc.)
string $route_type, // 'archive' | 'term' | 'author' | 'date' | 'search' | 'feed' | 'home' | 'front_page'
array $context
);
// 期待戻り値: WP_Query args 配列
デフォルト値
array(
'post_type' => $post_types, // route 別に計算
'post_status' => 'publish',
'posts_per_page' => 50,
'paged' => $paged,
'orderby' => 'date',
'order' => 'DESC',
'has_password' => false,
'no_found_rows' => true,
);
サンプル 1: posts_per_page を増やす
add_filter( 'ksmd_archive_query_args',
function ( $args, $route_type, $context ) {
if ( $route_type === 'archive' || $route_type === 'feed' ) {
$args['posts_per_page'] = 100;
}
return $args;
}, 10, 3
);
サンプル 2: 修正日順にソート
add_filter( 'ksmd_archive_query_args',
function ( $args, $route_type, $context ) {
if ( $route_type === 'archive' ) {
$args['orderby'] = 'modified';
}
return $args;
}, 10, 3
);
サンプル 3: meta_query で sticky を先頭に
add_filter( 'ksmd_archive_query_args',
function ( $args, $route_type, $context ) {
if ( $route_type === 'home' ) {
$args['meta_key'] = '_pinned';
$args['orderby'] = array(
'meta_value' => 'DESC',
'date' => 'DESC',
);
}
return $args;
}, 10, 3
);
ksmd_schema_type
post_type / route 別の Schema.org type を動的に決定します。設定の schema_type_map を上書きする最終ゲートです。
シグネチャ
apply_filters( 'ksmd_schema_type',
string $type, // 設定値 schema_type_map[$post_type] or route 別デフォルト
string $post_type_or_route, // 'post' | 'page' | 'archive' | 'term' | 'author' | 'date' | 'home' | 'front_page' | 'search' | 'feed' | '404'
array $context // singular: ['post' => WP_Post] / route: route context
);
// 期待戻り値: Schema.org type 文字列 (例: 'NewsArticle', 'BlogPosting')
デフォルト値
| post_type / route | デフォルト type |
|---|---|
post | Article |
page | WebPage |
archive | CollectionPage |
term / category / tag | CollectionPage |
author | ProfilePage |
date | CollectionPage |
home / front_page | WebSite |
search | SearchResultsPage |
404 | Thing |
feed | CollectionPage |
サンプル 1: post を NewsArticle として宣言
add_filter( 'ksmd_schema_type',
function ( $type, $key, $context ) {
if ( $key === 'post' ) {
return 'NewsArticle';
}
return $type;
}, 10, 3
);
サンプル 2: カテゴリ別に type を変える
add_filter( 'ksmd_schema_type',
function ( $type, $key, $context ) {
if ( $key !== 'post' ) {
return $type;
}
$post = isset( $context['post'] ) ? $context['post'] : null;
if ( ! ( $post instanceof WP_Post ) ) {
return $type;
}
if ( has_category( 'tutorial', $post ) ) {
return 'TechArticle';
}
if ( has_category( 'news', $post ) ) {
return 'NewsArticle';
}
return $type;
}, 10, 3
);
サンプル 3: search ページを ItemList に
add_filter( 'ksmd_schema_type',
function ( $type, $key, $context ) {
if ( $key === 'search' ) {
return 'ItemList'; // SearchResultsPage より具体的
}
return $type;
}, 10, 3
);
ksmd_route_schema_header_lines
route 別の Schema.org ヘッダブロックの行配列を上書きします。
シグネチャ
apply_filters( 'ksmd_route_schema_header_lines',
array $lines, // Markdown 行の配列 ('> **Schema.org/...**' 等)
string $type, // Schema.org type
string $headline, // タイトル
string $url, // seo の正規 URL (md_host 化前)
array $context
);
// 期待戻り値: Markdown 行の配列
デフォルト値
array(
"> **Schema.org/{$type}**",
"> - name: {$headline}",
"> - inLanguage: {$bcp47}",
"> - url: {$url}", // seo URL
">",
"> **Schema.org/BreadcrumbList**",
"> - 1: {$site_name} ({$home_md})", // md_host
"> - 2: {$headline} ({$url_md})", // md_host
);
サンプル 1: WebSite に SearchAction を追加
add_filter( 'ksmd_route_schema_header_lines',
function ( $lines, $type, $headline, $url, $context ) {
if ( $type !== 'WebSite' ) {
return $lines;
}
$search_url = home_url( '/?s={query}' );
$lines[] = '>';
$lines[] = '> **Schema.org/SearchAction**';
$lines[] = '> - target: ' . $search_url;
$lines[] = '> - query-input: required name=query';
return $lines;
}, 10, 5
);
サンプル 2: BreadcrumbList を完全削除
add_filter( 'ksmd_route_schema_header_lines',
function ( $lines, $type, $headline, $url, $context ) {
$kept = array();
$skip = false;
foreach ( $lines as $line ) {
if ( strpos( (string) $line, '**Schema.org/BreadcrumbList**' ) !== false ) {
$skip = true;
continue;
}
if ( $skip && preg_match( '/^>\s*-\s+\d+:/', (string) $line ) ) {
continue;
}
$skip = false;
$kept[] = $line;
}
return $kept;
}, 10, 5
);
サンプル 3: author route で sameAs を追加
add_filter( 'ksmd_route_schema_header_lines',
function ( $lines, $type, $headline, $url, $context ) {
if ( $type !== 'ProfilePage' ) {
return $lines;
}
$author = isset( $context['author'] ) ? $context['author'] : null;
if ( ! ( $author instanceof WP_User ) ) {
return $lines;
}
$twitter = get_user_meta( $author->ID, 'twitter', true );
if ( $twitter ) {
$lines[] = '> - sameAs: https://twitter.com/' . $twitter;
}
return $lines;
}, 10, 5
);
ksmd_route_schema_footer_lines
route 別の Schema.org フッタブロック (Organization) の行配列を上書きします。
シグネチャ
apply_filters( 'ksmd_route_schema_footer_lines',
array $lines // フッタの Markdown 行配列 (---, > **Schema.org/Organization**, ...)
);
// 期待戻り値: Markdown 行の配列
デフォルト値
array(
"---",
"",
"> **Schema.org/Organization**",
"> - name: {$site_name}",
"> - url: {$site_url}", // seo URL
"> - logo: {$logo_url}", // get_site_icon_url() があれば
);
サンプル 1: Organization に sameAs を追加
add_filter( 'ksmd_route_schema_footer_lines', function ( $lines ) {
$lines[] = '> - sameAs: https://twitter.com/your_handle';
$lines[] = '> - sameAs: https://www.facebook.com/your_page';
$lines[] = '> - sameAs: https://www.linkedin.com/company/your_co';
return $lines;
}, 10, 1 );
サンプル 2: 連絡先を追加
add_filter( 'ksmd_route_schema_footer_lines', function ( $lines ) {
$lines[] = '>';
$lines[] = '> **Schema.org/ContactPoint**';
$lines[] = '> - contactType: customer support';
$lines[] = '> - email: support@example.com';
$lines[] = '> - availableLanguage: ja, en';
return $lines;
}, 10, 1 );
サンプル 3: フッタを完全に空にする
add_filter( 'ksmd_route_schema_footer_lines', '__return_empty_array' );
ksmd_schema_header_lines (singular)
singular post (post / page / CPT 単一) の Schema.org ヘッダ行を上書きします。route 用とは別 filter です。
シグネチャ
apply_filters( 'ksmd_schema_header_lines',
array $lines,
WP_Post $post
);
デフォルト値
array(
"> **Schema.org/{$type}**", // Article / WebPage / 上書き型
"> - headline: {$headline}",
"> - author: {$author_name}",
"> - datePublished: {$date_published}",
"> - dateModified: {$date_modified}",
"> - inLanguage: {$bcp47}",
"> - url: {$permalink}", // seo URL
">",
"> **Schema.org/BreadcrumbList**",
"> - 1: {$site_name} ({$home_md})",
"> - 2: {$archive_label} ({$archive_md})",
"> - 3: {$headline} ({$permalink_md})",
);
サンプル: 記事に keywords を追加
add_filter( 'ksmd_schema_header_lines',
function ( $lines, $post ) {
$tags = wp_get_post_tags( $post->ID, array( 'fields' => 'names' ) );
if ( ! empty( $tags ) ) {
$lines[] = '> - keywords: ' . implode( ', ', $tags );
}
return $lines;
}, 10, 2
);
ksmd_schema_footer_lines (singular)
singular post の Schema.org フッタ (Person + Organization) を上書きします。
シグネチャ
apply_filters( 'ksmd_schema_footer_lines',
array $lines,
WP_Post $post
);
サンプル: 著者の Twitter / GitHub を sameAs として追加
add_filter( 'ksmd_schema_footer_lines',
function ( $lines, $post ) {
$twitter = get_user_meta( $post->post_author, 'twitter', true );
$github = get_user_meta( $post->post_author, 'github', true );
$extras = array();
if ( $twitter ) {
$extras[] = '> - sameAs: https://twitter.com/' . $twitter;
}
if ( $github ) {
$extras[] = '> - sameAs: https://github.com/' . $github;
}
if ( empty( $extras ) ) {
return $lines;
}
// Person ブロックの末尾に sameAs を差し込む (簡易版: 最初の '>' 区切りの直前に挿入)
$kept = array();
$injected = false;
foreach ( $lines as $line ) {
if ( ! $injected && trim( (string) $line ) === '>' ) {
foreach ( $extras as $extra ) {
$kept[] = $extra;
}
$injected = true;
}
$kept[] = $line;
}
return $kept;
}, 10, 2
);
補助 filter
ksmd_robots_txt_lines
md ホストの /robots.txt 出力行を上書きします。
apply_filters( 'ksmd_robots_txt_lines', array $lines );
サンプル: 特定 UA を Disallow:
add_filter( 'ksmd_robots_txt_lines', function ( $lines ) {
$lines[] = '';
$lines[] = 'User-agent: BadBot';
$lines[] = 'Disallow: /';
return $lines;
}, 10, 1 );
ksmd_test_renderer_sslverify
診断タブ Test renderer の wp_remote_get 内 sslverify を制御します (オレオレ証明書のローカル検証用)。
apply_filters( 'ksmd_test_renderer_sslverify', bool $verify );
// ローカル開発のみ無効化
add_filter( 'ksmd_test_renderer_sslverify', function ( $verify ) {
if ( defined( 'WP_ENVIRONMENT_TYPE' )
&& WP_ENVIRONMENT_TYPE === 'local' ) {
return false;
}
return $verify;
}, 10, 1 );
ksmd_bootstrap_sslverify
Bootstrap installer の verify アクションで使う wp_remote_get の sslverify を制御します。
apply_filters( 'ksmd_bootstrap_sslverify', bool $verify );
複数 filter の組み合わせ例
例 1: multisite で md_host を動的化 + i18n を route 別に切替
/**
* multisite + i18n: blog ID ごとに md_host と inLanguage を切り替え
*/
// (1) blog ID ごとに md_host
add_filter( 'ksmd_host', function ( $md_host ) {
if ( ! function_exists( 'get_current_blog_id' ) ) {
return $md_host;
}
$map = array(
1 => 'md.example.com', // ja
2 => 'md-en.example.com', // en
3 => 'md-ko.example.com', // ko
);
$bid = get_current_blog_id();
return isset( $map[ $bid ] ) ? $map[ $bid ] : $md_host;
}, 10, 1 );
// (2) blog ID ごとに inLanguage を上書き (header lines に介入)
add_filter( 'ksmd_route_schema_header_lines',
function ( $lines, $type, $headline, $url, $context ) {
if ( ! function_exists( 'get_current_blog_id' ) ) {
return $lines;
}
$lang_map = array(
1 => 'ja-JP',
2 => 'en-US',
3 => 'ko-KR',
);
$bid = get_current_blog_id();
$lang = isset( $lang_map[ $bid ] ) ? $lang_map[ $bid ] : 'ja-JP';
// inLanguage 行を置換
foreach ( $lines as &$line ) {
if ( strpos( (string) $line, '> - inLanguage:' ) === 0 ) {
$line = '> - inLanguage: ' . $lang;
}
}
return $lines;
}, 10, 5
);
// (3) Singular でも同様
add_filter( 'ksmd_schema_header_lines',
function ( $lines, $post ) {
if ( ! function_exists( 'get_current_blog_id' ) ) {
return $lines;
}
$lang_map = array(
1 => 'ja-JP',
2 => 'en-US',
3 => 'ko-KR',
);
$bid = get_current_blog_id();
$lang = isset( $lang_map[ $bid ] ) ? $lang_map[ $bid ] : 'ja-JP';
foreach ( $lines as &$line ) {
if ( strpos( (string) $line, '> - inLanguage:' ) === 0 ) {
$line = '> - inLanguage: ' . $lang;
}
}
return $lines;
}, 10, 2
);
例 2: ニュースサイト向け統合プリセット
/**
* ニュースサイト最適化:
* - post を NewsArticle 化
* - 一覧は新着順 100 件
* - Organization に sameAs を 3 件追加
* - home の最近記事は post と news CPT
*/
add_filter( 'ksmd_schema_type', function ( $type, $key, $context ) {
if ( $key === 'post' ) return 'NewsArticle';
if ( $key === 'home' || $key === 'front_page' ) return 'NewsMediaOrganization';
return $type;
}, 10, 3 );
add_filter( 'ksmd_archive_query_args',
function ( $args, $route_type, $context ) {
if ( in_array( $route_type, array( 'archive', 'home', 'feed' ), true ) ) {
$args['posts_per_page'] = 100;
}
return $args;
}, 10, 3
);
add_filter( 'ksmd_route_schema_footer_lines', function ( $lines ) {
$lines[] = '> - sameAs: https://twitter.com/news_site';
$lines[] = '> - sameAs: https://www.facebook.com/news_site';
$lines[] = '> - sameAs: https://www.youtube.com/@news_site';
return $lines;
}, 10, 1 );
add_filter( 'ksmd_home_recent_post_type', function ( $default, $context ) {
return array( 'post', 'news' );
}, 10, 2 );
例 3: EC サイト向け統合プリセット
/**
* EC サイト向け:
* - product を Product として宣言
* - product 一覧 archive を ItemList に
* - 商品ブランド taxonomy で post_type を product のみに
* - home に products archive を最優先で
*/
add_filter( 'ksmd_schema_type', function ( $type, $key, $context ) {
if ( $key === 'product' ) return 'Product';
if ( $key === 'archive' ) {
$pt = isset( $context['post_type'] ) ? $context['post_type'] : '';
if ( $pt === 'product' ) return 'ItemList';
}
return $type;
}, 10, 3 );
add_filter( 'ksmd_term_archive_post_types',
function ( $list, $term, $context ) {
if ( $term->taxonomy === 'product_brand' ) {
return array( 'product' );
}
return $list;
}, 10, 3
);
add_filter( 'ksmd_home_archive_links', function ( $links, $context ) {
// products を先頭に
usort( $links, function ( $a, $b ) {
if ( $a['pt'] === 'product' ) return -1;
if ( $b['pt'] === 'product' ) return 1;
return 0;
} );
return $links;
}, 10, 2 );
filter 登録のタイミング
登録すべきタイミングは plugins_loaded 以降
本プラグインは plugins_loaded priority 0 で ksmd_bootstrap_plugin() を実行し、
その中で全モジュールを load します。filter は WordPress の filter システムに登録するだけなので、
実際にはどのタイミングで add_filter しても大丈夫です。ただし以下のガイドラインを推奨します:
- テーマ
functions.php: ファイルの最上位で直接add_filter()呼出 OK (テーマ load はplugins_loaded以降) - 他プラグイン:
plugins_loadedpriority 1 以降か、inithook 内で登録すれば確実 - 必要な関数が未定義の場合: filter コールバック内で
function_exists()ガードする
典型的なミス
⚠ Warning
ミス例 1: plugins_loaded priority -1 等の超早期で登録すると、
本プラグインの ksmd_bootstrap_plugin() より前に動くため、定数 KSMD_OPTION_KEY
等が未定義のままコールバックが呼ばれる可能性がある。priority 1 以上を推奨。
⚠ Warning
ミス例 2: after_setup_theme 等のテーマ初期化 hook で
get_post_types() を呼ぶと、init 後に登録される CPT がまだ未登録の可能性がある。
CPT を扱う filter コールバックは init priority 11 以降での登録を推奨。
register_post_type と filter の協調
// よくないパターン: priority 0 だと CPT 未登録
// add_action( 'plugins_loaded', function () {
// add_filter( 'ksmd_archive_default_post_types', function ( $list ) {
// return array_merge( $list, get_post_types( array( 'public' => true ) ) );
// }, 10, 3 );
// }, 0 );
// 良いパターン: init priority 11 以降
add_action( 'init', function () {
add_filter( 'ksmd_archive_default_post_types',
function ( $list, $route_type, $context ) {
$public = array_diff(
get_post_types( array( 'public' => true ) ),
array( 'attachment' )
);
return array_values( array_unique( array_merge( $list, $public ) ) );
}, 10, 3
);
}, 11 );
filter 起動タイミングの一覧
| filter | 呼ばれるタイミング |
|---|---|
ksmd_host | md ホスト判定時 + URL 書き換え時 |
ksmd_md_scheme | URL 書き換え時 (本文 / Schema 内 URL) |
ksmd_home_intro_markdown | home/front_page renderer 実行時 |
ksmd_home_archive_links | home renderer + ItemList 構築時 |
ksmd_home_recent_post_type | home renderer 「最近の記事」構築時 |
ksmd_archive_default_post_types | author/date/search/feed renderer の WP_Query 構築前 |
ksmd_term_archive_post_types | term renderer の WP_Query 構築前 |
ksmd_archive_query_args | 各 route の WP_Query 直前 |
ksmd_schema_type | Schema.org block 構築開始時 |
ksmd_route_schema_header_lines | route Schema header 構築完了直後 |
ksmd_route_schema_footer_lines | route Schema footer 構築完了直後 |
ksmd_schema_header_lines | singular Schema header 構築完了直後 |
ksmd_schema_footer_lines | singular Schema footer 構築完了直後 |
ksmd_robots_txt_lines | md ホスト /robots.txt 構築時 |
priority と $accepted_args の使い分け
add_filter() の第 3 引数は $priority、第 4 引数は $accepted_args です。
本プラグインの全 filter について、最低限必要な $accepted_args 値は以下です:
| filter | 引数の数 | 第 4 引数 |
|---|---|---|
ksmd_md_scheme | 3 | 3 |
ksmd_host | 1 | 1 (省略可) |
ksmd_home_intro_markdown | 2 | 2 |
ksmd_home_archive_links | 2 | 2 |
ksmd_home_recent_post_type | 2 | 2 |
ksmd_archive_default_post_types | 3 | 3 |
ksmd_term_archive_post_types | 3 | 3 |
ksmd_archive_query_args | 3 | 3 |
ksmd_schema_type | 3 | 3 |
ksmd_route_schema_header_lines | 5 | 5 |
ksmd_route_schema_footer_lines | 1 | 1 (省略可) |
ksmd_schema_header_lines | 2 | 2 |
ksmd_schema_footer_lines | 2 | 2 |
ksmd_robots_txt_lines | 1 | 1 (省略可) |
priority の指針
- priority 10 (デフォルト): 通常の上書き
- priority 1〜9: 他プラグインより先に動かしたい場合 (デフォルト計算前に介入)
- priority 11〜99: 他プラグインの 10 より後に動かしたい場合 (他プラグインの上書きを上書き)
- priority 100+: ほぼ最終確定したい上書き
$accepted_args の指針
必要な引数の数を正確に指定すること。デフォルトは 1 なので、
2 つ目以降の引数 (例: $post, $context) を使いたい場合は明示する必要があります。
指定しないと第 2 引数以降が常に null になります。
// よくある間違い: $context を使いたいが第 4 引数を省略 → $context が null になる
// add_filter( 'ksmd_archive_default_post_types', function ( $list, $route_type, $context ) {
// // $context が常に null
// } ); // ← デフォルト accepted_args=1 で $list しか渡されない
// 正しい記述
add_filter( 'ksmd_archive_default_post_types',
function ( $list, $route_type, $context ) {
// 全引数が利用可能
return $list;
},
10, // priority
3 // accepted_args
);
テーマ functions.php に書く例
すべてのカスタマイズを 1 ファイル (テーマ functions.php もしくは独自プラグイン)
に集約する書き方の例です。
<?php
/**
* theme/functions.php — ksmd 拡張
*/
// ----------------------------------------------------------
// 1. md_host を動的化 (multisite 対応)
// ----------------------------------------------------------
add_filter( 'ksmd_host', 'mytheme_ksmd_host', 10, 1 );
function mytheme_ksmd_host( $md_host ) {
if ( function_exists( 'get_current_blog_id' ) ) {
$bid = get_current_blog_id();
$map = array(
1 => 'md.example.com',
2 => 'md-en.example.com',
);
if ( isset( $map[ $bid ] ) ) {
return $map[ $bid ];
}
}
return $md_host;
}
// ----------------------------------------------------------
// 2. post を NewsArticle 扱いに
// ----------------------------------------------------------
add_filter( 'ksmd_schema_type', 'mytheme_ksmd_schema_type', 10, 3 );
function mytheme_ksmd_schema_type( $type, $key, $context ) {
if ( $key === 'post' ) return 'NewsArticle';
return $type;
}
// ----------------------------------------------------------
// 3. archive 一覧を 100 件に
// ----------------------------------------------------------
add_filter( 'ksmd_archive_query_args', 'mytheme_ksmd_archive_query_args', 10, 3 );
function mytheme_ksmd_archive_query_args( $args, $route_type, $context ) {
if ( in_array( $route_type, array( 'archive', 'home', 'feed' ), true ) ) {
$args['posts_per_page'] = 100;
}
return $args;
}
// ----------------------------------------------------------
// 4. Organization に sameAs を 3 件追加
// ----------------------------------------------------------
add_filter( 'ksmd_route_schema_footer_lines',
'mytheme_ksmd_org_sameAs', 10, 1 );
add_filter( 'ksmd_schema_footer_lines',
'mytheme_ksmd_org_sameAs_singular', 10, 2 );
function mytheme_ksmd_org_sameAs( $lines ) {
$extras = array(
'> - sameAs: https://twitter.com/your_handle',
'> - sameAs: https://www.facebook.com/your_page',
);
foreach ( $extras as $line ) {
$lines[] = $line;
}
return $lines;
}
function mytheme_ksmd_org_sameAs_singular( $lines, $post ) {
return mytheme_ksmd_org_sameAs( $lines );
}
// ----------------------------------------------------------
// 5. home の intro を季節で動的に変える
// ----------------------------------------------------------
add_filter( 'ksmd_home_intro_markdown',
'mytheme_ksmd_home_intro', 10, 2 );
function mytheme_ksmd_home_intro( $intro, $context ) {
$month = (int) date_i18n( 'n' );
if ( $month === 12 || $month === 1 ) {
return "新年の特集ページを公開中です。\n\n" . $intro;
}
return $intro;
}
他プラグインからのアクセス
Cocoon との連携
Cocoon は the_content 経由でショートコードを展開しますが、本プラグインは
the_content フィルタ通過後の HTML を Markdown 化するため、Cocoon のショートコード展開結果
(例: [toc] による目次) はそのまま反映されます。
ただし以下の挙動に注意:
nav/aside/footerは完全除外なので、Cocoon のサイドバー要素は出ない- Cocoon のスタイル付きボックスショートコード (
[box01]等) はdivラッパが透過されて中身だけ取り出される - Cocoon の関連記事ウィジェットは Markdown 化されないが、本プラグインの「最近の記事」セクションが代替する
Yoast SEO との連携
Yoast の canonical / sitemap 出力はメインサイト (www) で動作し、md ホストでは
template_redirect priority -1 で本プラグインが先に exit するため Yoast は動きません。
つまり md ホストで Yoast の <head> 出力が混入することはありません。
md ホストの canonical は本プラグインが HTTP Link ヘッダで宣言します。
X-Robots-Tag: noindex, follow も同様に本プラグインが付与します。
つまり Yoast と本プラグインは「メインサイトの SEO 担当 = Yoast」「md ホストの canonical 宣言 = 本プラグイン」
という分業が自然に成立します。
RankMath との連携
RankMath も Yoast と同様、メインサイト側でだけ動作します。md ホストには影響しません。
ただし RankMath が the_content hook で BreadcrumbList の自動挿入をしている場合、
その HTML 出力が Markdown 化されて含まれる可能性があります。本プラグインの BreadcrumbList と重複しないよう、
必要なら以下の filter で対処してください:
// 例: RankMath の breadcrumb HTML が記事冒頭に出ている場合、md 経路だけ remove
add_action( 'template_redirect', function () {
$host = isset( $_SERVER['HTTP_HOST'] )
? strtolower( $_SERVER['HTTP_HOST'] )
: '';
$opts = get_option( 'ksmd_settings', array() );
$md_host = isset( $opts['md_host'] ) ? $opts['md_host'] : '';
if ( $host !== strtolower( $md_host ) ) return;
// RankMath の breadcrumb 関連 filter を remove
remove_filter( 'the_content', 'rank_math_breadcrumbs_inject' );
}, -2 ); // ksmd の priority -1 より先
Polylang / WPML との連携
多言語プラグインを使う場合、md_host の言語別切替を ksmd_host filter で実装することが推奨です。
また inLanguage も言語別に上書きすると AI クローラに正しく多言語サイトとして認識されます。
add_filter( 'ksmd_host', function ( $md_host ) {
if ( function_exists( 'pll_current_language' ) ) {
$lang = pll_current_language( 'slug' );
if ( $lang === 'en' ) return 'md-en.example.com';
if ( $lang === 'ko' ) return 'md-ko.example.com';
}
return $md_host;
}, 10, 1 );
💡 Tip
言語別に md_host を切り替えた場合、それぞれの md_host について Bootstrap installer か手動 SSH で
index.php を配置する必要があります。設定タブの md_host は単一値しか保存できないため、
Bootstrap installer は 1 ホストのみ対応。残りのホストは SSH で同じ index.php を配置してください。
WP-CLI との連携
WP-CLI から本プラグインの cache を flush するには:
wp eval 'ksmd_cache_flush_all();'
# transient だけ消したい場合
wp transient delete --all --network
WP-CLI は DOING_CRON/DOING_AJAX/REST_REQUEST 定数を立てないため、
md ホストへ wp eval --url=md.example.com/... でリクエストすることはできますが、
通常は不要です (テスト用)。
まとめ
本章では本プラグインが提供する 16 個の filter を解説しました:
- 主要 11 個:
ksmd_md_scheme/ksmd_host/ksmd_home_intro_markdown/ksmd_home_archive_links/ksmd_home_recent_post_type/ksmd_archive_default_post_types/ksmd_term_archive_post_types/ksmd_archive_query_args/ksmd_schema_type/ksmd_route_schema_header_lines/ksmd_route_schema_footer_lines - singular 系 2 個:
ksmd_schema_header_lines/ksmd_schema_footer_lines - 補助 3 個:
ksmd_robots_txt_lines/ksmd_test_renderer_sslverify/ksmd_bootstrap_sslverify
これらを組み合わせれば、本プラグインのコードに一切手を入れずに以下のようなカスタマイズが可能です:
- multisite + 言語別 md_host
- ニュースサイト / EC サイト向け Schema.org type プリセット
- サイト固有の home intro / archive リンク
- archive 件数・ソート順の調整
- Organization / Person への sameAs / contactPoint 追加
- ローカル開発時の sslverify 制御
次章「トラブルシューティング」では、これらの filter を使っても解決しない問題への対処方法を解説します。