Laravel:権威性があるツイートを自動投稿する

こんにちは。フリーランス・コンサルタント&エンジニアの 九保すこひ です。

さてさて、私は個人サービスとして「ぷれりり」という名前の「無料で使えるプレスリリース」スタンドを運営しています。

ほぼボランティアで運営してるんですが 2024.5.18現在で40,000件以上プレスリリースが投稿されています。

そして、これは最近勉強してるマーケティングで言うと「権威性がある」状態です。

つまり「そんないっぱい投稿されてるってことは良いサイトなんじゃない!?」ってなる錯覚するわけですね(実際良いサイトだと思ってますが…)

そう考えてたら、ある開発アイデアが浮かんできました。

それは・・・・・・

投稿数が大台に乗るたびに自動でツイートをする

というものです。

例えば、次は「41,000件突破しました!」とツイートするということですね。

ということで、今回もLaravelを使って実装してみましょう。

※ちなみに権威性のあるツイートは新規フォロワーにつながりやすいのでアカウント開設した直後はより多めで投稿するといいでしょう。

何かの参考になりましたら嬉しいです。😊✨

「ビール醸造所で教えてもらった
マーケ本、勉強になりました❗」

開発環境: Laravel 11.x

やりたいこと

現状で40,000件を超えているので、実際の運用では1,000件ごとに自動でツイートできるようしようと考えてました。

でも、1000で固定だと別の新規サイトを作ったら遠すぎる道のりになってしまいます。

なので、環境変数でこの数字は自由に変更できるようにして今回は100をセットするようにします。

.env

RELEASE_COUNT_NEAREST_NUMBER=100

前提として

今回もすでにTwitter APIにアクセスするための以下4つのキーを取得していることが前提です。

  • CONSUMER KEY(API Key)
  • CONSUMER SECRET (API Secret)
  • ACCESS TOKEN(Access Token)
  • ACCESS SECRET(Access Secret)

なお、APIの登録やキーの取得は以下のページがわかりやすいです。

📝 【2023年度最新版】Twitter API 取得方法

そして、4つのキーを取得したら、.envにセットしておいてください。

.env

TWITTER_CONSUMER_KEY="(ここにAPI Key)"
TWITTER_CONSUMER_SECRET="(ここにAPI Key Secret)"
TWITTER_ACCESS_TOKEN="(ここにAccess Token)"
TWITTER_ACCESS_TOKEN_SECRET="(ここにAccess Token Secret)"

パッケージをインストールする

次にツイートするために必要なパッケージをインストールします。
以下のコマンドを実行して下さい。

composer require abraham/twitteroauth

このパッケージはLaravelでツイートするなら必須ですね!感謝♪

DB周りをつくる

実際のサイトでは少しDB構成が違いますが、releasesというテーブルで実装していきます。

では以下のコマンドを実行して下さい。

php artisan make:model Release -ms

すると、ファイルが3つ作成されるので中身をそれぞれ以下のようにします。

app/Models/Release.php

<?php

namespace App\Models;

use App\Events\ReleaseCreated;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Release extends Model
{
    use HasFactory;

    protected $fillable = [
        'body',
    ];

    // あとでここにイベントを追加します。
}

database/migrations/****_**_**_******_create_releases_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('releases', function (Blueprint $table) {
            $table->id();
            $table->text('body')->comment('プレスリリース本文');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('releases');
    }
};

database/seeders/ReleaseSeeder.php

<?php

namespace Database\Seeders;

use App\Models\Release;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class ReleaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        for($i = 0; $i < 98; $i++) {

            $release = new Release();
            $release->body = 'プレスリリース本文 その' . $i;
            $release->save();

        }
    }
}

では、SeederDatabaseSeeder.phpにセットして有効にします。

database/seeders/DatabaseSeeder.php

<?php

namespace Database\Seeders;

use App\Models\User;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     */
    public function run(): void
    {
        $this->call([
            ReleaseSeeder::class,
        ]);
    }
}

では、この状態でデータベースを初期化してみましょう。
以下のコマンドを実行して下さい。

php artisan migrate:fresh --seed

すると、実際のテーブルはこうなりました。

イベントをつくる

では、Releaseモデルを使って「新しいデータが追加されたら必ず実行される」イベントをつくります。

以下のコマンドを実行して下さい。

php artisan make:event ReleaseCreated

すると、ファイルが作成されるので中身を以下のようにします。

<?php

namespace App\Events;

use App\Models\Release;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Abraham\TwitterOAuth\TwitterOAuth;

class ReleaseCreated
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     */
    public function __construct()
    {
        $this->tweet();
    }

    private function tweet()
    {
        $cache_key = 'release_count';
        $prev_nearest_count = (int) cache()->get($cache_key, 0); // 前回のリリース数
        $nearest_number = (int) env('RELEASE_COUNT_NEAREST_NUMBER', 100);

        $release_count = Release::count(); // 現在のリリース数
        $current_nearest_count = $this->getNearestCount($release_count, $nearest_number);

        if ($prev_nearest_count < $current_nearest_count) { // 前回のリリース数よりもリリース数が増えていたらツイート

            cache()->put($cache_key, $current_nearest_count); // 新しいリリース数をキャッシュ化

            $tweet_body = view('achievement_tweet', ['count' => $current_nearest_count])->render();

            $connection = new TwitterOAuth(
                // 本来は config から取得するべきです
                env('TWITTER_CONSUMER_KEY'),
                env('TWITTER_CONSUMER_SECRET'),
                env('TWITTER_ACCESS_TOKEN'),
                env('TWITTER_ACCESS_TOKEN_SECRET')
            );
            $connection->setApiVersion(2);
            $parameters = [
                'text' => $tweet_body,
            ];
            $connection->post('tweets', $parameters, ['jsonPayload' => true]);

        }
    }

    private function getNearestCount($count, $nearest_number) { // 指定された数値の倍数で丸める

        return (int) floor($count / $nearest_number) * $nearest_number;

    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel>
     */
    public function broadcastOn(): array
    {
        return [
            new PrivateChannel('channel-name'),
        ];
    }
}

では、このイベントをモデルにセットしておきましょう。

<?php

namespace App\Models;

use App\Events\ReleaseCreated;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Release extends Model
{
    // 省略

    protected $dispatchesEvents = [ // 👈ここ
        'created' => ReleaseCreated::class,
    ];
}

ビューをつくる

では、実際にツイートする本文をビューでつくりましょう。
以下のコマンドを実行して下さい。

php artisan make:view achievement_tweet

すると、ビューファイルが作成されるので中身を以下のようにします。

resources/views/achievement_tweet.blade.php

【{{ number_format($count) }}件突破!】

プレスリリースの掲載件数が、
{{ number_format($count) }}件を突破しました!

これからもプレスリリースの投稿、掲載は無料なので
自社、個人サービスの集客に活用してください。

ご投稿はプロフィールのリンクからどうぞ!

これで作業は完了です!
お疲れ様でした。😊✨

テストしてみる

では実際にテストしてみましょう❗

想定するストーリーは、プレスリリースの件数が99100になったときです。
現在のテストデータは、98件なので、

  • 1件追加: 何も起きない
  • さらに1件追加: ここでツイート

ができるかをチェックします。

では、以下のコマンドでtinker(コマンド上でPHPを実行できるツール)を起動しましょう。

php artisan tinker

そして、以下のコードをコピペしてEnterキーを押します。

\App\Models\Release::create(['body' => 'test']);

すると・・・・・・

はい❗
実行が完了しました。

しかし、想定通りツイートはされていません。

では、本番の100件目登録してみましょう!

うまくいくでしょうか・・・・・・

はい❗
(ダークモードで申し訳ないですが)きちんとツイートが投稿されていました。

成功です😊✨

企業様へのご提案

今回のように権威性のある数値とTwitter(X)は親和性が高いです。

さらに、いちいち手動で変更する必要はないので、日々の業務に支障が出ることもありません。

もしそういったツイート運用をしたい方はぜひお問い合わせからご相談ください。

お待ちしております。😊✨

開発のご依頼お待ちしております
開発のご依頼はこちらから: お問い合わせ
どうぞよろしくお願いいたします! by 九保すこひ

おわりに

ということで、今回は権威性をつかったツイートを自動で投稿できるようにしてみました。

一度構築してしまえば、あとは特別難しいことはしてないので、便利&効果もでやすいんじゃないでしょうか。

ぜひ皆さんも一度試してみてくださいね。

ではでは〜❗

「崖の上のポニョのモデルになった
鞆の浦に行ってきました。感動!」

このエントリーをはてなブックマークに追加       follow us in feedly