はじめに
Movable Typeのコンテンツタイプでデータ件数が多くなった場合どうなるのか
テストしてみる・・
条件
コンテンツタイプの項目を約300項目
コンテンツタイプでカテゴリ使用
コンテンツデータデータ件数5000件
カテゴリセットで約300カテゴリを作成
カテゴリは下記を想定・・
親カテゴリ
子カテゴリ
孫カテゴリ
ひ孫カテゴリ
ひ孫カテゴリ
子カテゴリ
孫カテゴリ
子カテゴリ
孫カテゴリ
想定
上記条件にて、Movable Typeのコンテンツタイプで商品を登録することを想定・・・
CSVDataImExporterでのインポート・エクスポートなどのどれくらい時間がかかるのか・・
関連
小粋空間さまCSVDataImExporter
https://www.koikikukan.com/movabletype/plugin/CSVDataImExporter/
WP、Movable Typeもカスタムフィールド/コンテンツデータではSQLの構造上、1項目を追加するごとに1レコードずつSQLレコードが作成されるので・・
SQLのデータベースレコード構造
カスタムフィールド/コンテンツデータ1レコード項目1
カスタムフィールド/コンテンツデータ1レコード項目2
カスタムフィールド/コンテンツデータ1レコード項目3
カスタムフィールド/コンテンツデータ1レコード項目4
カスタムフィールド/コンテンツデータ1レコード項目5
カスタムフィールド/コンテンツデータ2レコード項目1
カスタムフィールド/コンテンツデータ2レコード項目2
カスタムフィールド/コンテンツデータ2レコード項目3
カスタムフィールド/コンテンツデータ2レコード項目4
カスタムフィールド/コンテンツデータ2レコード項目5
項目が可変になるので、上記な構造はしょうがない・・・
スクラッチでSQL作成の場合
1レコード 項目1 項目2 項目3 項目4 項目5
2レコード 項目1 項目2 項目3 項目4 項目5
コンテンツタイプ構造
商品用一部のみ
カテゴリイメージ
今回テストでカテゴリの拡張をコンテンツタイプでテストしてみる
Movable Typeでは、カテゴリ名、カテゴリベースネームしかないのでそれ以外を拡張したいときに
通常は、カテゴリベースネームをクラス名にあてるとかで十分だけど・・
結果
データ件数 5000件、300カテゴリをコンテンツタイプアーカイブ、コンテンツタイプリストアーカイブを作成して再構築が20分程度
CSVDataImExporterで5000件のインポート・エクスポートは・・・・・・6時間ほど・・・( ノД`)シクシク...
1レコード追加に1秒ほど、あとカテゴリを1つ追加することにより1秒ほど・・
カテゴリがなければ。5000秒で83分ほど・・
1レコード1カテゴリの場合は倍・・1レコードに3つカテゴリがあった場合は・・・5時間ほど。。。
同じデータをWPのCSVフォーマットに合わせてのWP All Import&ACFでテストしてみたけど・・似たような・・時間
注意)他のコンテンツデータとリンクなど、複合される場合は、再構築時間が変わると思います。また、インポート・エクスポートはスペックによって変わります。
Movable Typeのカテゴリについて・・・
個人的には、親カテゴリのみで重複カテゴリなしで済ませたいですが・・要件であったりと・・
下記で設定する場合は
ひ孫カテゴリの下にデータがひも付きますが・・親カテゴリ,子カテゴリ,孫カテゴリにはデータは配置されません。
親カテゴリ>子カテゴリ>孫カテゴリ>ひ孫カテゴリ
下記で設定することで各カテゴリの配下にデータが配置されます・・
SEO的にスパムになりそう?!
親カテゴリ
親カテゴリ>子カテゴリ
親カテゴリ>子カテゴリ>孫カテゴリ
親カテゴリ>子カテゴリ>孫カテゴリ>ひ孫カテゴリ
CSVDataImExporterの設定では
下記の場合
親カテゴリ>子カテゴリ>孫カテゴリ>ひ孫カテゴリ
>が--で登録をします。複数カテゴリの場合は、,カンマで区切ります・・
親カテゴリ--子カテゴリ--孫カテゴリ--ひ孫カテゴリ
重複の場合,カンマで区切り
親カテゴリ--子カテゴリ--孫カテゴリ--ひ孫カテゴリ1,親カテゴリ--子カテゴリ--孫カテゴリ--ひ孫カテゴリ2
下記にすると・・該当のカテゴリ名では降られますが・・階層は引き継ぎされません・・・
親カテゴリ,子カテゴリ,孫カテゴリ,ひ孫カテゴリ
カテゴリの拡張
こんなこと・・・やりたい?
「商品」と「商品カテゴリ拡張」では、カテゴリセットは同じ商品カテゴリをつかう。
Movable Typeのカテゴリ
Movable Typeでは、初期設定では、データの存在しないカテゴリは、HTMLが出力されません。
なので。設定>全般より、
記事やコンテンツデータがないアーカイブの公開 >記事やコンテンツデータが含まれない場合でも、カテゴリアーカイブを公開する にチェックします。
CategoryArchiveLinkについて・・
基本は「商品」でコンテンツタイプアーカイブ、コンテンツタイプリストアーカイブを作成して、「商品カテゴリ拡張」は両方作成しない。
この場合、CategoryArchiveLinkは、テンプレートのコンテンツタイプリストアーカイブ等で作成されないと
デフォルトで、サイトURL/cate/subcate/となるんで・・商品でアーカイブマッピングでカスタムしていると。うまくいかない。
商品のコンテンツタイプリストアーカイブのアーカイブマッピング
product/%-c/%i
商品のコンテンツタイプアーカイブのアーカイブマッピング
product/%-c/%-f
上記の場合「商品カテゴリ拡張」のほうでは、テンプレートでアーカイブを作成していないので(/product/を定義していないので)CategoryArchiveLinkが異なる・・・・
「商品」のコンテンツタイプリストアーカイブでは・・
カテゴリをもとに商品カテゴリ拡張を取得する・・
下記のように。表示させたい「商品」、「商品カテゴリ拡張」を合わせておきます。
「商品」カテゴリ
親カテゴリ>子カテゴリ>孫カテゴリ
「商品カテゴリ拡張」カテゴリ
親カテゴリ>子カテゴリ>孫カテゴリ
子カテゴリで、孫カテゴリを出力して、商品カテゴリ拡張のコンテンツデータとカテゴリで検索して出力
<mt:SubCategories>
<mt:if tag="CategoryCount">
<mt:SetVarBlock name="catelist" function="undef"></mt:SetVarBlock>
<mt:ParentCategories>
<mt:SetVarBlock name="catelist" function="push"><mt:CategoryLabel></mt:SetVarBlock>
</mt:ParentCategories>
<mt:SetVarBlock name="cmpcate" function="undef"></mt:SetVarBlock>
<mt:SetVarBlock name="cmpcate"><mt:loop name="catelist" glue="/"><mt:GetVar name="__value__"></mt:loop></mt:SetVarBlock>
<!-- 注)ここは「商品」のCategoryArchiveLink、product/cate/cate1/ -->
<p><a href="<$mt:CategoryArchiveLink$>"><$mt:CategoryLabel$></a></p>
<mt:Contents content_type="商品カテゴリ拡張" field:カテゴリのユニークID="$cmpcate">
<!-- 注)ここは「商品カテゴリ拡張」のCategoryArchiveLink、/cate/cate1/ -->
<p><mt:ContentField content_field="商品カテゴリ"><a href="<mt:CategoryArchiveLink archive_type="ContentType-Category">"><mt:CategoryLabel></a></mt:ContentField></p>
<p><img src="<mt:ContentField content_field="サムネール画像"><mt:ContentFieldValue></mt:ContentField>"></p>
<p><mt:ContentField content_field="class名"><mt:ContentFieldValue></mt:ContentField></p>
<p><mt:ContentField content_field="カテゴリ補足説明"><mt:ContentFieldValue></mt:ContentField></p>
<mt:CategoryLabel>
</mt:Contents>
</mt:if>
</mt:SubCategories>
<mt:SubCategories>
現在のカテゴリの子カテゴリを階層化して一覧表示する
ここで、カテゴリ写真など、補足するカテゴリを選定する
<mt:ParentCategories>
最上位のカテゴリから現在のカテゴリまでを繰り返して表示する
ここでは、「商品カテゴリ拡張」で登録されているカテゴリ階層を求める
cmpcate
ParentCategoriesで取得したカテゴリを/区切りの文字列を作成する
親カテゴリ/子カテゴリ
あとリストは、こんな感じで・・
リストでは、並び順変更とか、件数表示がある場合は、Movable TypeでJavaScriptで読み取り可能なデータを作成してJavaScriptとかで処理するとか
<table>
<mt:Contents content_type="商品">
<tr>
<td><mt:ContentField content_field="品番"><mt:ContentFieldValue></mt:ContentField></td>
<td><mt:ContentField content_field="商品名"><mt:ContentFieldValue></mt:ContentField></td>
<td><mt:ContentField content_field="商品カテゴリ"><a href="<mt:CategoryArchiveLink>" class="label category text-xsmaller"><mt:CategoryLabel></a></mt:ContentField></p>
<td><mt:ContentField content_field="価格"><mt:ContentFieldValue></mt:ContentField></td>
<td><a href="<mt:ContentPermaLink>">詳細</a></td>
</tr>
</mt:Contents>
</table>
上記で、価格が税抜き価格で1000と登録されているのを税込みにするには・・・
こんな感じで・・\1,100円で表示できます。
<mt:SetVarBlock name="products_price"><mt:ContentField content_field="価格"><mt:ContentFieldValue></mt:ContentField></mt:SetVarBlock>
<mt:Var name="products_price" setvar="tax_calc">
<MTSetVar name="tax_calc" value="1.10" op="*">
<MTSetVar name="tax_calc" value="0.5" op="+">
<MTGetVar name="tax_calc" regex_replace="/(\d*)\.(\d*)/","$1" setvar="tax_include">
税込価格\<mt:Var name="tax_include" numify="1">
商品詳細ページとかで、下記とか・・よくつかったり・・して
空のtableタグが・・いやなときは・・
<table>
<mt:ContentField content_field="項目1">
<tr>
<td>項目1</td>
<td><mt:ContentFieldValue></td>
</tr>
</mt:ContentField>
<mt:ContentField content_field="項目2">
<tr>
<td>項目1</td>
<td><mt:ContentFieldValue></td>
</tr>
</mt:ContentField>
<mt:ContentField content_field="項目2">
<tr>
<td>項目1</td>
<td><mt:ContentFieldValue></td>
</tr>
</mt:ContentField>
</table>
こんな感じで・・
ただ、あり、なしとかで、文字とか入っていると使えません・・
選択の値をなしは、値を登録しないとか工夫が必要です。
<mt:SetVarBlock name="checkdt"></mt:SetVarBlock>
<mt:ContentField content_field="項目1"><mt:SetVarBlock name="checkdt" function="push"><mt:ContentFieldValue></mt:SetVarBlock></mt:ContentField>
<mt:ContentField content_field="項目2"><mt:SetVarBlock name="checkdt" function="push"><mt:ContentFieldValue></mt:SetVarBlock></mt:ContentField>
<mt:ContentField content_field="項目3"><mt:SetVarBlock name="checkdt" function="push"><mt:ContentFieldValue></mt:SetVarBlock></mt:ContentField>
<mt:Var name="chk_cnt" value="0">
<mt:Var name="checkdt" function="count" setVar="chk_cnt">
<mt:If name="chk_cnt" ne="">
<table>
<mt:ContentField content_field="項目1">
<tr>
<td>項目1</td>
<td><mt:ContentFieldValue></td>
</tr>
</mt:ContentField>
<mt:ContentField content_field="項目2">
<tr>
<td>項目1</td>
<td><mt:ContentFieldValue></td>
</tr>
</mt:ContentField>
<mt:ContentField content_field="項目2">
<tr>
<td>項目1</td>
<td><mt:ContentFieldValue></td>
</tr>
</mt:ContentField>
</table>
</mt:if>
検索は・・・
javascriptでjsonで検索をつくる・・・
インデックステンプレートで全件をつくってもいいし、コンテンツタイプリストアーカイブを利用して。カテゴリごとでjson作ってもよいかも・・
全文検索であれば、下記ぐらいの項目にして、検索データに複数の検索したい項目をくっつけて・・
商品名 検索データ ページのURL
関連
Movabletypeコンテンツデータ2
https://www.omakase.net/blog/2023/02/movabletypecontent2.html
jQueryで新着情報をつくってみた。
https://www.omakase.net/blog/2024/09/jquery-1.html
インデックステンプレート
items.js
jsonでもよいけど・・変数名分、ファイルサイズが大きくなりそうなので・・jsの配列で行う・・
<mt:Unless name="blanklinedel" regex_replace="/^[\s\t]*\n/gm","">
var items = [
<mt:Contents content_type="商品">
['<mt:ContentField content_field="品番"><mt:ContentFieldValue></mt:ContentField>','<mt:ContentField content_field="商品名"><mt:ContentFieldValue></mt:ContentField>','<mt:ContentField content_field="商品説明"><mt:ContentFieldValue></mt:ContentField>','<mt:ContentField content_field="価格"><mt:ContentFieldValue></mt:ContentField>','<mt:ContentPermalink>' ],
</mt:Contents>
];
</mt:Unless>
検索用HTML
<!DOCTYPE html>
<html>
<head>
<title>検索サンプル</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link href="./common/css/reset.css" rel="stylesheet" type="text/css">
<link href="./common/css/pagination.css" rel="stylesheet" type="text/css">
<link href="./common/css/style.css" rel="stylesheet" type="text/css">
<script src="//code.jquery.com/jquery-3.6.1.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-csv/1.0.11/jquery.csv.min.js"></script>
<script src="./common/js/pagination.js"></script>
<script src="./common/js/search.js"></script>
<script src="items.js"></script>
</head>
<body>
<input type="text" name="keyword" id="keyword" placeholder="">
<input type="button" name="searchbtn" id="searchbtn" value="検索">
<br>
<br>
<input type="button" name="sortname" id="sortname" value="品名順">
<input type="button" name="sortno" id="sortno" value="品番順">
<input type="button" name="count10" id="count10" value="10件表示">
<input type="button" name="count50" id="count50" value="50件表示">
<input type="button" name="count100" id="count100" value="100件表示">
<div id="info">
<section>
<div class="data-container"></div>
<div id="pagination-item"></div>
</section>
</div>
</body>
</html>
検索用js
search.js
サンプルは、コメントを検索しています。
$(function() {
var search_record = [
"products_number" ,//品番
"products_name" ,//商品名
"products_comment" ,//説明
"products_price" ,//説明
"products_url" ,//URL
];
var PAGEMAX = 10; //1ページあたりのページ数
var itemrec = [];
//品番
items.sort(function(a, b){
if(a[0] < b[0]){
return -1;
} else if(a[0] > b[0]){
return 1;
}
return 0;
});
$(document).on("click", "#searchbtn", function () {
search();
});
$(document).on("click", "#count10", function () {
PAGEMAX = 10;
search();
});
$(document).on("click", "#count50", function () {
PAGEMAX = 50;
search();
});
$(document).on("click", "#count100", function () {
PAGEMAX = 100;
search();
});
$(document).on("click", "#sortname", function () {
//商品名
items.sort((a, b) => {
return a[1].localeCompare(b[1], 'ja');
});
search();
});
$(document).on("click", "#sortno", function () {
//品番
items.sort(function(a, b){
if(a[0] < b[0]){
return -1;
} else if(a[0] > b[0]){
return 1;
}
return 0;
});
search();
});
search();
//検索
function search() {
if($('#pagination-item').length) {
var json = [];
keyword = $("#keyword").val();
for(var i = 0; i < items.length; i++) {
var item = items[i];
for(var rec = 0; rec < item.length; rec++) {
itemrec[search_record[rec]] = item[rec];
}
if(itemrec['products_comment'].indexOf(keyword) > -1 ) {
var news_line = {
number: itemrec['products_number'],
name: itemrec['products_name'],
comment: itemrec['products_comment'],
price: itemrec['products_price'],
url: itemrec['products_url'],
};
json.push(news_line);
}
}
$('#pagination-item').pagination({
dataSource: json,
// totalNumber: 120,
pageSize: PAGEMAX,
showNavigator: true,
formatNavigator: '<%= totalNumber %> 件中 <%= rangeStart %>~<%= rangeEnd %>件目 ',
callback: function(response, pagination) {
var newshtml = '<div>';
$.each(response, function (index, item) {
newshtml += '<dl><dt><a href="' +item.url +'">' + item.name + '</a></dt>';
newshtml += '<dd>'+ item.number + '</dd>';
newshtml += '<dd>'+ item.comment + '</dd>';
newshtml += '<dd>'+ item.price + '円</dd></dl>';
});
newshtml += '</div>';
$('#pagination-item').prev().html(newshtml);
}
});
}
}
})
jsデータのキャッシュ対策・・再構築した日をセット MTのテンプレートで呼び出すとき・・・
<$mt:Date format="%Y%m%d"$ setvar="nowdate">
<script type="text/javascript" src="<$mt:WebsiteURL encode_xml="1"$>common/js/search/items.js"?<mt:Var name="nowdate">></script>
jsデータをダウンロードさせない・・htaccess
<Files items.js>
SetEnvIf Referer "^https?://(www\.)?yourdomain\.jp/" ref_ok
order deny,allow
deny from all
allow from env=ref_ok
</Files>
さいごに
5000件テストは、Wordpress,Movable Typeとも、インポート・エクスポートが遅い・・・
Wordpressは再構築しない代わりに,カテゴリに件数が多い場合、数秒かかる場合もあり、
Movable Typeは再構築するけど、静的生成なのでページの表示は早い・・
検索は、Movable TypeはDATAAPIあるが・・静的でこだわる場合・・JSでも行ける・・WordPressも検索はJSでもよさそう・・
まぁページ表示が3秒以上かかると・・離脱されちゃうなどあるので・・WPでレンタルサーバーだと・・厳しそう・・
昔から・・WPは記事増えると重くなるってあるからねぇ・・
あと、サンプルがうごかんぞーーとか・・クレーム入れないでね・・w