Movable Typeのコミュニティ機能で投票できない不具合を解消する
Movable Typeのコミュニティ機能(コミュニティブログ/コミュニティ掲示板)には、投票機能(スターアイコン★をクリックして投票)がデフォルトで用意されています。
具体的には、次のようにトピック単位に投票用のスターアイコンが表示され、スターアイコンまたは「X票」の部分にマウスをポイントするとクリックで投票できるようになっています。

クリックすると1票が追加され、自分が投票したことが分かるように、スターアイコンにチェックマークがつきます。もう一度クリックすれば投票を取り消します。

ところが、次のようにマウスをポイントしても投票できないケースがあります。

本エントリーでは投票できない原因と、問題がある場合の解消方法について紹介します。
1.原因1:コミュニティのユーザーとしてサインインしていない
コミュニティのユーザーとしてサインインしていない場合、投票することができません。ページ右上にある「サインイン」をクリックしてサインインすれば、投票できるようになります。

2.原因2:匿名の投票を有効にしていない
コミュニティのユーザーとしてサインインしていなくても、誰でも投票できるようにすることができます。
投票できるようにするには、ブログ管理画面の「設定」→「コミュニティ」をクリックして、「匿名での投票を許可する」をチェックします。

3.原因3:クロスドメイン問題
投票機能はAjaxを利用しており、ページ読み込み時にAjaxでコミュニティ用のCGI(mt-cp.cgi)にアクセスして投票情報を取得・表示します。このCGIにアクセスするURLのドメインと、コミュニティサイト自体のドメインが異なっているとクロスドメイン問題により、1項や2項の対処を行っても投票することができません(厳密にはサインインもできないはずです)。
例えば、それぞれのドメインの設定が次のようになっていると、この問題が発生します。
- コミュニティサイトのドメイン:blog.user-domain
- mt-cp.cgi実行時のドメイン:user-domain
投票できない問題がクロスドメインであるかどうかは、JavaScriptエラーの有無で切り分けることができます。例えばIE9でF12を押下して開発者モードの画面の「スクリプト」タブで確認すると、次のような「アクセスが拒否されました。」というエラーが表示されているはずです。

エラーが発生しているmt.jsの558~559行目のコードは次のとおりです。
598: var url = 'http://user-domain/mt/mt-cp.cgi';
599: xh.open('POST', url, true);
変数xhはAjax通信を行うためのXMLHttpRequestオブジェクトで、open()メソッド、つまり指定したURLへのリクエスト送信に失敗していることが分かります。598行目に表示されているドメインとコミュニティサイトのドメインが異なっていることからも判別可能です。
解消するには、コミュニティサイトのドメインとmt-cp.cgiのドメイン(=MTをインストールしているドメイン)を一致させます。言い換えると、コミュニティサイトのドメイン配下にMTをインストールする必要があります。アクセスするドメインが一致すれば良いので、MTをドメインに対応するパス直下にインストールする必要はありません。「mt」など適当なディレクトリを作って、そこにインストールすれば良いでしょう。
例えば次のような配置でMTをインストールします。
- MTのインストールパス:/home/user/www/mt
- コミュニティサイトのパス:/home/user/www
- コミュニティサイトのURL:http://blog.user-domain/
Movable Typeのコミュニティ機能でCKEditorを利用する
Movable Typeのコミュニティ機能でCKEditorプラグインを利用するカスタマイズを紹介します。
「CKEditor」はオープンソースの高機能WYSIWYGエディタです。これをMovable Typeで使えるようにしたものが「CKEditorプラグイン」です。
下のスクリーンショットはコミュニティ掲示板のトピック投稿画面のカスタマイズ前後のイメージです。カスタマイズ後はCKEditorによるWYSIWYGエディタが表示されます。フォントのデザインはもちろん、画像の表示も可能です。
以下、カスタマイズ方法です。
1.プラグインファイルの修正
プラグインのデフォルト状態では、投稿画面のテンプレートを再構築する際に必要な情報が取得できないため、プラグインファイルの一部を修正します。
CKEditorプラグインのCKEditor/lib/CKEditor/App.pmを任意のエディタで開き、167行目あたりにある以下のコードに青色の内容を追加します。
unless ($blog && $type && $lang) {
if ($app->param('__mode') ne 'rebuild') {
return '';
}
}
この修正はプラグインの既存のセキュリティを保障するものではありませんので、自己責任でお願い致します。
2.テンプレートの修正
コミュニティ掲示板・コミュニティブログのいずれも、「ブログ記事の作成」インデックステンプレートの後方に、青色部分を追加します。
…前略…
<$mt:CKEditorJavaScript$>
<script type="text/javascript">
CKEDITOR.replace("entry-body");
</script>
<$mt:Include module="フッター"$>
3.設定の変更
管理画面の「設定」→「コミュニケーション」をクリックして、「HTMLタグを制限」より「カスタム設定」を選択して、CKEditorで入力を許容する要素名をカンマ区切りで入力します。img要素のようにsrc属性が必須なものについては属性名をスペース区切りで設定します。
ここに設定されていない要素や属性は投稿時にすべて除去されるので注意してください。
なお、この設定は通常のコメント投稿フォームにも適用されるので注意してください。
4.コメント投稿フォームにCKEditorを適用させる
コメント投稿フォームにCKEditorを適用させる方法は、概ねこのエントリーで紹介した内容と同じです。細は「Movable Type 5.1 プロの現場の仕事術」に掲載していますのでよければご覧ください。
毎日コミュニケーションズ
コミュニティ機能のテンプレートのインクルード関係図
Movable Type のコミュニティ機能のテンプレートのインクルードを図にまとめました。参考になれば幸いです。
システムテンプレートを主体に書いているので、ブログ側のテンプレートは丸めたり省略してしまったりしています。
クリックすれば拡大表示されます。
コミュニティのカスタムフィールドの表示順序を入れ替える
Movable Type のコミュニティブログやコミュニティ掲示板では、ユーザー登録を行なえば、メインページからブログ記事作成画面に移動でき、ブログ記事の投稿が行なえます(図)。

