JanetterでRTユーザーにも相互フォローアイコンを表示する

最終更新:2017/02/01

TwitterクライアントJanetterでは、ツイートの発信元のユーザーと相互フォローになっている場合はツイート・ヘッダーに相互フォローアイコンとしてスマイル・マークが表示される。どのユーザーと相互フォローなのかひと目で判るJanetterの特徴のひとつ。本家Twitterの純正クライアントではタイムラインに相互フォローかどうかを示す情報は直接表示されない。

しかしながら、ツイート・フッターに表示される、リツイートしたユーザーを示す「Retweeted by (ユーザー名)」には同様のアイコンは表示されない。そこで、リツイートしたユーザーも相互フォローかどうかを判定し、ユーザー名にアイコンを表示するように改良する。

免責事項

本記事で紹介しているコードを使用したことによって生じた事態に当方は一切責任を負えない。動作を保証するものではないし、動作したとしても運用上生じたあらゆる問題にも同様に責任を負いかねる。相互フォローアイコンはあくまでもTwitterサーバーの応答を元にした目安であって、アイコンが表示されていないことをもってフォローを解除してしまったりして相手の心証を害することになっても関知できない。

決まり文句だけど、大事なことなので。

テンプレートの加工

Janetterカスタム・テーマのtweet.tplからリツイートユーザーを表示している次のようなコードを探す。独自にあちこち変更しているので、行番号はおおよその位置。

カスタム・テーマの作り方がわからない場合は、以前の記事をよく読んでもらって、新しくカスタム・テーマを追加する。くれぐれも、コモン・コードや標準で実装されているテーマに手を加えて上書きしてしまわないこと。

								<div class="tweet-footer-text">
									<p class="from">
										<span class="source">
											{if $sender}{* DM *}
												{if $isMe}
													&nbsp;to&nbsp;{$recipientName}
												{/if}
											{elseif $sourcevisible}
												{if $retweeted_status}{* RT *}
													via&nbsp;{$retweeted_status.source}
												{else}
													via&nbsp;{$source}
												{/if}
											{/if}
										</span>
									</p>
									{if $retweeted_status}
										<p class="retweetedBy">
											<span class="icon-rtby"></span><span>Retweeted by </span>
											{$retweetedBy}
										</p>
									{/if}
								</div>

位置を特定できたら、「Retweeted by」のテキストとユーザー名を示す{$retweetedBy}の間に次のようなコードを追加する。

ツイート・ヘッダーと同じようにユーザー名の後にアイコンが続くようにしてデザインを統一したいと思うかもしれないけど、ユーザー名が長い場合はタイムラインからはみ出した部分が自動的にカットされてしまうので、相互フォローアイコンが見えなくなる。

								<div class="tweet-footer-text">
									<p class="from">
										<span class="source">
											{if $sender}{* DM *}
												{if $isMe}
													&nbsp;to&nbsp;{$recipientName}
												{/if}
											{elseif $sourcevisible}
												{if $retweeted_status}{* RT *}
													via&nbsp;{$retweeted_status.source}
												{else}
													via&nbsp;{$source}
												{/if}
											{/if}
										</span>
									</p>
									{if $retweeted_status}
										<p class="retweetedBy">
											<span class="icon-rtby"></span><span>Retweeted by </span>
											{if $friendvisible && $user && $user.both_following}
												<span class="friend-rt"/>
											{/if}
											{$retweetedBy}
										</p>
									{/if}
								</div>

Janetterのデバッグ・モードを使えばわかるんだけど、122~124行と125行のコードを入れ換えればユーザー名の後にアイコンを表示すること自体はできるので、どうしてもアイコンの位置にこだわりたい人はデベロッパ・ツールを駆使して調べてみるといいだろう。

CSSの追加

上のテンプレートのコードでは、friend-rtというクラスを新しく使用しているので、tweet.cssの任意の場所に次のCSSを追加する。200行あたりに相互フォローアイコンに関する設定があるので、その辺がちょうどいいかもしれない。行番号は同じく大体の位置。

span.friend-rt{
	display: inline-block;
	width: 9px;
	height: 9px;
	text-indent: -99999px;
	background-image: url(../../../Common/images/timeLine/smile.png);
}

ちなみに、float: left;float: right;などを追加すると、相互フォローアイコンだけ独立して表示させることもできる。改行されてしまって見栄えはあまり良くないので、お好みで。

関連記事

固定ページに構造化データを考慮してパンくずリストを追加する

最終更新:2017/01/13

WordPressの固定ページにパンくずリストを追加する。どうせ追加するなら、Googleが収集して階層構造を認識してくれる構造化データを考慮したマークアップ記述にしたい。

基本的に、構造化データの記述を支援してくれるBreadcrumb NavXTプラグインを利用する。本記事を書いている時点での最新バージョンは5.6.0

インストール方法に特別変わった手順は必要ないので省略する。

パンくずリストを追加すること自体はそれほど難しくはないけど、構造化データを考慮するとなると話が異なってくる。最初は気付かずにだいぶ古い記事を参考にしていたのでGoogleの構造化データテストツールで試行錯誤しても一向にエラーが解消されずに苦労したので、改めて書き留めておく。

Breadcrumb NavXTの設定

Breadcrumb NavXTにはデフォルトでパンくずリストの各要素のためのマークアップがあらかじめ設定されているけど、Googleのパンくずリスト(Breadcrumbs)に関するドキュメントやサンプルを見ると若干異なる。今回は、RFDa形式のマークアップを参考にした。

また、Googleのサンプルには<li>要素にパンくずリスト用のプロパティやフィールドが直接記述されているけど、Breadcrumb NavXTの設定画面でそれをやろうとすると拒否されてしまう。そのため、<span>要素をもうひとつ追加し、その中にプロパティを記述することにした。

リンクありのマークアップ

次のマークアップは固定ページ用、あるいはホームページ用の「リンクあり」のパンくずリストの要素。見やすくするために改行、インデントしてあるけど、実際の設定画面に入力する時は改行やタブを削除する。

<li>
	<span property="itemListElement" typeof="ListItem">
		<a property="item" typeof="WebPage" href="%link%" class="%type%">
			<span property="name">%htitle%</span>
		</a>
		<meta property="position" content="%position%">
	</span>
</li>

リンクなしのマークアップ

次のマークアップは固定ページあるいはホームページのもので、現在表示されているページなど、リンクする必要がないページのパンくずリスト。

<li>
	<span property="itemListElement" typeof="ListItem">
		<span property="name">%htitle%</span>
		<meta property="position" content="%position%">
	</span>
</li>

投稿などのフォーマットについて

ブログ記事などの投稿(post)にパンくずリストを表示したいケースもあるだろうし、Breadcrumb NavXTにも設定項目が備えられてはいる。ただ、投稿の場合は複数のカテゴリを設定できるために親子関係が複雑になりがちで、Breadcrumb NavXTの設定以外にも考えなければならないことが多くなる。基本的な考え方やマークアップは固定ページと同じだけど、本記事ではとりあげない。

テンプレートにパンくずリストを追加する

いつも使っているテーマのテンプレートにパンくずリストを追加する。次のコードは、twentyfifteenテーマの一般用固定ページを表示するcontent-page.phpに変更を加えた例。

	<header class="entry-header">
		<?php /* breadcrumbs */ ?>
			<ol class="breadcrumbs" typeof="BreadcrumbList" vocab="http://schema.org/">
				<?php if(function_exists('bcn_display'))
				{
					bcn_display();
				}?>
			</ol>
		<?php /* breadcrumbs */ ?>

		<?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
	</header><!-- .entry-header -->

RFDa形式の構造化データとしてリスト化したい場合は、3行目と8行目のパンくずリストを囲むタグを<ol>要素にして順序のあるリストにしておくことをGoogleは推奨している。

Googleで受け付けてくれる構造化データを意識しない場合は、Breadcrumb NavXTのインストールガイドにもあるように3行目と8行目は<div>タグでもよく、リストの各要素はデフォルト設定のような<span>要素でも構わない。特にCSSを設定しなくても簡素なテキストとして横一列にパンくずリストが並ぶ。

CSSの調整が手間だったので、パンくずリストをエントリ・ヘッダーの中に入れてしまったけど、サイトのデザインや他の構造化データの問題で都合が悪い場合は外に出してしまっても問題ない。構造化データというのは、ブラウザに表示されない<meta>要素などとは異なり、検索エンジンが識別に使用するクラス、プロパティ、フィールドが設定してありさえすれば、どういう文脈のところに入っていても識別される。つまり、検索エンジンが識別するためだけの特別なデータを別に用意する必要はなく、人間が見るための情報を検索エンジンに意味をわからせるためのデータとして兼ねてしまえるということ。

テンプレート・ファイルの変更が済んだらWordPressのサーバーにアップロードする。

構造化データのテスト

念のため、エラーが出ていないか構造化データ テストツールで固定ページ固有のURLを入力し、テストする。マークアップの改善がテストツールにすぐに反映されない場合は、ページのソースを表示させてパンくずリストの部分だけコピーしてエラーや警告が出ている部分に貼り付けたり、手入力で修正することでチェックだけはできる。

RFDa形式の場合、Googleによって解釈されたパンくずリストは次のように表示される。問題ないようならば、Googleボットがクロールに来るのを待つ。

クローラーが来て情報が収集されると、構造化データに従い、次の画像のようにパンくずリストが検索結果にも表示されるようになる。

CSSの追加

最後に、パンくずリスト用のCSSをテーマのstyle.cssに追加する。構造化した上で普通のテキストでいい場合はリストを横並びにするCSSだけでいいはず。

デザインは好みの問題が大半を占めるので、次のCSSはあくまでも例に過ぎない。特に、最近のCSSは高度化していて画像を使っていないのが不思議なくらい非常に凝った作りになっているものも多いので、CSSのコードを眺めているだけでは何を意図したプロパティなのかはわかりにくいと思われる。気になるデザインのパンくずリストを見つけたらブラウザの要素解析ツールで検証してみるといいだろう。

.breadcrumbs {
	list-style: none;
	display: table;
	margin-bottom: 2px;
	font-size: 12px;
}

.breadcrumbs li {
	display: table-cell;
	position: relative;
	left: 20px;
	padding: 0 20px 0 0;
	margin: 0;
	background-color: #c7dcef;
	line-height: 20px;
/* 	color: #fff; */
}

.breadcrumbs li > span {
	position: relative;
	padding: 0 10px;
}

.breadcrumbs li:after {
	content: "";
	position: absolute;
	top: 0;
	right: -4px;
	border: 0 solid #fff;
	border-left: 10px solid #c7dcef;
	border-top: 10px solid #c7dcef;
	border-width: 10px 10px;
	width: 0;
	height: 0;
}

.breadcrumbs li:before {
	content: "";
	position: absolute;
	top: 0;
	left: -20px;
	border: 0 solid #c7dcef;
	border-left: 10px solid transparent;
	border-top: 10px solid transparent;
	border-width: 10px 10px;
	width: 0;
	height: 0;
}

上記のCSSを使うと、次のようにパンくずリストが表示される。リストの各要素の前(:before疑似要素)と後(:after疑似要素)に斜めの切り欠きを追加している。

参考記事

WordPressの子テーマに固定ページ用テンプレートを追加する

最終更新:2017/01/13

WordPressの子テーマは親テーマのコードを直接変更することなくコードを差し替えたり追加したりできるため、各自の好みや目的に応じたカスタマイズがしやすいという特徴がある。

仮に手に負えなくなったとしても、子テーマを丸ごとサーバーから削除してしまえば元に戻せるため、初心者でも挑戦しやすい。もちろん、プログラミングの一種であることに変わりはないため、子テーマをカスタマイズしたことによって発生した事態には当方は一切責任を負えない。

テーマを構成するコードのほとんどはPHPというスクリプト言語で記述されている。一般的なHTMLの途中にPHPスクリプトをタグのような形式で挟んでいくような記述スタイルを採用しているので、HTMLさえ理解していれば比較的取っつきやすい。

一方、WEBデザインで頻繁に使われるものでも、JavaScriptはスクリプトのほうが優位で、HTMLタグはあくまでもJavaScriptから出力される文字列という扱いになるため、HTMLの階層構造がわかりやすくなるようにインデントしながら記述するのは難しいという特徴がある。できないわけではないけど、JavaScriptの構文上のネストなのかHTMLを見やすくするためのネストなのか判別しづらくなるためJavaScriptの都合に合わせるのが一般的で、スクリプト内のHTMLはキリのいいところまでひたすら1行で書くというのもそれほど珍しい話ではない。見た目にもまさにプログラムコードといった趣で、動的HTMLを実現する方法がJavaScriptくらいしかなかった時代にはオブジェクト指向言語にも通じる記述方法も相まって決して初心者向きとは言えなかった。

また、JavaScriptはウェブ・ブラウザのようなクライアント側で動作するものであるのに対し、PHPはサーバー側が適切なバージョンのライブラリを実装していないと動作しないという性質のあるものなので、一般的な環境のローカルPCでは試験できない。手直ししたコードをサーバーに逐一アップロードしなければならないため動作確認に若干時間がかかり、それなりに根気が必要になるという点は覚えておいたほうがいい。

当ブログのデザインはWordPress標準のTwenty Fifteenテーマをベースにした子テーマを使用しているけど、WordPressに実装されているテンプレート関連タグ(関数群)は共通なので、他のテーマでも作業そのものは大差ない。プログラムに詳しくなくても親テーマのコードを参考にして見よう見まねで組んでもなんとかなる。

テンプレートの追加

親テーマの固定ページ用テンプレート・ファイルpage.phpを複製し、追加テンプレート用のファイルを用意する。テンプレートは固定ページにしか使えないものなので自明ではあるんだけど、念のため「page」という単語をファイル名のどこかに入れておいたほうが後々改良を加えたくなった時にどこを変更すればいいのか思い出しやすくなる。

page.phpの記述は次のようになっている。ヘッダーと記事ループとフッターが記述されているだけのシンプルなもので、ここで悩むようなことはないだろう。24行目でcontent-page.phpというテンプレートファイルを読み込んでいる。

<?php
/**
 * The template for displaying pages
 *
 * This is the template that displays all pages by default.
 * Please note that this is the WordPress construct of pages and that
 * other "pages" on your WordPress site will use a different template.
 *
 * @package WordPress
 * @subpackage Twenty_Fifteen
 * @since Twenty Fifteen 1.0
 */

get_header(); ?>

	<div id="primary" class="content-area">
		<main id="main" class="site-main" role="main">

		<?php
		// Start the loop.
		while ( have_posts() ) : the_post();

			// Include the page content template.
			get_template_part( 'content', 'page' );

			// If comments are open or we have at least one comment, load up the comment template.
			if ( comments_open() || get_comments_number() ) :
				comments_template();
			endif;

		// End the loop.
		endwhile;
		?>

		</main><!-- .site-main -->
	</div><!-- .content-area -->

<?php get_footer(); ?>

新テンプレート用のファイル名の長さには特に制限はないけど、あまり長くてもメリットはないので、vfpage.phpとした。WordPressテーマの決まり事として、最初のコメント行にテンプレート名を必ず書いておく。WordPressはここに書いたテンプレート名を識別して編集画面に反映する仕様になっている。

<?php
/*
Template Name: VANGUARD FLIGHT
*/

get_header(); ?>

	<div id="primary" class="content-area">
		<main id="main" class="site-main" role="main">

		<?php
		// Start the loop.
		while ( have_posts() ) : the_post();

			// Include the page content template.
			get_template_part( 'content', 'vfpage' );

			// If comments are open or we have at least one comment, load up the comment template.
			if ( comments_open() || get_comments_number() ) :
				comments_template();
			endif;

		// End the loop.
		endwhile;
		?>

		</main><!-- .site-main -->
	</div><!-- .content-area -->

<?php get_footer(); ?>

16行目をget_template_part( 'content', 'vfpage' );に書き換え、content-vfpage.phpを呼び出すように変更しておく。表示させたい内容に変更がない場合は書き換えなくても問題はないだろうけど、テンプレートを分岐させておきながら、結局親テーマのテンプレートを再度呼び出すようなプログラミングは後で混乱の元になるため、内容はまったく同じでもcontent-page.phpを複製してcontent-vfpage.php作成しておく。

ここまで作成すると、固定ページ編集画面の「ページ属性」ボックスに追加したテンプレート名が追加される。

wordpress000

テンプレートを切り替えると、WordPressによって生成されたHTMLのbodyタグに「page-template-vfpage」といった、デフォルトとは異なるテンプレートを使用しているということを示すクラスが自動的に追加されるので、子テーマのstyle.cssに必要なスタイルを書き加える。

.page-template-vfpage h1,
.page-template-vfpage h2,
.page-template-vfpage h3,
.page-template-vfpage h4,
.page-template-vfpage h5,
.page-template-vfpage h6 {
	clear: none;
}

.page-template-vfpage table.infobox {
	table-layout: auto;
	float: right;
	width: 360px;
	margin: 0.5em 0 0.5em 1em;
}

Twenty Fifteenのデフォルトではレベルを問わず見出し行が来ると、CSSのfloatプロパティの左寄せ、右寄せが強制的に解除(clear: both;)されるようになっていたので、見出しが来ても右寄せ、左寄せを解除しないように変更した。また、infoboxというクラスを持つtableタグのスタイルを定義した。クラスを限定してあるので投稿フォーマットのブログ記事のスタイルにはまったく影響しない。

もちろん、新テンプレート専用のCSSファイルを別に用意してlinkタグで個別に読み込ませることもできるけど、テンプレート用のクラスをWordPressが追加してくれていることで煩雑な条件判定は既に済んでいると見なせるので、コード記述やファイル管理の手間が増える割にはメリットは少ない。

サイドバーの増設

Twenty Fifteenは片側のみ(デフォルトは左)のサイドバーしか想定していないので、親テーマのfunctions.phpには次に示すコードのように「sidebar-1」という名前のサイドバーがひとつしか登録されていない。有料テーマなど凝ったものでは複数のサイドバーがあらかじめ用意されているものもあるようだけど、WordPressが標準で用意してくれているテーマはいわば白地図のようなもので、各自のカスタマイズが前提みたいなところもあるので、あまり期待はしないほうがいい。

/**
 * Register widget area.
 *
 * @since Twenty Fifteen 1.0
 *
 * @link https://codex.wordpress.org/Function_Reference/register_sidebar
 */
