かたつむりくんのWWW

Movable Type でカテゴリ同士の相互リンクを貼る方法

Movable Type でカテゴリ同士の相互リンクを貼る方法

Movable Type のカテゴリアーカイブにおいて、そのブログ内のカテゴリ同士で相互リンクを貼る方法を紹介します。

このカスタマイズでは「SpecificCategory」という特定のカテゴリのコンテキストをセットするプラグインを使いますので、あらかじめインストールしておいてください。

さて、ブログに下記のようなカテゴリがあったとします。

  • MTテンプレート
  • MTプラグイン
  • 日記

この中の2つを下記のように相互リンクさせます。

  • MTテンプレート <=> MTプラグイン
  • MTプラグイン <=> MTテンプレート
  • 日記

続きを読む

Movable Type で自社のIPアドレスがロックされてしまったときの対処法

Movable Type 5 から、一定時間に一定回数以上サインインに失敗した場合、そのユーザーがロックされたり、IPアドレスがロックされたりします。初期設定では 1800 秒間に 10 回失敗するとロックされます。

さて、ユーザーがロックされた場合は、ロックされたことを通知するメールにあるリンクにアクセスしたり、管理画面のユーザー管理で解除できますが、IPアドレスがロックされた場合の解除方法が分かりませんでした。

IPアドレスのロックは(ユーザーのロックも同様)、一定時間(初期設定では 1,800 秒)が経過すれば自動的に解除されますが、待てないときは以下のようにデータベースの値を変更すれば解除出来るようです。

  1. MTのデータベースにアクセス
  2. mt_failedlogin テーブルにアクセス
  3. failedlogin_remote_id カラムをロックされたIPアドレスで検索
  4. 該当するレコードの failedlogin_ip_locked フィールドの値を 1 から 0 に変更

SQLにすると以下のような感じです。

UPDATE `mt_failedlogin`
SET `failedlogin_ip_locked`=0
WHERE `failedlogin_ip_locked` = 1 AND `failedlogin_remote_ip` LIKE 'ロックされたIPアドレス'

この方法は自己責任で! 僕は phpMyAdmin でやりました :-p

ちなみに、特定のIPアドレスをロックさせないようにするには、システムの全般設定の「アカウントロックの設定」の項目のところで設定するか、「LockoutIPWhitelist」という環境変数を設定すればOKです。

以上です。

MTEntryExcerpt タグの本文からの自動生成について整理してみた

MTEntryExcerpt タグの本文からの自動生成について、なんとなく整理してみました。

MTEntryExcerpt タグは、記事の「概要」欄の値を出力するファンクションタグですが、「概要」欄に値がない場合は、本文欄から自動で概要文を作成して表示してくれます(デフォルト設定は40文字)。

ちなみに、自動生成しないようにする場合には、no_generate="1" を指定すればOKです。

さて、今、本文欄に下記のテキスト(エディタは「改行を変換」)が入っていて、概要欄は空だとします。全角文字が45文字あり、<br>を含めると49文字です。

アイウエオ<br>カキクケコ
あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめも

Point 1 : 自動生成では改行コードは置換され、HTMLタグは除去される

このサンプル記事について、下記のテンプレートタグで出力される値を見てみます。

【テンプレートタグ】
<mt:EntryExcerpt>
【出力結果】
アイウエオカキクケコ あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへ...

このように、全角39文字と半角スペース1つ(カタカナの後ろ)の計40文字が出力されました。

本文欄からの自動生成では、改行コード(\r\nや\n)は半角スペースに変換され、HTMLタグは除去されます。連続する改行コードはまとめて1つのスペースになります。

Point 2 : convert_breaks は効かない

自動生成された概要文には convert_breaks モディファイア(1を設定すると改行を変換)は効きません。だって、HTML タグは除去されてしまうので。

【テンプレートタグ】
<mt:EntryExcerpt convert_breaks="1">
【出力結果】
アイウエオカキクケコ あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへ...

Point 3 : 文字数変更はブログの投稿設定か words モディファイアで

自動生成の概要文の文字数は、デフォルトでは40文字です。これを変更するときは、ブログの投稿設定の「概要の文字数」を変更するか、words モディファイアを指定します。

