アドベントカレンダー初投稿です。よろしくお願いいたします。
WordPressのブログタイトル・URLを1時間ごとにループで順番にツイートするシステムを作成してみました。
私はwordpress初心者ですので、wordpress関数や、プラグインとか使わずにやる方法でやっています。
また自動ツイートはwp_cronではなく、crontabで行なっています。
仕様など
- 1時間に一回、ブログ記事のタイトルとURLをツイートしていく。
- 公開日の古い順番にツイートしていく。全てツイートしたら最も古い投稿に戻ってまた順番にツイートする。
- 新しいブログ記事が公開されたら、直近のツイートは最新記事をツイートし、その後は元の順番に戻ってツイートしていく。
- 新しいブログ記事が2つ以上だった場合は、そのうちの古い投稿からツイートしていく。
- ツイートしたブログ記事は回数、ツイート日時を全て保存しておく。
また、今回作成したものは自分のSQLの勉強のために作ったものです。
cron設定
1時間おきに設定
0 */1 * * * /usr/local/bin/php /var/www/html/tweet.php
ツイートしたID、日時を保存しておくテーブルを作成
CREATE TABLE IF NOT EXISTS `wp_tweet` (
`wp_posts_id` bigint(20) unsigned NOT NULL,
`tweet_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`wp_posts_id`,`tweet_date`)
) DEFAULT CHARSET=utf8mb4;
現在のツイート数を見れるVIEWを作成
CREATE OR REPLACE VIEW `wp_tweet_cnt` AS
SELECT wp_posts_id,
MAX(tweet_date) tweet_date,
COUNT(*) cnt
FROM wp_tweet
GROUP BY wp_posts_id;
CREATE OR REPLACE VIEW `wp_posts_tweet` AS
SELECT a.id,
a.post_date,
a.post_title,
a.guid,
a.post_status,
a.post_type,
b.tweet_date,
b.cnt
FROM wp_posts a
LEFT JOIN wp_tweet_cnt b
ON a.id = b.wp_posts_id
WHERE a.post_status = 'publish' -- 公開済のみを選択
AND a.post_type = 'post'; -- ブログ記事のみを選択
SQL作成
以下のようにすることで現在ある記事を順番にループしてツイートすることができました。
処理の流れとしては、対象のidをwp_tweetにインサート→wp_tweetの最新データをツイートするという感じです。
新しいブログ記事が公開されたら、次のツイートは元の順番に戻ってツイートするというのがかなりややこしい、、
<?php
require_once __DIR__.'/vendor/autoload.php';
use Abraham\TwitterOAuth\TwitterOAuth;
try {
$pdo = new PDO('mysql:dbname=wp_tests;host=localhost;charset=utf8','root','password');
$stmt = $pdo->exec(
"INSERT INTO wp_tweet(
wp_posts_id
)
SELECT a.id
FROM wp_posts_tweet a
JOIN (
SELECT tmp.*
,CASE WHEN new_flg = 1
AND min_cnt < last_cnt_tmp
THEN last_cnt_tmp
ELSE last_cnt -- 前回ツイートが新規投稿だった場合、次のツイートは元の順番に戻さないといけないため、
END last_tweet_cnt -- 合計ツイート数が1 より大きいもの中で直近を前回ツイート数とする
FROM (
SELECT (SELECT COUNT(*) FROM wp_posts_tweet WHERE cnt IS NULL) new_post_cnt
,(SELECT MIN(cnt) FROM wp_posts_tweet WHERE tweet_date <= (SELECT tweet_date FROM wp_posts_tweet WHERE cnt > 1 ORDER BY tweet_date DESC LIMIT 1)) min_cnt
,(SELECT cnt FROM wp_posts_tweet ORDER BY tweet_date DESC LIMIT 1) last_cnt
,(SELECT cnt FROM wp_posts_tweet WHERE cnt > 1 ORDER BY tweet_date DESC LIMIT 1) last_cnt_tmp
,CASE WHEN (SELECT cnt FROM wp_posts_tweet ORDER BY tweet_date DESC LIMIT 1) = 1
AND (SELECT COUNT(*) FROM wp_posts_tweet WHERE cnt > 1) > 0
THEN 1
END new_flg -- 前回ツイートが新規投稿だったかどうか判定するフラグ
) tmp
) b
WHERE IFNULL(a.cnt,0) =
-- 条件 :まだツイートしていない記事が1つ以上ある場合
-- true :合計ツイート数0のものをツイートする
CASE WHEN b.new_post_cnt > 0
THEN 0
-- 条件 :「直近にツイートしたidの合計ツイート数-1」と同じ合計ツイート数の記事が1つ以上ある場合
-- true :「直近にツイートしたidの合計ツイート数-1」と同じの合計ツイート数の記事を次にツイートする
WHEN (SELECT COUNT(*) FROM wp_posts_tweet WHERE cnt = b.last_tweet_cnt - 1) > 0
THEN b.last_tweet_cnt - 1
-- 条件 :「直近にツイートしたidの合計ツイート数-1」より小さい合計ツイート数の記事が1つ以上ある場合
-- true :「「直近にツイートしたidの合計ツイート数-1」より小さい合計ツイート数」の記事の中で最大の合計ツイート数の記事を次にツイートする
-- false:合計ツイート数が最大のものをツイートする
WHEN (SELECT COUNT(*) FROM wp_posts_tweet WHERE cnt < b.last_tweet_cnt - 1) > 0
THEN (SELECT MAX(cnt) FROM wp_posts_tweet WHERE cnt < b.last_tweet_cnt - 1)
ELSE (SELECT MAX(cnt) FROM wp_posts_tweet)
END
ORDER BY post_date
LIMIT 1"
);
$stmt = $pdo->query("SELECT CONCAT(post_title,'\r\n',guid) post
FROM wp_posts_tweet
WHERE tweet_date = (SELECT MAX(tweet_date) FROM wp_posts_tweet)");
$res = $stmt->fetch(PDO::FETCH_ASSOC);
$paramater['status'] = $res['post'];
$connection = new TwitterOAuth(
'xxxxxxxxxxxxx',
'xxxxxxxxxxxxx',
'xxxxxxxxxxxxx',
'xxxxxxxxxxxxx'
);
$connection->post(
'statuses/update',
$paramater
);
} catch (PDOException $e) {
exit($e->getMessage());
}
動作
最初にブログ記事が3つある場合、古いものから順にツイート(データを保存)していき、全てツイートしたら、最初のidに戻る。
さらに、新しい記事が2つ追加される。
この状態ですと、まず新しい記事を2つツイートした後に、元の順番に戻るので、id:182が新しい記事の次にツイートされます。
もっと色々なテスト条件でテストした方がいいですが、とりあえず仕様通りの動きにできたようです。
人によって、全然違う書き方をするような内容だと思いますので、やってみると結構面白いんじゃないかなと思います。
最後まで読んでいただきありがとうございました。