janwebdev / symfony-social-post-bundle
Modern Symfony bundle for posting to social networks (Twitter, Facebook, LinkedIn, Telegram, Instagram, Discord, WhatsApp) with async support
Installs: 153
Dependents: 0
Suggesters: 0
Security: 0
Stars: 2
Watchers: 1
Forks: 0
Open Issues: 0
Type:symfony-bundle
pkg:composer/janwebdev/symfony-social-post-bundle
Requires
- php: >=8.4
- psr/http-client: ^1.0
- psr/log: ^3.0
- symfony/config: ^7.4
- symfony/dependency-injection: ^7.4
- symfony/event-dispatcher: ^7.4
- symfony/framework-bundle: ^7.4
- symfony/http-client: ^7.4
- symfony/messenger: ^7.4
- symfony/yaml: ^7.4
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.64
- php-coveralls/php-coveralls: ^2.7
- phpstan/phpstan: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-symfony: ^2.0
- phpunit/phpunit: ^11.0
- symfony/phpunit-bridge: ^7.4
- symfony/var-dumper: ^7.4
README
Modern Symfony bundle for posting to multiple social networks (Twitter, Facebook, LinkedIn, Telegram) with async support.
โจ Features
- ๐ Modern Stack: PHP 8.4+ & Symfony 7.4+
- ๐ Multiple Networks: Twitter (X), Facebook, LinkedIn, Telegram, Instagram, Discord, WhatsApp, Threads
- โก Async Support: Built-in Symfony Messenger integration
- ๐ฏ Type Safe: Full PHP 8.4 type coverage with readonly properties
- ๐ธ Media Support: Image attachments for all providers
- ๐ช Event System: Before/After publish events
- ๐ No External Dependencies: All API clients built-in (no SDK bloat)
- ๐ Fluent API: MessageBuilder for easy message creation
- ๐ Detailed Results: Rich result objects with post IDs and URLs
- ๐ก๏ธ Error Handling: Comprehensive exception handling and logging
๐ฆ Installation
composer require janwebdev/symfony-social-post-bundle
โ๏ธ Configuration
Create config/packages/social_post.yaml:
social_post: providers: twitter: enabled: true api_key: "%env(TWITTER_API_KEY)%" api_secret: "%env(TWITTER_API_SECRET)%" access_token: "%env(TWITTER_ACCESS_TOKEN)%" access_token_secret: "%env(TWITTER_ACCESS_TOKEN_SECRET)%" facebook: enabled: true page_id: "%env(FACEBOOK_PAGE_ID)%" access_token: "%env(FACEBOOK_ACCESS_TOKEN)%" graph_version: "v20.0" linkedin: enabled: true organization_id: "%env(LINKEDIN_ORG_ID)%" access_token: "%env(LINKEDIN_ACCESS_TOKEN)%" telegram: enabled: true bot_token: "%env(TELEGRAM_BOT_TOKEN)%" channel_id: "%env(TELEGRAM_CHANNEL_ID)%" instagram: enabled: true account_id: "%env(INSTAGRAM_ACCOUNT_ID)%" access_token: "%env(INSTAGRAM_ACCESS_TOKEN)%" graph_version: "v20.0" discord: enabled: true webhook_url: "%env(DISCORD_WEBHOOK_URL)%" whatsapp: enabled: true phone_number_id: "%env(WHATSAPP_PHONE_NUMBER_ID)%" access_token: "%env(WHATSAPP_ACCESS_TOKEN)%" api_version: "v20.0" threads: enabled: true user_id: "%env(THREADS_USER_ID)%" access_token: "%env(THREADS_ACCESS_TOKEN)%" api_version: "v1.0"
Environment Variables
Add to your .env:
# Twitter (X) API v2 TWITTER_API_KEY=your_api_key TWITTER_API_SECRET=your_api_secret TWITTER_ACCESS_TOKEN=your_access_token TWITTER_ACCESS_TOKEN_SECRET=your_access_token_secret # Facebook Graph API FACEBOOK_PAGE_ID=your_page_id FACEBOOK_ACCESS_TOKEN=your_page_access_token # LinkedIn API v2 LINKEDIN_ORG_ID=your_organization_id LINKEDIN_ACCESS_TOKEN=your_access_token # Telegram Bot API TELEGRAM_BOT_TOKEN=your_bot_token TELEGRAM_CHANNEL_ID=@your_channel # Instagram Graph API INSTAGRAM_ACCOUNT_ID=your_instagram_business_account_id INSTAGRAM_ACCESS_TOKEN=your_access_token # Discord Webhooks DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR_WEBHOOK_URL # WhatsApp Channel API (BETA/UNSTABLE) WHATSAPP_PHONE_NUMBER_ID=your_phone_number_id WHATSAPP_ACCESS_TOKEN=your_access_token # Threads API THREADS_USER_ID=your_threads_user_id THREADS_ACCESS_TOKEN=your_access_token
โ ๏ธ Note: WhatsApp Channel integration is in BETA and may be unstable. The API is subject to change.
๐ Usage
Basic Usage
use Janwebdev\SocialPostBundle\Message\MessageBuilder; use Janwebdev\SocialPostBundle\Publisher\PublisherInterface; class YourService { public function __construct( private PublisherInterface $publisher ) {} public function postToSocialNetworks(): void { $message = MessageBuilder::create() ->setText('Hello, world! ๐') ->setLink('https://example.com') ->build(); $results = $this->publisher->publish($message); foreach ($results as $network => $result) { if ($result->isSuccess()) { echo "Posted to {$network}: {$result->getPostUrl()}\n"; } else { echo "Failed to post to {$network}: {$result->getErrorMessage()}\n"; } } } }
With Image Attachment
$message = MessageBuilder::create() ->setText('Check out this amazing photo!') ->setLink('https://example.com') ->addImage('/path/to/image.jpg', 'Photo description') ->build(); $results = $this->publisher->publish($message);
Publish to Specific Networks Only
$message = MessageBuilder::create() ->setText('This goes to Twitter and Facebook only') ->forNetworks(['twitter', 'facebook']) ->build(); $results = $this->publisher->publish($message);
Async Publishing
// Dispatch to message queue for async processing $this->publisher->publishAsync($message);
Using Individual Providers
use Janwebdev\SocialPostBundle\Provider\Twitter\TwitterProvider; class YourService { public function __construct( private TwitterProvider $twitterProvider ) {} public function postToTwitter(): void { $message = MessageBuilder::create() ->setText('Twitter-specific post') ->build(); $result = $this->twitterProvider->publish($message); if ($result->isSuccess()) { echo "Tweet ID: {$result->getPostId()}\n"; echo "Tweet URL: {$result->getPostUrl()}\n"; } } }
๐ Advanced Usage
Event Listeners
Listen to publish events:
use Janwebdev\SocialPostBundle\Event\AfterPublishEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class SocialPostSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ AfterPublishEvent::class => 'onAfterPublish', ]; } public function onAfterPublish(AfterPublishEvent $event): void { $results = $event->getResults(); // Log successful posts foreach ($results->getSuccessful() as $network => $result) { // Store post IDs in database, send notifications, etc. } } }
Custom Metadata
$message = MessageBuilder::create() ->setText('Message with metadata') ->addMetadata('campaign_id', 'summer-2026') ->addMetadata('source', 'website') ->build(); // Access metadata later $campaignId = $message->getMetadataValue('campaign_id');
Working with Results
$results = $this->publisher->publish($message); // Check if all successful if ($results->isAllSuccessful()) { echo "Posted to all networks!\n"; } // Check if any successful if ($results->hasAnySuccessful()) { echo "Posted to at least one network\n"; } // Get specific result $twitterResult = $results->getResult('twitter'); if ($twitterResult && $twitterResult->isSuccess()) { $postId = $twitterResult->getPostId(); $postUrl = $twitterResult->getPostUrl(); $metadata = $twitterResult->getMetadata(); } // Iterate through results foreach ($results as $network => $result) { echo "{$network}: "; echo $result->isSuccess() ? 'Success' : 'Failed'; echo "\n"; }
๐ง API Documentation
Twitter (X)
- API Version: v2
- Authentication: OAuth 1.0a
- Features: Text posts, images, auto-truncation
- Character Limit: 280 characters
- Media: Up to 4 images per tweet
- API Version: Graph API v20.0+
- Authentication: Page Access Token
- Features: Text posts, link previews, images
- Note: Use non-expiring page access tokens
- API Version: v2
- Authentication: OAuth 2.0 Bearer token
- Features: Text posts, article sharing
- Note: Requires organization access
Telegram
- API Version: Bot API
- Authentication: Bot Token
- Features: Text messages, photos, HTML formatting
- Note: Works with channels and groups
- API Version: Graph API v20.0+
- Authentication: Access Token (Business Account)
- Features: Photo posts with captions, container-based publishing
- Character Limit: 2200 characters for captions
- Note: Requires Instagram Business Account linked to Facebook Page
Discord
- API Version: Webhooks
- Authentication: Webhook URL
- Features: Text messages, rich embeds, image attachments
- Note: Very simple setup, no bot required
WhatsApp (โ ๏ธ BETA/UNSTABLE)
- API Version: Graph API v20.0+ (Channels API)
- Authentication: Phone Number ID + Access Token
- Features: Text messages, image messages
- Note: API is in beta, requires special access, may change without notice
Threads
- API Version: Threads API v1.0
- Authentication: User Access Token
- Features: Text posts, image posts, container-based publishing
- Character Limit: 500 characters
- Note: Requires Instagram account connected to Threads, similar workflow to Instagram API
๐งช Testing
# Run tests composer run-tests # Run with coverage composer run-tests-with-clover # Static analysis composer run-static-analysis # Code style check composer check-code-style # Fix code style composer fix-code-style
๐ API Credentials Setup
Twitter (X) API v2
- Go to Twitter Developer Portal
- Create a new App
- Generate API Keys and Access Tokens
- Enable OAuth 1.0a
- Set permissions to "Read and Write"
Facebook Graph API
- Go to Facebook Developers
- Create an App
- Add Facebook Login and Pages products
- Get a Page Access Token (make it permanent)
- Use Graph API Explorer to test
How to get permanent page token
LinkedIn API
- Go to LinkedIn Developers
- Create an App
- Add "Share on LinkedIn" product
- Request access to Marketing Developer Platform
- Generate access token with proper scopes
Telegram Bot API
- Talk to @BotFather on Telegram
- Create a new bot with
/newbot - Get your bot token
- Add bot to your channel as admin
- Use channel username (e.g.,
@mychannel) or chat ID
Instagram Graph API
- Go to Facebook Developers
- Create an App (same as for Facebook)
- Add Instagram product
- Connect your Instagram Business Account
- Get the Instagram Business Account ID
- Generate access token with
instagram_basic,instagram_content_publishpermissions - Important: Instagram account must be a Business or Creator account
Discord Webhooks
- Open Discord and go to your server
- Go to Server Settings โ Integrations โ Webhooks
- Click "New Webhook"
- Choose channel, set name and avatar
- Copy webhook URL
- Done! (Simplest setup ever)
WhatsApp Channel API (โ ๏ธ BETA)
- Go to Facebook Developers
- Create a WhatsApp Business App
- Request access to Channels API (currently in beta)
- Get Phone Number ID from WhatsApp Business Account
- Generate access token
- Warning: This API is experimental and may change
Threads API
- Go to Facebook Developers
- Create an App (can be same as Instagram/Facebook)
- Add Threads product to your app
- Connect your Instagram account that has Threads enabled
- Get your Threads User ID
- Generate access token with
threads_basic,threads_content_publishpermissions - Important: Your Instagram account must be connected to Threads
๐ Migration from v2.x
The new v3.0 uses a completely different architecture. Key changes:
Old API (v2.x)
use Janwebdev\SocialPost\Message; use Janwebdev\SocialPost\Publisher; $message = new Message('Hello world'); $publisher->publish($message);
New API (v3.0)
use Janwebdev\SocialPostBundle\Message\MessageBuilder; use Janwebdev\SocialPostBundle\Publisher\PublisherInterface; $message = MessageBuilder::create() ->setText('Hello world') ->build(); $results = $publisher->publish($message);
Breaking Changes
- New namespace:
Janwebdev\SocialPostBundle\instead ofJanwebdev\SocialPost\ - No external SDK dependencies
- Different configuration structure
- Different Message API (use MessageBuilder)
- Detailed result objects instead of boolean
- Built-in async support
๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
๐ License
This bundle is licensed under the MIT License. See the LICENSE file for details.
๐ Credits
- Original concept by Martin Georgiev
- Refactored and modernized by Yan Rogozinsky
๐ Links
๐ Version History
3.0.0 (2026-01-16)
- ๐ Complete rewrite for PHP 8.4 and Symfony 7.4
- โจ No external SDK dependencies (all built-in)
- ๐ Twitter API v2 support
- ๐ Facebook Graph API v20+ support
- ๐ LinkedIn API v2 support
- ๐ฌ Telegram Bot API support
- ๐ธ Instagram Graph API support
- ๐ฎ Discord Webhooks support
- ๐ฑ WhatsApp Channel API support (BETA)
- โก Async publishing via Symfony Messenger
- ๐ฏ Type-safe with readonly properties
- ๐ฆ MessageBuilder with fluent interface
- ๐ Detailed result objects
- ๐ช Event system for extensibility
- ๐ก๏ธ Comprehensive error handling
- ๐งต Threads API support
- ๐ 8 social networks total