- WordPressのウィジェットは便利ですが、いじっているうちに「前はどうなっていたっけ?」という状況になることがあります。
- そんな時に役立つ、ウィジェットの構造をわかりやすく記録できるプラグインを作りました。
- このプラグインを使うと、現在のウィジェット配置とその設定内容をMarkdown形式で出力できます。
1. WordPressのウィジェット構造をメモしたい
WordPressでウェブサイトを作っているとき、サイドバーやフッターにあるウィジェットの調整は頻繁に行います。
しかし、調整しすぎて元の状態がわからなくなってしまったり、何か問題が起きたときに「以前はどうだったか」を確認したりする方法がありませんでした。
そこで、現在のウィジェット構造をMarkDown形式で出力するWordPressプラグインを作りました。
個人用プラグインなので、なるべく構造は管理しやすく設計しました。
このプラグインは、現在のウィジェット構造の確認、変更前の状態の記録、表示設定を含む詳細情報の出力ができます。

1-1. プラグインの使い方
このプラグインは非常にシンプルに使えます。
- プラグインファイル(chiilabo-widget-exporter.php)をWordPressの
wp-content/plugins/
フォルダー にアップロードして有効化します - 管理画面の「ツール」メニューから「ウィジェットエクスポーター」を選択します
- 「ウィジェット構造をエクスポート」ボタンをクリックします
- 表示されたMarkdown形式のデータをコピーまたはダウンロードします
<?php
/**
* Plugin Name: Chiilabo Widget Exporter
* Plugin URI:
* Description: WordPressのウィジェット構造をMarkdown形式でエクスポートするプラグイン
* Version: 1.1
* Author: Chiilabo
* Author URI:
* License: GPL2
*/
// 直接アクセスを防止
if (!defined('ABSPATH')) {
exit;
}
class Widget_Exporter {
/**
* コンストラクタ
*/
public function __construct() {
// 管理画面にメニューを追加
add_action('admin_menu', array($this, 'add_admin_menu'));
// AJAXハンドラーを登録
add_action('wp_ajax_export_widgets', array($this, 'ajax_export_widgets'));
}
/**
* 管理メニューを追加
*/
public function add_admin_menu() {
add_submenu_page(
'tools.php',
'ウィジェットエクスポーター',
'ウィジェットエクスポーター',
'manage_options',
'widget-exporter',
array($this, 'admin_page')
);
}
/**
* 管理画面を表示
*/
public function admin_page() {
?>
<div class="wrap">
<h1>ウィジェットエクスポーター</h1>
<p>現在のウィジェット構造をMarkdown形式でエクスポートします。</p>
<div class="card">
<h2>エクスポート</h2>
<p>
<button id="export-widgets" class="button button-primary">ウィジェット構造をエクスポート</button>
<label for="debug-mode" style="margin-left: 15px;">
<input type="checkbox" id="debug-mode" name="debug-mode"> デバッグ情報を含める
</label>
</p>
<div id="export-result" style="display:none;">
<h3>エクスポート結果</h3>
<textarea id="markdown-output" style="width: 100%; height: 500px; font-family: monospace;"></textarea>
<p>
<button id="copy-markdown" class="button">コピー</button>
<button id="download-markdown" class="button">ダウンロード</button>
</p>
</div>
</div>
</div>
<script>
jQuery(document).ready(function($) {
// エクスポートボタンのクリックイベント
$('#export-widgets').on('click', function() {
$(this).prop('disabled', true).text('処理中...');
// デバッグモードの状態を取得
var debugMode = $('#debug-mode').is(':checked');
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'export_widgets',
nonce: '<?php echo wp_create_nonce('widget_export_nonce'); ?>',
debug_mode: debugMode ? 1 : 0
},
success: function(response) {
$('#export-widgets').prop('disabled', false).text('ウィジェット構造をエクスポート');
if (response.success) {
$('#markdown-output').val(response.data);
$('#export-result').show();
} else {
alert('エクスポート中にエラーが発生しました: ' + response.data);
}
},
error: function() {
$('#export-widgets').prop('disabled', false).text('ウィジェット構造をエクスポート');
alert('エクスポート中にエラーが発生しました。');
}
});
});
// コピーボタンのクリックイベント
$('#copy-markdown').on('click', function() {
var copyText = document.getElementById("markdown-output");
copyText.select();
document.execCommand("copy");
alert("クリップボードにコピーしました");
});
// ダウンロードボタンのクリックイベント
$('#download-markdown').on('click', function() {
var text = $('#markdown-output').val();
var filename = 'widgets-' + new Date().toISOString().slice(0, 10) + '.md';
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
});
});
</script>
<?php
}
/**
* ウィジェットデータをエクスポートするAJAXハンドラ
*/
public function ajax_export_widgets() {
// nonceの検証
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'widget_export_nonce')) {
wp_send_json_error('セキュリティチェックに失敗しました。');
}
// 管理者権限の確認
if (!current_user_can('manage_options')) {
wp_send_json_error('十分な権限がありません。');
}
// デバッグモードの設定を取得
$debug_mode = isset($_POST['debug_mode']) && $_POST['debug_mode'] == 1;
$markdown = $this->generate_widgets_markdown($debug_mode);
wp_send_json_success($markdown);
}
/**
* ウィジェットデータをMarkdown形式で生成
*
* @param bool $debug_mode デバッグ情報を含めるかどうか
* @return string Markdown形式の出力
*/
private function generate_widgets_markdown($debug_mode = false) {
global $wp_registered_widgets, $wp_registered_sidebars;
$sidebars_widgets = wp_get_sidebars_widgets();
$output = "# WordPress ウィジェット構造\n";
$output .= "エクスポート日時: " . date_i18n('Y-m-d H:i:s') . "\n\n";
// アクティブなサイドバーのみ処理
foreach ($sidebars_widgets as $sidebar_id => $widgets) {
// wp_inactive_widgets は除外
if ($sidebar_id === 'wp_inactive_widgets' || empty($widgets) || !is_array($widgets)) {
continue;
}
// 特定のサイドバーをスキップしたい場合は以下のコメントを外して設定
// if ($sidebar_id === 'sidebar-scroll') {
// continue;
// }
// サイドバー名を取得
$sidebar_name = isset($wp_registered_sidebars[$sidebar_id]['name']) ?
$wp_registered_sidebars[$sidebar_id]['name'] : $sidebar_id;
$sidebar_description = isset($wp_registered_sidebars[$sidebar_id]['description']) ?
$wp_registered_sidebars[$sidebar_id]['description'] : '';
$output .= "## " . $sidebar_name . "\n";
if (!empty($sidebar_description)) {
$output .= $sidebar_description . "\n\n";
}
if (empty($widgets)) {
$output .= "このウィジェット表示場所にはウィジェットがありません。\n\n";
continue;
}
foreach ($widgets as $widget_id) {
// ウィジェット情報の取得
if (isset($wp_registered_widgets[$widget_id])) {
$widget_instance = $wp_registered_widgets[$widget_id];
$widget_name = $widget_instance['name'];
// ウィジェットオプションの取得
$widget_options = $this->get_widget_options($widget_id);
$is_hidden = isset($widget_options['hide_widget']) && $widget_options['hide_widget'];
// ウィジェットタイトルの取得
$widget_title = '';
// 標準的なtitleフィールドをチェック
if (isset($widget_options['title']) && !empty($widget_options['title'])) {
$widget_title = $widget_options['title'];
}
// 一部のウィジェットは別の名前でタイトルフィールドを持つ可能性がある
elseif (isset($widget_options['title_mobile_text']) && !empty($widget_options['title_mobile_text'])) {
$widget_title = $widget_options['title_mobile_text'];
}
// タイトルが空でない場合は表示
$title_display = !empty($widget_title) ? $widget_title : '';
// 表示/非表示ステータス
$visibility = $is_hidden ? '(非表示)' : '(表示)';
$output .= "### " . $widget_name . ": " . $title_display . $visibility . "\n";
// デバッグモードの場合、ウィジェットオプションの内容を出力
if ($debug_mode) {
$output .= "```php\n";
$output .= "// Widget ID: " . $widget_id . "\n";
$output .= "// Options:\n";
$output .= print_r($widget_options, true);
$output .= "```\n\n";
}
// 表示設定の取得
$display_options = $this->get_widget_display_options($widget_id);
if (!empty($display_options)) {
$output .= $display_options . "\n";
}
$output .= "\n";
}
}
}
return $output;
}
/**
* ウィジェットの表示設定情報を取得
*/
private function get_widget_display_options($widget_id) {
// ウィジェットオプションから直接表示設定を確認
$widget_options = $this->get_widget_options($widget_id);
$display_info = array();
$page_types = array();
$special_pages = array();
$display_type = '';
// 表示/非表示のアクションを確認
if (isset($widget_options['widget_action'])) {
$display_type = $widget_options['widget_action'] === 'show' ? '表示' : '非表示';
}
// カテゴリーの表示設定
if (isset($widget_options['widget_categories']) && is_array($widget_options['widget_categories']) && !empty($widget_options['widget_categories'])) {
$categories = array();
foreach ($widget_options['widget_categories'] as $cat_id) {
$cat = get_category($cat_id);
if ($cat) {
$categories[] = $cat->name;
}
}
if (!empty($categories)) {
$display_info[] = 'カテゴリ: ' . implode(', ', $categories);
}
}
// タグの表示設定
if (isset($widget_options['widget_tags']) && !empty($widget_options['widget_tags'])) {
if (is_array($widget_options['widget_tags'])) {
$tags = array();
foreach ($widget_options['widget_tags'] as $tag_id) {
$tag = get_tag($tag_id);
if ($tag) {
$tags[] = $tag->name;
}
}
if (!empty($tags)) {
$display_info[] = 'タグ: ' . implode(', ', $tags);
}
} else {
// 単一のタグIDの場合
$tag = get_tag($widget_options['widget_tags']);
if ($tag) {
$display_info[] = 'タグ: ' . $tag->name;
}
}
}
// ページの表示設定
if (isset($widget_options['widget_pages']) && is_array($widget_options['widget_pages']) && !empty($widget_options['widget_pages'])) {
// 特殊な条件チェック - WordPress条件関数名
$condition_functions = array(
'is_front_page' => 'フロントページ',
'is_home' => 'ブログページ',
'is_single' => '投稿',
'is_page' => '固定ページ',
'is_category' => 'カテゴリーページ',
'is_tag' => 'タグページ',
'is_author' => '著者ページ',
'is_date' => '日付アーカイブ',
'is_archive' => 'アーカイブページ'
);
foreach ($widget_options['widget_pages'] as $page_condition) {
// 条件関数名かチェック
if (is_string($page_condition) && isset($condition_functions[$page_condition])) {
if ($page_condition === 'is_single') {
$page_types[] = '投稿';
} elseif ($page_condition === 'is_page') {
$page_types[] = '固定ページ';
} elseif ($page_condition === 'is_front_page') {
$special_pages[] = 'フロントページ';
} elseif ($page_condition === 'is_category') {
$special_pages[] = 'カテゴリーページ';
} elseif ($page_condition === 'is_tag') {
$special_pages[] = 'タグページ';
} else {
$special_pages[] = $condition_functions[$page_condition];
}
} else {
// 数値IDの場合は固定ページのタイトルを取得
$page_title = get_the_title($page_condition);
if ($page_title) {
$display_info[] = 'ページ: ' . $page_title;
}
}
}
}
// 投稿の表示設定 (直接指定されている場合)
if (isset($widget_options['widget_posts']) && !empty($widget_options['widget_posts'])) {
$page_types[] = '投稿';
}
// 固定ページタイプの表示設定 (直接指定されている場合)
if (isset($widget_options['widget_fixed_pages']) && !empty($widget_options['widget_fixed_pages'])) {
$page_types[] = '固定ページ';
}
// 特殊ページタイプを表示情報に追加
if (!empty($special_pages)) {
$display_info[] = '特殊ページ: ' . implode(',', $special_pages);
}
// ページタイプを表示情報に追加
if (!empty($page_types)) {
$display_info[] = 'ページ: ' . implode(',', $page_types);
}
// カスタム投稿タイプの表示設定
if (isset($widget_options['widget_custom_post_types']) && is_array($widget_options['widget_custom_post_types']) && !empty($widget_options['widget_custom_post_types'])) {
$post_types = array();
foreach ($widget_options['widget_custom_post_types'] as $post_type) {
// 投稿タイプスラッグからオブジェクトを取得
$post_type_obj = get_post_type_object($post_type);
if ($post_type_obj) {
$post_types[] = $post_type_obj->labels->name;
} else {
// スラッグだけ表示
$post_types[] = $post_type;
}
}
if (!empty($post_types)) {
$display_info[] = '投稿タイプ: ' . implode(', ', $post_types);
}
}
// 著者の表示設定
if (isset($widget_options['widget_authors']) && is_array($widget_options['widget_authors']) && !empty($widget_options['widget_authors'])) {
$authors = array();
foreach ($widget_options['widget_authors'] as $author_id) {
$author = get_userdata($author_id);
if ($author) {
$authors[] = $author->display_name;
}
}
if (!empty($authors)) {
$display_info[] = '著者: ' . implode(', ', $authors);
}
}
if (empty($display_type)) {
return '';
}
// 表示設定の整形 - 重複を防ぐ
if (empty($display_info)) {
return "表示設定:{$display_type}";
} else {
return "表示設定:{$display_type}(" . implode(',', $display_info) . ")";
}
}
/**
* ウィジェットオプションを取得
*/
private function get_widget_options($widget_id) {
// ウィジェットIDからベース名と番号を抽出
if (preg_match('/^(.+)-(\d+)$/', $widget_id, $matches)) {
$base_id = $matches[1];
$widget_number = $matches[2];
// ウィジェット設定を取得
$widget_options = get_option('widget_' . $base_id);
if (isset($widget_options[$widget_number])) {
// 追加のウィジェット設定を確認(カスタムフィールドなど)
// これは特定のテーマやプラグインで追加された設定を取得するための拡張ポイント
$widget_options[$widget_number] = apply_filters('widget_exporter_options', $widget_options[$widget_number], $widget_id);
return $widget_options[$widget_number];
}
}
return array();
}
}
// プラグインの初期化
$widget_exporter = new Widget_Exporter();