【テンプレートタグ】
<mt:EntryExcerpt words="20">
【出力結果】
アイウエオカキクケコ あいうえおかきくけ...

Point 4 : 改行やHTMLタグを活かしたい場合

改行を活かしたい場合は自動生成の概要文ではダメなので、以下のようなテンプレートタグで EntryBody を書き出したら良いと思います。

【テンプレートタグ】
<mt:EntryExcerpt no_generate="1" setvar="entry_excerpt">
<mt:Unless name="entry_excerpt">
    <mt:EntryBody remove_html="1" trim_to="20+..." regex_replace="/\r?\n/g","<br>">
</mt:Unless>
【出力結果】
アイウエオカキクケコ<br><br>あいうえおかきく...

そして、HTMLタグについては指定した文字数で切れるところがちょうどHTMLタグの途中だと表示が崩れてしまうので、やはり remove_html="1" で除去した方が良いと思います。

おまけ : 自動生成概要文の...を変えたい

自動生成概要文の最後につく...を変えたい場合は、

Path-to-mt/lib/MT/Template/Tags/Entry.pm

の中の1722行目付近の以下のコードをカスタマイズすれば良いと思います。

return $excerpt . '...';

以上です。

特定のフィールドに保存されたIDに該当する記事を再構築する Movable Type プラグイン - RebuildRelatedObjects

RebuildRelatedObjects というプラグインを公開しました。

動作はいたってシンプルなのですが、なぜか説明がしにくいので、下図を使って説明します。

続きを読む

Movable Typeのカスタムフィールドの1行テキストは255文字まで

Movable Type のカスタムフィールドの1行テキストには、255文字まで保存できます。全角・半角どちらも255文字です。

全角だと半分くらいの128文字になるの?って気がしちゃうけど、255文字です。

豆知識として。

記事 n 件をランダムに取得するテンプレート - RandomArray プラグインバージョン

記事 n件をランダムに表示するPowerCMSのテンプレート | PowerCMS ブログ」に触発され、こんな感じの方法はどうだろうということで書いてみます。

bit part では、指定した配列からランダムに要素を取り出して配列で返す MTRandomArray タグを提供する「RandomArray プラグイン」を公開しています。

これを使うと、例えば「MTAppjQueryタグの付いた記事をランダムに5件表示したい」というのを以下のようなテンプレートで実現できます。

続きを読む

5 Star Comment Rating プラグインのコメント編集ページに「評価」が表示されないときの対処法

ここのところなぜか質問が連続している人気のプラグイン(謎)「5 Star Comment Rating」プラグインで、「コメントの編集画面で、以前は表示されていた投稿者のIPや評価数値がMT6では表示されません。」というご質問をいただきました。

このようなときは、mt-config.cgi に以下のように「ShowIPInformation」という環境変数に 1 を設定してみてください。

ShowIPInformation 1

これで IP アドレスや評価が表示されるようになります。

MTAppjQuery v1.4.0 リリース - $.MTAppSlideMenuV2() を追加ほか

MTAppjQuery v1.4.0 を公開しました。

今回のリリースでは、次のような新機能の追加と修正があります。

続きを読む

5 Star Comment Rating プラグインで記事に付いた各評価ごとのコメント数を表示させる

Movable Type のコメント機能を利用して、ブログ記事に5つ星の評価を追加することができる「5 Star Comment Rating」プラグインで、「ブログ記事につけられた各評価ごとの数を表示させることは可能なのでしょうか?」というご質問をいただきました。

実現したいのは以下のような感じです。

----------------------
★★★★★:5人
★★★★☆:3人
★★★☆☆:1人
★★☆☆☆:0人
★☆☆☆☆:1人
計:10人
----------------------

続きを読む

MTForで1ずつ減らす方法(from="12" to="1" の感じ)

Movable Type で「これが使えるようになるといろいろと便利になるよ」タグの一つである MTFor のお話しです。

<mt:For var="x" from="$from" to="$to" glue=" / ">
<mt:Var name="x">月
</mt:For>

これを再構築すると、変数 x が 1 ずつ増えて処理され以下のように出力されます。

1月 / 2月 / 3月 / 4月 / 5月 / 6月 / 7月 / 8月 / 9月 / 10月 / 11月 / 12月