そのブログ記事作成画面には、予め作成したカスタムフィールドが自動的に表示することができます(図では「性別」「アップロード画像」「お住まいの地域」が該当)が、残念ながら表示順序は決められません。かといって、カスタムフィールド用のテンプレートタグを書き直してひとつずつ並べるのは面倒です。
ということで、本エントリーでは表示順序を決めるためのカスタマイズを紹介します。
1.カスタムフィールドの設定
作成したカスタムフィールドの説明欄に、表示順序を決めるための数字を設定します。カスタムフィールドは昇順に並びます。

2.テンプレートの修正
「ブログ記事フォーム」テンプレートモジュールの以下の赤色部分を青色の内容に変更します。
変更前
…前略…
<mt:EntryCustomFields>
<mt:SetVarBlock name="custom_field_name"><$mt:CustomFieldName escape="html"$></mt:SetVarBlock>
<mt:SetVarBlock name="field-content"><$mt:CustomFieldHTML$></mt:SetVarBlock>
<mt:SetVarBlock name="custom_field_id">profile_<$mt:CustomFieldName dirify="1" escape="html"$></mt:SetVarBlock>
<mt:SetVarBlock name="required"><mt:CustomFieldIsRequired>1<mt:else>0</mt:CustomFieldIsRequired></mt:SetVarBlock>
<$mt:Include module="フォームフィールド" id="$custom_field_id" class="" label="$custom_field_name" required="$required"$>
</mt:EntryCustomFields>
…後略…
変更後
…前略…
<mt:EntryCustomFields>
<mt:SetVarBlock name="number"><mt:EntryCustomFieldsDescription></mt:SetVarBlock>
<mt:SetVarBlock name="cfn{$number}"><mt:CustomFieldName escape="html" /></mt:SetVarBlock>
<mt:SetVarBlock name="fc{$number}"><mt:CustomFieldHTML /></mt:SetVarBlock>
<mt:SetVarBlock name="cid{$number}">profile_<$mt:CustomFieldName dirify="1" escape="html"$></mt:SetVarBlock>
<mt:SetVarBlock name="req{$number}"><mt:CustomFieldIsRequired>1<mt:else>0</mt:CustomFieldIsRequired></mt:SetVarBlock>
</mt:EntryCustomFields>
<mt:Loop name="cfn" sort_by="key numeric">
<mt:GetVar name="__value__" setvar="custom_field_name" />
<mt:GetVar name="fc{$__key__}" setvar="field-content" />
<mt:GetVar name="cid{$__key__}" setvar="custom_field_id" />
<mt:GetVar name="req{$__key__}" setvar="required" />
<$mt:Include module="フォームフィールド" id="$custom_field_id" class="" label="$custom_field_name" required="$required"$>
</mt:Loop>
…後略…
以上です。
再構築してカスタムフィールドの内容が入れ替わっていることを確認してください。

