draliragab / socialize
Unified Laravel social media publishing for Facebook, Instagram, X, and LinkedIn.
Requires
- php: ^8.4
- illuminate/contracts: ^11.0|^12.0
- illuminate/filesystem: ^11.0|^12.0
- illuminate/http: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.9
- laravel/pint: ^1.27
- nunomaduro/collision: ^8.0
- orchestra/testbench: ^10.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.1
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpunit/phpunit: ^12.0
- rector/rector: ^2.3
- rector/type-perfect: ^2.1
- tomasvotruba/type-coverage: ^2.1
README
Unified social publishing for Laravel.
Socialize gives you one fluent API to share content to Facebook, Instagram, X, and LinkedIn, while still letting you use provider-specific features when needed.
Why Socialize
- One shared fluent API across providers
- Provider-specific chaining for platform-only features
- URL and local file media support with automatic normalization
- Named profile support per provider (multi-account ready)
- Strict typing, custom exceptions, and high test coverage
- Built for modern Laravel (11/12) and PHP 8.4+
Supported Providers
- Facebook (
facebook) - Instagram (
instagram) - X / Twitter (
twitterorx) - LinkedIn (
linkedin)
Requirements
- PHP
^8.4 - Laravel
^11.0 | ^12.0
Installation
composer require draliragab/socialize
Publish configuration:
php artisan vendor:publish --tag="socialize-config"
Quick Start
use DrAliRagab\Socialize\Facades\Socialize; $result = Socialize::provider('facebook') ->message('New release is live') ->link('https://example.com/release') ->share(); $id = $result->id(); $url = $result->url();
Comment on an existing post (all providers):
$comment = Socialize::provider('facebook') ->commentOn($id, 'Thanks everyone!');
Share then immediately add a comment:
$comment = Socialize::provider('linkedin') ->message('New release is live') ->link('https://example.com/release') ->shareAndComment('Happy to answer questions below.');
Switch provider with the same shared methods:
foreach (['facebook', 'instagram', 'twitter', 'linkedin'] as $provider) { Socialize::provider($provider) ->message('Hello from Socialize') ->link('https://example.com') ->share(); }
Fluent API
Shared methods
message(?string $message)link(?string $url, ?string $articleTitle = null)imageUrl(?string $url)videoUrl(?string $url)media(string $source, ?string $mediaType = null)mediaId(string $id)mediaIds(array $ids)metadata(array $metadata)option(string $key, mixed $value)share(): ShareResultcommentOn(string $postId, string $message): CommentResultshareAndComment(string $message): CommentResultdelete(string $postId): bool
Provider-specific methods
Facebook:
published(bool $published = true)scheduledAt(string|int|DateTimeInterface $dateTime)targeting(array $targeting)
Instagram:
carousel(array $imageUrls)altText(string $text)reel()
X / Twitter:
replyTo(string $postId)quote(string $postId)poll(array $options, int $durationMinutes)
LinkedIn:
visibility(string $visibility)distribution(string $distribution)mediaUrn(string $mediaUrn)poll(array $options, int $durationMinutes)
Poll notes:
poll()is supported fortwitterandlinkedin.- For LinkedIn,
message()is used as the poll question (max 140 chars). - LinkedIn accepts only these poll durations (minutes):
1440,4320,10080,20160.
Media Handling (URL + Local File)
Socialize keeps the API fluent and provider-agnostic:
- If a provider expects a URL (for example Facebook/Instagram) and you pass a local file, Socialize stores a temporary public file URL, uses it, then cleans it up.
- If a provider expects uploaded media IDs/URNs (for example X/LinkedIn) and you pass a URL, Socialize downloads and uploads it automatically.
Examples:
// Local image -> temporary URL flow for URL-based providers Socialize::provider('facebook') ->media('/absolute/path/banner.jpg', 'image') ->message('Local image test') ->share(); // URL image -> provider upload flow for upload-based providers Socialize::provider('linkedin') ->media('https://picsum.photos/1200/800', 'image') ->message('URL image test') ->share();
LinkedIn Link Title (Optional)
LinkedIn can require richer link content. You can pass an optional title using the second link() argument:
Socialize::provider('linkedin') ->message('Product update') ->link('https://example.com/post', 'Product update details') ->share();
This argument is optional and safe to keep in cross-provider fluent code.
Using Profiles
Socialize::provider('facebook', 'marketing') ->message('Campaign announcement') ->share();
Error Handling
use DrAliRagab\Socialize\Exceptions\ApiException; try { Socialize::provider('twitter')->message('Hello X')->share(); } catch (ApiException $e) { $provider = $e->provider()->value; $status = $e->status(); $response = $e->responseBody(); }
Model Trait
Use DrAliRagab\Socialize\Concerns\CanShareSocially to share directly from Eloquent models:
use DrAliRagab\Socialize\Concerns\CanShareSocially; class Post extends Model { use CanShareSocially; } $post->shareToFacebook(); $post->shareTo('linkedin');
The trait maps model fields using socialize.model_columns.
Configuration
All settings live in config/socialize.php.
General environment variables
SOCIALIZE_DEFAULT_PROFILE(optional, default:default)SOCIALIZE_HTTP_TIMEOUT(optional, default:120)SOCIALIZE_HTTP_CONNECT_TIMEOUT(optional, default:30)SOCIALIZE_HTTP_RETRIES(optional, default:1)SOCIALIZE_HTTP_RETRY_SLEEP_MS(optional, default:150)SOCIALIZE_TEMP_MEDIA_DISK(optional, default:public)SOCIALIZE_TEMP_MEDIA_DIRECTORY(optional, default:socialize-temp)SOCIALIZE_TEMP_MEDIA_VISIBILITY(optional, default:public)
SOCIALIZE_FACEBOOK_PAGE_ID(required)SOCIALIZE_FACEBOOK_ACCESS_TOKEN(required)SOCIALIZE_FACEBOOK_GRAPH_VERSION(optional, default:v25.0)SOCIALIZE_FACEBOOK_BASE_URL(optional)
SOCIALIZE_INSTAGRAM_IG_ID(required)SOCIALIZE_INSTAGRAM_ACCESS_TOKEN(required)SOCIALIZE_INSTAGRAM_GRAPH_VERSION(optional, default:v25.0)SOCIALIZE_INSTAGRAM_BASE_URL(optional)SOCIALIZE_INSTAGRAM_PUBLISH_RETRY_ATTEMPTS(optional, default:20)SOCIALIZE_INSTAGRAM_PUBLISH_RETRY_SLEEP_SECONDS(optional, default:3)
X / Twitter
SOCIALIZE_TWITTER_BEARER_TOKEN(required for runtime publishing)SOCIALIZE_TWITTER_BASE_URL(optional)SOCIALIZE_TWITTER_MEDIA_PROCESSING_POLL_ATTEMPTS(optional, default:15)
Token requirements:
- Use OAuth 2.0 User Context token, not app-only bearer token
- Required scopes:
tweet.read,tweet.write,users.read,media.write - Add
offline.accesswhen refresh tokens are needed
SOCIALIZE_LINKEDIN_AUTHOR(required, URN format likeurn:li:person:...)SOCIALIZE_LINKEDIN_ACCESS_TOKEN(required)SOCIALIZE_LINKEDIN_VERSION(optional, default:202602, format:YYYYMM)SOCIALIZE_LINKEDIN_BASE_URL(optional)
Local End-to-End Tester
You can test real provider calls without creating a full Laravel app.
- Copy
.testing.env.exampleto.testing.env - Fill credentials
- Run:
php bin/local-tester.php --help
Examples:
php bin/local-tester.php share --provider=facebook --message="Hello" --link="https://example.com" php bin/local-tester.php comment --provider=facebook --post-id="123_456" --comment="Nice post!" php bin/local-tester.php share-and-comment --provider=linkedin --message="Launch" --link="https://example.com" --comment="Any feedback?" php bin/local-tester.php share --provider=instagram --video-url="https://cdn.example.com/reel.mp4" --reel php bin/local-tester.php share --provider=twitter --message="Launch day" --media-source="/absolute/path/image.jpg" --media-type=image php bin/local-tester.php share --provider=linkedin --message="Professional update" --link="https://example.com" --link-title="Read more" php bin/local-tester.php delete --provider=linkedin --post-id="urn:li:share:123"
Development Quality Commands
composer analyse
composer test
composer test-coverage
composer format
composer rector
composer check
License
MIT