HTML5のVideoプレイヤーとFlashのビデオプレイヤーを併用し、いろいろな環境に合わせて動画再生を行える非常に便利なスクリプト「Video-js」。

私も多々利用させて頂いて居るのですが、ここにきてタイトル通りのバグ「ループ再生の2回目以降で、再生ボタンが表示されっぱなしになる」に遭遇し、解決したのでその方法を記載します。

まず、バグが発生する環境は下記の通り。

  • Video-jsのFlashプレイヤーで再生をしている
  • autoplayオプションをON
  • loopオプションをON
  • controlsオプションをON

HTML5のプレイヤーでも発生するかは未検証です。

原因

Video.jsでは動画の再生・停止などに合わせイベントを発行しており、内部の動作についてもそのイベントに依存して制御を行っているようです。

今回の問題はループ再生の場合にのみ発生するのですが、その発生機序としては下記のようなものでした。

  1. 1回目の動画再生が開始:playイベントが発生
  2. playコールバックの処理(1):「再生ボタン」が「display:none」になる
  3. 1回目の動画再生が終了:endedイベントが発生
  4. endedコールバックの処理(1):「ループ再生なら、再度最初から再生」という処理が実行される
  5. 2回目の動画再生が開始:playイベントが発生
  6. playコールバックの処理(1):「再生ボタン」が「display:none」になる
  7. endedイベントに登録された2つめ以降のコールバックが発生
  8. endedコールバックの処理(2):「再生ボタン」を再表示させる

要はコールバックの登録の順番が悪いというもので、endedイベントの最初のコールバックで再生処理を行ってしまっているものだから、endedイベントに登録された2個目以降のコールバックが、なぜかplayイベントの次に実行されるという訳のわからない状態に。

というわけで、このあたりのコードをさくっと修正すればバグも解消します。

コード修正

video.js(version 3.2.0現在)の926行目付近:

  init: function(player, options){
    this._super(player, options);

    player.addEvent("play", _V_.proxy(this, this.hide));
    player.addEvent("ended", _V_.proxy(this, this.show));
  },

下記のように改善します。

  init: function(player, options){
    this._super(player, options);

    player.addEvent("play", _V_.proxy(this, this.hide));
    
    if (!player.options.loop) {
      player.addEvent("ended", _V_.proxy(this, this.show));
    }
  },

要は「ループ指定がされていない場合のみ、再生終了時にボタンを再表示してねん」という処理に変更をかけます。

これで晴れて2回目以降の再生でも、再生ボタンがしっかり消えたままになります。

WordPressを複数のユーザーで運営しているとき、投稿やメディアに関しては自分以外が投稿したものも、標準で表示されるようになっています。

特にメディア関してはフィルタをするような項目がなく、自分が投稿したもののみを表示するような仕組みが用意されていません。

そのため、自分が投稿した画像を他人に利用されてしまったり、逆のこともできたりと、少々お粗末な管理になってしまっています。

フィルターフックを使って表示を制限

WordPressではWP_Queryクラスを利用して、一覧や詳細画面を表示する際にデータベースから投稿を取得してきます。

そこで、WP_Queryクラスが投稿を取得する前に、今現在ログインしているユーザーの投稿やメディアのみを取得するようにクエリを書き換える事で、上記のような問題を解決することができます。

下記のコードをfunctions.php等に記述してください。

function my_pre_get_posts_filter(&$wp_query)
{
	global $pagenow;
	$user = wp_get_current_user();

	if (WP_ADMIN && ($post_type = $wp_query->get('post_type'))) {
		if (in_array($pagenow, array('media-upload.php', 'upload.php')) && $post_type == 'attachment') {
			// メディアの表示情報を制限
			$wp_query->set('author', $user->ID);
		}
	}
}

add_action('pre_get_posts', 'my_pre_get_posts_filter', 10, 1);

管理画面で表示しているかどうかの条件判断についてはもっと良い方法があるかと思うんですが、とりあえず上記コードで問題無く動作しています。

