Movable Type や PowerCMS(X を除く)で作成したテンプレートを「テーマ」としてエクスポートすると、デフォルトのファイル名は template_N.html
(N は、テンプレート ID)となります。 この状態だと「どのファイルが、どのテンプレートに対応しているのか」が判断しづらいため、本番環境の最新データと手元のファイルとの差分を比較するのが手間・・・といった経験をお持ちの方は、少なからずいらっしゃることでしょう。
そこで、生成されるファイル名を制御できる「テンプレート識別子」を設定しておくと便利です。
Movable Type なら MTAppjQuery の導入、PowerCMS ならデバッグモードを有効にするだけで、テンプレートの編集画面で任意の「テンプレート識別子」をセットできるようになります。
MTAppjQuery でテンプレート識別子を設定可能にするには | プラグイン | Hei Blog
https://hei-a.net/blog/movable_type/plugin/template-identifier.html
テンプレートの識別子を変更したい | トラブルシューティング | ドキュメント | PowerCMS - カスタマイズする CMS
https://www.powercms.jp/products/document/troubleshooting/change-template-identifier.html
これで解決できればよいのですが、テーマを再適用したり、個別に新規テンプレートを作成したタイミングで意図せず template_N.mtml
が生成されてしまうことがあります。開発フェーズであれば自由に調整できるものの、運用フェーズではすべてを管理するのが難しいこともしばしば。。。
そこで、ファイル名の整合性が取れない状態でエクスポートされた MTML ファイルを PHP でリネームする仕組みを考えてみました。
リネーム前の差分を比較
ここでは、次のようなケースを想定しています。
- 左:
master
ディレクトリ(比較元のテーマファイル) - 右:
target
ディレクトリ(リネームしたいテーマファイル)
それぞれ、エクスポート時の「出力ファイル名」は website_main
です。master/website_main
がテンプレート識別子をひと通り設定してある状態、target/website_main
が本番環境などからエクスポートした際に「意図しないファイル名で出力されている」状態とします。
theme.yaml
を比較すると、テンプレート名は同じでもテンプレート識別子が異なっていることがわかります。
なお、差分の比較は Beyond Compare がオススメですので、気になった方は過去記事もご覧ください。
事前準備
ファイル構成
作業用ディレクトリのファイル構成イメージは、次の通りです。master
と target
ディレクトリ以外は、後続のステップで用意する Composer 関連のファイル・ディレクトリ、リネーム処理を行う PHP ファイルとなります。
./
├── composer.json
├── composer.lock
├── master/
│ └── website_main/
│ ├── templates/
│ │ ├── archive-entry.mtml
│ │ ├── index-top.mtml
│ │ ├── module-config.mtml
│ │ └── module-layout.mtml
│ └── theme.yaml
├── renameTemplate.php
├── target/
│ └── website_main/
│ ├── templates/
│ │ ├── module-config.mtml
│ │ ├── template_485.mtml
│ │ ├── template_54.mtml
│ │ └── template_917.mtml
│ └── theme.yaml
└── vendor/
まずは master
配下に「比較元のテーマファイル」、target
配下に「リネームしたいテーマファイル」を配置しておきましょう。
Composer パッケージのインストール
PHP で YAML の読み込みやパースを効率よく行うために、Spyc をインストールします。
作業用ディレクトリに移動し、次のコマンドを実行してください。
composer require mustangostang/spyc
なお、Symfony の Yaml Component も試してみたのですが、アーカイブマッピングに含まれる %b
などのアーカイブファイル名の記述部分がパースエラーになるため、Spyc を採用しています。
リネームを実行する PHP ファイルを作成
続けて、作業用ディレクトリに renameTemplate.php
を作成し、次の PHP コードを保存します。
<?php
/*
* renameTemplate.php:テンプレートのリネーム
* ----------------------------------------------
* - ローカル環境でテーマ開発時に使用
* - 機能
* - 「マスター」と「ターゲット」の theme.yaml を読み込み
* - 「マスター」と「ターゲット」の同一ラベルのテンプレート識別子を比較
* - 差分があれば、「ターゲット」のファイルをリネーム
*/
require 'vendor/autoload.php';
if(PHP_SAPI === 'cli') {
// コマンドラインから実行された場合
$theme_directory = (isset($argv) && count($argv) > 1) ? $argv[1] : '';
} else {
// ブラウザから実行された場合
$theme_directory = (isset($_GET['theme'])) ? $_GET['theme'] : '';
}
if($theme_directory === '') {
echo 'テーマのディレクトリ名は必須です。' . PHP_EOL;
return;
}
// theme.yaml からテンプレート識別子を取得
function getTemplateIdentifier($theme, $type = 'master') {
$response = [];
// $type が 'master' または 'target' 以外の場合は終了
if(!in_array($type, ['master', 'target'])) {
return $response;
}
// theme.yaml を読み込んで、配列に変換
$yaml = file_get_contents($type . '/' . $theme . '/theme.yaml');
$yaml = Spyc::YAMLLoad($yaml);
// テンプレートのブロックをループ処理
foreach ($yaml['elements']['template_set']['data']['templates'] as $templateType => $templates) {
// system を除外
if(!in_array($templateType, ['system'])) {
foreach ($templates as $identifier => $template){
$response[$template['label']] = $identifier;
}
}
}
return $response;
}
// マスター、ターゲットそれぞれのテンプレート識別子を取得
$master = getTemplateIdentifier($theme_directory);
$target = getTemplateIdentifier($theme_directory, 'target');
// $target のループ処理
foreach ($target as $label => $identifier) {
// $master に存在しないテンプレートはスキップ
if(!isset($master[$label])) {
continue;
}
// $master と $target のテンプレート識別子が異なる場合
if($master[$label] !== $identifier) {
$rename_from = 'target/' . $theme_directory . '/templates/' . $identifier . '.mtml';
$rename_to = 'target/' . $theme_directory . '/templates/' . $master[$label] . '.mtml';
if(file_exists($rename_from)) {
// 対象ファイルが存在すれば、リネーム
rename($rename_from, $rename_to);
echo 'リネームしました:' . $identifier . '.mtml' . ' → ' . $master[$label] . '.mtml' . PHP_EOL;
} else {
echo '対象ファイルが存在しません:' . $identifier . '.mtml' . PHP_EOL;
}
// ブラウザから実行されていれば、改行タグを出力
if(PHP_SAPI !== 'cli') {
echo '<br>' . PHP_EOL;
}
}
}
ポイントを解説すると、実行時に指定されたテーマディレクトリ直下の theme.yaml
を読み込み、$master
と $target
にそれぞれのテンプレート名をキーとするテンプレート識別子の配列をセット。ループ処理でテンプレート名ごとのテンプレート識別子を比較し、同一でなければ $master
の値に合わせてリネームを行います。
「とりあえず、目的が果たせれば...」くらいの軽い気持ちで作成していますので、あくまでもローカル環境での利用を想定しています。
リネーム処理の実行
コマンドラインから実行
作業用ディレクトリに移動し、次のコマンドを実行してください。 引数でテーマディレクトリ名を指定します。
php renameTemplate.php website_main
処理が完了すると、リネームされたファイル名が出力されます。
ブラウザから実行
Docker などでローカル環境を構築している場合、ブラウザからアクセスしても実行できます。
URL パラメータ theme
にテーマディレクトリ名を指定してください。
http://localhost/pathToDir/renameTemplate.php?theme=website_main
こちらも、リネームされたファイル名が出力されます。
実行後の差分比較
期待通りにリネームできたため、簡単に比較できるようになりました。
あとは master
側に MTML の差分をマージしてから編集を加えれば、本番環境への反映もロールバックの心配が軽減できそうです。
まとめ
今回は、Movable Type や PowerCMS でエクスポートしたテーマの差分を効率的に比較するための、テーマファイルのリネーム方法についてご紹介しました。
そもそもとして、標準機能で「テンプレート識別子」が設定でき、かつ、テーマ適用時にインデックステンプレートの識別子をリセットしないようにして欲しいところですが、とりあえずはこの方法で対応できるかと思います。
という訳で、これは Movable Type Advent Calendar 2024 1日目の記事です。
ネタを探して彷徨ってたら、4年経ってました w