ホーム > タグ > wordpress

wordpress

エントリの作成日を一括変更する方法

WordPressでエントリの作成日を一括変更したくなることって,ありますよね.いや,あるんですよ,実際.あなたが知らないだけです.ですので,やり方メモ.

一応,作業前にバックアップを取ってから,SQL直叩きで,以下のようなSQL文を実行します.

update [テーブル名]
set post_date = '2012-04-01 09:00:00',
post_date_gmt = '2012-04-01 00:00:00'
where post_status='publish';

where句は必要がないなら,外していいです.私には必要だっただけです.日付は好きなように変更して下さい.GMTとローカルタイムで時間がずれていてもいいのかどうかわからないので,とりあえず,ちゃんと合うように変更しましょう.JSTならGMT+9です.簡単ね!

WordPressのguidはGUIDじゃない

だからパーマリンクの設計はまず最初にやれとあれほど言っただろ(挨拶).ということで,パーマリンク関連ではまったので,愚痴エントリ.解決策もあるよ.

発生した問題

get_posts関数で記事一覧を取得して,その返り値からpost_titleとguidを使ってリンクを作っていたんです.まぁ,問題なく上手くいってました.しかし,ある時(っていうかついさっきだけど)パーマリンク構成を変更しました.そうすると,途端に問題と出くわしました.

どんな状態かといえば,パーマリンクを変更したのに,guidが変わっていないのです.そのため,リンクがあっちこっちでぶっ壊れました.そこで,調べてみたところ,どうもこのguidはパーマリンクではないようなのです.今回のようなパーマリンクの変更だけではなく,ブログを引っ越した際などでドメインが変わった場合も同様の問題が発生するようです.つまり,このguidってのは,記事を指し示すURIにはなってなくて,URIのように見えるだけで,単なるidentifierに過ぎないようなのです.よくよく読んでみると,確かにそのように書いてあります.

It’s merely a unique identifier, which so happens to be a link to the post at present.

Function Reference/get post ≪ WordPress Codex

それ,guid (Global Unique Identifier)っていうか??なんでHTTPなURI表現なんだ??ということで,漫然とguidを使うと,はまります.

解決策

guidは当てにならないので,代替策が必要になります.使えそうなのは,明確にパーマリンクだといっているget_permalink関数です.引数に記事IDを渡すとパーマリンクが返ってくるそうです.ですので,以下のようなコードが有力でしょうか.

