PHPackages                             janwebdev/symfony-social-post-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Queues &amp; Workers](/categories/queues)
4. /
5. janwebdev/symfony-social-post-bundle

ActiveSymfony-bundle[Queues &amp; Workers](/categories/queues)

janwebdev/symfony-social-post-bundle
====================================

Modern Symfony bundle for posting to social networks (Twitter, Facebook, LinkedIn, Telegram, Instagram, Discord, WhatsApp) with async support

3.2.5(1mo ago)2161↓100%MITPHPPHP &gt;=8.4

Since Mar 30Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/janwebdev/symfony-social-post-bundle)[ Packagist](https://packagist.org/packages/janwebdev/symfony-social-post-bundle)[ RSS](/packages/janwebdev-symfony-social-post-bundle/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (17)Versions (23)Used By (0)

Symfony Social Post Bundle
==========================

[](#symfony-social-post-bundle)

[![Latest Stable Version](https://camo.githubusercontent.com/6d16197d16ee6730c7100a836d5ea3d822482d23aab7a9004e5539e0c545ab26/68747470733a2f2f706f7365722e707567782e6f72672f6a616e7765626465762f73796d666f6e792d736f6369616c2d706f73742d62756e646c652f76657273696f6e)](https://packagist.org/packages/janwebdev/symfony-social-post-bundle)[![Total Downloads](https://camo.githubusercontent.com/297804fcccf8d621eca7d1980dec59a6ca5102e896e00715a2088095e0f1a153/68747470733a2f2f706f7365722e707567782e6f72672f6a616e7765626465762f73796d666f6e792d736f6369616c2d706f73742d62756e646c652f646f776e6c6f616473)](https://packagist.org/packages/janwebdev/symfony-social-post-bundle)[![License](https://camo.githubusercontent.com/dfc738f73b79ec922bd07c07940cdeb5a925f0c3b8e6539feaac9d54c92c40fa/68747470733a2f2f706f7365722e707567782e6f72672f6a616e7765626465762f73796d666f6e792d736f6369616c2d706f73742d62756e646c652f6c6963656e7365)](https://packagist.org/packages/janwebdev/symfony-social-post-bundle)

Modern Symfony bundle for posting to multiple social networks (Twitter, Facebook, LinkedIn, Telegram) with async support.

✨ Features
----------

[](#-features)

- 🚀 **Modern Stack**: PHP 8.4+ &amp; Symfony 7.4+
- 🌐 **Multiple Networks**: Twitter (X), Facebook, LinkedIn, Telegram, Instagram, Discord, Threads, Pinterest (+ WhatsApp ⚠️ deprecated)
- ⚡ **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
--------------

[](#-installation)

```
composer require janwebdev/symfony-social-post-bundle
```

⚙️ Configuration
----------------

[](#️-configuration)

Create `config/packages/social_post.yaml`:

```
social_post:
  providers:
    twitter:
      enabled: true
      consumer_key: "%env(TWITTER_CONSUMER_KEY)%"
      consumer_secret: "%env(TWITTER_CONSUMER_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: "v22.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: "v22.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: "v22.0"

    threads:
      enabled: true
      user_id: "%env(THREADS_USER_ID)%"
      access_token: "%env(THREADS_ACCESS_TOKEN)%"
      api_version: "v1.0"

    pinterest:
      enabled: true
      board_id: "%env(PINTEREST_BOARD_ID)%"
      access_token: "%env(PINTEREST_ACCESS_TOKEN)%"
```

### Environment Variables

[](#environment-variables)

Add to your `.env`:

```
# Twitter (X) API v2
TWITTER_CONSUMER_KEY=your_consumer_key
TWITTER_CONSUMER_SECRET=your_consumer_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

# Pinterest API v5
PINTEREST_BOARD_ID=your_board_id
PINTEREST_ACCESS_TOKEN=your_access_token
```

> ⚠️ **Note**: WhatsApp Channel integration is in BETA and may be unstable. The API is subject to change.

🚀 Usage
-------

[](#-usage)

### Basic 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

[](#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

[](#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

[](#async-publishing)

```
// Dispatch to message queue for async processing
$this->publisher->publishAsync($message);
```

### Using Individual Providers

[](#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
----------------

[](#-advanced-usage)

### Event Listeners

[](#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

[](#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

[](#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
-------------------

[](#-api-documentation)

### Twitter (X)

[](#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

### Facebook

[](#facebook)

- **API Version**: Graph API v22.0+
- **Authentication**: Page Access Token
- **Features**: Text posts, link previews, images
- **Note**: Use non-expiring page access tokens

### LinkedIn

[](#linkedin)

- **API Version**: Community Management API (/rest/posts)
- **Authentication**: OAuth 2.0 Bearer token
- **Features**: Text posts, article sharing
- **Note**: Requires organization access. Uses the Community Management API (`POST /rest/posts`), replacing the legacy `/v2/ugcPosts` endpoint.

### Telegram

[](#telegram)

- **API Version**: Bot API
- **Authentication**: Bot Token
- **Features**: Text messages, photos, HTML formatting
- **Note**: Works with channels and groups

### Instagram

[](#instagram)

- **API Version**: Graph API v22.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

[](#discord)

- **API Version**: Webhooks
- **Authentication**: Webhook URL
- **Features**: Text messages, rich embeds, image attachments
- **Note**: Very simple setup, no bot required

### WhatsApp (⚠️ DEPRECATED)

[](#whatsapp-️-deprecated)

> ⚠️ **DEPRECATED**: `WhatsAppProvider` is deprecated and will be removed in v4.0. WhatsApp Business Cloud API does not support posting to public Channels; it only sends template messages to opted-in users.

- **API Version**: Graph API v22.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

[](#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

### Pinterest

[](#pinterest)

- **API Version**: API v5
- **Authentication**: OAuth 2.0 Bearer token
- **Features**: Link pins, image URL pins
- **Note**: Requires Pinterest Business account. Image attachments must be publicly accessible URLs — local file paths are not supported.

🧪 Testing
---------

[](#-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
-----------------------

[](#-api-credentials-setup)

### Twitter (X) API v2

[](#twitter-x-api-v2)

1. Go to [Twitter Developer Portal](https://developer.twitter.com/en/portal/dashboard)
2. Create a new App
3. Generate API Keys and Access Tokens
4. Enable OAuth 1.0a
5. Set permissions to "Read and Write"

### Facebook Graph API

[](#facebook-graph-api)

1. Go to [Facebook Developers](https://developers.facebook.com/)
2. Create an App
3. Add Facebook Login and Pages products
4. Get a Page Access Token (make it permanent)
5. Use Graph API Explorer to test

[How to get permanent page token](https://developers.facebook.com/docs/pages/access-tokens#get-a-long-lived-page-access-token)

### LinkedIn API

[](#linkedin-api)

1. Go to [LinkedIn Developers](https://www.linkedin.com/developers/)
2. Create an App
3. Add "Share on LinkedIn" product
4. Request access to Marketing Developer Platform
5. Generate access token with proper scopes

### Telegram Bot API

[](#telegram-bot-api)

1. Talk to [@BotFather](https://t.me/botfather) on Telegram
2. Create a new bot with `/newbot`
3. Get your bot token
4. Add bot to your channel as admin
5. Use channel username (e.g., `@mychannel`) or chat ID

### Instagram Graph API

[](#instagram-graph-api)

1. Go to [Facebook Developers](https://developers.facebook.com/)
2. Create an App (same as for Facebook)
3. Add Instagram product
4. Connect your Instagram Business Account
5. Get the Instagram Business Account ID
6. Generate access token with `instagram_basic`, `instagram_content_publish` permissions
7. **Important**: Instagram account must be a Business or Creator account

### Discord Webhooks

[](#discord-webhooks)

1. Open Discord and go to your server
2. Go to Server Settings → Integrations → Webhooks
3. Click "New Webhook"
4. Choose channel, set name and avatar
5. Copy webhook URL
6. Done! (Simplest setup ever)

### WhatsApp Channel API (⚠️ BETA)

[](#whatsapp-channel-api-️-beta)

1. Go to [Facebook Developers](https://developers.facebook.com/)
2. Create a WhatsApp Business App
3. Request access to Channels API (currently in beta)
4. Get Phone Number ID from WhatsApp Business Account
5. Generate access token
6. **Warning**: This API is experimental and may change

### Threads API

[](#threads-api)

1. Go to [Facebook Developers](https://developers.facebook.com/)
2. Create an App (can be same as Instagram/Facebook)
3. Add Threads product to your app
4. Connect your Instagram account that has Threads enabled
5. Get your Threads User ID
6. Generate access token with `threads_basic`, `threads_content_publish` permissions
7. **Important**: Your Instagram account must be connected to Threads

[How to get Threads API access](https://developers.facebook.com/docs/threads/get-started)

### Pinterest API v5

[](#pinterest-api-v5)

1. Go to [Pinterest Developers](https://developers.pinterest.com/)
2. Create an App
3. Request "Read/Write" access for Pins
4. Generate an access token
5. Get your Board ID from a board URL: `pinterest.com/{username}/{board-name}/` → go to board settings to find the numeric ID
6. Permissions needed: `pins:read`, `pins:write`, `boards:read`

🔄 Migration from v2.x
---------------------

[](#-migration-from-v2x)

The new v3.0 uses a completely different architecture. Key changes:

### Old API (v2.x)

[](#old-api-v2x)

```
use Janwebdev\SocialPost\Message;
use Janwebdev\SocialPost\Publisher;

$message = new Message('Hello world');
$publisher->publish($message);
```

### New API (v3.0)

[](#new-api-v30)

```
use Janwebdev\SocialPostBundle\Message\MessageBuilder;
use Janwebdev\SocialPostBundle\Publisher\PublisherInterface;

$message = MessageBuilder::create()
    ->setText('Hello world')
    ->build();

$results = $publisher->publish($message);
```

### Breaking Changes

[](#breaking-changes)

- New namespace: `Janwebdev\SocialPostBundle\` instead of `Janwebdev\SocialPost\`
- No external SDK dependencies
- Different configuration structure
- Different Message API (use MessageBuilder)
- Detailed result objects instead of boolean
- Built-in async support

🤝 Contributing
--------------

[](#-contributing)

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License
---------

[](#-license)

This bundle is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.

👏 Credits
---------

[](#-credits)

- Original concept by [Martin Georgiev](https://github.com/martin-georgiev)
- Refactored and modernized by [Yan Rogozinsky](https://github.com/janwebdev)

🔗 Links
-------

[](#-links)

- [Documentation](https://github.com/janwebdev/symfony-social-post-bundle)
- [Issue Tracker](https://github.com/janwebdev/symfony-social-post-bundle/issues)
- [Packagist](https://packagist.org/packages/janwebdev/symfony-social-post-bundle)

📝 Version History
-----------------

[](#-version-history)

See [CHANGELOG.md](CHANGELOG.md) for full version history.

###  Health Score

50

—

FairBetter than 95% of packages

Maintenance97

Actively maintained with recent releases

Popularity15

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity68

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~34 days

Recently: every ~0 days

Total

22

Last Release

47d ago

Major Versions

1.6 → 2.02024-03-31

2.0 → v3.0.x-dev2026-01-17

PHP version history (2 changes)1.0PHP &gt;=8.1

v3.0.x-devPHP &gt;=8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/c883713524aa45bd05ea6b6bfae4b59807241e1d505630b4a4bdba9ef13ea7fd?d=identicon)[janwebdev](/maintainers/janwebdev)

---

Top Contributors

[![janwebdev](https://avatars.githubusercontent.com/u/6725905?v=4)](https://github.com/janwebdev "janwebdev (35 commits)")

---

Tags

apiphpsocial-networksymfonyasyncsymfonybundlefacebookinstagramtwittertelegramsocial networkwhatsapplinkedinMessengersocial mediadiscordsymfony7php84

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/janwebdev-symfony-social-post-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/janwebdev-symfony-social-post-bundle/health.svg)](https://phpackages.com/packages/janwebdev-symfony-social-post-bundle)
```

###  Alternatives

[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.4k5.6M647](/packages/sylius-sylius)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.3M152](/packages/sulu-sulu)[shopware/platform

The Shopware e-commerce core

3.3k1.5M3](/packages/shopware-platform)[contao/core-bundle

Contao Open Source CMS

1231.6M2.3k](/packages/contao-core-bundle)[prestashop/prestashop

PrestaShop is an Open Source e-commerce platform, committed to providing the best shopping cart experience for both merchants and customers.

9.0k15.4k](/packages/prestashop-prestashop)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

595.2M386](/packages/shopware-core)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