プロフィールページにタブを追加する
Movable Type コミュニティソリューションのプロフィールページに、任意のタブを追加する方法です。
変更前

変更後

1.テンプレートの修正
グローバルテンプレートの「プロフィール」に下記の青色部分を追加します。
...前略...
<ul id="tabs">
<li><a href="#profile-recent-actions" class="active" onclick="switchTabs('tabs',this)">最近のアクション</a></li>
<li><a href="#profile-comment-threads" class="" onclick="switchTabs('tabs',this)">コメントスレッド</a></li>
<li><a href="#profile-hoge" class="" onclick="switchTabs('tabs',this)">ほげほげ</a></li>
</ul>
<div id="profile-recent-actions" class="tab_content">
<h3 class="tab_content_label">最近のアクション</h3>
...中略...
</div>
<div id="profile-hoge" class="tab_content hidden">
<h3 class="tab_content_label">コメントスレッド</h3>
<p class="note">追加したタブメニューです。</p>
</div>
<mt:SetVarBlock name="profile_widgets">
...後略...
赤字の部分は他のタブメニューと異なる名称を設定して、a 要素の href 属性で設定したフラグメントが、div 要素のid 属性値と同じ内容になるようにします。
この規則を守れば、さらに複数のタブを追加することができます。
2.タブの初期動作を変更する
ページを表示したときに追加したタブを開きたい場合は、他のタブメニューに設定されている class 属性値 active(赤色)を削除し、追加したタブメニューの class 属性にactive(青色)を設定します。
さらに、他のタブコンテンツの div 要素の class 属性に hidden(青色)を追加し、追加したタブに対応するコンテンツの div 要素の class 属性には tab_content(青色)だけを設定します(前述のサブテンプレートでは追加したタブのコンテンツに hidden を設定しています)。
...前略...
<ul id="tabs">
<li><a href="#profile-recent-actions" class="active" onclick="switchTabs('tabs',this)">最近のアクション</a></li>
<li><a href="#profile-comment-threads" class="" onclick="switchTabs('tabs',this)">コメントスレッド</a></li>
<li><a href="#profile-hoge" class="active" onclick="switchTabs('tabs',this)">ほげほげ</a></li>
</ul>
<div id="profile-recent-actions" class="tab_content hidden">
<h3 class="tab_content_label">最近のアクション</h3>
...中略...
</div>
<div id="profile-comment-threads" class="tab_content hidden">
<h3 class="tab_content_label">コメントスレッド</h3>
...中略...
</div>
<div id="profile-hoge" class="tab_content">
<h3 class="tab_content_label">コメントスレッド</h3>
<p class="note">追加したタブメニューです。</p>
</div>
...後略...
コミュニティソリューションのプロフィールページに関する Tips
Movable Type 4.2(コミュニティソリューション)のプロフィールページに関する Tips です。
![]()
プロフィールページはコミュニティソリューションで欠かせないページで、サインアップユーザーの「最近のアクション」や「注目」「被注目」などの情報をダイナミックに表示してくれます。全く同じ機能ではありませんが、mixi にログインしたときに表示されるご自身のページを想像してもらえれば分かりやすいと思います。
プロフィールページはグローバルテンプレートの「プロフィール」が該当します。

1.プロフィールページの判定方法
プロフィールページと、それ以外のページを振り分けるには、次の If タグでくくります。変数 page_title には、「プロフィール」テンプレートで「ユーザーのプロフィール」が設定されているので、これを利用します。
<mt:if name="page_title" eq="ユーザーのプロフィール">
...略...
</mt:if>
2.プロフィールページの body 要素の class 属性値
body 要素の class 属性値には「mt-profile-view」が設定されます。これは、「プロフィール」テンプレートで次の処理があるためです。
<$mt:Include module="ヘッダー" body_class="mt-profile-view"$>
プロフィールページのスタイルを変更したい場合は、この class 属性値を利用すると良いでしょう。
3.利用中のヘッダーに追加する内容1
ヘッダーの先頭に下記のSetVarBlock タグを追加します。
<mt:SetVarBlock name="html_head" prepend="1">
<mt:SetVarBlock name="blog_id"><$mt:BlogID$></mt:SetVarBlock>
<mt:SetVarBlock name="profile_view_url"><$mt:CGIPath$><$mt:CommunityScript$>?__mode=view&blog_id=<$mt:BlogID$>&id=</mt:SetVarBlock>
</mt:SetVarBlock>
変数 html_head はhead 要素に各種データを追加するためのものでです。
変数 blog_id は、プロフィールページの title 要素にブログ名を表示するための判定用に使います。
変数 profile_view_url は、ユーザーのプロフィールページへのリンクになります。次のように、他のユーザーのリンクにジャンプするときの a 要素の href 属性にこの変数とユーザーIDを設定します。
<a href="<mt:GetVar name="profile_view_url" encode_html="1" /><mt:AuthorID />"><mt:AuthorDisplayName /></a>
以上です。
タブの追加方法は別エントリーします。
ユーザー一覧に最新のブログ記事を表示する
ユーザー一覧に最新のブログ記事を表示するカスタマイズです。コミュニティ・ソリューションの利用を想定して、ユーザー名をクリックすれば、ユーザーのプロフィールページにジャンプするようにしています。

MTAuthorsタグでMTEntriesタグを使っても該当のユーザーコンテキストにならないようなので、
<mt:AuthorName setvar="author_name" />
<mt:Entries author="$author_name" lastn="1">
:
と、MTEntriesタグにauthorモディファイアを与え、ユーザー名を設定しているのがこのサブテンプレートのキモです。
当サイトで配布しているテンプレート用のサブテンプレートは、次のようになります。これをウィジェットやテンプレートモジュールに設定すれば、冒頭のキャプチャ画像のような表示になります。
<mt:Authors>
<mt:If name="__first__">
<dt class="sidetitle">ユーザー一覧</dt>
<dd class="side">
</mt:If>
<ul>
<mt:If tag="AuthorDisplayName">
<li><a href="<mt:CGIPath />mt-cp.cgi?__mode=view&blog_id=<mt:BlogID />&id=<mt:AuthorID />"><$mt:AuthorDisplayName$></a>
</mt:If>
<mt:AuthorName setvar="author_name" />
<mt:Entries author="$author_name" lastn="1">
<mt:EntriesHeader>
<ul>
</mt:EntriesHeader>
<li><a href="<mt:EntryPermalink>"><mt:EntryTitle /></a></li>
<mt:EntriesFooter>
</ul>
</mt:EntriesFooter>
</mt:Entries>
</li>
</ul>
<mt:If name="__last__">
</dd>
</mt:If>
</mt:Authors>
MTEntriesタグのlastnモディファイアの値を変更すれば表示するブログ記事数を変更できます。
ユーザーへのプロフィールページへのリンクを外したい場合は、
<li><a href="<$mt:Var name="profile_view_url" encode_html="1"$><$mt:AuthorID$>"><$mt:AuthorDisplayName$></a>
を
<li><$mt:AuthorDisplayName$>
に変更してください。
なお、テンプレートセットでコミュニティブログやコミュニティ掲示板を使用している場合は、
<li><a href="<$mt:Var name="profile_view_url" encode_html="1"$><$mt:AuthorID$>"><$mt:AuthorDisplayName$></a>
の部分は、
<li><a href="<$mt:Var name="profile_view_url" encode_html="1"$><$mt:AuthorID$>"><$mt:AuthorDisplayName$></a>
でOKで、変数profile_view_urlにプロフィールページへのURLが設定されています。
Movable Type 4 のコミュニティ機能(その2:サインアップユーザーの権限自動付与とロールのカスタマイズ)
コミュニティブログ・コミュニティ掲示板では、新規ユーザーはブログ画面上からサインアップすることができます。
そしてサインアップしたユーザーは、管理画面ではなく、ブログのページ上からブログ記事の投稿やトピックの作成が行なえます。
その前段として、新規ユーザーがサインアップしたときに、自動的に必要な権限を与える設定を行なっておけば、管理者は登録ユーザーの権限を手動jで毎回与える必要はなくなります。
上記の権限の自動付与のために必要な設定を紹介します。なお、Movable Type のインストール時にメールの設定が行なわれていることが前提です(メールは環境変数を利用すれば後で設定することも可能ですがここでは割愛します)。
1.システムのメールアドレスを設定する
まず、前提として、システム管理画面の「設定」→「全般」でシステムのメールアドレスを設定します。この設定を行なわないと、ユーザー登録時に、登録ユーザーが入力したメールアドレスに確認用のメールが送信されないようです。

