記事公開日の「年」だけを集めて表示するとします。例えば記事検索フォームの「公開年」というselect要素の中身です。この時、MTEntries
で頑張るか、プラグインを書くかによって再構築の速度が大きく変わりました。大規模サイトでは再構築で扱うオブジェクト数・ファイル数が多くなるので、少しでも再構築時間を削ることが重要です。
記事は10,000件あると仮定します。大量のダミー記事を生成するコード(Python)はChatGPTに書いてもらい、生成したCSVファイルをインポートしました。
# coding=utf8
import csv
import lorem
import random
from datetime import datetime, timedelta
# ダミーデータを生成する関数
def generate_dummy_data(num_records):
data = []
for i in range(1, num_records + 1):
title = "記事{0:04}".format(i)
content = lorem.text()
date_time = datetime.now() - timedelta(days=random.randint(1, 365))
data.append([title, content, date_time.strftime("%Y-%m-%d %H:%M:%S")])
return data
# CSVファイルに書き込む
def write_to_csv(data, filename):
with open(filename, 'w') as csvfile:
csvwriter = csv.writer(csvfile)
csvwriter.writerow(["entry_title", "entry_text", "entry_published_on"])
csvwriter.writerows(data)
if __name__ == "__main__":
num_records = 4000
dummy_data = generate_dummy_data(num_records)
write_to_csv(dummy_data, "dummy_articles.csv")
テンプレートは下記です。(年が連続していない可能性がある前提で考えます。)MTEntriesの方はループして、変数に入れている年とオブジェクトの年が違う場合はHTMLを出力するというよく見かける処理です。プラグインの方は後でコードを示しますが、配列に年を格納しておりループでHTMLを出力しているだけです。
<mt:speedmeter name="use mtentries">
<mt:setvar name="current_year" value="">
<mt:entries cols="published_on" sort_by="published_on" sort_order="descend">
<mt:entrypublishedon format_ts="Y" setvar="year">
<mt:if name="year" ne="$current_year">
<option value="<mt:var name="year" escape />"><mt:var name="year" escape />年</option>
<mt:setvar name="current_year" value="$year" />
</mt:if>
</mt:entries>
<mt:unset name="year" />
</mt:speedmeter>
<mt:speedmeter name="use sql">
<mt:publishedyears model="entry" name="year" />
<mt:loop name="year">
<option value="<mt:var name="__value__" escape />"><mt:var name="__value__" escape />年</option>
</mt:loop>
</mt:speedmeter>
プラグインの処理は以下のように記事の公開年を集めるクエリを実行しているだけです。
public function hdlr_function_published_years( $args, $ctx ) {
$model = $args['model'] ?? null;
$name = $args['name'] ?? null;
if ( ! $model || ! $name ) {
return '';
} elseif ( ! in_array( $model, ['entry'], true ) ) {
// NOTE: $app->get_table()で調べれば良いのだが、現状entryモデルでしか使わないので簡素化
return '';
}
$app = $ctx->app;
$workspace_id = $app->workspace() ? $app->workspace()->id : 0;
// NOTE: 現状entryモデルでしか使わないのでstatusの値を直打ちしている
$sql = <<<EOQ
SELECT DISTINCT YEAR( `{$model}_published_on` ) AS year
FROM `mt_{$model}`
WHERE `{$model}_status` = 4 AND `{$model}_rev_type` = 0 AND `{$model}_workspace_id` = {$workspace_id}
ORDER BY year DESC;
EOQ;
$yearsResult = $app->db->db->query( $sql );
$yearsResult = $yearsResult->fetchAll( PDO::FETCH_ASSOC );
$years = array_map( function ( $item ) {
return $item['year'];
}, $yearsResult );
$ctx->vars[$name] = $years;
}
テンプレートを処理した結果は以下の通りです。プラグインを書いた方が圧倒的に速いという結果になりました。
<!--use mtentries start.-->
<option value="2023">(2023年)</option>
<option value="2022">(2022年)</option>
<option value="2021">(2021年)</option>
<!--use mtentries took 1.4193 seconds to process this block.-->
<!--use sql start.-->
<option value="2023">(2023年)</option>
<option value="2022">(2022年)</option>
<option value="2021">(2021年)</option>
<!--use sql took 0.0332 seconds to process this block.-->
プラグインの初期化時間があるかもしれませんが、私が関わる多くの案件では管理画面のカスタマイズ・タグの追加で案件固有のプラグインを開発することがほとんどなので考えないことにします。
なお、年が絶対に連続していることが保障されるのであれば、最新記事と最古記事の年を取り出してMTFor
でループすれば良さそうです。