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

Wechat Official Account Draft Bundle Laravel Package

tourze/wechat-official-account-draft-bundle

A Symfony bundle for managing WeChat Official Account drafts. It wires the WeChat draft APIs into your Symfony app, letting you create, list, update, and delete official account draft articles through clean, configurable services so content can be staged in WeChat before publishing.

View on GitHub
Deep Wiki
Context7

Getting Started

tourze/wechat-official-account-draft-bundle is the WeChat Official Account (公众号) draft box / 草稿箱 API binding — creating, listing, updating and deleting drafts, plus the handoff to the publish (freepublish) endpoints. Version 0.0.1 is the first tagged release with an empty changelog, so treat this as "source is the documentation".

Minimal steps:

composer require tourze/wechat-official-account-draft-bundle:0.0.1

Then, before writing any code, read the repository in this order:

  1. composer.json — required PHP version, whether it depends on symfony/http-client, a PSR-18 client, or tourze/wechat-official-account-bundle (the access-token layer).
  2. src/ — look for the request/response object pairs (*Request, *Response) and any *Bundle.php / *ServiceProvider. Note: Tourze's *-bundle packages are conventionally Symfony bundles. Confirm whether Laravel auto-discovery is wired up; if not, you instantiate the request classes directly and inject your own HTTP client.
  3. Existing tests / fixtures — usually the fastest way to see a valid article payload shape.

First use case to validate the integration end-to-end: create a single draft from one article and confirm you get a media_id back, then list drafts and find it. That exercises auth, serialization, and response parsing in one shot. Do not start with publishing — publishing consumes a quota and is harder to undo than a draft.

// Shape is indicative — verify class names against src/ first.
$response = $client->send(new AddDraftRequest([
    'articles' => [[
        'title'              => 'Hello',
        'author'             => 'team',
        'content'            => $html,
        'thumb_media_id'     => $thumbMediaId, // permanent image material
        'content_source_url' => 'https://example.com/post',
        'need_open_comment'  => 0,
    ]],
]));

$mediaId = $response->getMediaId();

Implementation Patterns

Bind it once, inject everywhere. Register the client/request factory as a singleton in a service provider so configuration (app id, secret, token source) lives in config/services.php and not in call sites. Wrap the bundle rather than calling it from controllers — a thin WeChatDraftService of your own means an eventual 0.0.x breaking change is a one-file fix.

Treat media_id as your primary key, not the article. Persist a drafts table: media_id, local content id, thumb_media_id, status (draft / submitted / published), submitted_at, plus the raw response JSON. Drafts are the unit WeChat's API addresses; your database should mirror that.

Pipeline it. The realistic day-to-day workflow is a multi-step job, not a single call:

  1. Upload cover image → get thumb_media_id (permanent material API).
  2. Rewrite <img src> in the article HTML to WeChat-hosted URLs (see Gotchas).
  3. draft/add → store media_id.
  4. Human review in the OA backend.
  5. freepublish/submit with the media_id, then poll freepublish/get for status.

Model steps 3–5 as queued jobs with $tries and exponential backoff; WeChat's API is rate-limited and transiently flaky.

Token handling is the seam to get right. If the bundle accepts an injected token provider, wire it to a cached, single-flight token store (Cache::lock around refresh) shared with every other WeChat package in your app. If it manages tokens internally, check whether it refreshes on 40001/42001 or just fails — this determines whether you need a retry decorator.

Testing. Put an interface in front of the client and fake it in tests. If the bundle is built on Symfony HttpClient, MockHttpClient with recorded fixtures is the cheapest way to get coverage; if it uses Laravel's Http facade, Http::fake() works directly. Assert on errcode handling, not just the happy path.

Gotchas and Tips

  • 0.0.1 is an unstable contract. Pin the exact version ("0.0.1", not ^0.0.1) and read the diff before every bump. The empty changelog means no BC promise has been stated.
  • Symfony bundle ≠ Laravel package. Verify package discovery; you may need $app->register(...) manually, or you may find the bundle cannot be resolved by Laravel's container at all and must be instantiated by hand.
  • WeChat returns HTTP 200 on failure. Always inspect errcode/errmsg in the decoded body. A response wrapper that only checks status codes will silently swallow 40007 (invalid media_id) and 45009 (rate limit).
  • thumb_media_id must be a permanent image material, not a temporary one, and not a URL. Upload it first; temporary media expires after three days and the draft will fail to publish later.
  • WeChat strips externally-hosted images. Article HTML referencing your own CDN renders as broken images in the published post. Upload each image to WeChat and rewrite src before the draft call — this is the single most common "it worked in staging" bug.
  • IP allowlist. The server's egress IP must be in the Official Account's IP whitelist, or every token call fails with 40164. Containerized/ephemeral egress IPs are a recurring trap.
  • Cache the access token centrally. Requesting a new token invalidates the previous one; two packages each fetching their own token will fight and cause intermittent 40001 errors everywhere.
  • Draft box and publish quotas exist and vary by account type. Surface quota errors as a distinct exception so your queue doesn't retry a permanently-blocked operation 10 times.
  • Debugging: log the full request body and raw response for every call behind a config flag. WeChat's error messages are terse; without the payload you cannot reproduce.
  • Extension points to look for: an injectable HTTP client (lets you add logging/retry middleware), and whether request classes are final — if they are, plan to wrap rather than extend.
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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route