WordPress等を利用している場合に、コメントシステムとして大変人気のあるDISQUSというコメントシステムがあります。

詳しくは下記のサイトなどをご覧頂くとして、このDISQUSはPC向けだけでは無く、スマートフォンなどでも表示できるモバイルテーマが標準で附属しています。

しかしこのモバイルテーマ、なぜかPC向けと違い、FacebookやTwitterでログインする機能が省略されてしまっています。

かといってPC版のインターフェースをスマートフォンで利用しようとすると、コメント部分は普通に利用できるものの、ログインウィンドウが画面からはみ出してしまい、相当解像度の高いスマートフォンではないとログインに支障がでてしまいます。

スマートフォン向け対応できるCSSを書いた

DISQUSはAPIの管理画面から、独自にCSSを適用することが可能です。

そこで、PC向けのログインウィンドウをスマートフォンで見た際にも、綺麗に画面内に収まるようカスタムCSSを作成してみました。

CONTINUE READING

WordPressのマルチサイトを利用して子ブログを作った場合、
子ブログでアップロードしたメディアファイルは、
全て /wp-content/blogs.dir/{blog_id}/{year}/{month}/{file_name} に保存されるようになっています。

しかしながら、実際にアップロードしたファイルのURLを取得すると、
/{account_name}/files/{year}/{month}/{file_name} というURLが帰ってきます。
これは、マルチサイト用の .htaccess にURLの書き換え処理が記載されているためです。

# uploaded files
RewriteRule ^([_0-9a-zA-Z-]+/)?files/(.+) wp-includes/ms-files.php?file=$2 [L]

このURLに直接アクセスすればファイルは表示されますし、通常の利用上では全く問題はありません。

しかしながら、サムネイルを生成する際に非常に便利なライブラリである TimThumbなどを利用する際に、この書き換えられたURLが問題になります。

TimThumbは、与えられたURLから実際のファイルパスを計算し、ファイルを読み込もうとします。

しかし、この与えられたURLは .htaccess により書き換えられたダミーのURLのため、実際にこの場所にはファイルは存在しません。

そのため、書き換えられる前のURLが必要になります。

関数作った

下記のような関数を作ってみました。

function ms_calc_media_url($blog_id, $media_url)
{
	global $wpdb;

	switch_to_blog($wpdb->siteid);
	$url = preg_replace('|^' . get_blog_option($blog_id, 'siteurl') . '/(files/[\d]{4}/[\d]{2}/.+)$|', get_bloginfo('url') . '/wp-content/blogs.dir/' . $blog_id . '/$1', $media_url);
	restore_current_blog();

	return $url;
}

$blog_id に当該のファイルをアップロードした子ブログのIDを指定して、$media_url にファイルのURLを与えれば、書き換えられる前のURLを計算して出力します。

この関数を使うことで、問題無くTimThumbなどのライブラリを活用できます。

WordPressをマルチブログで利用する場合に、子サイトのテーマをあらかじめ設定しておく方法を紹介します。

親サイトの functions.php に下記の記述をするだけです。

function default_theme_setting()
{
	update_option('template', 'theme_name');
	update_option('stylesheet', 'theme_name');
	update_option('current_theme', 'Theme Name');
}

add_action('populate_options', 'default_theme_setting');

theme_name となっている箇所は、テーマのディレクトリ名を入れます。
Theme Name となっている箇所は、テーマの名称を入れておきます。

子テーマを指定する方法

上記の設定で、あるテーマの子テーマを設定しようとすると上手くいきません。
これは、下記の記述にすることで対応可能です。

function default_theme_setting()
{
	update_option('template', 'parent_theme_name');
	update_option('stylesheet', 'child_theme_name');
	update_option('current_theme', 'Child Theme Name');
}

add_action('populate_options', 'default_theme_setting');

parent_theme_name は親テーマのディレクトリ名を入れます。
child_theme_name は子テーマのディレクトリ名を入れます。

要は stylesheet というオプションに子テーマ名を設定し、template というオプションには親テーマを設定しておかなきゃイカンよ、ということです。