function twentyfifteen_widgets_init() {
	register_sidebar( array(
		'name'          => __( 'Widget Area', 'twentyfifteen' ),
		'id'            => 'sidebar-1',
		'description'   => __( 'Add widgets here to appear in your sidebar.', 'twentyfifteen' ),
		'before_widget' => '<aside id="%1$s" class="widget %2$s">',
		'after_widget'  => '</aside>',
		'before_title'  => '<h2 class="widget-title">',
		'after_title'   => '</h2>',
	) );
}
add_action( 'widgets_init', 'twentyfifteen_widgets_init' );

サイドバーも「sidebar-vfpage.php」のようなテンプレート名を含むファイルを用意すれば、<?php get_sidebar('vfpage'); ?>といったコードでテンプレートによるデザインの切り替えも可能なんだけど、ダッシュボードの「外観」>「ウィジェット」からGUIを利用してウィジェットを編集可能なダイナミック・サイドバーを使えたほうが何かと都合が良い。

追加ダイナミック・サイドバーのために子テーマのfunctions.phpに次のようなコードを追加する。functions.phpがなく、style.cssだけでも子テーマとしては成立するし、特にエラーにもならないけど、ダッシュボードからコードを追加・編集することもできるようになるので、まったくの白紙状態でもいいからお約束としてfunctions.phpファイルは用意しておいたほうがいい。ただし、誤動作の元になるので親テーマのfunctions.phpを無闇に丸ごとコピーしてはいけない。

/* Add Extra Sidebar */
function vf_widgets_init() {
	register_sidebar( array(
		'name'          => __( 'VF用ウィジェット エリア', 'VANGUARD FLIGHT' ),
		'id'            => 'sidebar-2',
		'description'   => __( 'VF用サイドバーに表示されるウィジェットを追加できます。', 'VANGUARD FLIGHT' ),
		'before_widget' => '<aside id="%1$s" class="widget %2$s">',
		'after_widget'  => '</aside>',
		'before_title'  => '<h2 class="widget-title">',
		'after_title'   => '</h2>',
	) );
}
add_action( 'widgets_init', 'vf_widgets_init' );

ダイナミック・サイドバー(ウィジェット・エリア)を追加すると、ウィジェット編集画面に次の画像のように2つのウィジェット・エリアが表示されるようになる。

wordpress001

コンテンツでサイドバーを切り替える

Twenty Fifteenテーマはヘッダーエリアとサイドバーエリアが左側のエリアを共有していて、上下に分け合って表示される仕組みになっているので、サイドバー本体はheader.phpから呼び出されるようになっている。ヘッダーエリアが独立していてタイトルとメインメニューの表示のみに使っているテーマの場合は、記事ループが記述されているテンプレートからフッターの直前にサイドバーを呼び出すようになっているものもある。

親テーマのsidebar.phpは次のコードのようになっている。サイドバーをひとつしか使わないことを前提としたコードなので、ブログの記事を表示していても、固定ページを表示していても同じサイドバーが表示される。

		<?php if ( is_active_sidebar( 'sidebar-1' ) ) : ?>
			<div id="widget-area" class="widget-area" role="complementary">
				<?php dynamic_sidebar( 'sidebar-1' ); ?>
			</div><!-- .widget-area -->
		<?php endif; ?>

そこで、子テーマにsidebar.phpを複製して作成し、特定のテンプレートを使用している場合のみ新しく登録したダイナミック・サイドバーを表示するように条件分岐を書き加える。is_page_template関数は特定のテンプレート・ファイルを経由して表示しようとしているかどうかを判定するため、テンプレート・ファイル名を引数として指定する。

		<?php if ( is_page_template( 'vfpage.php' ) ) :
			if ( is_active_sidebar( 'sidebar-2' ) ) : ?>
				<div id="widget-area" class="widget-area" role="complementary">
					<?php dynamic_sidebar( 'sidebar-2' ); ?>
				</div><!-- .widget-area -->
			<?php endif;
		else :
			if ( is_active_sidebar( 'sidebar-1' ) ) : ?>
				<div id="widget-area" class="widget-area" role="complementary">
					<?php dynamic_sidebar( 'sidebar-1' ); ?>
				</div><!-- .widget-area -->
			<?php endif;
		endif; ?>

なお、PHPは、主にHTMLと混在している箇所で条件分岐内等のブロックコードの始まりと終わりを意味する中括弧{…}は必須ではない、というプログラミング言語としては変わった仕様を持つ。ブロックの開始はコロン(:)で置き換え可能で、終始の記号が一対一で対応している必要も、何かの記号で閉じる必要も特にない。

記事のメタ情報の書式変更

投稿(post)フォーマットのコンテント・フッターには次の画像のようにメタ情報が表示される。ここに、最終更新日の情報を追加したい。

wordpress002
改修前のコンテント・フッター

template-tags.phpに含まれる関数の移設

Twenty Fifteenテーマのコンテント・フッターは厳密にはテンプレートではなく、inc/template-tags.phpというファイルに記述された関数群で実現している。一度読み込まれると上書きを拒否するコードになっているため、他のテンプレート・ファイルと同様の感覚で子テーマにinc/template-tags.phpを追加して編集しても変更が反映されることはない。

まず、親テーマのtemplate-tags.phpの中からtwentyfifteen_entry_metaという関数を探す。

if ( ! function_exists( 'twentyfifteen_entry_meta' ) ) :
/**
 * Prints HTML with meta information for the categories, tags.
 *
 * @since Twenty Fifteen 1.0
 */
function twentyfifteen_entry_meta() {
:
:
(中略)
:
:
	}
}
endif;

template-tags.phpの代わりに、子テーマのfunctions.phpに同名の関数を追加、登録する。親テーマのtemplate-tags.phpよりも先に子テーマのfunctions.phpが実行されるため、こちらが優先される。

上のif ( ! function_exists( 'twentyfifteen_entry_meta' ) ) :endif;というコードで、一度定義された関数は重複して定義しないようになっているので、親テーマの同名の関数で上書きされたり、二重定義でエラーになったりすることはない。

15~37行が投稿日と最終更新日に関するコード。詳しくは説明しないけど、ところどころ出てくるprintf関数やsprintf関数がJavaScript式のHTML挿入方法によく似ていて、HTMLタグでは普通使わない「%1」や「$s」が出てきてプログラム初心者には少し敷居が高そうに見えるかもしれない。関数そのものはC++の祖先のC言語時代からある「初心者がまず最初に覚える関数」のひとつではあるんだけど、本来は英語であるシステム・メッセージの多言語翻訳の都合もあり、WordPressでは使い方がやや高度。

function twentyfifteen_entry_meta() {
	if ( is_sticky() && is_home() && ! is_paged() ) {
		printf( '<span class="sticky-post">%s</span>', __( 'Featured', 'twentyfifteen' ) );
	}

	$format = get_post_format();
	if ( current_theme_supports( 'post-formats', $format ) ) {
		printf( '<span class="entry-format">%1$s<a href="%2$s">%3$s</a></span>',
			sprintf( '<span class="screen-reader-text">%s </span>', _x( 'Format', 'Used before post format.', 'twentyfifteen' ) ),
			esc_url( get_post_format_link( $format ) ),
			get_post_format_string( $format )
		);
	}

	if ( in_array( get_post_type(), array( 'post', 'attachment' ) ) ) {
		$time_string = '<time class="entry-date published updated" datetime="%1$s">%2$s</time>';

		$time_string = sprintf( $time_string,
			esc_attr( get_the_date( 'c' ) ),
			get_the_date(),
			esc_attr( get_the_modified_date( 'c' ) ),
			get_the_modified_date()
		);

		printf( '<span class="posted-on"><span class="screen-reader-text">%1$s </span><a href="%2$s" rel="bookmark">%3$s</a></span>',
			_x( 'Posted on', 'Used before publish date.', 'twentyfifteen' ),
			esc_url( get_permalink() ),
			$time_string
		);

		if ( get_the_time( 'U' ) !== get_the_modified_time( 'U' ) ) {
			printf( '<span class="updated-on"><time class="updated" datetime="%1$s">%2$s</time></span>',
				esc_attr( get_the_modified_date( 'c' ) ),
				get_the_modified_date()
			);
		}
	}

	if ( 'post' == get_post_type() ) {
		if ( is_singular() || is_multi_author() ) {
			printf( '<span class="byline"><span class="author vcard"><span class="screen-reader-text">%1$s </span><a class="url fn n" href="%2$s">%3$s</a></span></span>',
				_x( 'Author', 'Used before post author name.', 'twentyfifteen' ),
				esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ),
				get_the_author()
			);
		}

		$categories_list = get_the_category_list( _x( ', ', 'Used between list items, there is a space after the comma.', 'twentyfifteen' ) );
		if ( $categories_list && twentyfifteen_categorized_blog() ) {
			printf( '<span class="cat-links"><span class="screen-reader-text">%1$s </span>%2$s</span>',
				_x( 'Categories', 'Used before category names.', 'twentyfifteen' ),
				$categories_list
			);
		}

		$tags_list = get_the_tag_list( '', _x( ', ', 'Used between list items, there is a space after the comma.', 'twentyfifteen' ) );
		if ( $tags_list ) {
			printf( '<span class="tags-links"><span class="screen-reader-text">%1$s </span>%2$s</span>',
				_x( 'Tags', 'Used before tag names.', 'twentyfifteen' ),
				$tags_list
			);
		}
	}

	if ( is_attachment() && wp_attachment_is_image() ) {
		// Retrieve attachment metadata.
		$metadata = wp_get_attachment_metadata();

		printf( '<span class="full-size-link"><span class="screen-reader-text">%1$s </span><a href="%2$s">%3$s &times; %4$s</a></span>',
			_x( 'Full size', 'Used before full size attachment link.', 'twentyfifteen' ),
			esc_url( wp_get_attachment_url() ),
			$metadata['width'],
			$metadata['height']
		);
	}

	if ( ! is_single() && ! post_password_required() && ( comments_open() || get_comments_number() ) ) {
		echo '<span class="comments-link">';
		/* translators: %s: post title */
		comments_popup_link( sprintf( __( 'Leave a comment<span class="screen-reader-text"> on %s</span>', 'twentyfifteen' ), get_the_title() ) );
		echo '</span>';
	}
}