2.サインアップユーザーに権限を自動付与する
システム管理画面の「一覧」→「ユーザー」→「権限」、またはブログ管理画面の「システムメニュー」→「ユーザー」→「権限」で権限設定画面に進み、「ユーザーに権限を付与」をクリック。

「(新規ユーザー)」を選択して「次へ」をクリック。

ここでは「ライター」を選択して、「確認」をクリック。

登録後の権限画面はこのように表示されます。

サインアップしたユーザーがサインインすればブログ記事投稿画面が表示されます。

3.ロールのカスタマイズ
ただし、「ライター」の権限には「ブログ記事の公開」という権限がありません。つまりブログ記事を投稿しても、管理者の承認がなければブログ記事は公開されません。投稿後は「投稿を受付ました」となります。

ブログ記事一覧画面上は承認待ちになります。自分で公開状態を変更することはできません。

下の画面は、公開権限のないユーザーでサインインしたときのブログ記事編集画面です。

ちなみにこれは、公開権限のあるユーザーでサインインしたときのブログ記事編集画面です。

コミュニティユーザーの権限は「ブログ記事の作成」「ブログ記事の公開」「コメント投稿」のようですが、この3つを同時に与え、なおかつ他の権限を与えないというロールは、デフォルトでは用意されていないようです。
ということで、「コミュニティ」という新しいロールを作り、そのロールで権限の自動付与を行なうようにカスタマイズします。
システム管理画面の「一覧」→「ユーザー」→「ロール」で「新しいロールを作成」をクリック。

ロール名に「コミュニティ」、権限の一覧にある「ブログ記事の作成」「ブログ記事の公開」「コメントの送信」をチェックして、「変更を保存」をクリック。

これで「コミュニティ」というロールができたので、「新規ユーザーに権限を自動付与する設定をする」の作業をやり直し、作成作業の中で、「コミュニティ」を選択します。

権限画面はこうなります。

新規ユーザーでサインアップして、サインイン後、ブログ記事を投稿すると「投稿を公開しました」と表示されます。

ブログ記事が自動的に公開されました。

ちなみにこの権限であればブログ記事の編集もできます。「すべてのブログ記事の編集」という権限を与えてしまうと、ブログ管理画面にログインしたときに、他のユーザーのブログ記事も編集できてしまうので気をつけましょう。
Movable Type 4 のコミュニティ機能(その1:プロフィール画面)
Movable Type 4 のコミュニティ機能について、少しずつ紹介していきます。
1.動作を確認するときの注意事項
コミュニティ機能は、プロフィールページなど、ログイン状態をチェックして表示を変更するようになっています。
インストールしたコミュニティの動作確認や実験を行うときは、異なるブラウザを2つ以上開き、
- ひとつは管理画面を操作するために使用する
- 他はコミュニティ機能を確認する(例えばプロフィールページなどの参照)ために使用する
としてください。
同じ種類のブラウザを2枚開いたり、異なるタブで開いても、同一のクッキーを参照するので、期待する動作にならない可能性があります。
2.プロフィールページの動作
まず、プロフィールのページから調べていきます。
2.1 サインインしている状態の自分のプロフィールページ
自分のプロフィールページには、ユーザー名とプロフィール画像と「ユーザー情報の編集」というリンクを表示します。

プロフィール画像は、これまではシステム管理画面からのアップロードが必要でしたが、「ユーザー情報の編集」をクリックした次の画面の「プロフィール画像」からアップロードできます。

アップロード直後の画面です。

プロフィールのページにも反映されます。

サイドバーの「注目」「被注目」は、「お気に入り」への追加、あるいは mixi の「マイミク」のようなものです。他のユーザーを注目している場合、あるいは注目されている場合に、そのユーザーがこの欄に表示されます(表示方法は後述)。初期状態は誰も注目、被注目していないので、このように表示されます。

2.2 サインインしている状態の他のユーザーのプロフィールページ
プロフィールページには、「注目する」というリンクが表示されます。このリンクをクリックすると、先ほどのサイドバーの「注目」に注目したユーザーが表示されます。

「注目」をクリックすると、Ajax によって即座に表示が変わります。

自分のプロフィールページのサイドバーもこのように表示が変わります。

2.3 サインインしていない状態のすべてのユーザーのプロフィールページ
プロフィールのページにはユーザー名と画像のみが表示されます。

3 注意事項
コミュニティのテンプレートセット(コミュニティブログ・コミュニティ掲示板)で新たにブログを作成した場合、新たに作成したブログにも他のユーザーのプロフィールが表示されるようです。

