enonic-content-management について
Enonic XP プロジェクトでのコンテンツ一括操作や移行を支援する手順型スキルです。開発者が適切な API を選び、バッチ処理、ブランチと公開の管理、進捗報告を行えるようにします。
主な機能
- 01Enonic XP のプロジェクトとバージョンの特定
- 02コンテンツ API またはノード API の選択
- 03NoQL によるコンテンツ検索
- 04一括操作のバッチ処理
- 05draft と master の公開管理
- 06長時間タスクの進捗追跡
活用シーン
- 01JSON や CSV からのコンテンツ取り込み
- 02クエリ条件に合うコンテンツの更新や削除
- 03パスや環境間でのコンテンツ移行
- 04大規模操作の進捗レポート
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ webmaxru/ enonic-agent-skills --skill enonic-content-managementインストール後、Claude Code で/enonic-content-managementを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/bulk-update.template.tstask-migration.template.tsreferences/compatibility.mdexamples.mdmigration-reference.mdtroubleshooting.mdscripts/find-enonic-targets.mjs詳細
Enonic コンテンツ管理
手順
ステップ 1:Enonic XP プロジェクトと操作範囲を特定する
- ワークスペースで Enonic XP プロジェクトの目印を確認します。例:
com.enonic.xp依存関係を含むbuild.gradle、src/main/resources/のディレクトリ構造、またはxpVersionを含むgradle.properties。 - Node ランタイムが利用可能な場合は、
node scripts/find-enonic-targets.mjs .を実行して、Enonic XP プロジェクトの目印と既存のコンテンツ操作ファイルをスキャンします。 - Enonic XP プロジェクトが見つからない場合は、ここで終了し、このスキルの対象は Enonic XP のコンテンツ操作のみであることを説明します。
gradle.propertiesまたはbuild.gradleから対象の XP バージョンを確認し、適切な API を選択します。- 依頼された操作を分類します。
- 一括作成:外部ソース(JSON、CSV、API)からコンテンツをインポートします。
- 一括更新:クエリ条件に一致する既存コンテンツを変更します。
- 一括削除:クエリ条件に一致するコンテンツを削除します。
- 移行:パス、サイト、または環境間でコンテンツを移動または変換します。
- クエリ/集計:NoQL と集計を使用してコンテンツを取得、分析します。
- 長時間実行タスク:進捗報告が必要な、約 100 件を超える項目を処理する操作です。
ステップ 2:API レイヤーとコンテキストを選択する
- クエリ DSL のパターン、バッチ処理の戦略、ブランチ処理のルールについては、
references/migration-reference.mdを読みます。 - CMS コンテンツを操作し、公開/非公開、コンテンツタイプの検証、コンテンツドメインの抽象化が必要な場合は、
lib-contentを選択します。 - 低レベルのノード操作、カスタムリポジトリ、または生データの移行におけるコンテンツタイプ検証の回避が必要な場合は、
lib-nodeを選択します。 - 必要なコンテキストを特定します。
- 変更操作は
draftブランチで、公開済みコンテンツの読み取りはmasterブランチで実行するために、lib-contextを使用します。 - 高い権限が必要な操作では、
role:system.adminプリンシパルを指定してlib-contextを使用します。
- 変更操作は
- 操作で約 100 件を超える項目を処理する場合は、
lib-taskを使用したタスクコントローラーでラップします。パターンについては、references/migration-reference.mdのタスクコントローラーに関するセクションを読みます。
ステップ 3:クエリを作成する
- 対象コンテンツに一致する NoQL クエリ文字列または DSL 式を作成します。
- コンテンツタイプで絞り込む場合は、
contentLib.query()のcontentTypesパラメーター、またはノードクエリのtypeプロパティ比較を使用します。 - 日付範囲クエリでは、
instant()またはdateTime()関数と、range()クエリ関数を使用します。 - 全文検索では、適切なフィールドパスと演算子(
AND/OR)を指定してfulltext()を使用します。 - パスを指定した操作では、子孫に一致させるために
_path LIKE '/content/site-path/*'を使用します。注:NoQL クエリの_pathプロパティには内部の/content/プレフィックスが含まれますが、結果のhit._pathはコンテンツドメインのパスを返し、このプレフィックスは含まれません。結果のパスからクエリを作成するときは、必ず/content/を先頭に付けてください。 exists、notExists、hasValue、またはbooleanの組み合わせを使用して、クエリ後の絞り込みを効率化するfiltersを追加します。- グループ化した統計情報(用語の件数、日付ヒストグラム、数値範囲、統計値)が必要な操作には、
aggregationsを追加します。 - クエリと集計の完全なパターンについては、
references/examples.mdを読みます。 ステップ 4:バッチ処理を実装する startパラメーターとcountパラメーターを使ってページネーションで取得し、すべての結果をメモリに読み込まないようにします。- アイテムごとの処理の複雑さに応じて、
countを 50~200 のバッチサイズに設定します。 result.hits.length === 0またはstart >= result.totalになるまでループし、反復ごとにstartをバッチサイズ分増やします。contentLib.create()を一括で実行する際は、アイテムごとのインデックス更新を避けるためにrefresh: falseを設定し、バッチ完了後に手動で更新します。contentLib.modify()では、各コンテンツアイテムを安全に変換するためにエディターコールバックパターンを使用します。contentLib.publish()では、大規模な公開セットでタイムアウトしないよう、キーを 50~100 件ずつのグループに分けて処理します。- レポート用に成功数と失敗数を記録します。
- 再利用可能なバッチ更新コントローラーテンプレートについては、
assets/bulk-update.template.tsを確認します。注:テンプレートでは TypeScript/ESM 構文(import、const、アロー関数)が使われています。.jsファイルとして XP ランタイムにデプロイする際は、CommonJS JavaScript(require()、var、function())に適合させてください。
ステップ 5:ブランチ操作と公開を処理する
- コンテンツの変更は
draftブランチのコンテキストで実行します。 - 変更が完了したら、
contentLib.publish()を使って変更したアイテムをmasterに公開します。XP < 7.12 の場合は、sourceBranch: 'draft'とtargetBranch: 'master'を渡します。XP 7.12 以降では、これらのパラメーターは無視されます(常に draft から master に公開されます)。 - 一括更新したアイテムを公開する際は、依存関係が意図せず公開されるのを避けるため、
includeDependencies: falseを設定します。 - draft と master の状態を比較する操作には、
lib-nodeのrepo.diff()を使用し、target: 'master'とincludeChildren: trueを指定します。
ステップ 6:時間のかかる操作をタスクコントローラーでラップする
- インラインのタスク関数には
taskLib.executeFunction()を、名前付きタスク記述子にはtaskLib.submitTask()を使用します。 - バッチ処理中は、一定の間隔で
taskLib.progress({ info, current, total })を使って進捗を報告します。 - 進捗報告に対応した再利用可能なタスクコントローラーテンプレートについては、
assets/task-migration.template.tsを確認します。 - 重複した操作を開始する前に、
taskLib.isRunning()で既存の実行中インスタンスを確認します。 - 操作による負荷が過剰な場合は、バッチ間のスロットリングに
taskLib.sleep()を使用します。 - XP 7.13 以降の名前付きタスクでは、
run関数の第 2 引数としてtaskIdが渡されます:exports.run = function(params, taskId) { ... }。
ステップ 7:結果を検証して報告する
- 操作の完了後、処理したアイテム数、作成・更新・削除したアイテム数、失敗したアイテム数、合計所要時間の概要をログに記録します。
- 移行操作では、移行先のパスをクエリして、移行先にコンテンツが存在することを確認します。
- 公開操作では、
masterブランチをクエリして、公開状態を確認します。 - エラーが発生した場合は、エラーの詳細(コンテンツパス、エラーメッセージ)を構造化レポートにまとめます。
エラー処理
scripts/find-enonic-targets.mjsで Enonic XP プロジェクトが見つからない場合は、ワークスペースに Enonic XP アプリケーションが含まれていないことを説明します。- コンテンツ操作で
contentAlreadyExistsエラーが発生した場合は、対象が存在するか確認し、更新するかスキップするかを判断します。重複の処理パターンについては、references/troubleshooting.mdを確認します。 - クエリ結果が 0 件の場合は、クエリ構文、ブランチのコンテキスト、プロパティのパスを確認します。NoQL の文字列形式の不一致(たとえば、日付比較で
instant()ラッパーがないこと)は、よくある原因です。 - タスクが失敗またはタイムアウトした場合は、
taskLib.get(taskId)で状態と進捗の詳細を確認します。タイムアウトや権限の問題については、references/troubleshooting.mdを確認します。 - 公開または変更時に
AccessDeniedExceptionが発生した場合は、lib-contextを介してコンテキストにrole:system.adminプリンシパルが含まれていることを確認します。
コメント
Markdown 対応