twitterでHTML実体参照を入力したら不思議だった。

別にどうでもいいことなんですけど、どうでもよくないかも知れないけど。笑

Twitter で、  を入力したらスペースに変換(正確には、そのまま。笑)されて表示されているのを発見して、ほんのちょっとだけ試して見ました。

入力したテキストは以下。

&yen; とか < とか &raquo とか &nbsp; とかエスケープされてない?

以下はtwitter for Macでの入力結果。

そして、以下の画像は twitter.com 上での表示。

で以下はtwitter api経由での表示。

¥ とか < とか » とか   とかエスケープされてない?

というわけで、よくわかんないけど、HTML実体参照がエスケープされないということを発見。

リスクがあるのか無いのかは、忙しくて調べる余裕が無いのでだれか教えてください。

instagramのパーマリンクからユーザーIDやJSONのURLを取得する。

最近、遅ればせながらinstagram がお気に入りなのですが、この写真のギャラリーとして表示するためのWordPressプラグインをつくろうかなーっと思ってます。

しかし、instagramのAPIを取得するには、メールフォームで問い合わせが必要そうなので、プラグイン作って配布ってのはムリかな?と思ってました。

http://instagram.com/developer/

しかし、サードパーティーのAPIを使えば、そのユーザーが投稿した写真の情報などをJSONデータで取得できることがわかりました。

なんの会社かよくわかりませんが、エライ!

http://www.heroku.com/

ただし、このJSONデータを取得するには、instagramのユーザーIDを取得する必要があるのですが、これはパーマリンクのURLからHTMLを取得してDOMを掘って…という処理が必要です。

というわけで、これらを処理するPHPのクラスを作りました。

このクラスの使い方は以下のような感じです。

$ins = new instagram();

$uid = $ins->getUID($url); // User ID
var_dump($ins->getJsonURI($uid)); // JSON URL
var_dump($ins->getAtomURI($uid)); // Atom URL

あとは、このJSONを feile_get_contents() などでとってきて、json_decode() しでギャラリーを生成みたいな感じです。

WordPressプラグインはおいおい作ります。

保存の際にfacebookのクローラーを再度お招きするWordPressプラグイン

Facebookではlikeボタンをクリックした時などにクローラーが攻めこんできてコンテンツをキャッシュします。

そのため、タイトルなどを後から修正しても、修正結果が反映されません。

しかし、Facebook謹製のURLリンターというツールでURLを送信するとクローラーがもう一度来てくれて、キャッシュを再生成してくれます。

そこで、WordPressのsave_postでフックして、URLリンターにURLを送信するプラグインを作りました。

  • 単なる手抜きですが、URL送信の成否に関する評価は一切しておりませんので、あしからず。
  • facebookのドキュメントではURLの末尾にformat=jsonとありますが実際のレスポンスはhtmlです。

WordPressのWP-OGPが怪しい気がしてしょうがない。

この数日facebookについて勉強してるんですが、OGPについていろいろ調べてるうちにWordPressのWP-OGPプラグインが不十分というか怪しい気がするので、OGPについて私なりに調べてみたことを書きます。

ていうか、誰か詳しい人は教えてください。お願いします。

OGPについては詳しく解説しませんので、Google先生などに聞いてください。

og:type について

og:typeの値はWP-OGPプラグインでは、全てのページがarticeで固定になっているようですが、違うような気がします。

まず、投稿の場合、これはarticleでいいと思われます。一時的な情報はarticleとすべしとのことなので。

しかし、サイトのトップページでは、以下のような感じになるような気がするんですけどどうでしょう?

  • 個人的なブログの場合はblog、場合によってはwebsite。
  • 企業のCMSとしてWordPressを使用している場合には、barとかcompanyとかcafeとかhotelとか、このページのObject Typesの一覧にあるものの中から適切なものを選ぶ。

あと、固定ページの場合。

これもarticle固定ではおかしい気がします。

たとえば、このサイトではWordPressのプラグインを配布しているのですが、それらのプラグインのページでは、productとなるべきではないのかな?

プロフィールのページがもしあるならprofileとすべきじゃないかと。

なんでarticleではマズイの?

facebookのAPIでは、”イイネ”ボタンをクリックしてくれたユーザーに対して、そのページの更新をお知らせすることができるようです。(試せてません…)

しかし、ブログの記事はファンの対象にはならない一時的なものであるため、articleを指定するべきであり、articleにはこの機能が働かないそうです。

http://d.hatena.ne.jp/amachang/20110117/1295233078

なので、例えば企業サイトの製品紹介のページを更新した場合に、せっかくそれをお知らせするための素敵な仕組みがあるのに、それを使えないのは悲しくないですか?

