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 Menu Bundle Laravel Package

tourze/wechat-official-account-menu-bundle

A Symfony bundle for managing custom menus on WeChat Official Accounts. It integrates menu creation and configuration into your Symfony application, helping developers define and publish official account menu structures through the familiar bundle workflow. Suitable for projects already using Symfon...

View on GitHub
Deep Wiki
Context7

Getting Started

tourze/wechat-official-account-menu-bundle 0.0.1 is an initial release with no changelog — the release notes are literally just a compare link. Treat it as pre-alpha: there is no upgrade path, no deprecation policy, and the public API can change in any 0.0.x bump.

First, confirm what you actually installed. Despite the "bundle" suffix (Tourze publishes Symfony bundles), check composer.json before assuming Laravel compatibility:

composer show tourze/wechat-official-account-menu-bundle

If type is symfony-bundle and it requires symfony/http-kernel / symfony/dependency-injection, you cannot composer require it into a Laravel app and expect a service provider to be auto-discovered. Your minimal first steps:

  1. Read src/ before writing any code. Look for the menu value objects (typically Button, SubButton, Menu), the service that calls https://api.weixin.qq.com/cgi-bin/menu/create, and how it obtains an access_token. That service boundary is the only thing you actually care about.
  2. Pin the exact version — "tourze/wechat-official-account-menu-bundle": "0.0.1" — and commit the lock file. Do not use ^0.0.1; a 0.0.2 can rename classes.
  3. Decide: bridge or borrow. For most Laravel apps the pragmatic path is to read the bundle's menu-building logic and the exact JSON shape it produces, then reimplement it as a small WechatMenu class in app/Services over Laravel's Http facade. Bridging a Symfony bundle into Laravel means manually registering its Extension and Bundle::build() container definitions, which is rarely worth it for a menu-payload builder.

Your first real use case is almost always the same: publish a static click/view menu with one level of sub-buttons for a single official account, in a queued job, so a marketing change doesn't need a deploy.

Implementation Patterns

Wrap the client, don't sprinkle it. Whatever the package exposes, put a single Laravel service in front of it so the eventual 0.1.0 rewrite touches one file:

final class WechatMenuService
{
    public function publish(Menu $menu): void
    {
        // delegate to the bundle's menu client, or POST the payload yourself
        Http::post('https://api.weixin.qq.com/cgi-bin/menu/create', [
            'access_token' => $this->token(),
            'button' => $menu->toArray(),
        ])->throw()->json();
    }
}

Build the menu declaratively from config, not from code. Menus change for business reasons, not engineering ones. A config/wechat-menu.php array mapped into the package's value objects gives you a menu that ops can amend without touching PHP:

'buttons' => [
    ['type' => 'view',  'name' => 'Shop',    'url' => env('WECHAT_SHOP_URL')],
    ['type' => 'click', 'name' => 'Support', 'event_key' => 'SUPPORT'],
    ['name' => 'More', 'sub_button' => [...]],
],

Publish via a job, gated by environment. Menu creation is a full replacement of the live menu. Run it from php artisan wechat:menu:publish on deploy, or a queued job triggered by a config change — never inline in a request. Guard with app()->isProduction() so local/staging runs against the test-account credentials, never the production account.

Cache the access token aggressively and centrally. WeChat issues a token valid ~7200s and rate-limits issuance; two concurrent calls refreshing it will invalidate each other (error 40001). Put token acquisition behind Cache::remember('wechat:access_token', 7000, ...) and wrap the refresh in Cache::lock().

Integrate with your existing event handling. If you already handle click events from WeChat's message push, keep event_key values in the same enum used by your webhook controller — that's the seam where the menu definition and the message handler must agree, and it's the thing most likely to silently break.

Test against a WeChat test account (测试号). The test sandbox supports the menu APIs with a separate appid/secret and doesn't expose your real followers. Point .env.testing at it.

Gotchas and Tips

  • Version 0.0.1 is the story here. No changelog means no stated compatibility range. Check the composer.json constraints against your Symfony/Laravel versions manually; do not trust that it installs cleanly.
  • Symfony bundle ≠ Laravel package. There is no extra.laravel.providers. Expect no auto-discovery, no Laravel config publishing, and possibly container-definition code that references services you must register yourself.
  • Menus are replaced wholesale. menu/create overwrites everything, including any personalized/conditional menus configured in the WeChat admin console. If a human has ever edited the menu in the MP console, your deploy will silently delete their work. Agree on one source of truth.
  • Hard structural limits, enforced server-side with unhelpful errors. Max 3 top-level buttons, max 5 sub-buttons each, top-level name ≤ 16 bytes, sub-button name ≤ 60 bytes (UTF-8 bytes, not characters — Chinese names hit this fast). A 40033/40017 response usually means you exceeded one.
  • Access token errors are the number one debugging trap. 40001 (invalid credential) is almost always a stale token invalidated by another process or by the user resetting the secret in the console. 40164 means your server IP is not in the account's IP whitelist — this bites immediately in Docker/CI where egress IPs differ.
  • Sub-button type: view requires a valid ICP-filed domain matching the account's configured business domain, otherwise the menu saves but the link 404s inside WeChat's browser.
  • Debugging tip: the API returns {"errcode":0,"errmsg":"ok"} on success with HTTP 200. Any HTTP-client throw() on status alone won't catch failures — you must inspect errcode. Add that check to your wrapper.
  • Extension points to watch for in later releases: how the bundle resolves credentials (a CredentialInterface-style abstraction is common in Tourze packages) and whether it ships a MenuProvider. If 0.1.0 introduces a provider interface, that's your migration hook — build the config-driven menu behind an interface now so you can adopt it.
  • Given the maturity, vendor-pin and monitor. Watch the repo for the first tagged release with real notes. Until then, avoid letting the bundle's classes leak into your domain layer; keep the dependency at the edge.
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.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast