ショートコード / ブロック / フロント出力
本プラグインはショートコードもブロックも登録しません。サイトの表示側(読者が見るページ)には一切出力しません。動作するのは管理画面・ブロックエディタ・サーバー側の公開処理だけです。
- ショートコード登録(
add_shortcode)・ブロック登録(register_block_type)・本文フィルタ(the_content)・フロント側の資産読み込み(wp_enqueue_scripts)・wp_head/wp_footerへの出力は、いずれも実装にありません。 - JavaScript / CSS を読み込むフックは
enqueue_block_editor_assets(校正サイドバー)とadmin_enqueue_scripts(管理画面 CSS/JS・オンボーディングツアー・バグ報告ウィジェット)だけです。 - 校正サイドバーの資産は、ブロックエディタであること(
$screen->is_block_editor())と、設定post_typesに含まれる投稿タイプであることの両方を満たすときにのみ読み込まれます。クラシックエディタには校正 UI が出ず、メタボックス等の代替 UI もありません。 - ビルド成果物
block/build/editor.js(エディタ)とadmin/build/tour.js(管理画面ツアー)は配布 zip に同梱済みです。ソース(block/src/admin/src)は配布物から除外されます。 @wordpress/hooksのaddFilter/applyFilters/doActionは使用していません。JavaScript 側の拡張ポイントはありません。
したがって、テーマ側で表示崩れ・追加 CSS・出力バッファへの干渉を考慮する必要はありません。連携する場合の入口は、次章の REST API と第 7 章のフィルタです。
REST API
名前空間は jpl/v1、認証は WordPress コア標準の cookie 認証 + nonce(wp_rest / X-WP-Nonce)です。独自の認証機構やトークン発行はありません。各ルートの permission_callback で capability を検証します。全 21 パス(メソッド×パスの組で 37 通り)。フロント公開用ではなく、管理画面・ブロックエディタ・外部の入稿ツール向けです。
校正・エディタ系
| エンドポイント | メソッド / 権限 | 内容 |
|---|---|---|
/jpl/v1/check | POST / context.post_id 指定時はその投稿の edit_post、未指定は edit_posts | 本文を渡して校正。引数は title slug excerpt content seo(object) context(object) trigger(auto / manual のみ受理。他の値は rest_invalid_param の 400)。戻りは findings[] / summary / profile / publish / truncated |
/jpl/v1/posts/{id}/check | POST / 対象投稿の edit_post | DB の保存値を使って校正。trigger=manual として jpl_logs に記録される |
/jpl/v1/posts/{id}/publish-status | GET / 対象投稿の edit_post | { blocked, error_count, checked_at }(checked_at は Y-m-d H:i:s の GMT)。ログは記録しない |
/jpl/v1/ignores | GET / 対象投稿の edit_post(post_id 必須)POST / jpl_ignore_findings +スコープ検査 | 無視設定の一覧・作成(201)。scope は finding / post / user / category / rule。user / category / rule は jpl_manage_rules が必要 |
/jpl/v1/ignores/{id} | DELETE / jpl_ignore_findings または jpl_manage_rules | 削除。最終判定は「作成者本人 または jpl_manage_rules 保持者」 |
/jpl/v1/ai-review | POST / 対象投稿の edit_post + jpl_use_ai + 可用性判定 | AI 最終チェック。引数は post_id(必須) content fields{title,excerpt}、戻りは { findings[], truncated, dropped }。AI が利用不可なら 400 |
/jpl/v1/tour-state | POST / capability 不要(ログイン済みであること) | オンボーディングツアーの進行状態。course / status / dismiss_notice / reset |
/check と /ai-review の finding オブジェクトは同じ形です: hash / rule_id / rule_key / rule_name / severity / message / text / suggestions[] / note / field / block_index / offset([開始, 終了] の 2 要素配列)/ auto_fixable / ignorable / source_layer。AI 由来の指摘は rule_id = 0・ignorable = false・source_layer = 'ai' になります。
管理(CRUD)系
| エンドポイント | メソッド / 権限 | 内容 |
|---|---|---|
/jpl/v1/rules | GET, POST / jpl_manage_rules | ルールの一覧・作成(201)。一覧は type 絞り込みに対応 |
/jpl/v1/rules/{id} | GET, PUT, DELETE / jpl_manage_rules | 単一ルールの取得・更新・削除 |
/jpl/v1/dictionaries | GET, POST / jpl_manage_dictionaries | 辞書の一覧・作成(201)。一覧は type 絞り込みに対応 |
/jpl/v1/dictionaries/{id} | GET, PUT, DELETE / jpl_manage_dictionaries | 取得・更新・削除。参照しているルールがあり force=false なら 409 |
/jpl/v1/dictionaries/{id}/entries | GET, POST, PATCH / jpl_manage_dictionaries | エントリの一覧・作成(201)・一括有効化/無効化。PATCH は enabled 必須、ids[] 省略時は辞書内全件で { updated: 件数 } を返す |
/jpl/v1/dictionaries/{id}/import | POST / jpl_manage_dictionaries | 辞書エントリの取り込み。multipart の file、format(csv / json・必須)、dry_run(既定 true)。dry run は 200、確定は 201 |
/jpl/v1/dictionaries/{id}/export | GET / jpl_manage_dictionaries | 書き出し。format 既定 csv。HTTP 経由では JSON エンベロープをバイパスして生の CSV / JSON 本文を返す(Content-Disposition: attachment 付き) |
/jpl/v1/entries/{id} | PUT, DELETE / jpl_manage_dictionaries | 単一エントリの更新・削除 |
/jpl/v1/profiles | GET, POST / jpl_manage_profiles | プロファイルの一覧・作成(201)。rules[] をネストで受け取る。rules の検証に失敗すると本体もロールバック |
/jpl/v1/profiles/{id} | GET, PUT, DELETE / jpl_manage_profiles | 取得・更新・削除。PUT に rules を渡すと全置換。参照する割り当てがあり force=false なら 409 |
/jpl/v1/assignments | GET, POST / jpl_manage_profiles | 割り当ての一覧・作成(201)。target_type / profile_id で絞り込み可 |
/jpl/v1/assignments/preview | GET / jpl_manage_profiles | 実効プロファイルのプレビュー。post_id / post_type(既定 post)/ category_ids[] / tag_ids[] / user_id。戻りは disabled / auto_fix / block_publish / applied[] / rules[] |
/jpl/v1/assignments/{id} | GET, PUT, DELETE / jpl_manage_profiles | 単一割り当ての取得・更新・削除 |
/jpl/v1/reports/dashboard | GET / jpl_view_reports | ダッシュボード集計。period は month / last_month / 90days(既定 month) |
作成・更新時の主なボディパラメータは次のとおりです。
| リソース | パラメータ |
|---|---|
| ルール | rule_key name type description pattern match_type case_sensitive suggestion severity auto_fixable is_forced params(object) is_enabled |
| 辞書 | name type description is_enabled |
| 辞書エントリ | pattern suggestion alternatives[] match_type case_sensitive note is_enabled |
| プロファイル | name description auto_fix_enabled block_publish is_enabled rules[](ネスト。各要素は rule_id と is_enabled / severity_override / params_override の上書き 3 項目) |
| 割り当て | target_type target_id profile_id priority is_enabled |
| 無視設定 | scope(必須) rule_id finding_hash matched_text post_id user_id term_id |
設定(オプション jpl_settings)を読み書きする REST ルートはありません。書き込み経路は管理画面「AI 校正」の保存ハンドラ(admin-post.php → Settings::update())だけで、しかも渡されるのは ai_enabled / ai_consent / ai_log_requests / ai_model_preference の 4 キーに限られます。残る post_types / realtime_default / log_findings_detail / log_retention_days / exclude_quotes に v0.1.0 の管理画面 UI はなく、変更するには update_option( 'jpl_settings', … ) 相当の直接操作が要ります。なお Settings API(options.php / 設定グループ jpl_settings_group)で保存しているのは jpl_delete_data_on_uninstall の 1 項目だけです。
一覧系の共通クエリ引数
| 引数 | 型 / 既定 | 制約 |
|---|---|---|
page | integer / 1 | 最小 1 |
per_page | integer / 20 | 最小 1・最大 200(リポジトリ層でも 1〜200 にクランプ) |
search | string / '' | ルールは name / rule_key、辞書とプロファイルは name、エントリは pattern / suggestion が対象。/assignments では受理されるが無視されます |
enabled | string / '' | '' / '0' / '1' |
type | string | /rules と /dictionaries のみ。/profiles /assignments にはありません |
一覧の総件数は X-WP-Total ヘッダで返します(X-WP-TotalPages は返しません)。enum の実値は次のとおりです。
| enum | 値 |
|---|---|
ルールの type | 8 種(第 9 章の表を参照) |
match_type(ルール / 辞書エントリ) | exact / partial / regex |
severity | error / warning / info / suggestion |
辞書の type | notation / forbidden / caution / proper_noun / allowed / term / client / genre |
割り当ての target_type | global / post_type / category / tag / role / user / post |
無視設定の scope | finding / post / user / category / rule |
エラー規約
リポジトリ層が返す WP_Error のコードから HTTP ステータスを決定します。マップに無いコードは 400 にフォールバックします。
| エラーコード | HTTP | 意味 |
|---|---|---|
jpl_forbidden | 401 / 403 | capability 不足(未ログインは 401、ログイン済みは 403)。/ai-review の権限不足のみ 403 固定 |
jpl_not_found | 404 | 対象が存在しない |
jpl_rule_key_exists | 409 | rule_key の一意制約違反 |
jpl_assignment_exists | 409 | 割り当ての UNIQUE(target_type, target_id) 違反 |
jpl_dictionary_in_use | 409 | 参照しているルールがある辞書の削除 |
jpl_profile_in_use | 409 | 参照している割り当てがあるプロファイルの削除 |
jpl_db_error | 500 | DB 書き込み失敗 |
jpl_invalid_entry / jpl_invalid_pattern / jpl_invalid_override / jpl_invalid_format | 400 | エントリ検証・正規表現コンパイル失敗・プロファイルのルール上書き不正・format 不正 |
jpl_no_file / jpl_upload_error / jpl_file_too_large | 400 | インポートのファイル未添付・アップロードエラー・5MB 超 |
jpl_ai_unavailable | 400 | AI が利用不可(環境・設定・同意のいずれかが未達) |
jpl_ai_encode_failed | 500 | 送信データの生成失敗 |
jpl_ai_request_failed / jpl_ai_invalid_response | 502 | AI API 呼び出し失敗 / 応答を解釈できない |
jpl_publish_blocked | 403 | 公開前ゲート(第 6 章) |
rest_invalid_param | 400 | args スキーマ(enum・型)違反。WordPress コアが返す |
作成系(POST /rules /dictionaries /entries /profiles /assignments /ignores)の成功ステータスは 201、インポートは dry run が 200・確定が 201、それ以外は 200 です。
エクスポートを PHP 内部から rest_do_request() で呼んだ場合は rest_pre_serve_request が走らないため、戻り値は {filename, mime, content} の配列のままになります。生の CSV / JSON になるのは HTTP 経由のときだけです。
同梱モジュール由来の /plugin-bug-report/v1/report(POST)は別名前空間で、ライセンスが有効かつ所定の capability を持つときだけ受け付けます(本プラグインの校正 API ではありません)。WP-CLI コマンドは提供していません。
データベース(カスタムテーブル 8 本)
物理テーブル名は $wpdb->prefix + 論理名です(サイトの DB プレフィックスに従うため、wp_jpl_rules と決め打ちはできません)。作成は有効化時の dbDelta()。日時カラムはすべて UTC 保存です。
| 論理テーブル名 | 役割 |
|---|---|
jpl_rules | 校正ルール本体(種別・パターン・重要度・ワンクリック修正可否・params) |
jpl_dictionaries | 辞書セット(表記ゆれ/禁止語/許可語などの束) |
jpl_dictionary_entries | 辞書の語句エントリ(検出表記・推奨表記・一致方式) |
jpl_profiles | ルールプロファイル(ルールの束 + 自動修正可否・公開ブロック可否) |
jpl_profile_rules | プロファイル×ルールの上書き(有効/無効・重要度・パラメータ)。UNIQUE(profile_id, rule_id) |
jpl_assignments | プロファイルの割り当て(対象種別 7 種と優先度)。UNIQUE(target_type, target_id) |
jpl_ignored_items | 無視設定(指摘/投稿/ライター/カテゴリ/ルール) |
jpl_logs | 指摘ログ(ダッシュボード集計元。重要度別件数・blocked フラグ・明細 JSON) |
jpl_dictionary_entriesに(dictionary_id, pattern)の UNIQUE 制約はありません(キーは PRIMARY・dictionary_id・is_enabled)。同じ語を二重登録できます。jpl_logs.findingsは明細 JSON です。設定log_findings_detailで記録を止められます(管理画面 UI は無く、jpl_settingsをコードで書き換える必要があります)。保持日数は既定 90 日・設定値は保存時に 1〜3650 日へクランプされます(これも UI 無し)。日次 cronjpl_purge_logsがパージします。- スキーマバージョンは
1.0.0、保存先はオプションjpl_db_version。毎リクエストのplugins_loadedで保存値と比較し、差分があれば「テーブル作成(dbDelta 差分適用)→ capability の付与判定 → 既定設定の投入 → バージョン保存」を行います。 - 同梱データ(辞書 5 冊・73 エントリ、ルール 9 本、既定プロファイル、サイト全体割り当て)の投入は 有効化フック経由の 1 回だけで、プラグイン更新の経路では走りません(マイグレータは seed を呼びません)。
オプション・post meta・user meta
オプション(すべて jpl_ 接頭辞)
| キー | 内容 |
|---|---|
jpl_settings | 全体設定。既定値は post_types = ['post','page'] / realtime_default = 1 / log_findings_detail = 1 / log_retention_days = 90 / exclude_quotes = 1 / ai_enabled = 0 / ai_consent = 0 / ai_log_requests = 0 / ai_model_preference = '' |
jpl_delete_data_on_uninstall | アンインストール時のデータ削除オプトイン('1' / ''。既定は空=削除しない) |
jpl_db_version | スキーマバージョン |
jpl_caps_granted | capability 付与済みフラグ |
jpl_builtin_version | 同梱データ投入済みバージョン |
jpl_installed_version | 初回インストール時のバージョン |
jpl_ai_review_log | AI 実行履歴(ai_log_requests が ON のときだけ書き込み・最大 50 件・本文は保存しない。閲覧する管理画面は無く、参照するには get_option() で直接読む必要があります) |
jpl_license_key / jpl_license_status / jpl_license_expires_at / jpl_license_last_check / jpl_license_max_activations / jpl_license_current_activations | ライセンス情報(キーは暗号化して保存)。jpl_license_status は active / expired / suspended / revoked |
jpl_pbr_disabled | バグ報告ウィジェットの無効化フラグ |
transient も同じ接頭辞です: jpl_update_data_<md5> / jpl_releases_data(更新情報・12 時間)、jpl_license_notice(60 秒)、jpl_ai_text_generation_supported(300 秒)、jpl_ai_model_choices(3600 秒)、jpl_matcher_<md5>(辞書の事前コンパイル結果・12 時間)、jpl_notice_<token>(管理画面のフラッシュ通知)、jpl_import_<token>(辞書インポートのプレビュー・15 分)、jpl_publish_blocked_{user_id}(公開ゲートの差し戻し通知・5 分)。
post meta(すべて _jpl_ 接頭辞)
| メタキー | 型 / 既定 | 内容 |
|---|---|---|
_jpl_profile_id | integer / 0 | この投稿に使うプロファイルの差し替え。0 は「差し替えなし」。差し替え先が無効・削除済みなら無視されます |
_jpl_disabled | boolean / false | この投稿の校正を丸ごと止める。指摘 0 件・公開ブロックもしない |
どちらも show_in_rest で登録されていますが、auth_callback が edit_post かつ jpl_manage_profiles を要求します(寄稿者がコア REST 経由でメタを直接書き、公開ゲートを回避する経路を塞ぐためです)。エディタ側の「この投稿の設定」パネルも jpl_manage_profiles 保持者にしか表示されません。
_jpl_profile_id による差し替えは、post レイヤーの中で priority / id ともに PHP_INT_MAX の合成割り当てとして扱われます。つまり全レイヤー中で最強ですが、合成そのものは続きます(下位レイヤーの結果を全部捨てて置き換えるわけではありません)。
user meta
| メタキー | 内容 |
|---|---|
_jpl_tour | オンボーディングツアーの進行状況(/tour-state が読み書きする)。アンインストール時にも削除されません(第 10 章) |
独自 capability(8 種)とロール既定
| capability | 用途 | administrator | editor | author | contributor |
|---|---|---|---|---|---|
jpl_manage_settings | 最上位メニューの設定画面・「AI 校正」画面の表示と保存 | ○ | – | – | – |
jpl_manage_rules | 「ルール」画面と /rules、無視設定の広域スコープ・他人の無視解除 | ○ | ○ | – | – |
jpl_manage_profiles | 「プロファイル」「割り当て」画面と REST、投稿単位メタの書き込み | ○ | ○ | – | – |
jpl_manage_dictionaries | 「辞書」画面と REST、エディタからの「辞書に登録」 | ○ | ○ | – | – |
jpl_view_reports | 「ダッシュボード」画面と /reports/dashboard | ○ | ○ | – | – |
jpl_ignore_findings | 指摘の「無視」(/ignores)。エディタの無視ボタン表示可否 | ○ | ○ | ○ | ○ |
jpl_force_publish | 公開前ゲートのバイパス | ○ | ○ | – | – |
jpl_use_ai | AI 最終チェックの実行(/ai-review) | ○ | – | – | – |
- 購読者(subscriber)には何も付きません。
jpl_use_aiが管理者のみなのは意図した既定で、編集者・投稿者へは運用側で付与する想定です。 - 付与は初回インストール時の 1 回だけです。フラグオプション
jpl_caps_grantedが立っていれば、有効化時も DB バージョン差分検出時も何もしません。運用側でロールから外した capability(例: 編集者からjpl_force_publishを剥奪してゲートを厳格化する)を、プラグイン更新や再有効化で黙って復元しない設計です。 - 付与は role への
add_capのみで、個別ユーザーへ付与する UI はありません。権限管理プラグイン等の標準機構で行います。 - ライセンス画面だけは独自 capability ではなく
manage_optionsを要求します。jpl_manage_settingsを編集者に付けてもこの画面は出ません。 - アンインストール時の
revoke()は、既定付与の対象外だったロールも含めて全ロールを走査し 8 種をremove_capします。
公開前ゲートの挙動(開発者向け)
ブロックされるのは 「その記事の実効プロファイルで block_publish が有効」かつ「Error 指摘が 1 件以上」の 2 条件が同時に成立したときだけです。件数のしきい値は 1 件以上に固定で、設定項目はありません。Warning / Info / Suggestion は何件あっても止まりません。
配線しているフックは 3 本です: 対象投稿タイプごとの rest_pre_insert_{$post_type}、wp_insert_post_data、admin_notices。transition_post_status と save_post は使っていません。
| 経路 A: REST 主経路 | 経路 B: 非 REST フォールバック | |
|---|---|---|
| フック | rest_pre_insert_{$post_type} | wp_insert_post_data |
| 対象 | ブロックエディタの公開、/wp/v2/posts などコア REST コントローラ経由の書き込み | Classic Editor、クイック編集、wp_insert_post() を使うプログラム・インポータ |
| ブロック時の動作 | 保存そのものを中断して WP_Error を返す | ステータスを draft に書き換えて保存を続行(下書きに差し戻し) |
| エラーコード / HTTP | jpl_publish_blocked / 403 | なし(通常の保存として完了する) |
| 付帯情報 | data.summary(重要度別件数)と data.findings(Error 指摘だけを rule_key / message / text で抜粋) | なし。admin_notices で次に 1 回だけ通知(投稿編集画面のみ・有効期間 5 分) |
REST 主経路が処理した保存は、続く wp_insert_post_data では再評価しません(内部フラグ)。ただし REST であってもコア posts コントローラを通らない書き込み(独自ルート・インポータ等)は経路 B が評価します。403 レスポンスに truncated は含まれません。
対象になる状態遷移
定数は PUBLIC_STATUSES = ['publish', 'future']、LIVE_STATUSES = ['publish']。
| 新ステータス | 旧ステータス | ゲート対象 |
|---|---|---|
publish | (新規)/ draft / pending | 対象 |
future | (新規)/ future | 対象(予約公開の設定時も、予約投稿を編集して保存したときも検査する) |
publish | publish | 対象外(公開済み記事の更新はブロックしない) |
draft / pending / private | 任意 | 対象外 |
- WP-Cron による
future→publishの自動公開はwp_insert_post_dataを通らないためゲートが走りません。だからこそfutureへの遷移・編集の側を対象にしています。 - REST の部分更新で
post_statusが送られない場合は、既存投稿の現在のステータスを新ステータスとみなします。本文・タイトル・スラッグ・抜粋も送られなければ DB の現在値で評価します。「ステータスだけpublishに変える」保存でも、タイトルに残った Error でブロックされます。 - ゲートが張られるのは設定
post_typesの投稿タイプだけです。既定はpostとpageの 2 つで、v0.1.0 にこれを変更する管理画面 UI はありません。カスタム投稿タイプを対象にするにはオプションjpl_settingsをコードで書き換える必要があります。 - 公開前チェックの時間予算は 5.0 秒です。超過すると残りのルールをスキップした部分結果で判定します。
- ゲートが呼ぶのはルールエンジン(
trigger = 'prepublish')だけで、AI 最終チェックの指摘は公開ブロックに一切関与しません。
バイパス
評価順は capability が先、フィルタが後です。capability を持っていればフィルタは呼ばれません。2 経路とも同じ判定を通ります。
- capability
jpl_force_publish— 判定対象は現在ログイン中のユーザーであって、記事の著者ではありません。 - フィルタ
jpl_skip_publish_gate— cron・インポータ向けの逃し弁として実装されています(設定 UI ではありません)。
バイパスしても評価とログ記録は必ず走ります。ログには blocked = 1 が残ります(blocked は「ブロック条件を満たしたか」であって「実際に公開が止まったか」ではありません)。誰がバイパスしたかを記録する列は jpl_logs にありません(記録される author_id は記事の著者です)。
フック(フィルタ)
提供している拡張ポイントは フィルタ 4 本のみです。do_action() によるカスタムアクションは 0 件で、プラグインが独自に発火するアクションフックはありません。JavaScript 側(@wordpress/hooks)のフックもありません。
| フック名 | 引数 | 用途 |
|---|---|---|
jpl_seo_adapters | Seo_Adapter[] $adapters | SEO 連携アダプタ(Yoast SEO / Rank Math / All in One SEO)の一覧を差し替える |
jpl_seo_fields | array<string,string> $fields, int $post_id | 抽出済みの seo_title / seo_description を上書きする |
jpl_skip_publish_gate | bool $skip(既定 false), WP_Post|null $post(新規は null), array $context(post_type / content) | 公開前ゲートの逃し弁(cron・インポータ等) |
jpl_tour_sample_content | array $sample(title / slug / excerpt / content) | オンボーディングツアーのデモ原稿を差し替える。content は Gutenberg のシリアライズ済みブロックであること |
apply_filters(
'jpl_skip_publish_gate',
false, // bool バイパスするか
$post, // WP_Post|null
[ 'post_type' => $post_type, 'content' => $content ] // array
);
SEO 欄の取得は、Yoast SEO / Rank Math / All in One SEO のアダプタを順に試し、最初に有効だったもの 1 つだけを使います。どれも有効でなければ空になります。取得したキーは正規化され、キー名に title を含むものは seo_title、desc を含むものは seo_description に寄せられます。
同梱モジュール由来の plugin_bug_report_is_license_active / plugin_bug_report_should_display / plugin_bug_report_allow_with_heavy_plugin はバグ報告ウィジェットのフックで、校正機能とは無関係です。
辞書のインポート / エクスポート形式
インポート/エクスポートがあるのは辞書エントリだけです。ルール・プロファイル・割り当て・無視設定・プラグイン設定に入出力機能はありません。取り込み先の辞書は URL の {id} で決まるため、先に辞書を作っておく必要があります。
CSV(7 列・順序固定)
1 行目のヘッダは必須です。小文字化・トリム後にこの並びと完全一致しなければ、1 行目エラーとして全件不採用になります。
| # | 列名 | 必須 | 既定(空欄時) | 値の規則 |
|---|---|---|---|---|
| 1 | pattern | ○ | — | 検出表記。空はエラー。最大 500 バイト |
| 2 | suggestion | — | null | 推奨表記。空文字は DB では null |
| 3 | alternatives | — | null | 許容表記を |(パイプ)区切り。前後空白は除去、空要素は捨てる |
| 4 | match_type | — | exact | exact / partial / regex(小文字化される)。regex は保存前にコンパイル検証 |
| 5 | case_sensitive | — | 0 | 0 / 1 / true / false(大小無視)。それ以外はその行がエラー |
| 6 | note | — | null | メモ |
| 7 | is_enabled | — | 1 | 0 / 1 / true / false。それ以外はその行がエラー |
- UTF-8 BOM は除去して受け付けます。全セルが空の行はスキップ、列数が 7 でない行はエラーとしてスキップします。
- エラー行の行番号は CSV レコード番号(ヘッダ = 1)です。引用符内改行を含むセルがあると物理行とはずれます。
fgetcsv/fputcsvは$escape = ''(RFC 4180 準拠)で呼びます。\で終わるセルが後続行を飲み込む問題を回避するためです。- 往復で保たれるのは 7 列の値だけです。
id/dictionary_id/created_at/updated_atは列に無く、取り込み先で新しい ID が振られます。無効(is_enabled=0)のエントリも書き出されます。 alternativesの値そのものに|が含まれる場合、往復で分割されます(区切り文字と衝突するため)。
JSON
「辞書メタ + entries 配列」の単一オブジェクトです。出力は JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT(日本語がそのまま読める整形済み JSON)。
{
"name": "辞書名",
"type": "notation",
"description": "説明",
"entries": [
{
"pattern": "Wordpress",
"suggestion": "WordPress",
"alternatives": null,
"match_type": "exact",
"case_sensitive": 0,
"note": null,
"is_enabled": 1
}
]
}
case_sensitive/is_enabledは整数 0/1で出力します。取り込み時はtrue/false/"true"/"false"/0/1/ bool を受け付け、"false"は 0 になります(単純な truthy 判定ではありません)。- 辞書メタ(
name/type/description)は取り込みに使われません。参考情報です。 - エラー行の行番号は
entries配列の位置(1 始まり)です。entriesが無い・JSON が壊れている場合はline: 0の 1 件エラーで全件不採用になります。
取り込みの挙動
| 論点 | 実装 |
|---|---|
| 既存データとの関係 | 追記型(append)。既存エントリの上書きも重複スキップもしません。同じファイルを 2 回入れれば同じ語が 2 行できます |
| 2 段階フロー | 既定 dry_run=true で件数とエラー行だけを返し、DB は触りません。dry_run=false で確定します |
| dry run のレスポンス | total(解析できた行 + フォーマット層エラー行)/ valid(取り込み可能行)/ errors[]({line, reason}・行番号昇順) |
| エラー行 | スキップして報告。1 行でも壊れていれば全体が止まる、という挙動ではありません |
| 確定時の再検証 | dry run 済みでも validate_entry を通し直します |
| 書き込み単位 | 200 行ずつのチャンクで複数行 INSERT し、全チャンクを 1 トランザクションで括ります。途中失敗時は全体 ROLLBACK して jpl_db_error |
| ファイルサイズ上限 | 5,242,880 バイト(5MB)。超過は 400 jpl_file_too_large。行数の上限は実装にありません |
| 存在しない辞書への取り込み | 404 jpl_not_found |
| 管理画面経路 | REST とは別に admin-post.php 経路(jpl_import_entries → プレビュー、jpl_import_commit → 確定)があります。ファイル内容は 15 分の transient に生のまま保持し、表示・確定時に再パースします。プレビューのエラー表示は先頭 100 件まで |
CSV インジェクション対策: 書き出し時、' を 0 個以上挟んで = + - @ に到達するセルの先頭に ' を前置します。取り込み時は同じ規則で 1 つだけ剥がすため、エクスポート → 編集 → 再インポートで語が変質しません。あわせて suggestion / note は sanitize_textarea_field、alternatives の各要素は sanitize_text_field を通し、一括 INSERT を含む全値を $wpdb->prepare に通します。ダウンロードファイル名は sanitize_file_name() を通し、空なら dictionary-{id}.csv にフォールバックします。
管理画面のエクスポートリンクは REST URL に _wpnonce(wp_rest nonce)を付けたものです。公開ダウンロード URL ではありません。管理画面経路のアップロードは is_uploaded_file() を必須とし、nonce(check_admin_referer)と capability を検証します。
校正エンジンの拡張ポイントと制約
ルールの挙動は jpl_rules.params(longtext / JSON)で調整します。専用の入力欄はなく、管理画面「ルール」の「その他パラメータ(JSON)」テキストエリアに書く方式です(参照辞書だけはチェックボックス UI)。未設定のキーは既定値でマージされます。プロファイル側の params_override は丸ごと置換で、キー単位の部分マージはしません。
| 種別キー | 画面表示名 | params キー | 既定値 | 意味 |
|---|---|---|---|---|
notation | 表記ゆれ | dictionaries | なし | 参照する辞書 ID の配列 |
choon | 未設定 | 'short' のときだけ「語末の長音符を省く」ヒューリスティクスを追加。語末の ー を除いて 3 文字以上残るカタカナ語が対象 | ||
forbidden | 禁止語・注意語 | dictionaries | なし | 参照する辞書 ID の配列 |
redundancy | 冗長表現 | dictionaries | なし | 参照する辞書 ID の配列 |
style | 文体 | tone | null | 'desumasu' / 'dearu' を指定すると期待文体を固定。null なら多数決(同数なら指摘しない) |
max_ending_repeat | 3 | 同じ語尾がこの回数連続したら指摘(2 未満を指定しても 2 に丸められる) | ||
phrase_frequency | [] | {"表現": 閾値} のマップ。閾値は最低 1 に丸められる | ||
long_sentence | 長文 | max_chars | 80 | 1 文の文字数上限(超えたら指摘) |
max_commas | 4 | 1 文中の 、 , の個数上限 | ||
max_conjunction_repeat | 2 | 同じ文頭接続詞で始まる文の連続回数(対象は固定 15 語) | ||
max_bracket_depth | 1 | 括弧の入れ子の深さ上限 | ||
list_suggestion_commas | 6 | 読点がこの数以上なら箇条書きを提案する一文を追記 | ||
char_width | 全角半角 | alnum | 'half' | 全角英数字を半角に寄せる |
space | 'half' | 全角スペースを半角に寄せる | ||
half_kana | 'full' | 半角カタカナを全角に寄せる | ||
symbols | 'half' | 全角記号を半角に寄せる。対象は %/:-+=&#@~| の 11 文字のみ | ||
punctuation | 句読点 | style | 'ten_maru' | 'ten_maru'(、。)/ 'comma_period'(,.) |
require_period | 1 | 段落末の句点欠落を指摘するか | ||
seo_field | SEO 項目 | fields | ['title','excerpt','slug','seo_title','seo_description'] | チェック対象のフィールド |
checks | ['notation','forbidden','redundancy','char_width','punctuation'] | 委譲するルール種別 |
各 char_width の params は既定以外の値(例 'ignore')にすればその検出が無効になります。seo_field は自前で検出せず、同じ実効プロファイル内の他ルールを本文以外のフィールドへ再実行させる委譲型です(seo_field どうしの委譲は起きません)。既定の checks に style と long_sentence は含まれないため、タイトル・抜粋・SEO 欄では文体・長文チェックは既定では走りません。
正規表現ルールの制約
- パターンはデリミタなしで保存し、使用時に
~デリミタ +u(Unicode)フラグでコンパイルします。大小を区別しない設定ならiフラグを追加します。ユーザーが書いた未エスケープの~だけを自動エスケープします(既存の\~を二重エスケープしません)。 - 長さ上限は 500 バイト(
strlen判定)。空・空白のみは拒否します。保存時に~+uでコンパイルしpreg_matchを試行して、失敗すればjpl_invalid_patternで保存を拒否します。 - バックトラック爆発(ReDoS)そのものは検出しません。500 バイト上限が予防を兼ねている、という位置づけです。実行時にパターンが失敗しても例外は出さず「0 件ヒット」として進みます。
- 検証は「ルールの
pattern(match_type=regex)」「辞書エントリのpattern(保存時・インポートの dry run と確定の両方)」で走り、照合実行時も保存時と同じコンパイル処理を使います。
エンジン側の制約
- 形態素解析器(MeCab / Sudachi 等)は使いません。正規表現 + 辞書 + 文分割ヒューリスティクスで動き、外部 API への送信もありません(AI 最終チェックは別機能・既定 OFF・手動実行)。
- 照合は NFKC 正規化したテキストに対して行い、ヒット位置を原文の文字位置へ写像します。intl 拡張(
\Normalizer)が無い環境ではmb_convert_kana($text, 'asKV')にフォールバックするため、intl は必須ではありません。 - 日本語に語境界(word boundary)を付けられません。CJK を含むパターンの「完全一致」は実質「出現一致」と同じ挙動になります。語境界が付くのは ASCII 英数字・アンダースコアのみで構成された
exactパターンだけです。 - 辞書は 500 語単位の交替正規表現に事前コンパイルし、辞書の更新スタンプとエントリのフィンガープリントをキーに 12 時間 transient にキャッシュします。同一パターンの重複登録は先勝ちで 1 件に、包含される短いヒットは落として長い語を優先します。
- 時間予算はルール 1 本ごとに判定します(自動・手動 3.0 秒 / 保存・公開前 5.0 秒)。超過すると
truncated = trueにしてループを抜け、それまでの指摘は部分結果としてそのまま返します。1 本のルールの実行中に予算を超えてもそのルールは最後まで走ります(チェック内部に予算判定はありません)。 - 校正対象にならないブロック:
core/code/core/html/core/preformatted/core/embed/core/shortcode/core/freeform-embedと、core-embed/で始まる旧形式の埋め込み。設定exclude_quotes(既定 1)が有効ならcore/quote/core/pullquoteも除外します。除外ブロックの innerBlocks も連鎖して除外されます。 - 本文中の URL・メールアドレス・ショートコードは、オフセットを保つため同じ文字数のマスク文字
U+FFFCに置換されてから照合されます(=指摘の対象外)。<script>/<style>は中身ごと削除、残りの HTML タグはwp_strip_all_tags()で除去します。 - 実効プロファイルは DB に保存せず都度計算します(キャッシュはありません)。レイヤーは弱→強の順に
global→role→post_type→tag→category→user→postの 7 段で、priorityは同一レイヤー内のタイブレーク専用です(数値でレイヤーの上下は覆せません)。role/userがマッチするのは投稿の著者であって、編集中のログインユーザーではありません。 - ワンクリック修正が実際に適用されるのは、ルールの
auto_fixableが真・指摘にsuggestionがある・field === 'content'かつblock_index !== null・実効プロファイルのauto_fixが真、をすべて満たすときだけです。書き換え対象はブロック属性(RichText 値)で、post_content の生 HTML ではありません。RichText の生の値に<か&が含まれるブロックは誤置換を避けるため修正せず「指摘のみ」に倒します。
アンインストール時の挙動
プラグインをアンインストール(削除)しても、既定ではデータは削除されません。設定画面のチェックボックス(オプション jpl_delete_data_on_uninstall・既定は空文字=オフ)を '1' にしたうえで削除した場合のみ、次のデータが削除されます。停止(無効化)では何も削除されません。
| 対象 | 処理 |
|---|---|
| カスタムテーブル 8 本 | prefix 付きで DROP TABLE IF EXISTS |
| 独自 capability 8 種 | 全ロールから remove_cap |
| オプション | option_name LIKE 'jpl_%' を一括 DELETE(ライセンス情報を含む) |
| transient | _transient_jpl_% と _transient_timeout_jpl_% を一括 DELETE |
| post meta | meta_key LIKE '_jpl_%' を一括 DELETE(_jpl_profile_id / _jpl_disabled) |
| オブジェクトキャッシュ | 直 SQL 削除の後始末として wp_cache_flush() |
削除されないものは次のとおりです。
- user meta
_jpl_tour(オンボーディングツアーの進行状況)—uninstall.phpに user meta を削除する処理はなく、オプトインを有効にしていてもwp_usermetaに残ります。 - 投稿本文・記事データ — 触る処理はありません。
- cron イベント(
jpl_purge_logs/jpl_daily_license_check)—uninstall.phpでは解除しませんが、削除前に必ず通る無効化フックで解除済みです。
無効化(deactivate)時に行うのは、日次 cron jpl_purge_logs の解除、ライセンス cron jpl_daily_license_check の解除(自プロダクトのインスタンスのときだけ)、flush_rewrite_rules() の 3 つです。データ・capability・ライセンス情報はいずれも残ります。
※ 本ページの内容は v0.1.0 時点の実装に基づきます。マルチサイトのネットワーク対応コードは実装されておらず、テーブルは有効化したサイトの $wpdb->prefix でのみ作成されます。翻訳ファイル(.po / .mo)は同梱していないため、UI にはソース内の日本語がそのまま表示されます。