(だからといって、なんでもかんでもarticle以外にして呼び戻し機能を使うのは、スパムって言われちゃう可能性があります。)

fb:app_id と fb:admins について

根本的にWP-OGPではfb:appidと出力されていますが、fb:app_idの間違いのようです。

あと、fb:admins と fb:ap_id はどちらか片方だけを使用するべきのような気がします。 両方でもいいみたいです。

Open Graph protocol

fb:admins or fb:app_id – A comma-separated list of either Facebook user IDs or a Facebook Platform application ID that administers this page. It is valid to include both fb:admins and fb:app_id on your page.

og:title と og:type は変更できない可能性がありますよ。

facebookの説明によると、50個以上”いいね”をゲットすると”og:title”が固定され、10,000以上”いいね”をゲットすると、og:typeは固定されるようです。
(キャッシュされて、修正しても反映されないようです。)

Open Graph protocol

You can update the attributes of your page by updating your page’s <meta> tags. Note that og:title andog:type are only editable initially – after your page receives 50 likes the title becomes fixed, and after your page receives 10,000 likes the type becomes fixed. These properties are fixed to avoid surprising users who have liked the page already. Changing the title or type tags after these limits are reached does nothing, your page retains the original title and type.

まとめ

以上、私なりに調べた結果を書いたのですが、OGPに関連するAPIとかの挙動については、わからない事だらけです。

詳しい方は、ぜひ教えてください。お願いします!

facebook向けiframeアプリの横幅や高さの設定方法

現在、WordPressをfacebookのアプリとして動作させるためのプラグインを作ってるのですが、コンテンツ部分の横幅や高さに関するメモ。

アプリのキャンバスの横幅

facebook アプリは、アプリとして登録するとiframeで外部サーバーのコンテンツを表示しています。

iframeなので、好き勝手に横幅を設定しちゃとスクロールバーが出てカッコ悪いので、CSSなどで横幅を予め合わせておく必要があります。

わかりにくいのですが、アプリは単独で開かれる場合とタブで開かれる場合があって、それぞれ最大の横幅が違います。

  • タブ経由で開かれる場合の横幅 – 520px
  • アプリ単独で開かれる場合の横幅 – 760px

アプリ側のbody要素のmarginとpaddingの調整もお忘れなく。

アプリの高さ

高さもコンテンツが縦長になると縦スクロールが出てみっともない事になってしまいますが、これはfacebookのJavaScript SDKで親ページのiframeの高さを変更するためのAPIが提供されています。

以下はAPIを使った高さ調節の例で、body要素の終了タグ直前にコピペしてください。

jQueryを使ってます。

FB.Canvas.setAutoResize() で自動的に高さが調整されるのですが、サイトによっては FB.Canvas.setSize() も紹介されていることが多いようです。

個人的には、FB.Canvas.setSize() のほうは他のJavaSCript でコンテンツ領域の高さが変わる場合に、いちいちコールする必要があったので、使いにくいと思いました。

facebookのlikeボタンとGoogle Analyticsとieのいけない関係

先日、このサイトを軽くリニューアルしました。

そのリニューアル作業の中で、ソーシャルボタンを設置しなおしたのですが、それ以来Google Analyticsが挙動不審になりました。

具体的には以下のような現象です。

  • fb_xd_fragment というクエリー文字列付きのリクエストがやたら多い。
  • 訪問別ページ数が不自然に高い。
  • 一部のページだけが飛び抜けてページビュー数が高い。

など。

正しい対処方法

これらはどうやらfacebookのいいねボタンとGoogle Analytics とIEの組み合わせで起こるバグのようです。

http://seoblog.seosearch.biz/?eid=45

微妙な対処方法

なお、この件に関しては複数のブログで記事にされているようですが、対処方法に微妙に間違いがあるものがちらほらありました。

たとえば、以下のような感じ。

http://www.myu-zin.com/webridge/archives/687.html

このページに記載されている方法ではクエリー文字列を無視するだけなので、やたらページビュー数が高いページが出てきてしまいました。

twitterの最新のツイートをfacebookに投稿する。

twitterで指定したユーザーの最新のツイートをfacebookのウォールに投稿するPHPスクリプトを作りました。

このアプリのために作りました。

ただーし、実際にこれを動かすには、

  • facebook にアプリケーション登録をする。
  • アクセストークンを取得する。

という一見簡単そうだけど、めっちゃめんどくさい手続きが必要です。

以上が完了したら、以下のスクリプトの”YOUR …”の部分を修正して Cron でぶん回してください。

twitterのユーザー名は、コマンドライン引数で渡すようになっています。

あと、require してるファイルは facebook のPHP 用の SDK です。

Cronには、以下のように渡したほうが幸せになれると思います。