$posts = get_posts('numberposts=-1);
foreach($posts as $post) {
  $links[$post->post_title] = get_permalink($post->ID);
}

まぁ,こんなもんですよね.

エントリ名をトリガにしたオートリンクの方法

ブログを長いこと書いていると,エントリ数が膨大になるので,過去に書いた記事を探し出してリンクを張ることが面倒になってきます.エントリ名をトリガにして,テキストをハイパーリンクに置換して,オートリンクすることができれば,便利だなぁなんて思うわけです.ですので,それをWordpressで実現してみます.方法はかなり泥臭い手法です.

前提条件と基本戦略

前提条件を以下のように設定します.

  • エントリ本文に対してオートリンクを行う.
  • エントリ本文は基本的にプレーンテキストである.
  • 置換対象文字列は既存のエントリ名とする.
  • 置換後は既存エントリにハイパーリンクを張る.

上記条件を前提として,オートリンクを実現します.基本的な戦略は以下の通り.

  • 既存エントリ名を全て取得する.
  • エントリ本文から既存エントリ名があるかどうかを探す.
  • もし見つかれば,オートリンクに置換する.

既存エントリ名を全て取得する

これは別に難しくないですね.Wordpressの関数を使って,サクッと作ると,以下のような感じでしょうか.

$posts = get_posts('numberposts=-1');
foreach($posts as $post) {
  $links[$post->post_title] = $post->guid;
}

こんな感じで,$link[]な連想配列にkeyとしてエントリ名,valueとしてパーマリンクが格納されます.簡単ちんね.この辺りは,頻繁に変わらないだろうから,キャッシュを仕掛けるとか,どっかに定数として準備しておいても良いかも.

エントリ本文に既存エントリ名があるかどうかを探す

では,文字列置換をしましょう.PHPで文字列置換といえば,str_replaceですが,単純に使うとマズイです.以下のような例を想定しましょう.

私はコーヒーよりもコーヒー牛乳が好きです.

ここで,既存エントリとして「コーヒー」および「コーヒー牛乳」があったとします.置換順序が「コーヒー」「コーヒー牛乳」だった場合,以下のように置換されて行きます.ここでは,マッチした部分を強調で示します.

私はコーヒーよりもコーヒー牛乳が好きです.

次に「コーヒー牛乳」で置換したいのですが,既に「コーヒー」で置換されているので,マッチしません.マズイですね.ですので,置換文字列は,文字数が多い順に並んでいる必要性があると思います.そうすることで,最長一致による文字列置換が実現されます.では,それだけでよいでしょうか?置換順序が「コーヒー牛乳」「コーヒー」の順番になっても,次の問題が発生します.

私はコーヒーよりもコーヒー牛乳が好きです.

この文字列に対して,「コーヒー」の置換を行うと,「コーヒー牛乳」の「コーヒー」が再度置換されます.結果として,入れ子のaタグで挟まれる形になります.これはマズイです.つまり,単純な置換はできないので,正規表現を使うことにしましょう.

正規表現による戦略

mb_ereg_replaceを用います.置換文字列が対象文字列内にあり,さらにaタグで挟まれていない場合に,置換を行いましょう.皆さまご存じの通り,私は正規表現を苦手としており,四苦八苦です.ですので,一生懸命探しました.しかし,結構見つからないのです.出てくるのは,HTMLタグの除去とか,URLっぽい文字列を見つけたらオートリンクで置換とかばっかりです.ちょっと違うのです.しかし,需要がないはずはないと思い,頑張って探したところ,見つかりました.ググリ力は大事ですね!

とりあえず、「aタグの内部には他のタグは含まれていない」という前提の元で話を進めます。

$string = "朝一番のコーヒーは<a href='index.html'>3時のコーヒーや</a>食後のコーヒーより旨い";
$pattern = 'コーヒー(?![^<]*</a>)';
$result = mb_ereg_replace($pattern, '紅茶', $string);
echo $result;

タグにはさまれている文字以外を置換したい – PHP – 教えて!goo

ktkr!これでバッチリです.

functions.phpでフィルターフックをかける

では上記基本検討に従って,エントリ本文を表示する際に,エントリ本文中に既存エントリ名があった場合,オートリンクを張るような仕掛けを作ります.今回は,テーマで使われるfunctions.phpにフィルターフックを仕掛けてみました.対象とするフィルタフックはthe_contentです.つまり,まとめると,以下のようなコードをfunctions.phpに書きます.

function myautolink($content='') {
  mb_regex_encoding('UTF-8');
  $links = array();
  $length = array();

  $posts = get_posts('numberposts=-1');
  foreach($posts as $post) {
    $links[$post->post_title] = $post->guid;
    $length[$post->post_title] = mb_strlen($post->post_title);
  }
  arsort($length);

  foreach($length as $link => $val) {
    $pattern = $link.'(?![^<]*</a>)';
    $replacement = '<a href="'.$links[$link].'">'.$link.'</a>';
    $result = mb_ereg_replace($pattern, $replacement, $content);
    if(false != $result) {
      $content = $result;
    }
  }
  return $content;
}
add_filter('the_content', 'myautolink');

簡単ね!

まとめ

エントリ数が膨大だったり,置換対象の文章が長い場合には,性能が低下する可能性が高くなるので,キャッシュを準備するとか,なんかそういう工夫が必要になります.それについて,今回は触れないので,必要があれば工夫して下さい.

WordPressでエントリを50音順にソートする試み

WordPressのエントリを「あいうえお」順にソートしたかったのです.一般的に考えて,こんな方法で取り出します.

query_posts('showposts=-1&orderby=title&order=asc');

あると思います.しかし,これには日本語特有の問題があります.アルファベットやひらがなやカタカナはまぁまぁそこそこ思い通りに出力されると思いますが,漢字が入ると途端にダメです.当たり前ですね.「海」を「うみ」と読むのか「かい」と読むのかは字面からでは判断できません.そのため,日本語で書かれたエントリタイトルを単純な方法でソートしても,期待通りの結果を得ることはできません.

では,どうしますか?以下のような解決方法が考えられます.

  1. タイトルに漢字を使わない
  2. タイトル以外の要素を利用してソートする

タイトルに漢字を使わないというのは,なかなか強行的で,利便性への配慮が欠けすぎています.非現実的なソリューションです.非実在解決法.では,タイトル以外の要素を利用してソートすることを考えたとき,どのような手法があり得るのでしょうか.

  1. スラッグ
  2. カテゴリ
  3. タグ
  4. カスタムフィールド

まずスラッグです.スラッグは以下のように説明されています.

スラッグとは、投稿や固定ページを表すいくつかの単語のこと。スラッグは(WordPress によって自動生成された)URL に適する形式の投稿タイトルであることが多いが、その他の好きなフレーズでもかまわない。URL にあるコンテンツを説明する支援として、スラッグはパーマリンクで使われる。

用語集 – WordPress Codex 日本語版

好きなフレーズでも構わないので,ひらがなかカタカナでエントリの読みを振っておけば,ソートに利用できそうです.なかなかいいですね.

ではカテゴリはどうでしょうか.カテゴリでは問題は解決しません.エントリの数だけカテゴリを作るというなら,読みをカテゴリ名に与えて解決することもできますが,本来の利用方法から逸脱しすぎです.しかしながら,これはこれで別に役に立つ使い方があります.これは後述します.

タグを使う場合はどうでしょうか.タグに読みを与えれば解決できます.しかし,カテゴリと同じく,エントリの数だけタグが生成され,実に美しくないです.本来の用途でタグを使おうとしたときに,邪魔であるという問題もあります.ですので,積極的に採用したい解決策ではありません.

最後に,カスタムフィールドはどうでしょう.カスタムフィールドの使い方として,以下のような例示があります.

WordPress には、投稿者が投稿に「カスタムフィールド」を追加できる機能があります。この任意の情報は「メタデータ」と呼ばれており、たとえば以下のような情報を含めることができます。

  • 現在のムード: 幸せいっぱい
  • 今読んでいる本: 星の王子様
  • BGM: Rock Around the Clock
  • 今日の天気: 晴れ

さらに、ちょっとしたコードを付け加えるだけで、このメタデータに投稿の表示期限を付け加えたりすることも可能です。

カスタムフィールドの使い方 – WordPress Codex 日本語版

これは今回の目的にぴったりです.ではカスタムフィールドを使って実装しましょう.

カスタムフィールドを用いたエントリ50音ソート

まず前提として,以下を想定します.

  • カスタムフィールド名”yomi”に値として「ふりがな」を入力する
  • カスタムフィールド”yomi”を利用してエントリを50音ソートする
  • エントリタイトルは通常通りに英数漢字かなカナ混合
  • Exec-PHPなどが導入されていて,エントリやページにPHPを書ける状態である

では,以上のような想定環境下で全エントリを50音ソートさせてみます.以下のようなコードを「エントリ一覧」などとしたページに書くと,なんとなくそれっぽい出力が得られると思います.

query_posts('showposts=-1&orderby=meta_value&meta_key=yomi&order=asc');
while (have_posts()) : the_post();
echo '<p><a href="';
the_permalink();
echo '">';
the_title();
echo '</a></p>';
endwhile;

簡単ですね.

カスタムフィールドの入力を必須項目にしたい

ここからはおまけです.カスタムフィールドを使ってソートを実現しましたが,カスタムフィールド”yomi”に値が入力されていなければ,正しくソートされません.となれば,この項目は入力必須に指定したくなります.それを可能にするプラグインがCustom Field GUI Utility 3です.conf.iniを以下のように設定すれば,カスタムフィールド”yomi”は入力必須項目になります.

[yomi]
fieldname = ひらがなでの読み
type = textfield
class = post
default = あいうえお
size = 35
must = 1

もっといえば,ちゃんと「ふりがな」が入力されているかのバリデーションもやりたいところですね.そのときは,functions.phpでedit_postにフックを引っかけて,バリデーションしたら良いと思います.やってないので,コードは紹介できませんが.

201109181121追記

後述しますって書いておいて,カテゴリの使用方法を後述してませんでしたので,追記します.

50音順ソートはカスタムフィールドでやるとして,「あ行」とか「か行」とか,もっと細かく「あ」とか「い」とかやるには,カテゴリを打つのが便利です.カテゴリ毎のエントリをカスタムフィールドで並べれば良いだけなので.カスタムフィールド単体でやると,出力時に「あ」なのか「い」なのかを判別する処理を加える必要があります.それでも良いと思うけど.

参考

XML-RPCを使ってWordPressに記事を投稿する

何番煎じだかわかりませんが,備忘録として.XML-RPCを使って,スクリプトからWordpressに記事を投稿しまくる方法です.参考にしたのは以下のエントリ.

見ればわかりますが,プログラミング言語はPHPです.まずは,何はなくとも,PHPでXML-RPCを扱えないといけないので,PEARからインストールします.

# pear install XML_RPC

続いて,これもサンプルコードそのままなので,深く考えずに,書いていきます.ところが,どっこい!このエントリではカスタムフィールドの扱い方が説明されていません.なんてこったい!これは困りました.今回はカスタムフィールドに値を入れられないと,ものごっつ面倒くさいことになるような件数を突っ込むのです.ですので,どうしてもXML-RPCでやりたいので,調べたところ,以下のエントリがヒットしました.

完璧です.以上より,作成したコードは以下の通り.

require_once("XML/RPC.php");

$host = 'example.com';
$xmlrpc_path = '/wordpress/xmlrpc.php';
$appkey = '';
$user = 'username';
$passwd = 'password';

$title = 'エントリのタイトル';
$categories = array(
  new XML_RPC_Value('未分類', 'string'), );
$description = 'ここに本文を入れます.';
$custom_fields = array();
$custom_fields[] = new XML_RPC_Value(
  array(
    'key' => new XML_RPC_Value('yomi', 'string'),
    'value' => new XML_RPC_Value('ふりがな', 'string')
  ), 'struct');

$c = new XML_RPC_client($xmlrpc_path, $host, 80);
$appkey = new XML_RPC_Value($appkey, 'string');
$username = new XML_RPC_Value($user, 'string');
$passwd = new XML_RPC_Value($passwd, 'string');
$message = new XML_RPC_Message(
  'blogger.getUsersBlogs',
  array($appkey, $username, $passwd));
$result = $c->send($message);

if(!$result){
  exit('Could not connect to the server.');
} else if($result->faultCode()){
  exit($result->faultString());
}

$blogs = XML_RPC_decode($result->value());
$blog_id = new XML_RPC_Value($blogs[0]["blogid"], 'string');
$content = new XML_RPC_Value(
  array(
    'title' => new XML_RPC_Value($title, 'string'),
    'categories' => new XML_RPC_Value($categories, 'array'),
    'description' => new XML_RPC_Value($description, 'string'),
    'dateCreated' => new XML_RPC_Value(time(), 'dateTime.iso8601'),
    'custom_fields' => new XML_RPC_Value($custom_fields, 'struct'),
  ), 'struct');
$publish = new XML_RPC_Value(1, "boolean");
$message = new XML_RPC_Message(
  'metaWeblog.newPost',
  array($blog_id, $username, $passwd, $content, $publish));
$result = $c->send($message);

if(!$result){
  exit('Could not connect to the server.');
} else if( $result->faultCode() ){
  exit($result->faultString());
}

簡単ね!あとは自動でガンガン投稿するようにゴニョゴニョすれば万事快調.

1 / 212

Home > タグ > wordpress

アフィリエイト

Return to page top