0

WordPress Related Posts Pluginインストール

このblog(wordpress)で使っているinoveテーマをアップデートしたので、LDRize/AutoPagerizeが動くようにするためにmicroformatsを埋め込んだりやってたらwp23_related_postsというプラグインがあるか判定をしている箇所があった。

調べてみた。発見した。記事のtagで類似度を判定して似た記事のリストを返すプラグインだった。
たぶん本文は解析してない。


インストールしよう

cd wp-content/plugins
wget http://downloads.wordpress.org/plugin/wordpress-23-related-posts-plugin.1.0.zip
unzip wordpress-23-related-posts-plugin.1.0.zip
rm wordpress-23-related-posts-plugin.1.0.zip

wordpressの管理画面からpluginを有効化すると、設定タブの下の方にWordPress Related Postsという設定項目が現れる。
表示する記事数などが設定できる。
inoveテーマではwp23_related_postsがあるか確認して表示しているけど、設定画面から記事の下に自動的に挿入するというオプションもある。

if(function_exists('wp23_related_posts')) {
  wp23_related_posts();
}

0

google-code-prettifyをインストール

google-code-prettify – Project Hosting on Google Code

wget http://google-code-prettify.googlecode.com/files/prettify-21-May-2009.zip
unzip prettify-21-May-2009.zip

srcとtestsのディレクトリが解凍されたので、httpで見える場所に置く
mkdir ~/www/shokai.org/js
cp -R src/ ~/www/shokai.org/js/pre

inoveテーマを使っているので、 wp-content/themes/inove/header.php を編集
headの中に
  <script type="text/javascript" src="http://shokai.org/js/pre/prettify.js"></script>
<link rel="stylesheet" type="text/css" href="http://shokai.org/js/pre/prettify.css" />

bodyタグを修正
  <body onload="prettyPrint()">

これでpreやcodeタグでclass=”prettyprint”すれば色が付く

さすがに>や<は&gt;と&lt;に置換しないとならんかった
line-heightが広くなりすぎたのでcssで修正

c++テスト
#include "cv.h"
#include "highgui.h"
#include <boost/program_options.hpp>
#include <iostream>
using namespace boost;
using namespace std;

int main(int argc, char* argv[]) {
program_options::options_description opts("options");
opts.add_options()
("help,h", "ヘルプを表示")
("cascade,c", program_options::value<string>(), "haarcascade設定ファイル")
("input,i", program_options::value<string>(), "入力画像ファイル名")
("output,o", program_options::value<string>(), "出力ファイル名")
("preview,p", "プレビュー表示");
program_options::variables_map argmap;
program_options::store(parse_command_line(argc, argv, opts), argmap);
program_options::notify(argmap);
if (argmap.count("help") || !argmap.count("cascade") || !argmap.count("input")) {
cerr << "cascadeとinputが必要です" << endl;
cerr << opts << endl;
return 1;
}

CvHaarClassifierCascade *cascade;
cascade = (CvHaarClassifierCascade*)cvLoad(argmap["cascade"].as<string>().c_str(), 0, 0, 0);
if(!cascade){
cerr << "error! Cascade not Found" << endl;
return -1;
}

IplImage *image = cvLoadImage(argmap["input"].as<string>().c_str());
if(!image){
cerr << "error! Image File not Found" << endl;
return -11;
}

CvMemStorage *storage = 0;
storage = cvCreateMemStorage(0);
CvSeq* faces = cvHaarDetectObjects(image, cascade, storage,
1.1, 2, CV_HAAR_DO_CANNY_PRUNING,
cvSize(30, 30));

bool isOutput = (argmap.count("preview")||argmap.count("output"));
for(int i = 0; i < faces->total; i++){
CvRect *rect = (CvRect*)cvGetSeqElem(faces, i);
cout << "x:" << rect->x << ", y:" << rect->y
<< ", width:" << rect->width << ", height:" << rect->height << endl;
if(isOutput){
CvPoint center;
center.x = rect->x + rect->width/2.0;
center.y = rect->y + rect->height/2.0;
int r = (rect->width + rect->height)/4.0;
cvCircle(image, center, r, CV_RGB(255, 0, 0), 2, CV_AA, 0);
}
}

if(argmap.count("output")){
string out_filename = argmap["output"].as<string>();
cout << "save! " << out_filename << endl;
cvSaveImage(out_filename.c_str(), image);
}

if(argmap.count("preview")){
char winName[] = "haarcascade test";
cvNamedWindow(winName, CV_WINDOW_AUTOSIZE);
cvShowImage(winName, image);
while (1) {
if (cvWaitKey(1) == 'q') break;
}
cvDestroyWindow(winName);
}

cvReleaseImage(&image);
return 0;
}


rubyテスト
#!/usr/bin/env ruby
require 'rubygems'
require 'active_record'
require 'feed-normalizer'
require 'open-uri'
require 'kconv'
require 'yaml'
require File.dirname(__FILE__) + "/model_post.rb"