このプラグインを使うと、次のような形式でウィジェット情報が出力されます:
# WordPress ウィジェット構造
エクスポート日時: 2025-03-12 14:30:00
## サイドバー
*サイドバーの説明文がある場合表示*
### 検索: サイト内検索(表示)
表示設定:表示(カテゴリ: 日々の投稿)
### 最近の投稿: おすすめ投稿(表示)
### 最近のコメント: (表示)
表示設定:非表示(投稿タイプ: 固定ページ)

この出力から、どのサイドバーにどのウィジェットが配置されているか、各ウィジェットの設定内容、そして表示設定(どのページやカテゴリーで表示/非表示になるか)が一目でわかります。
2. プラグインのメインクラス(UI部分)
プラグインのメイン機能を実装するクラスでは、WordPressの「ツール」メニュー内に「ウィジェットエクスポーター」という項目を追加しています。
class Widget_Exporter {
/**
* コンストラクタ
*/
public function __construct() {
// 管理画面にメニューを追加
add_action('admin_menu', array($this, 'add_admin_menu'));
// AJAXハンドラーを登録
add_action('wp_ajax_export_widgets', array($this, 'ajax_export_widgets'));
}
/**
* 管理メニューを追加
*/
public function add_admin_menu() {
add_submenu_page(
'tools.php',
'ウィジェットエクスポーター',
'ウィジェットエクスポーター',
'manage_options',
'widget-exporter',
array($this, 'admin_page')
);
}
add_submenu_page
は、WordPressの管理画面にメニュー項目を追加するための関数です。
2-1. 管理画面の作成
プラグインの管理画面を作成します。
これは、ウィジェット情報をエクスポートするためのボタンなどを配置する画面です。
/**
* 管理画面を表示
*/
public function admin_page() {
?>
<div class="wrap">
<h1>ウィジェットエクスポーター</h1>
<p>現在のウィジェット構造をMarkdown形式でエクスポートします。</p>
<div class="card">
<h2>エクスポート</h2>
<p>
<button id="export-widgets" class="button button-primary">ウィジェット構造をエクスポート</button>
</p>
<div id="export-result" style="display:none;">
<h3>エクスポート結果</h3>
<textarea id="markdown-output" style="width: 100%; height: 500px; font-family: monospace;"></textarea>
<p>
<button id="copy-markdown" class="button">コピー</button>
<button id="download-markdown" class="button">ダウンロード</button>
</p>
</div>
</div>
</div>
このコードでは、シンプルな管理画面を作成しています。「ウィジェット構造をエクスポート」ボタンをクリックすると、JavaScriptを使ってAJAXリクエストが送信され、現在のウィジェット情報が取得されます。結果は大きなテキストエリアに表示され、コピーやダウンロードができます。
2-2. JavaScript部分とAJAX処理部分
ボタンのクリックイベントやAJAX通信を行うJavaScript部分で、3つの機能を実装しています:
- エクスポートボタンをクリックすると、AJAXリクエストを送信してウィジェット情報を取得
- コピーボタンをクリックすると、出力されたテキストをクリップボードにコピー
- ダウンロードボタンをクリックすると、Markdown形式のファイルをダウンロード
<script>
jQuery(document).ready(function($) {
// エクスポートボタンのクリックイベント
$('#export-widgets').on('click', function() {
$(this).prop('disabled', true).text('処理中...');
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'export_widgets',
nonce: '<?php echo wp_create_nonce('widget_export_nonce'); ?>'
},
success: function(response) {
$('#export-widgets').prop('disabled', false).text('ウィジェット構造をエクスポート');
if (response.success) {
$('#markdown-output').val(response.data);
$('#export-result').show();
} else {
alert('エクスポート中にエラーが発生しました: ' + response.data);
}
},
error: function() {
$('#export-widgets').prop('disabled', false).text('ウィジェット構造をエクスポート');
alert('エクスポート中にエラーが発生しました。');
}
});
});
// コピーボタンのクリックイベント
$('#copy-markdown').on('click', function() {
var copyText = document.getElementById("markdown-output");
copyText.select();
document.execCommand("copy");
alert("クリップボードにコピーしました");
});
// ダウンロードボタンのクリックイベント
$('#download-markdown').on('click', function() {
var text = $('#markdown-output').val();
var filename = 'widgets-' + new Date().toISOString().slice(0, 10) + '.md';
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
});
});
</script>
<?php
}
AJAXリクエストを処理する関数では、まずセキュリティチェック(nonce検証)と権限チェックを行い、問題がなければウィジェット情報のMarkdownを生成して返します。
/**
* ウィジェットデータをエクスポートするAJAXハンドラ
*/
public function ajax_export_widgets() {
// nonceの検証
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'widget_export_nonce')) {
wp_send_json_error('セキュリティチェックに失敗しました。');
}
// 管理者権限の確認
if (!current_user_can('manage_options')) {
wp_send_json_error('十分な権限がありません。');
}
$markdown = $this->generate_widgets_markdown();
wp_send_json_success($markdown);
}
nonceは、クロスサイトリクエストフォージェリ(CSRF)攻撃を防ぐためのセキュリティ対策です。

