WordPressでGeneratePressみたいなシンプルなテーマを使ってると、記事内にウィジェットを追加したくなりますよね。タイトル下や見出し前、記事末尾にウィジェットを設置できるプラグインを自作してみました。テーマを直接カスタマイズするより簡単で、更新の影響も受けません。軽量なプラグインで速度も維持できますよ!
はじめに
ブログを書いていると、「記事のここにもウィジェットを置きたい!」と思うことはありませんか?通常、WordPressのウィジェットはサイドバーやフッターなど、決められた場所にしか設置できません。しかし、記事の途中、例えば見出しの前や記事の終わりに関連コンテンツやバナーなどを表示できたら便利ですよね。
そんな悩みを解決するために、記事内の特定位置にウィジェットを設置できるプラグインを開発しました。このプラグインを使えば、記事タイトルの下、最初の見出しの前、そして記事の終わりに好きなウィジェットを簡単に設置できます。
なぜこのプラグインが必要だったのか
現在、GeneratePressというシンプルなテーマを使用しています。このテーマは軽量で高速ですが、ウィジェットエリアが限られています。もちろん、テーマをカスタマイズして必要なウィジェットエリアを追加することも可能ですが、それにはコードの編集が必要で、テーマの更新時に変更点が上書きされる恐れもあります。
プラグインとして実装すれば、テーマの更新に影響されず、必要なときにオン・オフできる柔軟性も得られます。さらに、他のシンプルなテーマを使用している方にも役立つでしょう。
WordPressでブログを運営していると、記事の流れを崩さずに追加情報を表示したいケースがよくあります。例えば:
- 記事の冒頭(タイトル下)に著者紹介や要約を表示したい
- 目次や重要なお知らせを最初の見出し前に置きたい
- 記事の終わりに関連記事や「次に読むべき記事」を表示したい
このような配置は、ユーザーの読書体験を向上させ、サイト内の回遊率を高めるのに役立ちます。料理のレシピでいえば、材料と手順の間に「ポイント」を挟み込めるようなものです。
プラグインの機能と使い方
このプラグインは非常にシンプルですが、とても便利です。以下の3つの特別なウィジェットエリアを追加します。
- 記事タイトル下部 – 記事のタイトル直後に表示されます
- 最初の見出し上部 – 記事内の最初のh2タグ(大見出し)の前に表示されます
- 記事コンテンツ下部 – 記事の最後に表示されます
使い方は普通のウィジェットと同じです。WordPress管理画面の「外観」→「ウィジェット」から、これらの特別なエリアにお好みのウィジェットをドラッグ&ドロップするだけです。テキスト、画像、最新記事リスト、カスタムHTMLなど、標準のウィジェットはもちろん、他のプラグインが提供するウィジェットも設置できます。
技術的な仕組み
このプラグインは、WordPressの「フィルターフック」という仕組みを利用しています。フィルターフックは、WordPressの内部データが画面に表示される前に、そのデータを加工・変更できるシステムです。学校の給食で例えると、配膳係が食事を運ぶ途中で「ここにふりかけをかけよう」と調整できるような仕組みです。
<?php
namespace ChiiLabo\ContentWidgetAreas;
if (!defined('ABSPATH')) {
exit;
}
define(__NAMESPACE__ . '\\VERSION', '1.0.0');
define(__NAMESPACE__ . '\\PLUGIN_DIR', plugin_dir_path(__FILE__));
define(__NAMESPACE__ . '\\PLUGIN_URL', plugin_dir_url(__FILE__));
function register_widget_areas() {
register_sidebar(
array(
'name' => '記事タイトル下部',
'id' => 'below-title',
'description' => '記事タイトルの下に表示されるウィジェットエリア',
'before_widget' => '<div id="%1$s" class="widget below-title-widget %2$s">',
'after_widget' => '</div>',
'before_title' => '<h4 class="widget-title">',
'after_title' => '</h4>',
)
);
register_sidebar(
array(
'name' => '最初の見出し上部',
'id' => 'before-first-h2',
'description' => '最初のh2タグの前に表示されるウィジェットエリア',
'before_widget' => '<div id="%1$s" class="widget before-h2-widget %2$s">',
'after_widget' => '</div>',
'before_title' => '<h4 class="widget-title">',
'after_title' => '</h4>',
)
);
register_sidebar(
array(
'name' => '記事コンテンツ下部',
'id' => 'after-content',
'description' => '記事の最後に表示されるウィジェットエリア',
'before_widget' => '<div id="%1$s" class="widget after-content-widget %2$s">',
'after_widget' => '</div>',
'before_title' => '<h4 class="widget-title">',
'after_title' => '</h4>',
)
);
}
add_action('widgets_init', __NAMESPACE__ . '\\register_widget_areas');
function insert_widget_areas($content) {
if (!is_singular() && !is_date()) {
return $content;
}
$content = insert_below_title_widget($content);
$content = insert_before_first_h2_widget($content);
$content = insert_after_content_widget($content);
return $content;
}
add_filter('the_content', __NAMESPACE__ . '\\insert_widget_areas');
function insert_below_title_widget($content) {
ob_start();
dynamic_sidebar('below-title');
$title_widget = ob_get_clean();
if (!empty($title_widget)) {
$content = $title_widget . $content;
}
return $content;
}
function insert_before_first_h2_widget($content) {
if (strpos($content, '<h2') === false) {
return $content;
}
ob_start();
dynamic_sidebar('before-first-h2');
$h2_widget = ob_get_clean();
if (!empty($h2_widget)) {
$h2_pos = strpos($content, '<h2');
$content = substr_replace($content, $h2_widget, $h2_pos, 0);
}
return $content;
}
function insert_after_content_widget($content) {
ob_start();
dynamic_sidebar('after-content');
$after_content_widget = ob_get_clean();
if (!empty($after_content_widget)) {
$content .= $after_content_widget;
}
return $content;
}
function enqueue_styles() {
wp_enqueue_style(
'content-widget-areas',
PLUGIN_URL . 'css/content-widget-areas.css',
array(),
VERSION
);
}
add_action('wp_enqueue_scripts', __NAMESPACE__ . '\\enqueue_styles');
function plugin_activation() {
$css_dir = plugin_dir_path(__FILE__) . 'css';
if (!file_exists($css_dir)) {
$dir_created = mkdir($css_dir, 0755, true);
if (!$dir_created) {
error_log('Content Widget Areas: CSSディレクトリの作成に失敗しました。');
return;
}
}
$css_file = $css_dir . '/content-widget-areas.css';
if (!file_exists($css_file)) {
$css_content = "
/* Content Widget Areas スタイル */
.below-title-widget {
margin-bottom: 20px;
}
.before-h2-widget {
margin: 20px 0;
}
.after-content-widget {
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #eee;
}
";
$bytes_written = file_put_contents($css_file, $css_content);
if ($bytes_written === false) {
error_log('Content Widget Areas: CSSファイルの作成に失敗しました。');
}
}
if (function_exists('wp_cache_flush')) {
wp_cache_flush();
}
}
register_activation_hook(__FILE__, __NAMESPACE__ . '\\plugin_activation');
function plugin_deactivation() {
if (function_exists('wp_cache_flush')) {
wp_cache_flush();
}
}
register_deactivation_hook(__FILE__, __NAMESPACE__ . '\\plugin_deactivation');
function plugin_action_links($links, $file) {
static $this_plugin;
if (!$this_plugin) {
$this_plugin = plugin_basename(__FILE__);
}
if ($file === $this_plugin) {
$settings_link = '<a href="' . admin_url('widgets.php') . '">' . __('ウィジェット設定', 'content-widget-areas') . '</a>';
array_unshift($links, $settings_link);
}
return $links;
}
add_filter('plugin_action_links', __NAMESPACE__ . '\\plugin_action_links', 10, 2);Code language: HTML, XML (xml)
show less
具体的には、記事の内容(コンテンツ)がフィルターを通過する際に、特定の位置を見つけてウィジェットの内容を挿入しています。例えば、最初の見出し(h2タグ)を探し、その直前にウィジェットを配置する処理を行っています。
コードの一部を見てみましょう:
function insert_before_first_h2_widget($content) {
if (strpos($content, '<h2') === false) {
return $content;
}
ob_start();
dynamic_sidebar('before-first-h2');
$h2_widget = ob_get_clean();
if (!empty($h2_widget)) {
$h2_pos = strpos($content, '<h2');
$content = substr_replace($content, $h2_widget, $h2_pos, 0);
}
return $content;
}
Code language: PHP (php)
この関数では、記事の内容から最初のh2タグを探し、その位置にウィジェットを挿入しています。同様の仕組みで、タイトル下と記事末尾のウィジェットも実装しています。
リファクタリングによる改善
当初は基本的な機能を実装しただけでしたが、コードの可読性と保守性を高めるためにリファクタリングを行いました。主な改善点は次のとおりです:
- 命名空間の導入 – 他のプラグインとの関数名の衝突を防ぐため
- 関数の分割 – 1つの関数が1つの役割だけを持つように整理
- エラー処理の強化 – ファイル作成などの際に起こりうる問題に対応
- コメントの拡充 – コードの目的と動作を明確に
これらの改善により、将来の機能拡張や不具合修正が容易になりました。家の基礎をしっかり固めておくと、後から増築や改装がしやすくなるのと同じです。
まとめ
シンプルなテーマを使っていても、記事内の好きな場所にウィジェットを追加できるようになりました。特にGeneratePressのようなシンプルなテーマでは、この機能が役立つでしょう。プログラミングの知識がなくても、通常のウィジェット操作と同じ感覚で使えるため、誰でも簡単に記事内のレイアウトを強化できます。
このプラグインは、必要最小限の機能に絞っているため軽量で、サイトの表示速度に影響を与えにくいのも特徴です。シンプルなテーマの良さを損なわずに、必要な機能だけを追加する—それが今回のプラグイン開発の基本姿勢でした。