*/10 * * * * export LANG=ja_JP.UTF-8; /usr/bin/php /path/to/cron.php twitter_user

facebookアプリ ”Tokyoでんき予報”

初のfacebookアプリを作りました。

Tokyoでんき予報

このアプリは東京電力の電力需要のデータを表示するアプリです。

いいねボタンをクリックしてもらえば、最新の需要データを受け取ることができます。

今後の予定

  • スマートフォンへの対応
  • ユーザー認証してサイドバーに常駐できるように
  • サーバー負荷の低減

とりあえず、facebookアプリ開発のいい練習になってくれました。

PerlでTwitterのキーワード検索&リツイート(oAuth編)

先日、twitter API の仕様が変更になって、基本認証が使えなくなった。

そのため、以下の記事のスクリプトが動かなくなった。

そこで、oAuthに対応したものをご紹介。

目的

Twitterの検索メモに登録されたキーワードのリストを取得して、タイムラインを検索し、マッチしたものを公式リツイートする。

  • 自分自身の投稿はリツイートしない。
  • RTや@が含まれる投稿はリツイートしない。
  • すでにリツイートした投稿はリツイートしない。
  • ログに保存されたIDより古い投稿はリツイートしない。

アプリケーション登録申請

oAuth認証を行うには以下の情報が必要なので、アプリケーション登録申請を行う。

  • Consumer key
  • Consumer secret
  • Access Token
  • Access Token Secret

登録申請の手順は以下のサイトが分かりやすかった。

実用! PerlでコマンドラインからTwitter投稿(OAuth対応) – perl-mongers.org

ソース

以下のような感じ。
13行目〜17行目を書き換えること。

あとは、Cron等に登録して使用する。

#!/opt/local/bin/perl -wT

#binmode(STDOUT, ":utf8");

use strict;
use Encode;
use Net::Twitter;
use URI::Escape;
use LWP::Simple;
use XML::DOM;

# Config
my $user    = ''; # Twitter のユーザー名
my $key     = ''; # Consumer key
my $secret  = ''; # Consumer secret
my $token   = ''; # Access Token
my $tsecret = ''; # Access Token Secret

my $lang         = 'ja';
my $api          = 'http://search.twitter.com/search.atom';

# do not need to edit
my $max_length      = 140;
my $home;
if (-d $ENV{'HOME'} && $ENV{'HOME'} =~ /^(\/.+)$/) {
    $home = $1;
}
my $log = $home.'/.twitbot.txt'; # 最新のIDを保存して次回以降はこのID以下は無視
if (!-e $log) {
    open (OUT, ">", $log);
    close(OUT);
}

my $max_id = 0;
open (IN, "<", $log);
my $n = <IN>;
if ($n) {
    chomp $n;
    $max_id = $n;
}
close(IN);

# connect to twitter
my $twt = Net::Twitter->new(
    traits => [qw/API::REST OAuth WrapError/],
    consumer_key    => $key,
    consumer_secret => $secret
);

$twt->access_token       ($token);
$twt->access_token_secret($tsecret);

my $sch = $twt->saved_searches();
my %posted;
my $since = $max_id;
foreach (@$sch) {
    my $k = uri_escape_utf8($_->{query});
    my $url = $api.'?show_user=true&q='.$k.'&lang='.$lang;
    my $atom = get($url);
    my $parser = new XML::DOM::Parser;
    my $doc = $parser->parse ($atom);
    my $nodes = $doc->getElementsByTagName ("entry");
    for (my $i=0; $i<$nodes->getLength; $i++) {
        my $node = $nodes->item($i);
        my $txt = getvalue($node, 'title');
        my $id = getvalue($node, 'id');
        if ($id =~ /([0-9]+)$/) {
            $id = $1;
        } else {
            die ('can not get id');
        }
        if ($max_id < $id) {
            $max_id = $id;
        }
        # 以下に該当するものはRTしない
        # 自分の投稿
        # RT(スペース)が含まれる投稿
        # @が含まれる投稿
        # すでにRTした投稿
        # ログに保存されたIDより古い投稿
        if ($txt !~ /^$twitter_user/ && $txt !~ /RT\s/ && $txt !~ /\@/ && !$posted{$id} && $since < $id) {
            $posted{$id} = 1; # 重複投稿しないためのフラグ
            eval {$twt->retweet($id)};
            if ($@) {
                warn "update failed because: ".$@."\n";
            }
        }
    }
}

open (OUT, ">", $log);
print OUT $max_id;
close(OUT);

exit;

sub getvalue {
    my $node = shift @_;
    my $tag = shift @_;
    my $n = $node->getElementsByTagName($tag)->item(0);
    return $n->getFirstChild->getNodeValue;
}

参考