Genericonsの新規使用指定

Twenty FifteenはGenericonsを使用している。せっかくなので見栄えも揃えたい。上で改変したtwentyfifteen_entry_meta関数では更新日の表示にupdated-onクラスを新たに使用することにしているので、当該クラスをstyle.cssのGenericonsを使用するクラスに追加する。

.social-navigation a:before,
.secondary-toggle:before,
.dropdown-toggle:after,
.bypostauthor > article .fn:after,
.comment-reply-title small a:before,
.comment-navigation .nav-next a:after,
.comment-navigation .nav-previous a:before,
.posted-on:before,
.updated-on:before,
.byline:before,
.cat-links:before,
.tags-links:before,
.jetpack_views:before,
.comments-link:before,
.entry-format:before,
.edit-link:before,
.full-size-link:before,
.pagination .prev:before,
.pagination .next:before,
.image-navigation a:before,
.image-navigation a:after,
.format-link .entry-title a:after,
.entry-content .more-link:after,
.entry-summary .more-link:after,
.author-link:after {
	-moz-osx-font-smoothing: grayscale;
	-webkit-font-smoothing: antialiased;
	display: inline-block;
	font-family: "Genericons";
	font-size: 16px;
	font-style: normal;
	font-weight: normal;
	font-variant: normal;
	line-height: 1;
	speak: none;
	text-align: center;
	text-decoration: inherit;
	text-transform: none;
	vertical-align: top;
}

使いたいアイコンをウェブサイトのサンプルから選び、アイコン・コードをstyle.cssのGenericonsの各クラス定義部分に追加する。

.format-aside .entry-format:before {
	content: "\f101";
}

.format-image .entry-format:before {
	content: "\f473";
}

.format-gallery .entry-format:before {
	content: "\f103";
}

.format-video .entry-format:before {
	content: "\f104";
}

.format-status .entry-format:before {
	content: "\f105";
}

.format-quote .entry-format:before {
	content: "\f106";
}

.format-link .entry-format:before {
	content: "\f107";
}

.format-chat .entry-format:before {
	content: "\f108";
}

.format-audio .entry-format:before {
	content: "\f109";
}

.posted-on:before {
	content: "\f307";
}

.updated-on:before {
	content: '\f420';
}

.byline:before {
	content: "\f304";
}

.cat-links:before {
	content: "\f301";
}

.tags-links:before {
	content: "\f302";
}

.comments-link:before {
	content: "\f300";
}

.full-size-link:before {
	content: "\f402";
}

.edit-link:before {
	content: "\f411";
}

改修が終わったコンテント・フッター。矢印が円形につながっている更新マーク(正確にはリフレッシュ・アイコン)の後に最終更新日が表示されている。

wordpress003
改修後のコンテント・フッター

参考記事

Janetterにフォロワー数/リツイート数/いいね数を表示する

最終更新:2017/01/27

カスタムテーマを設定すると、アカウントのアイコンの下にフォロワー数が表示される。6桁までは表示できた。リツイートされたツイートだとしても、ツイート元のアカウントのフォロワーが表示されるようになっている。また、本文の下にリツイート数といいね(お気に入り)の回数が表示されるようになる。自分のツイートでは良い条件のツイートがなかったので、ニュース記事のツイートを借りてきた。

TwitterクライアントJanetter(ジャネッター)にはタイムラインの表示方法やデザインを選べる「テーマ」という機能がある。標準で実装されているシンプルなテーマ群でも実用上はそれほど困らないんだけど、本家のTwitterのウェブ・クライアントと比べて情報量がやや少ない。

本家では「リツイート」や「いいね」(旧仕様の「お気に入り」)の回数がこれといった操作なしに常に表示されているけど、Janetterでは各ツイートの日付・時刻に備えられたリンクをクリックしてブラウザで確認しないとどのくらい「リツイート」や「いいね(お気に入り)」されているツイートなのか確認できない。

また、そのツイートをつぶやいたアカウントがどのくらいのTwitterユーザーにフォローされているのかはアカウントのリンクをクリックしてプロフィール用ウィンドウを表示させなければならない。本家のウェブ・クライアントではマウス・ポインタをユーザー名の上に置けば簡単なプロフィールを確認することができる。

全部は無理としても、アカウントのフォロワー数とツイートのリツイート数といいね(お気に入り)の回数くらいは視覚的に確認できるようにしたい。なお、名前が変わっただけで、Twitterの内部的には「いいね」と「お気に入り」はまったく同じもので、APIから送られてくるツイートの情報は相変わらず「Favorite(d)」になっている。

そこで、改良したユーザーテーマを作成してこれらの情報を表示させてみようと思う。なお、テーマの作成は一種のプログラミングなので失敗しても当方は責任を負えない。プログラムやスクリプトの作成経験がない場合は特に慎重に。

言うまでもないことだろうけど、Janetterを終了してからテーマの変更を行う。

テーマの移設

テーマを最初から全部作成するのは大変なので、標準のテーマのうちのひとつを複製して移設する。ここではもっとも標準的なSparrowテーマを使用する。

テーマを構成するデータは次のフォルダに入っているので、これをフォルダごと複製し、まずはフォルダに適当な名前をつける。ここでは仮に「TestTheme」とする。

C:\Program Files (x86)\Janetter2\Theme\Items\Sparrow

本来は*.janetthemeというテーマ・ファイルからJanetterに読み込ませてテーマを自動インストールするんだけど、自作の場合はフォルダを増設することで手動インストールすることができる。また、テーマ・ファイルは名前が違うだけで実態はzip形式の圧縮ファイルなのでJanetterの代わりに自分が解凍済みのデータをインストールしたと思えばいい。

TestThemeフォルダに入ったら、theme.iniという初期設定ファイルを開く。UTF-8(BOMなし)で記述されているので、Windows標準のメモ帳(Notepad)よりはあらゆる文字コードに対応した高機能テキスト・エディタを使用したほうが無難。

[TestTheme]
name = TestTheme
description = Left side menu
sample_image = sample.jpg
author = Jane, Inc.
url = http://janetter.net
twitter_id = Janetter_jp
main_frame_html = index.htm
popup_html = ..\..\Common\notice\notice.htm
image_viewer_html = ..\..\Common\viewer\viewer.htm
map_viewer_html = ..\..\Common\viewer\map.htm
profile_html = ..\..\Common\profile\profile.htm

最初の2行を書き換える。Janetterは最初の1行でテーマの存在を識別するので、必ず2行とも書き換える。また、標準のテーマから移設した場合、index = 0010といったようにインデックス番号を付けられているけど、この行は削除しておく。あっても害はないけど、Janetterでのテーマの表示順に関係しているので、最後に表示させることにする。

テンプレートの改造

次に、標準テーマで共通で使用されている共有テンプレートのtweet.tplファイルをTestThemeフォルダにあるtemplateフォルダにコピーする。

C:\Program Files (x86)\Janetter2\Theme\Common\template\tweet.tpl

また、同じフォルダにあるtweet.cssファイルも同様にコピーしておく。

C:\Program Files (x86)\Janetter2\Theme\Common\template\tweet.css

tweet.tplファイルを開くわけだけど、ここからは本当に高機能テキスト・エディタを使うべき。コードの間違いなのかファイルのデータ形式の問題なのか区別できなくなるので、信頼できるコーディング用テキスト・エディタを使うことを強くおすすめする。無料で使えるところではStyleNote5などがおすすめ。ウェブ作成関連で使用しそうな言語やマークアップにはすべて対応しており、コメントの閉じ忘れなど単純な書き間違いはその場でわかる。

フォロワー数の表示

テンプレートはJartyという一種のスクリプト言語で記述されている。ファイルの最初のほうは次のようになっている。わからなければprofile-boxというクラスを目印にして検索するといい。

				<div class="profile-box">
					{if $retweeted_status}{* RT *}
						<p class="main-profile">
							<a action="all"><img src="{$retweeted_status.user.profile_image_url}"></a>
						</p>
						<p class="sub-profile">
							<a action="all" class="sub-profile"><img src="{$user.profile_image_url}"></a>
						</p>
						<div class="icon-rt"></div>
					{elseif $user}{* Normal *}
						<p class="main-profile">
							<a action="all"><img src="{$user.profile_image_url}"></a>
						</p>
					{elseif $sender}{* DM *}
						<p class="main-profile">
							<a action="all"><img src="{$sender.profile_image_url}"></a>
						</p>
						{if $isMe}
							<p class="sub-profile-dm">
								<a action="all" class="sub-profile"><img src="{$recipient.profile_image_url}"></a>
							</p>
							<div class="icon-dm"></div>
						{/if}
					{else}{* Search *}
						<p class="main-profile">
							<a action="all"><img src="{$profile_image_url}"></a>
						</p>
					{/if}
				</div>