WordPressのウィジェット管理は、サイトの見た目や機能に大きく影響します。しかし、その設定状態を記録する標準的な方法がなかったため、このプラグインを作成しました。このプラグインを使うことで、ウィジェットの設定変更前に状態を記録したり、問題発生時に設定を確認したりするのが簡単になります。
3. ウィジェットデータの取得と解析
ここでは、WordPressの内部機能を使ってウィジェットデータを取得します。
private function generate_widgets_markdown($debug_mode = false) {
global $wp_registered_widgets, $wp_registered_sidebars;
$sidebars_widgets = wp_get_sidebars_widgets();
// 以下、エクスポート処理...
}
ウィジェットデータを取得する際、まず注目すべきは各ウィジェットがどのように保存されているかを理解することです。WordPressはウィジェット設定をwp_options
テーブルにシリアライズされた配列として保存しています。
各ウィジェットのオプションを取得するには、ウィジェットIDからベース名と番号を抽出し、対応するオプションを取得します。
private function get_widget_options($widget_id) {
// ウィジェットIDからベース名と番号を抽出
if (preg_match('/^(.+)-(\d+)$/', $widget_id, $matches)) {
$base_id = $matches[1];
$widget_number = $matches[2];
// ウィジェット設定を取得
$widget_options = get_option('widget_' . $base_id);
if (isset($widget_options[$widget_number])) {
return $widget_options[$widget_number];
}
}
return array();
}
3-1. 表示/非表示条件の解析
この部分が最も難しく、興味深い部分でした。ウィジェットの表示/非表示条件は各テーマやプラグインによって実装方法が異なります。まず、デバッグ出力機能を追加して実際のデータ構造を確認しました。
// デバッグモードの場合、ウィジェットオプションの内容を出力
if ($debug_mode) {
$output .= "```php\n";
$output .= "// Widget ID: " . $widget_id . "\n";
$output .= "// Options:\n";
$output .= print_r($widget_options, true);
$output .= "```\n\n";
}
デバッグ出力からわかったのは、表示/非表示条件が以下のような形式で保存されていることです。
widget_action
– 表示/非表示を決める値(show
またはhide
)widget_categories
– カテゴリーID配列widget_pages
– ページ条件(ただしこれが数値IDだけでなく、is_single
やis_page
などの関数名も含む)- その他条件(タグ、著者、カスタム投稿タイプなど)

