「PDFをアップロードしたら、自動でサムネイルが生成されたらいいのに」
そんな素朴な思いから始まったプラグイン開発。完成までに何度もWordPress.orgの審査に落ち、コードを書き直し、セキュリティを見直し…。この記事では、Rapls PDF Image Creatorというプラグインを開発し、公式ディレクトリに公開するまでの全工程を、失敗談も含めて赤裸々に綴ります。
きっかけ:PDFのサムネイルが欲しい
私のサイトでは、PDFファイルを頻繁にアップロードします。カタログ、マニュアル、レポート…。
でも、WordPressのメディアライブラリを開くと、PDFはすべて同じアイコン。

「このPDF、何だっけ?」
いちいちダウンロードして開かないと中身がわからない。これが地味にストレスでした。
既存のプラグインも探しましたが、どれも微妙に違う。GhostScriptが必要だったり、有料だったり、更新が止まっていたり。
「ないなら作ろう」
エンジニアなら誰もが一度は思うこのセリフ。私もその誘惑に負けました。
開発環境の準備
まずはローカル環境の構築から。私はLocal by Flywheelを使っています。
必要なもの:
- Local by Flywheel(ローカルWordPress環境)
- Cursor(エディタ)
- - PHP 7.4以上
- - ImageMagick(PDF変換用)
プラグインの基本構造はこんな感じで設計しました:
rapls-pdf-image-creator/
├── rapls-pdf-image-creator.php # メインファイル
├── includes/
│ ├── Plugin.php # シングルトンのエントリーポイント
│ ├── Generator.php # PDF→画像変換のコア
│ ├── Settings.php # 設定値の管理
│ ├── Admin.php # 管理画面
│ ├── MediaLibrary.php # メディアライブラリ連携
│ └── Engine/
│ └── ImagickEngine.php # ImageMagick実装
├── admin/
│ ├── views/ # 設定画面のテンプレート
│ ├── css/ # 管理画面用CSS
│ └── js/ # 管理画面用JS
└── languages/ # 翻訳ファイル
名前空間(Namespace)を使ってクラスを整理。オートローダーも自前で実装しました。
最初の壁:PDF変換エンジン
PDFを画像に変換する方法は主に2つあります:
- ImageMagick(Imagick PHP拡張) – PHPから直接呼び出せる
- GhostScript – コマンドラインツール、exec()で実行
最初は両方に対応しようと思っていました。「ユーザーの環境に合わせて選べるようにしよう」と。
でも、これが後で大きな問題になるとは、この時は知る由もありませんでした…。
機能実装:こだわったポイント
1. アップロード時の自動生成
PDFをアップロードしたら、何もしなくてもサムネイルが生成される。これが一番こだわったポイントです。
add_attachmentフックを使って、PDFがアップロードされたタイミングを検知:
add_action('add_attachment', function($attachmentId) {
$mime = get_post_mime_type($attachmentId);
if ($mime === 'application/pdf') {
// サムネイル生成処理
}
});

2. アイキャッチ画像として設定
生成したサムネイルをPDFの「アイキャッチ画像」として設定できるようにしました。
これでget_post_thumbnail_id()がPDF添付ファイルでも使えるようになります。テーマ開発者にとっては嬉しい機能のはず。
3. 既存PDFの一括処理
プラグインを有効化する前にアップロードしたPDFはどうする?
「一括生成」機能を実装しました。AJAXで1件ずつ処理して、プログレスバーで進捗を表示。

