月別: 2013年2月

複数のカスタムフィールドでソート

WordPressでの特殊なソート方法。

通常WordPressの記事取得は以下のような形で行えます。
以下の感じだとカスタム投稿タイプhogehogeの記事を取得してきます。

$args = array(
'post_type'      => 'hogehoge',
);
query_posts( $args );

ソート

WordPressの記事の取得はorderbyで指定した内容の並び順にする事ができます。
指定できる内容は以下の通り。

'ID' - post id 順
'author' - 投稿者順
'title' - タイトル順
'date' - 投稿日付順
'modified' - 最終更新日順
'parent' - 親記事のID順
'rand' - ランダムにする
'comment_count' - コメント数で並べ替え(バージョン 2.9 以降のみ)
'menu_order' - 記事のメニューオーダー順
'meta_value' - 指定したカスタムフィールド順
'meta_value_num' - カスタムフィールドの値を数値として扱ってソート(1と10とかのソートをちゃんとしてくれる)

記事の並びをタイトル順にしたいときは以下のようにします。

$args = array(
'post_type'      => 'hogehoge',
'orderby'        => 'title',
'order'          => 'DESC'
);
query_posts( $args );

このとき、「タイトルで並び替えた後に日付順で並び替えたい」という時はこんな感じにスペース区切りで複数指定すればOKです。

$args = array(
'post_type'      => 'hogehoge',
'orderby'        => 'title date',
'order'          => 'DESC'
);
query_posts( $args );

さらにカスタムフィールドの値でもソート可能です。meta_keyでカスタムフィールドを指定し、orderbyでmeta_valueを選択します。
以下の例だと、カスタムフィールド「地域」の値でソートを行います。

$args = array(
'post_type'      => 'hogehoge',
'meta_key'       => '地域',
'orderby'        => 'meta_value',
'order'          => 'DESC'
);
query_posts( $args );

複数のカスタムフィールドでソート

ここで記事タイトルにもある、複数のカスタムフィールドでのソート方法。
特定のWordPressで上記のことを実現する必要が出てきたので調べてみましたが、
query_postsでは複数のカスタムフィールドでソートする方法はないようです。

途方にくれてたところWordPressにはadd filterというDBや出力前に関数をフックする機能があり、
さらにプラグイン API/フィルターフック一覧にSQLクエリのORDER BYやJOINにフックさせるAPIが用意されておりこの機能を使って実現する事が出来ました。

たとえば「国」というカスタムフィールドの値でソートした後に、「町」というカスタムフィールドでソートしたい場合。

function.phpにて以下のような関数を作成します。
これは単純に動作させたいSQL文を作っているだけです。

//function.php
function custom_posts_join( $join, $query ) {
global $wpdb;
$join .= " INNER JOIN $wpdb->postmeta AS m1 ON m1.post_id = $wpdb->posts.ID AND m1.meta_key = '国'";
$join .= " INNER JOIN $wpdb->postmeta AS m2 ON m2.post_id = $wpdb->posts.ID AND m2.meta_key = '町'";
return $join;
}
function custom_posts_orderby( $orderby, $query ) {
$orderby = 'm1.meta_value ASC, m2.meta_value ASC';
return $orderby;
}

実際のテンプレート内では以下のように使用します。
add_filterやremove_filterの第一引数はフィルターフックの指定で、第二引数が上記で作成した関数を指定します。
第三引数はプライオリティで第四引数は関数が受け取る引数の数となります。

//template
add_filter( 'posts_join', 'custom_posts_join', 10, 2 );
add_filter( 'posts_orderby','custom_posts_orderby', 10, 2 );
$args = array(
'post_type'      => 'hogehoge',
);
query_posts( $args );
if(have_posts()): while(have_posts()): the_post();
~
HTMLをかいて出力させる
~
endwhile; endif;
remove_filter( 'posts_join', 'custom_posts_join', 10, 2 );
remove_filter( 'posts_orderby','custom_posts_orderby', 10, 2 );

結構実現まで時間がかかりました・・・。

(明日はバレンタインということで)イラレでハートを書いてみましょう!

