6月はWordCampKOBE、JS MEET UP、WordBench京都とあちこちの勉強会に参加してきました。
いずれも参考になる話が聞けて大変勉強になりましたので、それぞれの勉強会で得たものを何らかのかたちにできればと思いWordPressのプラグインを作成しました。
いつもfunctions.phpに直接書いてますが勉強も兼ねて。至ってない点突っ込みどころなどいろいろあるかと思いますが、ご容赦ください。。。
ADs
Blog Old Post XML-RPC (Github)
このプラグインは、XML-RPCでの投稿を許可しているブログへ過去記事をランダムで投稿するというどう考えてもゲスい使い方しか思いつかないプラグインです。
過去記事をランダムでツイートするTweet Old Postのブログ版だと思えば分かりやすいです。
運営しているサイトが増えてきたので、その情報をとりまとめて新しい価値が創造できないかという発想で生まれたものであり、スパムブログの量産を手助けするとかネットにゴミをばらまくつもりなどは決してないのです・・・(;´Д`)
参加した中で以下のお話を参考にしつつ作成いたしました。
大変勉強になりました。ありがとうございます。
そしてそのお話を聞いた結果がこれかよ!という感じで申し訳ございません。。。。
WordCampKOBEでの@yuka2pyさんのセッション
プラグインAPIから理解するWordPress※WordCampのセッションではないけどこちらも大変参考になりました。
WordPressプラグイン作成入門
WordBench京都での@as_chachamaruさんのセッション(こちらでXML-RPCの話を聞いた)
WordPress管理パネル以外から記事を投稿してみよう!
プラグインを有効化すると「Blog Old Post XML-RPC」というメニューが増えます。
投稿間隔、投稿したいブログのID、パスワード、エンドポイントを入力することでcron(wp-cron)を使用し、定期的に過去記事からランダムに1件選んで投稿します。
エンドポイントについては、無料ブログであれば調べて公開されているブログなどが多く見つかりますので見てみてください。
※このプラグインはAtomPubで投稿するタイプのブログ(ameba,Livedoorなど)では使えません。
また、投稿されるタイトルや本文を編集したいというケースもあるかと思いますので、
blog_old_post_title
blog_old_post_content
というフィルターフックでfunctions.phpより変更できるようになっています。
たとえばhogehogeというカスタムフィールドに入っているURLをimgタグで本文として投稿したいという場合は、以下のように記述します。
1 2 3 4 5 |
add_filter('blog_old_post_content','custom_content',10,2); function custom_content($text,$post){ $text = '<img src="'.$post->hogehoge . '" />'; return $text; } |
他のサイトを参考にした部分が相当多いですし行数も短いですし、ということで私が説明できることもさほどないですが、メモ程度に。。。
過去の記事をランダムでピックアップして定期的に外部ブログへ投稿する、という目的を達成するために以下の機能が必要です。
1.外部ブログのID、パスワード、投稿先(エンドポイント)を入力して保存できる管理画面
2.過去記事をランダムに選んで投稿内容を生成
3.2.の投稿内容を1.の情報を用いて投稿処理を行う
4.3.の処理を定期的に実行する
5.プラグインの削除時に1.で保存したデータを削除する
このそれぞれの機能をつくっていきます。
WordPressのプラグインというのはテーマに書くfunctions.phpとまったく同じものです。
先頭に以下のようなコメントを書いたPHPファイルを用意し、/wp-content/plugins/内にディレクトリを作って置けばWordPressがプラグインとして認識してくれます。
1 2 3 4 5 6 7 |
/* Plugin Name: Blog Old Post XML-RPC Description: 過去の記事をランダムにXML-RPCに対応した外部ブログに投稿 Author: @woodroots Version: 1.0 Author URL: https://wood-roots.com */ |
まずadd_menu_page関数でメニューを追加し、そのメニュー内のページを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
//多次元配列を綺麗にするfunction(update_option時に使用する) //valueが空で投稿されたときにその配列を削除しています。 function array_filter_recursive($input) { foreach ($input as &$value) { if (is_array($value)) { $value = array_filter_recursive($value); } } return array_filter($input); } //管理画面生成 function blog_old_post_menu(){ add_menu_page( 'Blog Old Post XML-RPC', //メニューページのタイトル 'Blog Old Post XML-RPC', //メニュー名 'administrator', //メニューの権限 'blog_old_post_menu', //スラッグ 'blog_old_post_setting' //メニューページのコールバック(この名前でfunctionを定義し、echoでページ内のHTMLを作成します) ); } //メニュー add_action('admin_menu','blog_old_post_menu'); //IDとPASS設定画面 function blog_old_post_setting(){ //ID、パスワードなどが後半のフォームで入力されたときの処理。 if(isset($_POST["submit"]) && wp_verify_nonce( $_POST['_wpnonce'], 'blog_old_post')){ update_option('blog_old_post_interval',intval($_POST['blog_old_post_interval'])); update_option('blog_old_post_settings',array_filter_recursive($_POST['blog_old_post_settings'])); //投稿間隔(blog_old_post_interval)を変更した際、既にcronに登録済みの命令が変更されない。 //そこで1回cron登録済みの命令を削除し、再度登録する(もっといい方法あるかもしれない) wp_clear_scheduled_hook('blog_old_post_cron'); wp_schedule_event(time(), 'blogpost', 'blog_old_post_cron'); } /* ここから実際に表示されるHTMLとなります。 ・スタイル・・・適宜見栄えがいいように。極力WPが使っているクラスなどを使うと統一されていいかもしれない ・jQuery・・・フォームを追加するときのためのもの(クリックして入力フォームが増える) ・HTML部分・・・実際のフォーム */ echo ' <style type="text/css"> .btn { margin-top: 20px; } .taright { text-align: right; } .blog_old_post_table { width: 100%; } .blog_old_post_table th { width: 150px; text-align: center; background: #eee; } .blog_old_post_table th,.blog_old_post_table td { border: 1px solid #ccc; } </style> <script type="text/javascript"> (function($){ var nameset = function(){ $(".blog_old_post_table").each(function(key,value){ $(this).find("input").attr("name",$(this).attr("name").replace(/\[[0-9]*?\]/,"["+key+"]")); }); } $(function(){ nameset(); $("#add_form").on("click",function(){ obj = $(".blog_old_post_table:last-of-type").clone(); $(this).parent().before(obj); nameset(); return false; }); }); })(jQuery); </script> <h2>Blog Old Post XML-RPC設定画面</h2>'; //データが入力され、submitされたあとにお知らせを表示する。 //WPダッシュボード内ではfadeというクラスをつけるとフェードインするようになっています。 if(isset($_POST["submit"]) && wp_verify_nonce( $_POST['_wpnonce'], 'blog_old_post')){ echo '<div class="updated fade" id="message"> <p>設定が更新されました。</p> </div>'; }; //念のためCSRF対策で_wpnonceを設定・・・ echo '<h3>ランダム投稿設定</h3> <form action="" method="post"> <input type="hidden" name="_wpnonce" value="'.wp_create_nonce('blog_old_post').'" /> <div> <input type="text" name="blog_old_post_interval" value="'.htmlspecialchars(get_option('blog_old_post_interval')).'" />分おきに投稿する </div> <div class="btn"><input type="submit" name="submit" class="button-primary" value="この内容で登録" /></div> '; echo '<h3>ID・パスワード・エンドポイント設定</h3>'; /* 「blog_old_post_settings」は以下のようにID,パスワード、エンドポイントが保存されるようになっています。 array( array( user_id => aaaa, pass => bbb, endpoint => cccc/xmlrpc ). array( user_id => aaaa, pass => bbb, endpoint => cccc/xmlrpc ). ); */ $settings = get_option('blog_old_post_settings'); if($settings){ foreach($settings as $key=>$val){ echo ' <table class="blog_old_post_table"> <tr> <th>ID</th> <td><input name="blog_old_post_settings[1][user_id]" type="text" value="'.htmlspecialchars($val[user_id]).'" /></td> </tr> <tr> <th>パスワード</th> <td><input name="blog_old_post_settings[1][pass]" type="text" value="'.htmlspecialchars($val[pass]).'" /></td> </tr> <tr> <th>エンドポイント</th> <td>http://<input name="blog_old_post_settings[1][endpoint]" type="text" value="'.htmlspecialchars($val[endpoint]).'" /></td> </tr> </table> '; } }//endif echo ' <table class="blog_old_post_table"> <tr> <th>ID</th> <td><input name="blog_old_post_settings[2][user_id]" type="text" value="" /></td> </tr> <tr> <th>パスワード</th> <td><input name="blog_old_post_settings[2][pass]" type="text" value="" /></td> </tr> <tr> <th>エンドポイント</th> <td>http://<input name="blog_old_post_settings[2][endpoint]" type="text" value="" /></td> </tr> </table> '; echo ' <div class="btn taright"><button id="add_form">入力フォームの追加</button></div> <div class="btn"><input type="submit" name="submit" class="button-primary" value="この内容で登録" /></div> </form> <h2>前回実行時のログ</h2> '; //必要かどうかは分かりませんが前回実行時にログファイルをオプションで保存して、それを表示させる echo '[crayon-673eff611b227131228090 ]'.get_option('blog_old_post_log').' |
’;
}
[/crayon]
次に、WordPress内の記事からランダムで1件取得し、投稿する処理を作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
//実行 function blog_old_post(){ //設定値の取得 /* blog_old_post_settings内には array( array( user_id => aaaa, pass => bbb, endpoint => cccc/xmlrpc ). array( user_id => aaaa, pass => bbb, endpoint => cccc/xmlrpc ). ); と入っている */ $settings = get_option('blog_old_post_settings'); if($settings){ //投稿処理 $mes = ''; foreach($settings as $val){ //記事の取得 $post = get_posts(array( 'numberposts' => 1, 'orderby' => 'rand' )); $post = $post[0]; //投稿用記事生成 $title = $post->post_title ? $post->post_title : 'タイトルなし'; $title = apply_filters('blog_old_post_title',$title,$post); $text = '<div class="content">' . $post->post_content . '</div>'; $text = apply_filters('blog_old_post_content',$text,$post); //ここで投稿 //blog_old_post_submitはのちほど定義します。 $mes .= blog_old_post_submit($title, $text, $val['endpoint'],$val['user_id'],$val['pass']); } update_option('blog_old_post_log',$mes); } } |
XML-RPCでの投稿を実装するために以下のライブラリを使用させていただきました。
FC2ブログとなっていますがXML-RPCで投稿できるのであれば他のブログでも使えます。
Paradigm Shift Design
FC2ブログに記事を投稿するスクリプト
行頭でrequire_onceでロードしておきます。
1 2 |
require_once 'XML/RPC.php'; require_once 'FC2BlogManager.php'; |
XML/RPC.phpというファイルはPEARのサイトからダウンロードできます。前述のリンクの「Download」から取得可能です。
.taz.gz形式のアーカイブですが、解凍するとXMLというフォルダがあります。これをプラグインと同階層に置きます。
投稿処理自体は2.のblog_old_post_submitという関数を実行した段階で完了しているのですが、このblog_old_post_submitという関数は以下のように定義されています。
これはFC2BlogManager.phpをそのまま使うことで、実質10行程度で投稿処理を実現しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
//投稿する処理 function blog_old_post_submit($title, $text, $endpoint,$user_id,$pass) { //入力されたエンドポイントの「/」以前をホスト名、以降をスクリプト名としている //(この条件に合わないエンドポイントが出てくると投稿できないのですが・・・) $host = substr($endpoint,0,strpos($endpoint,'/')); $xmlrpc_path = str_replace($host,'',$endpoint); //ログ用 $mes = ''; try { $bm = new FC2BlogManager($host, $xmlrpc_path); $bm->setUser($user_id); $bm->setPassword($pass); $bm->postEntry($title, $text); //ログ用 $mes .= date( "Y/m/d (D) H:i:s", time() ) . 'に実行されました:<br />' . "\n"; $mes .= print_r($bm,true) . "\n"; } catch(Exception $e) { $mes .= date( "Y/m/d (D) H:i:s", time() ) . 'に実行されましたがエラーでした:<br />' . "\n"; $mes .= print_r($e,true) . "\n"; } return $mes; } |
定期的な実行を行うためには2.で定義したblog_old_postという関数を定期的に実行すればいいです。
これはwp-cronに登録して実行させます。
なお、wp-cronは何らかのアクセスがあったときに実行されるものであるため、まったくアクセスのないサイトなどの場合は実行されることがありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//Cron登録 if(get_option('blog_old_post_interval')){ add_filter('cron_schedules','blog_old_post_time'); function blog_old_post_time($schedules){ //オプション値よりcronの間隔を設定する $blog_post_interval = intval(get_option('blog_old_post_interval')); $schedules['blogpost'] = array( 'interval' => $blog_post_interval*60,//入力値を「分」としていたので。 'display' => __( 'blogpost' ) ); return $schedules; } add_action('blog_old_post_cron', 'blog_old_post'); function blog_old_post_setcron() { if ( !wp_next_scheduled( 'blog_old_post_cron' ) ) { wp_schedule_event(time(), 'blogpost', 'blog_old_post_cron'); } } add_action('wp', 'blog_old_post_setcron'); } |
これで、ダッシュボードから設定が可能なプラグイン本体ができあがりました。
・・・が、プラグインが削除されるときのことを考えて、設定値などを削除する処理を用意しておきます。
以下の記事を参考にしました
プラグインを設置したディレクトリにuninstall.phpというファイル名でファイルを作成し、delete_optionで不要なオプションを削除します。
blog_old_post_interval
blog_old_post_log
blog_old_post_settings
の3つと、登録したcronを削除するように設置しました。
1 2 3 4 5 6 7 |
<?php if (!defined('ABSPATH') && !defined('WP_UNINSTALL_PLUGIN')) {exit();} delete_option('blog_old_post_interval'); delete_option('blog_old_post_log'); delete_option('blog_old_post_settings'); wp_clear_scheduled_hook('blog_old_post_cron'); ?> |
ダウンロードと最新版の確認はGithubよりお願いします。
コードの記述順は上記の手順とは順番が異なってますが気にしないでください(;´∀`)
ADs
Morimoto様
はじめまして。
貴サイト様の「Blog Old Post XML-RPC」を勝手ながら使用させて頂いている者です。
1つ質問がありまして…教えて頂けないでしょうか。
【質問】
タイトルと本文に加えてカテゴリ・タグ・アイキャッチ画像を過去記事から取得して他サイトへ投稿してやるには「Blog Old Post XML-RPC」のソースコードをどのように書き換えてやれば良いのでしょうか?
当方コードについて知識が乏しく、良ければ教えて頂きたいです。よろしくお願いします。
斉藤様
コメントありがとうございます。
また、プラグインをご利用いただきありがとうございます。
本文についてですが、プラグイン本体を書き換えるよりは使用テーマのfunctions.phpにフィルターフックとして追加するほうが簡単です。
※動作確認をしてないので上手く動かなかったら申し訳ありません。
プラグインを有効にして、以下をfunctions.phpに追記します。
function custom_old_post_content($text,$post){
//カテゴリ一覧を取得
$cats = get_the_category($post->ID);
$cathtml = ”;
if($cats){
$cathtml = ”;
foreach($cats as $cat){
$cathtml .= ‘term_id) .'”>‘;
}
$cathtml .= ”;
}
//タグ一覧を取得
$tags = get_the_terms($post->ID,’post_tag’);
$taghtml = ”;
if($tags){
$taghtml = ”;
foreach($tags as $tag){
$taghtml .= ‘term_id,’post_tag’) .'”>‘;
}
$taghtml .= ”;
}
//アイキャッチを取得
$thumbhtml = ‘ID,’full’) . ‘” alt=”” />’;
//出力されるHTML
$text = $thumbhtml;
$text .= ” . $post->post_content . ”;
$text .= ” . $cathtml . ”;
$text .= ” . $taghtml . ;
return $text;
}
add_filter(‘custom_old_post_content’,10,2);
そうすると以下のようなHTMLが出力されます。
カスタマイズしたい場合は上記functions.phpの「//出力されるHTML」のところで制御されますので、クラス名などを適宜書き換えてください。