config = YAML::load open(File.dirname(__FILE__)+'/config.yaml')

user = config["usernum"] # twitterID
if user == nil
puts 'Error!: usernum not Found on config.yaml'
exit(1)
end

ActiveRecord::Base.establish_connection(
:adapter => 'sqlite3',
#:dbfile => ':memory:',
:dbfile => File.dirname(__FILE__) + '/db',
:timeout => 30000
)

last = 10
last = ARGV[0].to_i if ARGV[0].to_i > 0
first = 1
first = ARGV[1].to_i if ARGV[1].to_i > 0

errors = Array.new
for page in first..last
uri = "http://twitter.com/statuses/user_timeline/#{user}.atom?page=#{page}"
begin
if(config["user"] != nil && config["pass"] != nil)
feed = FeedNormalizer::FeedNormalizer.parse open(uri, :http_basic_authentication => [config["user"], config["pass"]])
else
feed = FeedNormalizer::FeedNormalizer.parse open(uri)
end

rescue
puts "feed fetch error! page:#{page}"
errors.push(page)
sleep 10
next
end

puts uri
feed.entries.each{ |e|
if Post.find_by_uri(e.url) == nil
post = Post.create(:uri => e.url,
:message => e.content.gsub(/&#(?:(\d*?)|(?:[xX]([0-9a-fA-F]{4})));/) { [$1.nil? ? $2.to_i(16) : $1.to_i].pack('U') },
:time => e.last_updated
)
puts post
end
}
puts "-----page:#{page} (#{first}-#{last}) finished-----"
sleep 10 if page < last
end

if errors.size > 0
print "feed fetch error at page:"
puts errors.join(' ')
end


jsテスト
var radio = new Object();
radio.id = 1;
radio.channel = 15;

var led = new Object();
led.pin = 7;
led.state = false;
pinMode(led.pin, true); // 出力設定

nodes = new Array(16);
for(i = 1; i < nodes.length; i++){
nodes[i] = new Node(i);
}

radioInit(0xDEAD, radio.id, radio.channel, 31);
serialInit(9600);

for(i = 0; i < 6; i++){
pinMode(i, true); // pull-up
}


function Node(id){ // Node型
this.id = id;
this.led = true;
}

function loop() {
for(i = 0; i < 6; i++){
if(serialAvailable()){
recv = serialRead();
serial_parse(recv);
}
if(digitalRead(i)){
id = i+6;
node = nodes[id];
digitalWrite(led.pin, led.state = !led.state);
request = "id:" + node.id + ",led:";
if(node.led) request += "1";
else request += "0";
radioSend(0xFFFF, request);
serialSend(request+"\r\n");
sleep(50);
}
}
}

function serial_parse(data){
for(i = 0; i < data.length; i++){
c = data.charAt(i);
switch(c){
case "a":
nodes[6].led = false;
break;
case "b":
nodes[7].led = false;
break;
case "c":
nodes[8].led = false;
break;
case "d":
nodes[9].led = false;
break;
case "e":
nodes[10].led = false;
break;
case "f":
nodes[11].led = false;
break;
case "A":
nodes[6].led = true;
break;
case "B":
nodes[7].led = true;
break;
case "C":
nodes[8].led = true;
break;
case "D":
nodes[9].led = true;
break;
case "E":
nodes[10].led = true;
break;
case "F":
nodes[11].led = true;
break;
}
}
}

function sleep(count){
for(var i = 0; i < count*10; i++){
}
}

while(true){
loop();
}

function pinMode(pin_id, mode){
}

function digitalWrite(pin_id, state){
}

function digitalRead(pin_id){
}

function analogWrite(pin_id){
}

function analogRead(pin_id){
}

function soundWrite(value){
}

function radioInit(panID, deviceID, channel){
}

function radioConnect(){
}

function radioSend(){
}


function radioClose(){
}

function serialInit(baudRate){
}

function serialAvailable(){
}

function serialRead(){
}

function serialSend(message){
}

function debug(message){
}

0

AutoPagerize/LDRizeのmicroformatsを埋め込んだ

wedataにSITEINFOを書くのではなく、wordpress2.7.1のHTMLにmicroformats埋め込んで設定した。
これでインデックスページタグページなどで無限スクロールでjjjjkpjjpjpjkjpoできる

たいへん参考になった:
mixi Engineers’ Blog ? Find Job !がAutoPagerizeとLDRizeに対応


HTMLってひとつのtagに複数classを設定する時は、スペース区切りで列挙できるんですね

■LDRize対応
wp-content/theme/テーマ個別ディレクトリ/ 以下の記事に関わるファイル全部修正し、jk移動に関わる情報を埋め込む

  • 記事1つのコンテナタグに class=”hentry” → スクロールする区切りになる
  • 記事タイトルに class=”entry-title” → pした時に右下に記事タイトルがたまる
  • 記事permalinkに rel=”bookmark” → vやoした時に開くリンク


■AutoPagerize対応
wordpressの関数を修正する。次のページへのリンク要素を指定しておくと、自動で継ぎ足してくれる
参考:WordPress サイトの AutoPagerize 対応 – JACO-BASS
wp-includes/link-template.php を編集
  • function get_previous_posts_link
  • function get_next_posts_link
の最後でreturnしてるaタグ内にそれぞれ rel=”prev”とrel=”next” を追加

autopagerizeの場合、prevはいらないか

pageElementとinsertBeforeは書かなくてもinoveテーマだと動いた


LDRizeのほうはテーマに書けたからいいけど、AutoPagerizeはwordpress本体の関数を修正してるので本体アップデートでリセットされそう。毎回手動で書き直すしかない。

0

wordpress 2.7へアップグレード

日本語版も出ていたのでアップグレードした。
さくらインターネットスタンダードプランなのでshellでやる

参考:WordPress のアップグレード – WordPress Codex 日本語版

プラグイン全停止してから

mkdir ~/tmp
cd ~/tmp
wget http://ja.wordpress.org/wordpress-2.7-ja.zip
unzip wordpress-2.7-ja.zip
cp -R ~/www/blog/ ~/tmp/blog-backup
rm -rf ~/www/blog/wp-admin/
rm -rf ~/www/blog/wp-includes/
cp -R ~/tmp/wordpress/ ~/www/blog/

一応バックアップして、wp-admin, wp-includeを削除してから上書き。
wp-adminにアクセスするとDBがupdateされる。
プラグインを有効化。Akismet, brBrbr, Ktai Entry, WP Multibyte Patch, WPtouch iPhone Theme

テーマエディタで、タイトルが「記事名 blog名」になってるのが気に入らないので「blog名 記事名」に直す
header.phpを

<title><?php bloginfo(‘name’); ?><?php wp_title(); ?></title>



しばらく様子みてから

rm -rf ~/tmp/blog-backup

1

MT3.2からWordPress2.6に移行した時の不具合をWWW::Mechanizeで修正

今年の春にSFCで動かしていたMovableType3.2が調子悪くなって、さくらに置いたWordPressに移行したわけだけど(さくらレンタルサーバ+wordpressにしてみた
その時に過去ページのいくつかが見えなくなる不具合があった。んで今朝からそれを解消するスクリプトを動かしている。今1000件目あたり。昼過ぎには完了するはず。

どういう不具合かというと、wordpressにログインしていない人がアクセスしたページは404ステータスになる。apacheが吐く404ではなくwordpressが吐く404で、「エラー 404 – 見つかりませんでした」と出る。ログインしていると普通に記事を見る事が出来る。
このせいで、俺は見れているのにURLを送ると「記事がないですよ」とみんなに言われて、原因を特定するのに時間がかかった。

そしてその修正方法だが、単に個別記事編集画面で「保存」を押すだけでその記事は復活した。なぜだかわからない。
さくらのコントロールパネルからMySQLのテーブルを見ても、どのテーブルが悪さしているのかよく分からなかったのでRubyのWWW::Mechanizeを使って全ページ「保存」ボタンを押しなおす事にした。

WWW::Mechanizeはログインフォームにパスワードを入れたり、UserAgentを偽装してwebページにアクセスしたりできる非常に有用なモジュール。Perlでは使った事あったけどRubyでは今回が初。

参考




必要なものをインストール

sudo gem install mechanize hpricot



普通にwp-login.phpからログインしてdashboardへ行き、cookieを持った状態で各記事個別ページへ移動して保存ボタンを押していく。記事個別ページが連番で助かった。あと自分のサーバをいじめたくないのでsleepは長めにしてある

shokai-blogfix.rb として保存

#!/usr/bin/env ruby
require ‘rubygems’
require ‘kconv’
require ‘mechanize’
require ‘pp’
user = “username”
pass = “password”

puts ‘start’

agent = WWW::Mechanize.new
page = agent.get(“http://shokai.org/blog/wp-login.php”)
login_form = page.forms_with(“loginform”).first
login_form.log = user
login_form.pwd = pass
dashboard = agent.submit(login_form)

puts “login: ” + dashboard.title

# 各ページ処理
for i in 1..1558
  sleep 10
  begin
    page = agent.get(“http://shokai.org/blog/wp-admin/post.php?action=edit&post=#{i}”)
    post_form = page.forms_with(“post”).first
    page = agent.submit(post_form)

    puts i.to_s+”success!” if page.body =~ /投稿が更新されました/
  rescue
    puts i.to_s+”error”
  end
end

puts ‘–finished–‘

パスワードなどは適宜変更。
URLもハードコーディングしている。1回しか使わないスクリプトだし