明日はバレンタインデーということで、今頃メッセージカードにハートを描いてる方が多いのではないでしょうか?

イラレでハートを描くのって、案外難しかったりします。
でもコツを覚えれば、ホントは簡単!

ポイントは、「ハートを描くのではなく、ハート形の図形を作る」ということです。
今回は、丸みのある柔らかいイメージのハートを作ってみましょう。

描くのではなく、つくる

ベースとなる図形を作る

まずはベースとなる図形を作ります。
今回は、丸みのある柔らかいイメージなので、楕円形ツールを選択し、

楕円形ツールを選択

適当な大きさの正円を作ります。


それから、ダイレクト選択ツールで下側のパスを選択し、


適当なサイズに伸ばします。

これでベースとなる図形ができました。

複製して配置する

つぎは、ハートのくぼみ(こぶの部分)を作っていきます。

回転ツールを選択し
-90度回転させて複製します。
(OKボタンではなく、コピーボタンをクリック)


そして オブジェクト>変形>移動 で水平、垂直ともに同じ数値を入力し、-45度に複製移動させます。
このとき、プレビューでチェックしながら、きれいなこぶになるように調整しましょう。
今回は、5pxに移動させてみました。
(OKボタンではなく、コピーボタンをクリック)

それから、2つの図形をグループ化し、
回転ツールで45度回転させます。


やっとハートが見えてきましたね。
あとは、不要な部分を切り取るだけです。

シェイプ形成ツールで整える

不要な部分を切り取るには色々な方法がありますが、
今回は、便利なシェイプ形成ツールを使用します。

シェイプ形成ツールを選択し

まずは、必要な部分をドラックします。

すると、一発でパスが結合されました。

逆に、不要な部分に対しては、
「optionキー」を押しながらドラッグすると、
削除してくれます。

どうですか?こんなに簡単に作れちゃいました。

これでハートを描くよりもメッセージを書く方に時間をかけられますよ。
それでは皆さん、チョコよりも甘い一日を!

PHPでIRCのログ収集を行うbotを作成

IRCで発言を逃さない為に・・・

弊社では作業環境としてMacBookProを使用している人も多いのですが、ノートパソコンだとしばらくするとスリープになってしまい、ネットワークも切れるため、IRCサーバーからログアウトした状態になり、その間の発言ログは見る事ができない状態になります。

単にログを収集するbotを簡単に作れないかと思い調べてみました。

PHPにこだわらないのであればIRCproxyの「tiarra」等で上記の問題は対応でき、完璧なツールです、が今回はスルーです。(tiarraについてはカヤックさんのブログがとてもわかりやすかったです。)
stone を使って tiarra を SSL 化する方法

PEAR::Net_SmartIRC を使ってPHPで作る

PEARにてばっちりなIRC用のPHPクラスがあったのでこちらを使いました。

pear install Net_SmartIRC

とりあえず作成したPHPソースの全文です。
88. PEAR::Net_SmartIRCではじめるIRC Bot入門
を参考にしました。

logbot.php
[code]
<?php

include_once(‘Net/SmartIRC.php‘);

define(“LOG_PATH”, “/path/to/irc-logs.txt”); //ログの保存先
$irc_host = “localhost“; //IRCサーバー
$irc_port = “6667”; // IRCサーバーのポート
$irc_name = “bot“; // 名前
$irc_channel = “#hogehoge”; // チャンネル名

class mybot
{
function welcome(&$irc, &$data)
{
// welcome
$irc->message(SMARTIRC_TYPE_NOTICE, $data->channel, $data->nick.’さん : ようこそー。’);
}

