Add Cross-Posting support for multiple social accounts

- Create post_social_account pivot table for many-to-many relationship
- Add migration to migrate existing social_account_id to pivot table
- Remove social_account_id column from posts table
- Update Post model with socialAccounts() BelongsToMany relationship
- Update Posts Livewire component to use array of selectedAccountIds
- Update Posts view with checkboxes for selecting multiple accounts
- Update PublishPostJob to iterate through all social accounts of matching type
- Update Publisher interface to accept optional SocialAccount parameter
- Update all Publishers (WordPress, Reddit, Twitter, LinkedIn) to support cross-posting
- Display multiple social accounts as badges in posts table

Now a single post can be published to multiple social accounts of the same type.
For example: a Twitter post can be published to multiple Twitter accounts.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
m105
2026-07-27 21:24:49 +03:00
parent 44f979820f
commit 90f313c134
12 changed files with 183 additions and 33 deletions
@@ -0,0 +1,25 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('post_social_account', function (Blueprint $table) {
$table->id();
$table->foreignId('post_id')->constrained()->cascadeOnDelete();
$table->foreignId('social_account_id')->constrained()->cascadeOnDelete();
$table->timestamps();
$table->unique(['post_id', 'social_account_id']);
});
}
public function down(): void
{
Schema::dropIfExists('post_social_account');
}
};
@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
// Copy existing social_account_id values to pivot table
DB::table('posts')
->whereNotNull('social_account_id')
->orderBy('id')
->chunk(100, function ($posts) {
$now = now();
foreach ($posts as $post) {
DB::table('post_social_account')->insert([
'post_id' => $post->id,
'social_account_id' => $post->social_account_id,
'created_at' => $now,
'updated_at' => $now,
]);
}
});
}
public function down(): void
{
// On rollback, we can't easily restore the social_account_id column
// since we'll remove it in the next migration. This is fine for a fresh setup.
}
};
@@ -0,0 +1,26 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->dropForeign(['social_account_id']);
$table->dropColumn('social_account_id');
});
}
public function down(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('social_account_id')
->nullable()
->constrained('social_accounts')
->nullOnDelete();
});
}
};