profile-boxクラスはツイートしたアカウントやそれをリツイートしたアカウントのアイコンが表示される領域で、そこにツイート元のアカウントのフォロワー数を表示する行を追加する。

				<div class="profile-box">
					{if $retweeted_status}{* RT *}
						<p class="main-profile">
							<a action="all"><img src="{$retweeted_status.user.profile_image_url}"></a>
							<div style="width:36px; margin:0 0 4px 0; text-align:center; color:Black; font-size: x-small;">{$main_user.followers_count}</div>
						</p>
						<p class="sub-profile">
							<a action="all" class="sub-profile"><img src="{$user.profile_image_url}"></a>
						</p>
						<div class="icon-rt" style="top: 57px;"></div>
					{elseif $user}{* Normal *}
						<p class="main-profile">
							<a action="all"><img src="{$user.profile_image_url}"></a>
							<div style="width:36px; margin:0 0 4px 0; text-align:center; color:Black; font-size: x-small;">{$main_user.followers_count}</div>
						</p>
					{elseif $sender}{* DM *}
						<p class="main-profile">
							<a action="all"><img src="{$sender.profile_image_url}"></a>
						</p>
						{if $isMe}
							<p class="sub-profile-dm">
								<a action="all" class="sub-profile"><img src="{$recipient.profile_image_url}"></a>
							</p>
							<div class="icon-dm"></div>
						{/if}
					{else}{* Search *}
						<p class="main-profile">
							<a action="all"><img src="{$profile_image_url}"></a>
							<div style="width:36px; margin:0 0 4px 0; text-align:center; color:Black; font-size: x-small;">{$main_user.followers_count}</div>
						</p>
					{/if}
				</div>

リツイート数/いいね(お気に入り)数の表示

次に74行目付近。tweet-bodyクラスが記述されている。ここにツイートの本文を表示するようになっている。

							<div class="tweet-body">
								{if $retweeted_status}{* RT *}
									<p class="text">{$retweeted_status.text}</p>
								{else}
									<p class="text">{$text}</p>
								{/if}
							</div>

本文の直後に「リツイート」の回数が2回以上あればリツイート数を表示し、「いいね(お気に入り)」の回数が1回以上あればいいね(お気に入り)数を表示するコードを記述する。

							<div class="tweet-body">
								{if $retweeted_status}{* RT *}
									<p class="text">{$retweeted_status.text}</p>
								{else}
									<p class="text">{$text}</p>
								{/if}
								{if $retweeted_status}{* RT *}
									{if $retweeted_status.retweet_count>1}
										<p class="rtcount">{$retweeted_status.retweet_count}</p>
									{/if}
									{if $retweeted_status.favorite_count>0}
										<p class="favcount">{$retweeted_status.favorite_count}</p>
									{/if}
								{else}
									{if $retweet_count>1}
										<p class="rtcount">{$retweet_count}</p>
									{/if}
									{if $favorite_count>0}
										<p class="favcount">{$favorite_count}</p>
									{/if}
								{/if}
							</div>

$retweet_count変数はTwitterから取得したリツイートの回数を、$favorite_count変数はいいね(お気に入り)の回数を格納している。ただし、これらの変数の数値はリツイートの場合($retweeted_status == true)にはリツイートした人のツイートについての情報になるため、元のツイートのリツイート数を知りたい場合は$retweeted_status.retweet_count変数から参照しなければならない。いいね(お気に入り)の回数についても同様で、$retweeted_status.favorite_count変数から参照する。

以上でテンプレートの編集は終了。ファイルを保存する。

CSSの追加

次に、tweet.cssファイルを開く。ファイルの最後までスクロールし、次のスタイルを追加する。リツイート数といいね(お気に入り)数の表示にはそれぞれrtcountとfavcountというクラスを割り当ててあり、それをどのような表示形式にするかという指定にあたる。CSSの記述方法を知っているのならば、ここは好みで自由に変更できる。

.rtcount {
	color: #fff;
	background-color: #19cf86;
	display: inline-block;
	width: 25%;
	border-radius: 5px;
	text-align: center;
	font-weight: bold;
}
.favcount {
	color: #fff;
	background-color: #e2264d;
	display: inline-block;
	width: 25%;
	border-radius: 5px;
	text-align: center;
	font-weight: bold;
}

厳密には、Jartyが表示する場所や内容をクラスで管理していると言ったほうが正しく、新しい表示要素を追加したい場合にはそれに対応するクラスを新たに定義しなければならない。

例えば、textクラスはツイート本文のクラスだけど、ただのテキストだからと思ってこれを別の用途に流用しようとすると、ツイート本文が2回、3回と連続で表示されたりする。また、クラスを定義していないHTMLタグを記述するとタイムラインが表示されなくなる。つまり、クラスはCSSのためだけにあるのではなく、内容にも紐付けられて管理されているということになる。

最初はHTMLを動的に生成するPHPのようなものかと思っていたけど、テンプレートに特化したスクリプトなのでPHPほどには融通はきかない。フォロワー数がクラスを定義しなくても表示できたのは本当に偶然。なんで大丈夫なのかは今でもよくわかっていない。とは言え、Jartyは構文をPHPに似せて作ってあり、関係演算子などはそのままコピーできるように設計されているようだ。

アイコン画像パスの変更

Sparrowテーマは独自のtweet.cssファイルを持っていないため共通ファイルから引っ張ってきたわけだけど、アイコン画像は共通のものをそのまま使いたいのでパスを変更しなければならない。基本的には、../../Common/images/timeLine/../../../Common/images/timeLine/に一律に置換すればいい。

独自のtweet.cssファイルを最初から持っているテーマから移設した場合は変更しなくてもいい。なお、CSSには独自にかなり変更を加えてしまったので、行番号は大体の位置。

「お気に入り」アイコン。今のTwitterの仕様で言うところの「いいね(お気に入り)」をしたツイートの左上隅に表示される黄色い星のアイコン。

.favorited .star-batch{
	position: absolute;
	top:0px;
	left:0px;
	width: 15px;
	height: 15px;
	background-image: url(../../../Common/images/timeLine/star-batch.png);
}

相互フォロー(スマイル)アイコン、非公開アカウント(鍵)アイコン、未読アイコン、位置情報(ジオピン)アイコン。

span.friend{
	float: left;
	display: block;
	width: 9px;
	height: 9px;
	margin: 4px 1px 0 1px;
	text-indent: -99999px;
	background-image: url(../../../Common/images/timeLine/smile.png);
}
span.protected{
	float: left;
	display: block;
	width: 9px;
	height: 11px;
	margin: 5px 0 0 2px;
	zoom: 0.9;
	text-indent: -99999px;
	background-image: url(../../../Common/images/timeLine/key2.png);
}
span.unread{
	float: left;
	display: block;
	width: 9px;
	height: 9px;
	margin: 4px 0 0 1px;
	text-indent: -99999px;
	background-image: url(../../../Common/images/timeLine/unread.png);
}
span.geopin{
	float: left;
	display: block;
	width: 9px;
	height: 11px;
	margin: 0 2px 0 0;
	text-indent: -99999px;
	background-image: url(../../../Common/images/timeLine/geopin2.png);
}

タイムラインのギャップに表示される波型のアイコン。

.gapArea{
	margin: 3px 0 10px 0;
	height: 24px;
	text-align: center;
	background-image: url(../../../Common/images/timeLine/gap_line.png);
	background-repeat: repeat-x;
}

以上でCSSの編集は終了。ファイルを保存する。

CSSファイルを保存したら、Janetterを起動する。設定画面から「デザイン」を選び、最も右に作成したTestThemeがあるので、それを選択し、「テーマを変更する」ボタンをクリックする。もしも、画面が真っ白になってしまって変化がない場合はテンプレートのコードがどこか間違っているので、別のテーマに戻して不具合を探す。エラーコードなどがはっきり出るわけではないので、変更した箇所をよく確認する。CSSの記述が間違っている程度であればタイムラインが止まってしまうような事態が起こることはまずない。

問題点

Janetter002
(参考)Janetterを利用したことがない方のために変更前のSparrowテーマの表示。フォロワー数、リツイート数、いいね(お気に入り)の回数は表示されない。サムネイル画像のサイズが大きいのはカスタムスタイルシートを設定してあるため(前の記事参照)。

フォロワー数は概ね期待どおりの結果になったんだけど、リツイート数といいね(お気に入り)の回数には少し問題があった。

リツイート数といいね(お気に入り)の回数はあくまでも大体のものだと思ったほうがよさそう。Janetterが定期的にAPIを叩いた時点での数値なのでツイートを読むまでに時差があった場合、本家のウェブ・クライアントと比べてみるとリツイート数にかなり差が出てしまっていることもよくある。

特に、「いいね(お気に入り)」の回数はかなりあてにならない。実は、実装はしていても$favorite_count変数はJanetterの公式でも現在公開されていなくて、信頼性が低いことは認識しているようだ。

それから、フォローしているアカウントのツイートが流れる「ホーム」のタイムラインに限ってはリツイート数もいいね(お気に入り)の回数も表示されないことがある。「再読み込み」をかけると表示されるんだけど、リアルタイムで追加されていくツイートには表示されない。一方、同じくリアルタイムで追加されていくものでも「リスト」では正しく表示される。

テンプレートは同じものを使っているので、おそらくリアルタイム性を重視したホーム用のユーザーストリームAPIとリストのデータをまとめて読み込むクローラーAPIの違いなんだろうと思うけどTwitter本家の仕様なのでクライアント側ではどうしようもない。Janetterがリツイート数といいね(お気に入り)数の表示に標準で対応していないのはこのへんに理由があるのかもしれない。

表示例

関連記事

参考記事

Janetterのサムネイルの画像サイズを変更する

最終更新:2017/01/27

Janetter000
サムネイル画像サイズ変更前。CSSで最大120×80pxに設定されている。Twitterからはthumbサイズで呼び出されるため、実質80×80px。

Janetter(ジャネッター)は、国産Twitterクライアントのひとつ。公式のアプリケーションやウェブ・クライアントではやってくれない未読管理もできてとても便利なんだけど、右の画像のようにツイートに添付されたサムネイル画像が非常に小さくて見づらいのが難点だった。

調べてみると、Janetterはウェブ・ブラウザのようにHTMLとCSSで画面表示の内容やデザインを決定しているようなので、やりようによってはカスタマイズできそうだった。

サムネイル画像サイズの変更

ユーザースタイルシートを記述できる空のファイルが用意されているので、そこに任意のCSSを記述する。具体的には次の場所。ユーザーフォルダの下の階層にあるので注意。

C:\Users\[user_name]\AppData\Roaming\Jane\Janetter2\UserStyleSheets\Custom.css

Custom.cssには次のように記述する。

.tweet-thumb img,
.tweet-thumb canvas{
	float: left;
	margin: 5px 5px 3px 0;
	max-height: 150px;
	max-width: 150px;
	border-radius: 5px;
}

なお、Twitterサーバーに置かれている画像ファイルには、Janetterで動作しているJavaScriptによって一律に「:thumb」のサフィックスが追加されるようになっているので、縦横ともに最大でも150pxまでしか指定できない。

上のスタイルの元になっているCSSは、次のtweet.cssファイルに記述されている。

C:\Program Files (x86)\Janetter2\Theme\Common\template\tweet.css

Janetterデバッグモード

他の要素(クラス、セレクタ)に対するスタイルがどこのCSSファイルに記述されているか調べるには、Janetterのデバッグモードを使用する。

まず、Janetterをいったん終了する。Janetterへのショートカットを別に作成し、次のように「リンク先」に--debugを追加する。

"C:\Program Files (x86)\Janetter2\bin\Janetter.exe" --debug

編集したショートカットをダブルクリックするとデバッグモードで起動される。デバッグモードになっているか確認するには、左上の「Janetter」のロゴを左クリックして「Developer Tools」や「Test」といったメニューが追加されているかどうかで判断する。

「Developer Tools」を選択すると、Chromiumの要素解析画面が表示される。上から順に要素を選択していくと、対応するJanetterの画面の一部がブロック(コンテント、パディング、ボーダー、マージン)で色分けされて表示されるので、それを参考にCSSの構造を解析する。

「:thumb」サフィックスの解除

Twitter規定のサムネイルのサイズ(150px)が実質上の最大サイズになってしまう制限を解除するには、次の場所にあるthumbnail.jsファイルをカスタムテーマのフォルダに複製してからJavaScriptコードを書き換える。カスタムテーマの作り方についてはこちらの記事を参照のこと。

(以前の版ではコモン・コードを直接書き換えていたけど、全部のテーマに影響を与えてしまい、褒められた方法ではないので、カスタムテーマをちゃんと用意するほうが良い。また、元のコードがわからなくならないように複製してコメントアウトしておいてから改変するほうが無難)

C:\Program Files (x86)\Janetter2\Theme\Common\js\janet\thumbnail.js

thumbnail.jsの125行目あたり。

		//-------------------------------------------------------
		// Twitter
		//-------------------------------------------------------
		function twimg(permalink){
			var a = _content.find('div.tweet-body p a[expanded="' + permalink + '"]'),
				media_url = a.attr('media'),
				extended_media_url = a.data('extended'),
				type = a.attr('type');
			if(media_url && (type=='photo' || type=='video' || type=='animated_gif')){
				if(extended_media_url){
					$.each(extended_media_url, function(){
						_append(this + ':thumb', type=='photo'? this + ':orig': '', permalink);
					});
				}else{
					_append(media_url + ':thumb',  type=='photo'? media_url + ':orig': '', permalink);
				}
				return true;
			}
			return false;
		}

136行目と139行目を次のように書き換える。

		//-------------------------------------------------------
		// Twitter
		//-------------------------------------------------------
		function twimg(permalink){
			var a = _content.find('div.tweet-body p a[expanded="' + permalink + '"]'),
				media_url = a.attr('media'),
				extended_media_url = a.data('extended'),
				type = a.attr('type');
			if(media_url && (type=='photo' || type=='video' || type=='animated_gif')){
				if(extended_media_url){
					$.each(extended_media_url, function(){
						_append(this + '', type=='photo'? this + ':orig': '', permalink);
					});
				}else{
					_append(media_url + '',  type=='photo'? media_url + ':orig': '', permalink);
				}
				return true;
			}
			return false;
		}

大きな画像やTwitterサーバー以外に置かれているメディアのことは考えていないので、タイムラインの幅にフィットさせるには上のCustom.cssの最大サイズを適宜書き換える必要がある。タイムラインの最小幅が300pxくらいだとすると、サムネイルの幅は250pxくらいになる(Developer Toolsを使えば厳密に測定できる)。

Janetter001
サムネイル画像サイズ変更後。「:thumb」サフィックスを解除してあるため画像全体が表示される。CSSで最大サイズを255×1024pxに設定してあるためサムネイルは縦に並ぶ。

「:thumb」サフィックスを解除し、Custom.cssを調整すると右の画像のようになる。1件のツイートが縦長になってスクロールするのが大変になる傾向にあるけど、未読のツイートをあまり時間をかけずに一気に閲覧していきたい時にはクリックの回数を減らせて便利。

流し読みをすると当然細かい見落としは多くなるけど、Twitter公式のウェブ・クライアントでは「1000件の新着ツイート」と表示されていても取得できるツイート数に上限があり、1000件全部を読むことはできない。寝る前に最後に見た時点のタイムラインに遡行するのも難しい。Janetterではそういう心配がない。

その代わりに、大量の未読ツイートに埋もれることにもなるけど、とにかく寝ている間や他の作業に集中している間の時系列がちゃんとつながっているだけでも大事な告知などの決定的な見落としがなくなって気分的にはだいぶ違う。

ただ、Twitterの本家は「Twitterカード」や「アンケート(投票)」など新しい機能を次々に実装しつつあるため、Janetter(この記事を書いている時点でWindows版はVer. 4.3.1.0)が徐々に旧式化しているのは事実。奇特な方が新機能に対応するプラグインを作ってくれるか、Janetterのバージョンアップを気長に待つしかない。

関連記事

参考記事

MediaWikiの見出しをサンセリフ・フォントに戻す

最終更新:2016/09/06

最近のトピックではないんだけど、2014年4月頃にリリースされたMediaWiki 1.22.5以降からCSSが見直され、記事見出し(見出しレベル1)と見出しレベル2のフォントがサンセリフ・フォント(ゴシック体)からセリフ・フォント(明朝体)に一律に変更された。

MediaWiki公式サイトではTypography refreshという記事でどういった経緯や理由でフォントを変更することになったのか説明されている。元に戻す方策を示してくれているわけではないので、無理して全部読む必要はまったくなく、要は「とにかく見出しをセリフ・フォントに変えたよ」ということを伝える記事に過ぎない。

ラテン文字を主に使用する英語圏の人にとってはある程度説得力のある話なんだろうけど、日本語のように全角文字と半角文字を混ぜて書くことがある言語では問題になることがある。また、元は海外製のInternet Explorerをはじめとするブラウザに潜在的な不具合があって、日本語では通常使われない文字が表示されたりする問題などがウィキペディア日本語版のプロジェクトで指摘された。ラテン文字を主流とする他言語の人から見たら判別不能な『漢字』という特殊な文字を使っている日本語と韓国語(朝鮮語)と中国語がごっちゃになってしまっていることが原因のようだ。詳しいことは当該議事録を参照(長文)。

色々な修正方法が検討されたんだけど、もっともシンプルな解決方法は次のようなCSSをMediaWiki:Vector.cssに追加する。Vectorスキンを標準の外装にしていない場合は、更に上位のMediaWiki:Common.cssか対応するスキンのCSSを適宜変更する。

div#content h1, div#content h2, div#content #firstHeading {
 font-family: sans-serif;
}
html, body {
 font-family: sans-serif;
}
div#content .mw-editsection {
 font-family: sans-serif;
}

ひとまず、これで標準記事名前空間と付随する名前空間の見出しはサンセリフ・フォントに戻せる。

ただ、この方法でもログインや個人設定のページといった特別ページの一部はセリフ・フォントのままになってしまう。ブラウザの要素解析機能を使ってセレクタやクラスを丹念に調べれば対処可能なんだろうけど、もっとも重要な標準記事名前空間の記事名に問題が出なければよしとして、これ以上深入りはしないことにした。


[2016年3月12日追記]

深入りしないことには決めたが、やはり気にはなるので、要素解析をやってみた。標準記事名前空間(付随する名前空間含む)と個人設定の特別ページの見出しのクラスとセレクタは同じだった。

div#content.mw-body h1#firstHeading.firstHeading

同じならばMediaWiki:Vector.cssに記述したCSSが反映されてもよさそうなものだけど、個人設定の特別ページのレベル1(h1)とレベル2(h2)の見出しに最後に適用されているスタイルは次のようなもの。これが問題になっている。

.mw-body h1,.mw-body h2 {
	font-family:"Linux Libertine",Georgia,Times,serif;
	line-height:1.3;
	margin-bottom:0.25em;
	padding:0
}

確かに、これなら見出しがセリフ・フォントになってしまう。実際、ブラウザの要素解析機能を使って font-family のプロパティを一時的に解除してみるとサンセリフ・フォントに戻る。

標準記事名前空間の見出しでも同様のスタイルが設定されているんだけど、MediaWiki:Vector.cssにサンセリフ・フォントに戻すプロパティを設定してあるので、それが読み込まれて強制的に上書きされている。ところが、個人設定の特別ページではユーザー設定のMediaWiki:Vector.cssをStyleSheetとして読み込んでいるコードが見当たらない。どのスタイルシートを呼び出して適用するか決定しているのはMediaWiki本体だから、いくらMediaWiki:Vector.cssを変更しても画面の表示に反映されないのは当たり前ということになる。

どうも、問題のスタイルはどこかのファイルにまとめて記述してあるものではなく、MediaWikiがその都度「load.php」という名前のスクリプトに引数を渡してリソース・ローダー(ResourceLoader)と呼ばれるモジュールが自動的に生成するものらしい。PHPやJavaScriptのソースコードもひととおり検索してみたけど、該当する箇所が見つからなかった。リソース・ローダーの説明もざっと読んでみたけど、確かに凄い機能を持ったモジュールなのはわかる。凄いけど、高度すぎてまったく手に負える感じがしない。仮に、どこかを改変して問題を解決できたとしても、MediaWikiがアップグレードされた時に上書きされてしまうので書き戻す手間が発生するし、最悪、誤動作して本当に手に負えなくなってしまう可能性さえある。よっぽどのことがない限りMediaWikiの本体には手を着けたくないので、個人設定の特別ページの見出しについては諦める他にない。

iPad/iPhoneでMediaWikiのロゴが英語版ウィキペディアになってしまう問題

最終更新:2016/09/06

ある時から、自分のウィキをiPadやiPhoneで表示しようとすると、MediaWikiのロゴがオリジナルのものから英語版ウィキペディアのものに変わってしまって、不思議に思っていた。PCで表示する分にはどのブラウザでも正常に表示される。しかも、iOSに標準でインストールされているSafariだけではなく、Chromeでも同じ問題が起こる。PC版のブラウザと違って要素解析ができないので、しばらく原因がわからず問題を放置していた。ところが、MediaWikiのサポートデスクの該当スレッドを注意深く読んでみると、最後のほうに#p-logoというidセレクタをもう一度確認してみよう、という一文があった。

当初は「iOSのバージョンが古いんじゃない?」とか「単純にキャッシュの問題じゃないの?」といった回答が多かったので、そういうものなんだろうかと思って最後まで読んでなかった。

原因は、ウィキペディア風の外観にするためのMediaWiki:Common.cssをコピーして移設したことにあった。最後のほうに、モバイル端末向けの表示用に次のようなCSSが記述されている。確かに、英語版ウィキペディアのロゴ・ファイルをダイレクトで呼び出しているので、iPadやiPhoneでロゴが変わってしまうのは当然だった。

/* [[MediaZilla:35337]] */
@media (-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (min-resolution: 1.5dppx) {
        #p-logo a {
                background-image: url("//upload.wikimedia.org/wikipedia/commons/thumb/b/b3/Wikipedia-logo-v2-en.svg/204px-Wikipedia-logo-v2-en.svg.png") !important;
                background-size: 136px auto;
        }
}
@media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (min-resolution: 2dppx) {
        #p-logo a {
                background-image: url("//upload.wikimedia.org/wikipedia/commons/thumb/b/b3/Wikipedia-logo-v2-en.svg/270px-Wikipedia-logo-v2-en.svg.png") !important;
                background-size: 135px auto;
        }
}

ウィキペディアのロゴはウィキメディア財団が著作権を持っているので、まったく無名のウィキだけど、このまま放置しておくのは賢明ではない。これを、次のように書き換える。

/* [[MediaZilla:35337]] */
@media (-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (min-resolution: 1.5dppx) {
        #p-logo a {
                background-image: url("//[domain]/[wiki-directory]/images/b/bc/Wiki.png") !important;
                background-size: 136px auto;
        }
}
@media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (min-resolution: 2dppx) {
        #p-logo a {
                background-image: url("//[domain]/[wiki-directory]/images/b/bc/Wiki.png") !important;
                background-size: 135px auto;
        }
}

~/images/b/bc/ というディレクトリは、ウィキにファイルをアップロードするとMediaWikiが自動的に生成するもので、画像などの格納に使うもの。各自の環境によって異なるので、目的の画像を自分のウィキで表示させた上で右クリックしてURLを確認する。管理者権限を有するユーザーが削除しない限り、新しいバージョンのファイルをアップロードしても過去のバージョンは残るため、URLが一意に定まることを利用する。

このように指定しておけば、ロゴを変更したくなった時は、FTP転送ではなく、ウィキからHTTP経由でアップロードしてデータベースを書き換えてやることで簡単に対応できるし、将来MediaWikiがバージョンアップした際にアップグレードした場合でもロゴのファイルを上書きされなくて済む。MediaWiki:Common.cssはそもそもデータベース上に存在するものなので、MediaWikiのソフトウェアのアップグレードには直接影響を受けない。

MediaWikiのインストール手順

最終更新:2016/09/06

現在、このWordPressのブログも含めて、さくらのレンタルサーバを使っているけど、せっかく最大容量が増えて30GBから100GBになったのに、1GBにも満たないほどしか使っていない。月額500円とは言っても少々もったいない気もする。

WordPressには数えきれないほどのプラグインやテーマがあってカスタマイズに自由度があるのが長所。ブログやCMSとしては十分なんだけど、HTMLの文法に制限されるためリンクや段落わけが気軽にできず、ひとつの題材を持った作品やデータベースを少しずつ育てていくという使い方にはあまり向いていないような気がする(あくまでも個人的な感想)。ついつい備忘録的なブログ記事を書いてしまっているのが現状。

そこで、少々敷居は高いけど、ウィキ文法が確立していて記事を編集しやすいウィキペディアで使用されているMediaWikiを導入してみることにした。MicrosoftのWebMatrix3を使用してローカルホストで実験してみた限りではそれほど難しくはなさそうだった。もちろん、ここにわざわざ備忘録を残すくらいなので、設定を半自動的にやってくれるWebMatrix3とは異なり、いくつかハードルにぶかったことは言うまでもない。

インストール要件

MediaWikiは、WordPressと同様に、ホスト側にPHPとSQLデータベースが動作する環境がなければならない。MediaWiki 1.20からPHP 5.3.2以上が必要となったため、WordPressの要件に合わせてPHP 5.2.17を使っている場合は注意が必要。さくらのサーバコントロールパネルの「PHPのバージョン選択」で簡単に変更できる。今回は、PHP 5.4.26に変更した。なお、同じサーバに同居しているWordPressには影響なかった。

データベース作成

いつも使っているウェブブラウザでさくらのサーバコントロールパネルにログインし、「データベースの設定」からデータベースを新規作成する。

既にデータベースを使用している場合は、データベース名を入力して文字コードを選択するだけで設定は終わる。まだデータベースをひとつも作っていない場合は、データベースユーザー名(普通は初期アカウント名)とデータベース接続パスワードを設定する。サーバコントロールパネルにログインするパスワードとは独立しているので、忘れないように記録しておく。文字コードは必ず「UTF-8」を選択する。MediaWikiの初期設定時に使うため、ホスト名も記録しておく。

MediaWikiソフトウェアのアップロード

MediaWikiの公式サイトからmediawiki-1.22.4.tar.gz(2014年3月26日現在)をダウンロードし、ローカルPCの適当なフォルダに解凍する。一般に普及しているFTPクライアント・ソフトウェアで/home/[user-name]/www/以下に作ったMediaWiki用のディレクトリにアップロードする。ディレクトリ名はなんでもいいけど、初期設定が済んでしまうと容易に変更できなくなるので、後で変更するつもりなら今のうちに。ここでは、ディレクトリ名を仮に[wiki-directory]とする。

ちなみに、ついつい使ってしまいそうな/wikiという名前のディレクトリはショートURLのために予約されているので、ショートURLを使うつもりであれば、使ってはいけない。なお、さくらのレンタルサーバーではショートURLを利用できる。詳しくは、MediaWikiでショートURLを使うを参照。