特にwidget_pages
の処理が複雑でした。この配列には固定ページのIDだけでなく、is_single
(投稿ページ)やis_page
(固定ページ)のような条件関数名も含まれていました。
3-2. 条件関数名の処理
デバッグ出力から得られた情報を元に、条件関数名を適切な表示名に変換する処理を追加しました。
// 特殊な条件チェック - WordPress条件関数名
$condition_functions = array(
'is_front_page' => 'フロントページ',
'is_home' => 'ブログページ',
'is_single' => '投稿',
'is_page' => '固定ページ',
// その他の条件...
);
foreach ($widget_options['widget_pages'] as $page_condition) {
// 条件関数名かチェック
if (is_string($page_condition) && isset($condition_functions[$page_condition])) {
if ($page_condition === 'is_single') {
$page_types[] = '投稿';
} elseif ($page_condition === 'is_page') {
$page_types[] = '固定ページ';
} elseif ($page_condition === 'is_front_page') {
$special_pages[] = 'フロントページ';
} else {
$special_pages[] = $condition_functions[$page_condition];
}
} else {
// 数値IDの場合は固定ページのタイトルを取得
$page_title = get_the_title($page_condition);
if ($page_title) {
$display_info[] = 'ページ: ' . $page_title;
}
}
}
3-3. タグやその他の条件処理
タグの処理も工夫が必要でした。デバッグ出力から、タグが配列だけでなく単一の数値(ID)として保存されているケースもあることがわかりました。
// タグの表示設定
if (isset($widget_options['widget_tags']) && !empty($widget_options['widget_tags'])) {
if (is_array($widget_options['widget_tags'])) {
// 配列の場合の処理
} else {
// 単一のタグIDの場合
$tag = get_tag($widget_options['widget_tags']);
if ($tag) {
$display_info[] = 'タグ: ' . $tag->name;
}
}
}
![[WordPress]ウィジェットタイトルを非表示にするCSS](https://chiilabo.com/wp-content/uploads/2024/07/image-3-1024x576.jpg)