以下のように increment モディファイアを指定すれば 2 ずつ増やすといったことも可能です。

<mt:For var="x" from="$from" to="$to" increment="2" glue=" / ">
<mt:Var name="x">月
</mt:For>
1月 / 3月 / 5月 / 7月 / 9月 / 11月

さて、これを「12月 / 11月 / 10月 / 9月 / 8月 / 7月 / 6月 / 5月 / 4月 / 3月 / 2月 / 1月」としたい場合はどうしたらいいのでしょうか。残念ながら increment="-1" や decrement="1" といったような「 1 ずつ減らす」といった指定はできないようです。

そんな時は、以下のようなテンプレートを書いてあげればOKです。

<mt:SetVar name="from" value="1">
<mt:SetVar name="to" value="12">
<mt:Var name="from" op="+" value="$to" setvar="y">
<mt:For var="x" from="$from" to="$to" glue=" / ">
<mt:Var name="y" op="-" value="$x" setvar="i">
<mt:Var name="i">月
</mt:For>

これを出力すると以下のようになります。

12月 / 11月 / 10月 / 9月 / 8月 / 7月 / 6月 / 5月 / 4月 / 3月 / 2月 / 1月

以上です。

AlfredMTRefSearch - Alfred Powerpack から一発で Movable Type のタグリファレンスなどを検索できる Workflow を作ってみた

日頃 MacBook Pro で愛用している Alfred から、Movable Type のタグリファレンスやグローバル・モディファイアリファレンス、環境変数リファレンスを一発で検索できる Alfred Workflow を作ってみました。

Alfred は Powerpack を購入している必要がありますが、MT と Alfred を使っている人にはオススメですよ。

続きを読む

Movable Type の記事投稿画面のカテゴリ覧をタイトル欄の上に移動する

カテゴリを必ず選択するような運用では良くあるカスタマイズです。MTAppjQueryプラグインを使えば、とても簡単に実現することができます。

MTAppjQueryプラグインの user.js に以下のようなコードを書けばOKです。

(function($){
    $.MTAppCustomize({basename: 'category'}).insertBefore("#title-field");
})(jQuery);

もし、カテゴリリストのところのスクロールをなくして全部表示したい場合は、user.css に以下のように書けばOKです。

#category-selector-list {
  height: auto !important;
}

さらに、カテゴリ名のところが狭くて変だなというときは、user.css に以下のスタイルも追加しましょう。

#category-selector-list > div.list-item > div > div {
  width: auto !important;
  margin-right: 15px !important;
}

以上です。

インデックステンプレートで手っ取り早く複数ファイルアップローダーを作っちゃおう

タイトルの通りですが、プラグイン無しで、とりあえず複数ファイルアップローダーを使いたい人のためのインデックステンプレートです。Data API を使うので Movable Type 6 限定です。

テンプレートは以下のとおり。これをインデックステンプレートで書き出して、そのページにアクセスすればOKです。出力されたページにアクセスすると、最初にログインを求められます。

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Multi file uploader</title>
    <style type="text/css">
    body {
      background-color: black;
      font-family: 'Source Code Pro', Monaco, Consolas, 'Courier New', Courier, monospace;
      color: white;
      text-align: center;
    }
    </style>
</head>
<body>
<h1>Multi file uploader</h1>
<form id="itemUpload">
<p><input type="file" id="itemUploadFile" multiple></p>
<p><input id="itemUploadBtn" type="button" value="Upload" class="button"></p>
</form>
<div id="results"></div>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="<mt:StaticWebPath>data-api/v1/js/mt-data-api.min.js"></script>
<script type="text/javascript">
(function($){
  var uploadDirImages = "upload/img";
  var uploadDirFiles = "upload/file";
  var api = new MT.DataAPI({
    baseUrl:  "<mt:CGIPath><mt:Var name= "config.DataAPIScript">",
    clientId: "WBf8rxuf48"
  });
  var siteId = <mt:BlogId>;
  var $results = $("#results");
  api.getToken(function(response) {
    if (response.error) {
      if (response.error.code === 401) {
        location.href = api.getAuthorizationUrl(location.href);
      }
      else {
        alert("Error:" + response.error.message);
      }
    }
    else {
      $("#itemUploadBtn").on("click", function(){
        var count = 0;
        var l = document.getElementById("itemUploadFile").files.length;
        for (var i = 0; i < l; i++) {
          var fileObj = document.getElementById("itemUploadFile").files[i];
          var data = {
            file: fileObj,
            path: "upload",
            autoRenameIfExists: true,
            normalizeOrientation: true
          };
          if (fileObj.type.indexOf("image") !== -1) {
            data.path = uploadDirImages;
          }
          else {
            data.path = uploadDirFiles;
          }
          api.uploadAsset(siteId, data, function(response) {
            if (response.error) {
              $results.append('<p style="font-weight:bold;color:red;">Error Code: ' + response.error.code + ':' + response.error.message + '</p>');
              return;
            }
            count++;
            $results.append('<p>' + response.filename + ' was uploaded![' + count + ']</p>');
          });
        }
      });
  }
});
})(jQuery);
</script>
</body>
</html>