        function url(&amp;$irc,&amp;$data)
{
preg_match_all('|http://\w+(?:-\w+)*(?:\.\w+(?:-\w+)*)+(?::\d+)?(?:[/\?][\w%&amp;=~\-\+/;\.\?]*(?:#[^]*)?)?|', $data-&gt;message, $match);
$url=$match[0][0];
$urldata = file_get_contents($url);
$urldata = mb_convert_encoding($urldata, "UTF-8", "auto" );
preg_match( "/<title>(.*?)/i", $urldata, $matches);
$irc-&gt;message(SMARTIRC_TYPE_NOTICE, $data-&gt;channel,$matches[1] . ' - ' . $url );
}
function getlog(&amp;$irc,&amp;$data)
{
$data-&gt;message;
$fp = fopen(LOG_PATH, "a+");
fwrite($fp, date("Y-m-d H:i:s") . ' - (' . $data-&gt;nick . ') - ' . "$data-&gt;message \n");
fclose($fp);
}

}

$bot = &new mybot();
$irc = &new Net_SmartIRC();
//$irc->setDebug(SMARTIRC_DEBUG_ALL);
$irc->setUseSockets(TRUE);
$irc->registerActionhandler(SMARTIRC_TYPE_CHANNEL, ‘(?:^|[\s ]+)*1;
$irc->listen();
$irc->disconnect();

[/code]

簡単な解説

詳細なドキュメントはこちらです。
http://pear.php.net/package/Net_SmartIRC/docs/latest/Net_SmartIRC/Net_SmartIRC_base.html

URLを含む発言があったら、そのページのタイトルを取得して発言させる

[code]
$irc->registerActionhandler(SMARTIRC_TYPE_CHANNEL, ‘(?:^|[\s ]+)((?:https?|ftp):\/\/[^\s ]+)’, $bot, ‘url’);
[/code]

これはログの保存とは関係ないですが・・・
registerActionhandlerの第一引数でSMARTIRC_TYPE_CHANNELを選ぶ事で発言を監視し、第二引数の正規表現にマッチした場合に特定の動作を行わせる事ができます。
上記の例だと発言にURLが含まれていた場合にmybotクラスのurl関数を実行します。
url関数はURLに接続してtitleタグを取得しNOTICEとしてIRCでタイトルとURLを発言します。
こんな感じになります ↓

ログを収集する

[code]
$irc->registerActionhandler(SMARTIRC_TYPE_CHANNEL, ‘.*’, $bot, ‘getlog’);
[/code]
こちらがメインのログを収集する処理。
さきほどと同じく発言を監視しますがすべての発言にマッチするような正規表現となっています。
今回はgetlog関数を実行し、時間と発言者と発言内容をファイルに書きだす処理になってます。

JOINしたユーザーにwelcomeメッセージをとばす

[code]
$irc->registerActionhandler(SMARTIRC_TYPE_JOIN, ‘.*’, $bot, ‘welcome’);
[/code]
こちらはお遊び。第一引数をSMARTIRC_TYPE_JOINとするとユーザーがJOINしてきた時になんらかの動作を行わせる事ができます。
今回はチャンネルにJOINしてきた方へbotは「ようこそー」と発言させています。

実行

バックグラウンドで実行しておきます。

php logbot.php &amp;

このときIRCサーバーに正常にログインし、指定されたチャンネルへbot君がJOINしていれば成功。

おまけ

あとは書き出されたログをPHPとかで表示してやればOKです。
ドキュメントルート以下におけばブラウザから参照できますね。

logview.php

[code]
<!DOCTYPE html>
<html lang=”ja”>
<head>
<meta content=”text/html; charset=utf-8” http-equiv=”Content-Type”>
<title>IRC Log
</head>
<body>
<p>

<?php
$lines = file(‘/path/to/irc-logs.txt’);
foreach ($lines as $line_num => $line) {
echo nl2br(htmlspecialchars($line));
}
?>

</p>
</body>
</html>
[/code]

*1:?:https?|ftp):\/\/[^\s ]+)’, $bot, ‘url’);
$irc->registerActionhandler(SMARTIRC_TYPE_CHANNEL, ‘.‘, $bot, ‘getlog’);
$irc->registerActionhandler(SMARTIRC_TYPE_JOIN, ‘.
‘, $bot, ‘welcome’);
$irc->connect($irc_host, $irc_port);
$irc->login($irc_name, $irc_name, 0, $irc_name, $irc_pass);
$irc->join(array($irc_channel

© SEEDS Co.,Ltd.