WordPress.org審査:地獄の始まり
※以下のメール文面は、個人情報(メールアドレス等)を伏せたうえで、要点のみ抜粋しています。
メールのやり取り(時系列の要点)
- 自動プレレビュー(AI):名前/スラッグが一般的すぎる、所有権(メールドメイン)確認、プレフィックス、ディレクトリアセット同梱、Deprecated 指摘などが提示される
- 私の対応:プラグイン名を Rapls PDF Image Creator に変更し、スラッグも
rapls-pdf-image-creatorへ。所有権についても「raplsworks は自分のサイト」である旨を明確化 - 人のレビュー:Ghostscript エンジンで
exec()を使っている点が危険として指摘される(ホスト側でブロックされる/悪用され得る) - 再提出(v1.0.5):
exec()/shell_exec()を完全削除し、Ghostscript エンジンを廃止。Imagick のみに一本化 - 再提出(v1.0.6):Plugin Check フィードバックを踏まえ、翻訳ロード等を整理。加えて「外部通信なし・追跡なし・nonce/権限チェック・適切なサニタイズ」など、審査チームが確認しやすい形で補足
メールで実際に来た主な指摘(要点)
- 名前/スラッグが一般的すぎる:既存プラグインと混同されやすいので、ブランド/識別子を含めて区別する
- 所有権の確認:プラグインの関連URLと、提出アカウントのメールドメインが一致しない場合は説明が必要(第三者なりすまし防止のため)
exec()/shell_exec()は危険:リモートコード実行につながり得る/多くのホストで無効化されているため、削除が求められる- プレフィックス不足:関数・グローバル・保存データ(option/meta/transient など)に衝突回避のプレフィックス(4文字以上)が必要
- ディレクトリ用アセットは ZIP に入れない:バナー/アイコン/スクショ等は承認後に SVN の assets へアップロード(ZIP同梱は避ける)
- Deprecated 関数:将来的に壊れる可能性があるため、代替手段へ置き換える
私が再提出コメントで書いたこと(コピペできる“短い型”)
返信は長文にせず、レビュアーが「確認すべき点」をすぐ拾えるように、次の順で短くまとめました。
Thank you for reviewing my submission.
- Removed all exec()/shell_exec() usage and the Ghostscript-based engine.
- The plugin now uses Imagick only (no OS command execution).
- No external API calls / tracking / remote assets (no CDN).
- Admin/AJAX actions include capability checks and nonce verification.
- Output is sanitized appropriately; logging runs only when WP_DEBUG is enabled.
Thank you again for your guidance.
プラグインが完成し、意気揚々とWordPress.orgに提出。
数日後、メールが届きました。
Your plugin has been reviewed and we have concerns…
却下。
ここから、審査との長い戦いが始まりました。
指摘1: プラグイン名が一般的すぎる
最初は「PDF Image Creator」という名前でした。
プラグイン名にユニークなプレフィックスを付けてください。
「Rapls PDF Image Creator」に変更。Raplsは私のブランド名です。
指摘2: exec()は使用禁止
これが一番痛かった。
GhostScriptエンジンはexec()関数でコマンドを実行していました。
exec()、shell_exec()、system()などのシェル実行関数は、セキュリティ上の理由から使用できません。
せっかく実装したGhostScript対応を、泣く泣く削除。ImageMagick一本に絞りました。
指摘3: プレフィックスの統一
関数名、定数、オプション名…すべてに一貫したプレフィックスが必要でした。
// 修正前
function get_pdf_thumbnail() { ... }
define('PLUGIN_VERSION', '1.0.0');
// 修正後
function rapls_pic_get_thumbnail() { ... }
define('RAPLS_PIC_VERSION', '1.0.0');
指摘4: flush_rewrite_rules()の削除
有効化・無効化時にflush_rewrite_rules()を呼んでいましたが、これも指摘を受けました。
このプラグインはカスタム投稿タイプやリライトルールを登録していません。不要な処理は削除してください。
確かに、意味もなく入れていました。反省。
指摘5: error_log()のファイルパス露出
デバッグ用に入れていたerror_log()が問題に。
// 修正前(危険)
error_log('Error in ' . __FILE__ . ': ' . $e->getMessage());
// 修正後(安全)
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('Rapls PDF Image Creator: ' . $e->getMessage());
}
サーバーのファイルパスが露出するのはセキュリティリスク。WP_DEBUGが有効な時だけログを出すように修正しました。
指摘6: load_plugin_textdomain()は不要
翻訳の読み込み処理を入れていましたが…
WordPress 4.6以降、WordPress.orgでホストされるプラグインは翻訳が自動的に読み込まれます。load_plugin_textdomain()は非推奨です。
知らなかった…。削除しました。
指摘7: 日本語翻訳のスタイル
日本語翻訳ファイルも審査対象でした。
WordPress日本語チームの翻訳スタイルガイドに従う必要があります。
// 修正前
"PDFファイルからサムネイルを生成"
// 修正後(半角英字の前後にスペース)
"PDF ファイルからサムネイルを生成"
細かいですが、約50箇所を修正しました。
最終的なコード品質
審査を通過するために、以下の点を徹底しました:
セキュリティ
- すべての入力値をサニタイズ(
sanitize_text_field()、absint()など) - すべての出力をエスケープ(
esc_html()、esc_attr()、esc_url()) - AJAX処理には必ずnonce検証と権限チェック
- カスタムHTMLには
wp_kses_post()でサニタイズ
コーディング規約
- WordPress Coding Standardsに準拠
- PHPDoc形式のコメント
- 適切な名前空間とクラス設計
互換性
- PHP 7.4以上で動作(
readonlyプロパティやmatch式は使わない) - WordPress 5.0以上で動作
ついに承認!

何度もの修正を経て、ついにメールが届きました。
Congratulations, your plugin hosting request for Rapls PDF Image Creator has been approved.

正直、泣きそうになりました。
公開後の反省と学び
良かったこと
- 審査プロセスを通じて、セキュリティ意識が大幅に向上した
- WordPressのコーディング規約を深く理解できた
- 「動けばいい」から「正しく動く」へ意識が変わった
反省点
- 最初からWordPress.orgのガイドラインを読んでおくべきだった
- GhostScript対応に時間をかけすぎた(結局削除)
- 翻訳スタイルガイドの存在を知らなかった
これからプラグインを開発する人へ
- まずガイドラインを読む – Plugin Guidelinesは必読
- Plugin Check プラグインを使う – 提出前に自動チェックできる
- exec()系は諦める – 外部コマンド実行は審査に通らない
- プレフィックスは最初から統一 – 後から変更するのは大変
- セキュリティは妥協しない – サニタイズ・エスケープ・nonce検証
プラグインのダウンロード
Rapls PDF Image Creatorは、WordPress公式ディレクトリから無料でダウンロードできます。

PDFを扱うサイトを運営している方は、ぜひ試してみてください。
開発者向け:テンプレート関数
テーマ開発者の方向けに、テンプレート関数も用意しています:
<?php
// サムネイルがあるか確認
if (rapls_pic_has_thumbnail($pdf_id)) {
// サムネイル画像を表示
echo rapls_pic_get_thumbnail_image($pdf_id, 'medium');
}
?>
ショートコードも4種類用意しているので、コードを書かなくても使えます。
さいごに
プラグイン開発は、想像以上に学びの多い経験でした。
特にWordPress.orgの審査は厳しいですが、その分、公開されているプラグインの品質が担保されています。ユーザーとして、これは安心材料ですよね。
もし「自分でもプラグインを作ってみたい」と思っている方がいれば、ぜひ挑戦してみてください。審査で落ちても、それは成長のチャンス。私も何度も落ちました(笑)
質問があれば、コメント欄でお気軽にどうぞ!
この記事が役に立ったら、シェアしていただけると嬉しいです。
開発を続けるモチベーションになります。
☕ Buy me a coffeeで応援していただけると、さらに嬉しいです!


コメント