インデックステンプレートで作る Multi file uploader(Data API 版)

アイテムはインデックステンプレートを作ったブログの配下にアップロードされ、そのブログのアイテムに登録されます。

アップロードしたアイテムが画像の場合は upload/img、それ以外の場合は upload/file に入ります。変更したい場合は、テンプレートの27、28行目を編集しましょう。

使い終わったらこのテンプレートは非公開にしておきましょうね。

実際に使った様子は以下の通り。最後の方はカットして短くしてあります。

以上です。

Data API で特定のフィールドを認証を通さないと見れないようにする

「本文を見るには会員登録が必要です」といったような会員制サイトを作っているとします。

このサイトの情報に Data API で記事の情報にアクセスすると、デフォルトの状態だと本文欄は普通に見えてしまいます。

例えば、Data API の JavaScript ライブラリーの listEntries を使って記事の一覧をコンソールに表示してみると以下のようになります。

ちなみに、今パラメータには limit=3、status=Publish、fields=title,body を指定しています。もちろん、URL で entries のエンドポイントを叩いても同様です。

そこで、以下のようなプラグインを作ることにより、本文欄を認証を通さないと見れない状態に変えることができます。

name: DataAPIPrivateFields
version: 1.0.0
applications:
  data_api:
    resources:
      entry:
        fields:
          - name: body
            condition: |
              sub {
                  ! MT->instance->user->is_anonymous;
              }

ここでは、プラグイン名を「DataAPIPrivateFields」としているので、MT のプラグインディレクトリに「DataAPIPrivateFields」というディレクトリを作り、その中に上記の内容を config.yaml として保存してあげればOKです。

このプラグインをインストールした状態で先程の結果を再読込してみると、以下のように本文欄(body)が表示されなくなります。

この本文欄を再度表示させるには、api.getAuthorizationUrl(); などで一度ログインすればOKです。

以上です。

jQueryAutoHeight.js をレスポンシブデザインで使う

細々と公開しているんですけれども意外と使われている「jQueryAutoHeight.js - 複数のカラムの高さを最大値にそろえるjQueryプラグイン」を、レスポンシブデザインのサイトで使いたいというご意見を頂きました。

PC版のときはカラムが横に並ぶので高さを揃えるといい感じになるのですが、スマホのときは1カラムになって縦に並ぶので、そこで高さを揃えてしまうと無駄に間延びしちゃうということですね。

そんなときは、jQueryAutoHeight.js を実行するところで、以下のように横幅の最小値を設定し、その最小値とウィンドウサイズを比較して実行するかリセットするかを分けてあげれば良いと思います。

<script type="text/javascript">
jQuery(function($){
    var minWidth = 450;
    $(window).resize(function(){
        if (minWidth <= $(this).width()) {
            $('div.box').autoHeight();
        }
        else {
            $('div.box').removeAttr('style');
        }
    }).trigger('resize');
});
</script>

minWidth の値を適宜設定してください。

このように .resize() を使えば、iPhone などを横に倒したりした時にも横幅をチェックして実行し直してくれると思います。

以上です。

Movable Type で n 個ずつ div で囲む場合の書き方

なんかいいタイトルが思いつかなかったのですが、要するに以下のような場合を想定したテンプレートの書き方です。

<div class="row">
    <div>hoge</div>
    <div>hoge</div>