ここで一点だけ注意。それは、FTPクライアントの「アップロード時にファイル名をすべて小文字(大文字)にする」という設定をオフにするということ。MediaWikiのファイルには大文字・小文字を併用しているものがかなりある。MediaWikiの公式サイトのインストールガイドにも太字で Make sure the “Change file names to lowercase” option for upload is disabled. と書いてあるんだけど、リネームするのが面倒で普段は自分のWEBページを更新する時には小文字にしてアップロードするのが当たり前になっていたため、すっかり忘れていた。そのために初期設定からいきなり動かず、2700個くらいあるファイルのアップロードをやり直す羽目に。気をつけましょう。

MediaWikiの初期設定

ブラウザからhttp://[domain]/[wiki-directory]/index.phpにアクセス。インストール要件を満たしているかチェックされ、主にPHPのバージョンが要件に達していない場合は設定を見直して再度アクセスするように促される。要件を満たしていれば、次の図のように「set up the wiki」と表示されるので、それをクリックし、あとは画面の指示に従って入力する。あくまでも例示なので、設定の細部はお好みで。
MediaWiki-1.22.4

言語

あなたの言語 日本語
ウィキの言語 日本語
MediaWikiのインターフェースに使用する言語。

データベースに接続

データベースの種類 MySQL
データベースのホスト 記録しておいたデータベースのホスト名。
データベース名 記録しておいたデータベース名。
データベーステーブルの接頭辞 他のデータベースと識別するためのプリフィックス。MediaWiki専用にデータベースを作った場合は未入力でもいいけど、後で変更するのは手間なので、できればそういうものだと思って入力しておいたほうが無難。後でわかったことだけど、さくらのレンタルサーバーでは独立したデータベースを複数作ることができるので、プリフィックスを入力しなくてもまったく問題ない。
データベースのユーザー名 記録しておいたデータベースユーザー名。
データベースのパスワード 記録しておいたデータベースパスワード。

データベースの設定

ウェブアクセスのためのデータベースアカウント チェックボックスにチェック☑しておく。
ストレージエンジン InnoDB
データベースの文字セット バイナリ
データベースの文字セットをUTF-8にしたのだからUTF-8なのかと思ったら説明書きを読むとバイナリのほうが良さそう。

名前

ウィキ名 これから作成するWikiの名前($wgSitename)。
プロジェクト名前空間 標準記事名前空間と区別してプロジェクト上のメタな事柄を書くための名前空間の接頭辞($wgMetaNamespace)。ウィキペディアなら「Wikipedia:~」がそれにあたる。例えば、Wikipedia:著作権はウィキペディア上での著作権の取り扱いなどを書き、標準名前空間の著作権は「著作権とは何か」を書くための記事。
管理アカウント名前 Wikiにログインして管理するためのアカウント名。最初のユーザーでもある。
パスワード 上記アカウントのパスワード。

以上で、基本的な設定は終了。「私にもっと質問してください。」をチェックして続行すると、引き続き閲覧や編集が可能なユーザーグループを設定したり、著作権などの詳細な設定ができる(機会があれば追加する)。

初期設定が完了すると、LocalSettings.phpというPHPファイルのダウンロードが自動的に始まるので、一回ローカルPCに保存して、[wiki-directory]の直下にアップロードする。

LocalSettings.phpは、DefaultSettings.php(これは変更禁止)を元に、これまで設定した基本データを反映した設定ファイル。暗号化されていないパスワードなどがそのまま書かれているので、他のユーザーに見られてしまうと困る。FTPクライアントの属性変更コマンド(chmodコマンド)で必ず属性(パーミッション)を「700」か「600」に設定して不特定多数が閲覧できないようにしておく。

ちなみに、LocalSettings.phpはいつでも変更できるため、初期設定を変更したくなった場合はUTF-8を編集できるエディタで変更して再アップロードしてブラウザをリロードすると反映される(とは言ってもデータベース関連はいじらないほうが無難だし、いじる必要はそうそう発生しない)。

起動

LocalSettings.php[wiki-directory]に存在している状態で、再び http://[domain]/[wiki-directory]/index.phpにアクセスすると普通ならばおなじみのMediaWikiのメインページが表示されるわけだけど、私はこんなエラーメッセージに阻まれた。

Fatal exception of type MWException Error

どうやら、拡張機能で適当に追加したLocalisationUpdate.phpというファイルが悪さをしているらしい(MediaWiki:当該トラブルシュートスレッド)。そこで、何をするファイルなのかはよくわからないので、ひとまず次のようにコメントアウトして、ようやく起動した。

# Enabled Extensions. Most extensions are enabled by including the base extension file here
# but check specific extension documentation for more details
# The following extensions were automatically enabled:
require_once "$IP/extensions/Cite/Cite.php";
require_once "$IP/extensions/Gadgets/Gadgets.php";
# require_once "$IP/extensions/LocalisationUpdate/LocalisationUpdate.php";
require_once "$IP/extensions/Nuke/Nuke.php";
require_once "$IP/extensions/ParserFunctions/ParserFunctions.php";
require_once "$IP/extensions/Renameuser/Renameuser.php";
require_once "$IP/extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.php";
require_once "$IP/extensions/WikiEditor/WikiEditor.php";

サイドバー

MediaWikiには主要なリンクやツールをまとめたサイドバーというものがある。WordPressのウィジェットとは比べるべくもない簡素な見た目のツール群だけど、これが一定の規則に基づいたキーワードを元にJavaScriptで自動的に生成されているらしく、/[wiki-directory]/skins/common/に格納されているすべてのスキンの根本のCSSであるcommonElements.cssを変更してもリンクの色が変わらない。生成されたソースを見てもよくわからない。

とても人力で解析できそうには思えなかったので、FireFoxの要素解析ツールを使って構造を調べてみた。<a>タグのエレメントに直に割り当ててあったリンク色も上書きしていて複雑なIDとクラスの構造になっていた。その結果を反映したものが次のCSS。これをMediaWikiのサイト上からMediaWiki:Common.cssに反映する。色はお好みで。

div#mw-panel
div.portal
div.body ul li a { color: #003BC8; }

div#mw-panel
div.portal
div.body ul li a:visited { color: #003BC8; }

名前空間

現在、日本語版の名前空間接頭辞はカタカナや漢字に訳されている。一般的にはこのほうがわかりやすいんだろうし、多言語に対応するために英語版の接頭辞も使えるようになっているけど、UTF-8のマルチバイト文字をURLにするとどこの名前空間なのかわかりにくいので私はあまり好きではない。そこで、システムメッセージは日本語のまま($wgLanguageCode = "ja";)にしておいて、名前空間の接頭辞だけを英語版仕様に戻すというワガママ仕様にすることにした。

具体的には、/[wiki-directory]/languages/messages/MessagesJa.phpというファイルを変更し、同じディレクトリにあるMessagesEn.phpから$namespaceNamesをコピーして移入する(システムに直接影響するので、下手に手動入力しないほうが無難)。日本語化されていた接頭辞も念のためエイリアス(別名)として残しておいた。

$namespaceNames = array(
	NS_MEDIA            => 'Media',
	NS_SPECIAL          => 'Special',
	NS_MAIN             => '',
	NS_TALK             => 'Talk',
	NS_USER             => 'User',
	NS_USER_TALK        => 'User_talk',
	# NS_PROJECT set by $wgMetaNamespace
	NS_PROJECT_TALK     => '$1_talk',
	NS_FILE             => 'File',
	NS_FILE_TALK        => 'File_talk',
	NS_MEDIAWIKI        => 'MediaWiki',
	NS_MEDIAWIKI_TALK   => 'MediaWiki_talk',
	NS_TEMPLATE         => 'Template',
	NS_TEMPLATE_TALK    => 'Template_talk',
	NS_HELP             => 'Help',
	NS_HELP_TALK        => 'Help_talk',
	NS_CATEGORY         => 'Category',
	NS_CATEGORY_TALK    => 'Category_talk',
);

$namespaceAliases = array(
	'ノート'               => NS_TALK,
	'利用者‐会話'         => NS_USER_TALK,
	'$1‐ノート'           => NS_PROJECT_TALK,
	'画像'                 => NS_FILE,
	'画像‐ノート'         => NS_FILE_TALK,
	'ファイル‐ノート'     => NS_FILE_TALK,
	'MediaWiki‐ノート'    => NS_MEDIAWIKI_TALK,
	'Template‐ノート'     => NS_TEMPLATE_TALK,
	'Help‐ノート'         => NS_HELP_TALK,
	'Category‐ノート'     => NS_CATEGORY_TALK,
	'メディア'             => NS_MEDIA,
	'特別'                 => NS_SPECIAL,
	'トーク'               => NS_TALK,
	'利用者'               => NS_USER,
	'利用者・トーク'       => NS_USER_TALK,
	'$1・トーク'           => NS_PROJECT_TALK,
	'ファイル'             => NS_FILE,
	'ファイル・トーク'     => NS_FILE_TALK,
	'MediaWiki'            => NS_MEDIAWIKI,
	'MediaWiki・トーク'    => NS_MEDIAWIKI_TALK,
	'テンプレート'         => NS_TEMPLATE,
	'テンプレート・トーク' => NS_TEMPLATE_TALK,
	'ヘルプ'               => NS_HELP,
	'ヘルプ・トーク'       => NS_HELP_TALK,
	'カテゴリ'             => NS_CATEGORY,
	'カテゴリ・トーク'     => NS_CATEGORY_TALK
);

参考記事