Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Social Post Laravel Package

martin-georgiev/social-post

Social Post is a Laravel package for publishing content to multiple social networks from a single API. Compose a post once and share it to Facebook, Twitter/X, LinkedIn and more, with a clean, framework-friendly interface for managing cross-platform social updates.

Deep Wiki
Context7

Getting Started

composer require martin-georgiev/social-post — but read the archived state first. The last release was 2018-08-02, so pin it in a scratch project on PHP 7.1/7.2 to explore it, and treat it as a blueprint you vendor or fork, not a dependency you ship to production on PHP 8.

Where to look first (in the repo, in this order):

  1. src/Publisher.php — the single entry point; it fans a message out to a set of drivers and aggregates results.
  2. src/Driver/ — one class per network (Facebook, LinkedIn, Twitter) plus a DriverInterface with roughly publish(string $message, array $options = []) and getMaxMessageLength(): int.
  3. src/Exception/ — the failure types the publisher aggregates.
  4. The README usage block — shows the constructor wiring and the publish() call.

First use case — post one status update to all three networks and see the truncation behaviour:

use SocialPost\Publisher;
use SocialPost\Driver\Facebook;
use SocialPost\Driver\Twitter;
use SocialPost\Driver\LinkedIn;

$publisher = new Publisher([
    'facebook' => new Facebook($fbAppId, $fbAppSecret, $pageAccessToken),
    'twitter'  => new Twitter($consumerKey, $consumerSecret, $token, $tokenSecret),
    'linkedin' => new LinkedIn($clientId, $clientSecret, $accessToken),
], $logger);   // PSR-3 LoggerInterface

$publisher->publish('Shipping v2.0 of the API today. https://example.com/blog/v2');

The library deliberately does not do the OAuth dance. You obtain access tokens yourself (or with a dedicated SDK) and hand them in. That is the first thing to internalise: half your integration work lives outside this package.

Implementation Patterns

Wire it as a Laravel singleton with config, not inline news. Put credentials in config/services.php under social.*, build the driver map in a SocialServiceProvider, and bind Publisher as a singleton. Keep one config flag per network so you can disable a broken channel without a deploy.

Fan out per network, not per message. The biggest architectural mistake is calling publish() with all drivers in one request: one Twitter 429 blocks the LinkedIn post and the user waits for three HTTP round-trips. Instead resolve the publisher once, and dispatch one queued job per enabled network:

foreach (config('social.enabled') as $network) {
    PublishToNetwork::dispatch($network, $post->id)->onQueue('social');
}

Each job builds a single-driver publisher (or calls the driver directly), catches failures, and records the outcome on the posts row.

Keep a social_posts + social_deliveries table. Store the canonical message once, and one row per network with status, remote_id, error, attempts, published_at. Without remote_id you cannot delete, edit, or de-duplicate after a retry — and retries will happen.

Override the message per network when truncation is unacceptable. A 400-character announcement will be silently chopped on Twitter. Prefer storing body, body_twitter (≤280), body_linkedin and falling back to the publisher's truncation only for incidental content.

Test against fakes, not the network. Implement DriverInterface in a FakeDriver that records calls and optionally throws; assert your publisher/job logic against it. The real drivers are thin Guzzle wrappers, so integration tests are better done as one manual smoke test per network per quarter.

Extension point: the driver map is keyed by network name, so adding Mastodon/Bluesky/Threads is a new class implementing the same two methods plus a config entry — no changes to Publisher. This is the package's genuinely good idea and the reason to copy the abstraction into your own App\Social\ namespace.

Gotchas and Tips

  • Facebook is dead as written. publish_actions (posting to a user's timeline) was removed in 2018 — right around this release — and facebook/graph-sdk is abandoned. You must post as a Page with pages_manage_posts and app review, using /{page-id}/feed with a long-lived Page token. Expect to rewrite this driver entirely.
  • Twitter truncation is 140, not 280. A 2018 driver almost certainly hardcodes getMaxMessageLength() to 140 and may use byte-based substr. Check for mb_substr and bump to 280 (and account for t.co's 23-char URL counting). Twitter/X v1.1 statuses/update also now sits behind paid tiers; v2 requires a different endpoint and payload.
  • LinkedIn v1 shares are gone. people/~/shares with w_share was retired; the modern path is the UGC/Posts API with w_member_social, an author URN (urn:li:person:...), and headers like X-Restli-Protocol-Version: 2.0.0 plus a LinkedIn-Version header. Any 2018 driver will 403/404 immediately.
  • Dependency hell on modern PHP. Expect pinned facebook/graph-sdk, abraham/twitteroauth ^1.0, zoonman/linkedin-api-php-client, and php: ^7.0. Installation on PHP 8 needs --ignore-platform-reqs and will still hit removed functions. Don't fight it — fork the two files you need.
  • No retries, no rate-limit awareness. The publisher is a synchronous loop. Wrap calls with Http::retry() or Laravel's job $backoff/$tries, and honour Retry-After on 429 yourself.
  • Token lifetimes differ and are your problem. LinkedIn access tokens are ~60 days (refresh tokens are gated), Facebook needs short-lived→long-lived page token exchange, Twitter OAuth 1.0a tokens don't expire but the app does. Build a token refresh command before you launch, not after the first 401.
  • Inspect the exception chain. The publisher tends to throw an aggregate/"failed to publish" exception with the real driver error buried in getPrevious(). Log $e->getMessage() and iterate the chain, or you'll see "Could not publish" with no cause for hours.
  • Silent partial failures. If you pass all drivers and one throws, verify whether the others still ran — assert this explicitly in a test, because the semantics changed across point releases.
  • Emoji and multilingual copy. Confirm multibyte-safe truncation before you promise anyone a character budget; byte-slicing produces mojibake and rejected posts.
  • Never log driver constructor args. They contain consumer secrets and access tokens; scrub them from Laravel's exception context.

Bottom line for a Laravel team: don't require this in 2024+. Spend an hour reading Publisher and DriverInterface, then write ~200 lines of App\Social\{Publisher, Contracts\Driver, Drivers\*} using the current Graph API, X v2, and LinkedIn Posts API. You keep the one good interface, lose the abandoned dependencies, and gain the retry/queue/idempotency behaviour you'd have built on top anyway.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console