</div>
<div class="row"> <div>hoge</div> <div>hoge</div> </div>
<div class="row"> <div>hoge</div> <div>hoge</div> </div>

この場合だと2個ずつの div を div.row で囲んでますね。Twitter Bootstrap を使ってるとちょくちょく直面したりするかも?

ここでは mt:Entries を例にしてやってみたいと思います。

続きを読む

今さらだけど Apache の gzip の設定をしてみた

gzip の説明や設定の仕方は @burnworks さんの下記の記事をどうぞ。

gzip 設定の前後でこのブログのトップページを計測してみました。

【設定前】

【設定後】

400ミリ秒くらい早くなりました。なんでもっと早く設定しなかったんだろうか・・・

RandomArray - Movable Typeの配列変数からランダムで値を取り出すプラグイン

Movable Type の配列変数からランダムで値を取り出せる MTRandomArray というファンクションタグを提供するプラグインです。

プラグインの詳細、ダウンロードは以下からお願いします。

日本語の使い方は以下に書いてあります。

使い方はシンプルですが、destructive モディファイアがノンプログラマ(俺もか)の方にはちょっと分かりにくいかもしれませんので、以下のサンプルテンプレートをインデックステンプレートに貼り付けて再構築してみたらいいかもしれません。

ダイナミックパブリッシングでこのサンプルを試したいときは、1行目の use_dynamic 変数に 1 をセットしてあげてください。

ランダムに記事を取り出すプラグインは他にもあるようですね。このプラグインは、事前に何かしらの配列をセットしないといけないですが、その分汎用性が高くなっていると思います。

以上です。

Movable Type の配列変数を MTUnless で判定するときのスタティックとダイナミックの違い

Movable Type のテンプレートで配列を変数に入れて扱っているときに、以下のような MTUnless の判定を入れてみます。

<mt:SetVar name="array">
<mt:SetVar name="array" function="push" value="soccer">

<mt:Unless name="array">
Stefan Edberg
<mt:Else>
Robert Baggio
</mt:Unless>

これをスタティックパブリッシングで再構築すると、変数 array には soccer という値が入っているので、 MTElse タグの方が評価されて「Robert Baggio」と表示されます。

しかし、これをそのままダイナミックパブリッシングにすると、

preg_match() expects parameter 2 to be string, array given

というエラーが表示されてしまいます。

これを回避するには、以下のようなテンプレートにして、一度配列の一番目の要素を array_exist 変数にセットして、その変数の有無をチェックするようにすればエラーはでなくなります。

<mt:SetVar name="array">
<mt:SetVar name="array" function="push" value="soccer">

<mt:Var name="array" index="0" setvar="array_exist">
<mt:Unless name="array_exist">
Stefan Edberg
<mt:Else>
Robert Baggio
</mt:Unless>

以上、豆知識として。

MTSetVarにpushする前に変数を初期化するときのスタティックとダイナミックの違い

Movable Type で MTSetVar に function="push" して配列を作っていくとき、事前に変数を初期化というか宣言しておくことがあります。

ことのき、以下のように書くと、スタティックパブリッシングだと問題ありませんが、ダイナミックパブリッシングだと「'mtlover' is not an array.」のようなメッセージでエラーになります。

<mt:SetVar name="mtlover" value="">
<mt:SetVar name="mtlover" function="push" value="bit">
<mt:SetVar name="mtlover" function="push" value="part"> <mt:Loop name="mtlover" glue="-"><mt:Var name="__value__"></mt:Loop>

これは1行目の value="" で文字列として初期化してるのが原因なので、value="" を削除して、

<mt:SetVar name="mtlover">
<mt:SetVar name="mtlover" function="push" value="bit">
<mt:SetVar name="mtlover" function="push" value="part"> <mt:Loop name="mtlover" glue="-"><mt:Var name="__value__"></mt:Loop>

というようにすればエラーはでなくなります。

まあ、変数を初期化しなくても良いのですが、「この後こういう変数を使うよ」というのは宣言しておいた方がテンプレートが見やすくなると思います。

2015/10/14 追記:ダイナミックの場合は初期化しないで function="push" するとエラーになりました。なので、最初の

<mt:SetVar name="mtlover">

は必須のようです。

以上、豆知識として。