or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-services.mdindex.mdmaterial-management.mdmenu-management.mdmessage-handling.mdservice-management.mdshopping-guide.mdtemplate-messaging.mduser-management.md

menu-management.mddocs/

0

# Menu Management

1

2

Create, update, and delete custom menus for WeChat Official Accounts, providing interactive navigation for users.

3

4

## Menu Service Interface

5

6

```java { .api }

7

interface WxMpMenuService {

8

// Menu operations

9

String menuCreate(WxMenu menu) throws WxErrorException;

10

void menuDelete() throws WxErrorException;

11

WxMenu menuGet() throws WxErrorException;

12

WxMpGetSelfMenuInfoResult getSelfMenuInfo() throws WxErrorException;

13

14

// Conditional menu operations

15

String menuTryMatch(String userId) throws WxErrorException;

16

String conditionalMenuCreate(WxMenuConditional menu) throws WxErrorException;

17

void conditionalMenuDelete(String menuid) throws WxErrorException;

18

}

19

```

20

21

## Menu Data Models

22

23

### Basic Menu Structure

24

25

```java { .api }

26

class WxMenu implements Serializable {

27

private List<WxMenuButton> buttons;

28

private WxMenuRule matchRule;

29

30

public List<WxMenuButton> getButtons();

31

public void setButtons(List<WxMenuButton> buttons);

32

public WxMenuRule getMatchRule();

33

public void setMatchRule(WxMenuRule matchRule);

34

}

35

36

class WxMenuButton implements Serializable {

37

private String type;

38

private String name;

39

private String key;

40

private String url;

41

private String mediaId;

42

private String appid;

43

private String pagepath;

44

private String articleId;

45

private List<WxMenuButton> subButtons;

46

47

public String getType();

48

public void setType(String type);

49

public String getName();

50

public void setName(String name);

51

public String getKey();

52

public void setKey(String key);

53

public String getUrl();

54

public void setUrl(String url);

55

public String getMediaId();

56

public void setMediaId(String mediaId);

57

public String getAppid();

58

public void setAppid(String appid);

59

public String getPagepath();

60

public void setPagepath(String pagepath);

61

public String getArticleId();

62

public void setArticleId(String articleId);

63

public List<WxMenuButton> getSubButtons();

64

public void setSubButtons(List<WxMenuButton> subButtons);

65

}

66

```

67

68

### Conditional Menu

69

70

```java { .api }

71

class WxMenuConditional extends WxMenu {

72

private String menuid;

73

74

public String getMenuid();

75

public void setMenuid(String menuid);

76

}

77

78

class WxMenuRule implements Serializable {

79

private String tagId;

80

private String sex;

81

private String country;

82

private String province;

83

private String city;

84

private String clientPlatformType;

85

private String language;

86

87

public String getTagId();

88

public void setTagId(String tagId);

89

public String getSex();

90

public void setSex(String sex);

91

public String getCountry();

92

public void setCountry(String country);

93

public String getProvince();

94

public void setProvince(String province);

95

public String getCity();

96

public void setCity(String city);

97

public String getClientPlatformType();

98

public void setClientPlatformType(String clientPlatformType);

99

public String getLanguage();

100

public void setLanguage(String language);

101

}

102

```

103

104

### Menu Information Result

105

106

```java { .api }

107

class WxMpGetSelfMenuInfoResult implements Serializable {

108

private Boolean isMenuOpen;

109

private List<WxMpSelfMenuInfo> selfMenuInfo;

110

111

public Boolean getIsMenuOpen();

112

public void setIsMenuOpen(Boolean isMenuOpen);

113

public List<WxMpSelfMenuInfo> getSelfMenuInfo();

114

public void setSelfMenuInfo(List<WxMpSelfMenuInfo> selfMenuInfo);

115

116

public static class WxMpSelfMenuInfo implements Serializable {

117

private String type;

118

private String name;

119

private String value;

120

private WxMpSelfMenuInfo newsInfo;

121

private List<WxMpSelfMenuInfo> subButton;

122

123

public String getType();

124

public void setType(String type);

125

public String getName();

126

public void setName(String name);

127

public String getValue();

128

public void setValue(String value);

129

public WxMpSelfMenuInfo getNewsInfo();

130

public void setNewsInfo(WxMpSelfMenuInfo newsInfo);

131

public List<WxMpSelfMenuInfo> getSubButton();

132

public void setSubButton(List<WxMpSelfMenuInfo> subButton);

133

}

134

}

135

```

136

137

## Menu Button Types

138

139

```java { .api }

140

// Menu button type constants

141

public static final String BUTTON_TYPE_CLICK = "click";

142

public static final String BUTTON_TYPE_VIEW = "view";

143

public static final String BUTTON_TYPE_SCANCODE_PUSH = "scancode_push";

144

public static final String BUTTON_TYPE_SCANCODE_WAITMSG = "scancode_waitmsg";

145

public static final String BUTTON_TYPE_PIC_SYSPHOTO = "pic_sysphoto";

146

public static final String BUTTON_TYPE_PIC_PHOTO_OR_ALBUM = "pic_photo_or_album";

147

public static final String BUTTON_TYPE_PIC_WEIXIN = "pic_weixin";

148

public static final String BUTTON_TYPE_LOCATION_SELECT = "location_select";

149

public static final String BUTTON_TYPE_MEDIA_ID = "media_id";

150

public static final String BUTTON_TYPE_VIEW_LIMITED = "view_limited";

151

public static final String BUTTON_TYPE_MINIPROGRAM = "miniprogram";

152

public static final String BUTTON_TYPE_ARTICLE_ID = "article_id";

153

public static final String BUTTON_TYPE_ARTICLE_VIEW_LIMITED = "article_view_limited";

154

```

155

156

## Usage Examples

157

158

### Create Basic Menu

159

160

```java

161

import me.chanjar.weixin.mp.bean.menu.WxMenu;

162

import me.chanjar.weixin.mp.bean.menu.WxMenuButton;

163

164

// Create menu

165

WxMenu menu = new WxMenu();

166

List<WxMenuButton> buttons = new ArrayList<>();

167

168

// First level button - Click type

169

WxMenuButton button1 = new WxMenuButton();

170

button1.setType(WxConsts.MenuButtonType.CLICK);

171

button1.setName("About Us");

172

button1.setKey("ABOUT_US");

173

buttons.add(button1);

174

175

// First level button - View type (URL)

176

WxMenuButton button2 = new WxMenuButton();

177

button2.setType(WxConsts.MenuButtonType.VIEW);

178

button2.setName("Website");

179

button2.setUrl("https://www.example.com");

180

buttons.add(button2);

181

182

// First level button with sub-buttons

183

WxMenuButton button3 = new WxMenuButton();

184

button3.setName("Services");

185

186

List<WxMenuButton> subButtons = new ArrayList<>();

187

188

// Sub-button 1

189

WxMenuButton subButton1 = new WxMenuButton();

190

subButton1.setType(WxConsts.MenuButtonType.CLICK);

191

subButton1.setName("Service A");

192

subButton1.setKey("SERVICE_A");

193

subButtons.add(subButton1);

194

195

// Sub-button 2

196

WxMenuButton subButton2 = new WxMenuButton();

197

subButton2.setType(WxConsts.MenuButtonType.VIEW);

198

subButton2.setName("Service B");

199

subButton2.setUrl("https://www.example.com/service-b");

200

subButtons.add(subButton2);

201

202

button3.setSubButtons(subButtons);

203

buttons.add(button3);

204

205

menu.setButtons(buttons);

206

207

// Create menu

208

String result = wxService.getMenuService().menuCreate(menu);

209

System.out.println("Menu created: " + result);

210

```

211

212

### Create Advanced Menu with Special Button Types

213

214

```java

215

WxMenu advancedMenu = new WxMenu();

216

List<WxMenuButton> buttons = new ArrayList<>();

217

218

// Scan QR code button

219

WxMenuButton scanButton = new WxMenuButton();

220

scanButton.setType(WxConsts.MenuButtonType.SCANCODE_PUSH);

221

scanButton.setName("Scan QR");

222

scanButton.setKey("SCAN_QR");

223

buttons.add(scanButton);

224

225

// Photo button

226

WxMenuButton photoButton = new WxMenuButton();

227

photoButton.setType(WxConsts.MenuButtonType.PIC_PHOTO_OR_ALBUM);

228

photoButton.setName("Upload Photo");

229

photoButton.setKey("UPLOAD_PHOTO");

230

buttons.add(photoButton);

231

232

// Location button

233

WxMenuButton locationButton = new WxMenuButton();

234

locationButton.setType(WxConsts.MenuButtonType.LOCATION_SELECT);

235

locationButton.setName("Send Location");

236

locationButton.setKey("SEND_LOCATION");

237

buttons.add(locationButton);

238

239

advancedMenu.setButtons(buttons);

240

wxService.getMenuService().menuCreate(advancedMenu);

241

```

242

243

### Create Menu with Mini Program Button

244

245

```java

246

WxMenu miniProgramMenu = new WxMenu();

247

List<WxMenuButton> buttons = new ArrayList<>();

248

249

// Mini program button

250

WxMenuButton miniProgramButton = new WxMenuButton();

251

miniProgramButton.setType(WxConsts.MenuButtonType.MINIPROGRAM);

252

miniProgramButton.setName("Mini Program");

253

miniProgramButton.setUrl("https://fallback.url.com"); // Fallback URL for older versions

254

miniProgramButton.setAppid("your-miniprogram-appid");

255

miniProgramButton.setPagepath("pages/index/index");

256

buttons.add(miniProgramButton);

257

258

miniProgramMenu.setButtons(buttons);

259

wxService.getMenuService().menuCreate(miniProgramMenu);

260

```

261

262

### Create Menu with Media Button

263

264

```java

265

// Upload media first (image/voice)

266

File mediaFile = new File("path/to/media.jpg");

267

WxMpMaterialUploadResult uploadResult = wxService.getMaterialService()

268

.materialFileUpload(WxConsts.MediaFileType.IMAGE, mediaFile);

269

270

// Create menu with media button

271

WxMenu mediaMenu = new WxMenu();

272

List<WxMenuButton> buttons = new ArrayList<>();

273

274

WxMenuButton mediaButton = new WxMenuButton();

275

mediaButton.setType(WxConsts.MenuButtonType.MEDIA_ID);

276

mediaButton.setName("View Image");

277

mediaButton.setMediaId(uploadResult.getMediaId());

278

buttons.add(mediaButton);

279

280

mediaMenu.setButtons(buttons);

281

wxService.getMenuService().menuCreate(mediaMenu);

282

```

283

284

### Create Conditional Menu

285

286

```java

287

// Create conditional menu for specific user groups

288

WxMenuConditional conditionalMenu = new WxMenuConditional();

289

290

// Set menu rule (conditions)

291

WxMenuRule rule = new WxMenuRule();

292

rule.setTagId("100"); // For users with tag ID 100

293

rule.setSex("1"); // For male users (1=male, 2=female)

294

rule.setCountry("China");

295

rule.setProvince("Beijing");

296

conditionalMenu.setMatchRule(rule);

297

298

// Set menu buttons

299

List<WxMenuButton> buttons = new ArrayList<>();

300

WxMenuButton vipButton = new WxMenuButton();

301

vipButton.setType(WxConsts.MenuButtonType.CLICK);

302

vipButton.setName("VIP Services");

303

vipButton.setKey("VIP_SERVICES");

304

buttons.add(vipButton);

305

306

conditionalMenu.setButtons(buttons);

307

308

// Create conditional menu

309

String menuid = wxService.getMenuService().conditionalMenuCreate(conditionalMenu);

310

System.out.println("Conditional menu created with ID: " + menuid);

311

```

312

313

### Get Current Menu

314

315

```java

316

// Get current menu configuration

317

WxMenu currentMenu = wxService.getMenuService().menuGet();

318

319

if (currentMenu != null && currentMenu.getButtons() != null) {

320

for (WxMenuButton button : currentMenu.getButtons()) {

321

System.out.println("Button: " + button.getName() + " - Type: " + button.getType());

322

323

if (button.getSubButtons() != null) {

324

for (WxMenuButton subButton : button.getSubButtons()) {

325

System.out.println(" Sub-button: " + subButton.getName() +

326

" - Type: " + subButton.getType());

327

}

328

}

329

}

330

}

331

```

332

333

### Get Self Menu Information

334

335

```java

336

// Get detailed menu information including conditionally displayed menus

337

WxMpGetSelfMenuInfoResult selfMenuInfo = wxService.getMenuService().getSelfMenuInfo();

338

339

System.out.println("Menu open: " + selfMenuInfo.getIsMenuOpen());

340

341

if (selfMenuInfo.getSelfMenuInfo() != null) {

342

for (WxMpGetSelfMenuInfoResult.WxMpSelfMenuInfo menuInfo : selfMenuInfo.getSelfMenuInfo()) {

343

System.out.println("Menu: " + menuInfo.getName() + " - Type: " + menuInfo.getType());

344

345

if (menuInfo.getSubButton() != null) {

346

for (WxMpGetSelfMenuInfoResult.WxMpSelfMenuInfo subMenu : menuInfo.getSubButton()) {

347

System.out.println(" Sub-menu: " + subMenu.getName() +

348

" - Type: " + subMenu.getType());

349

}

350

}

351

}

352

}

353

```

354

355

### Delete Menu

356

357

```java

358

// Delete current menu

359

wxService.getMenuService().menuDelete();

360

System.out.println("Menu deleted successfully");

361

362

// Delete conditional menu

363

wxService.getMenuService().conditionalMenuDelete("menuid");

364

```

365

366

### Test Menu Matching

367

368

```java

369

// Test which menu a specific user would see

370

String userId = "user_openid";

371

String menuResult = wxService.getMenuService().menuTryMatch(userId);

372

System.out.println("User would see menu: " + menuResult);

373

```

374

375

### Handle Menu Click Events

376

377

```java

378

// In your message handler

379

public class MenuClickHandler implements WxMpMessageHandler {

380

@Override

381

public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,

382

Map<String, Object> context,

383

WxMpService wxMpService,

384

WxSessionManager sessionManager) throws WxErrorException {

385

386

String eventKey = wxMessage.getEventKey();

387

388

switch (eventKey) {

389

case "ABOUT_US":

390

return TextBuilder.build("About our company...", wxMessage);

391

392

case "SERVICE_A":

393

return buildServiceAResponse(wxMessage);

394

395

case "VIP_SERVICES":

396

return buildVipResponse(wxMessage);

397

398

case "SCAN_QR":

399

return TextBuilder.build("Please scan the QR code", wxMessage);

400

401

case "UPLOAD_PHOTO":

402

return TextBuilder.build("Please upload your photo", wxMessage);

403

404

case "SEND_LOCATION":

405

return TextBuilder.build("Please share your location", wxMessage);

406

407

default:

408

return TextBuilder.build("Menu option not implemented", wxMessage);

409

}

410

}

411

412

private WxMpXmlOutMessage buildServiceAResponse(WxMpXmlMessage wxMessage) {

413

// Build rich response for Service A

414

List<WxMpXmlOutNewsMessage.Item> articles = new ArrayList<>();

415

416

WxMpXmlOutNewsMessage.Item item = new WxMpXmlOutNewsMessage.Item();

417

item.setTitle("Service A Details");

418

item.setDescription("Complete information about Service A");

419

item.setUrl("https://www.example.com/service-a");

420

item.setPicUrl("https://www.example.com/service-a-image.jpg");

421

articles.add(item);

422

423

return NewsBuilder.build(articles, wxMessage);

424

}

425

}

426

427

// Register menu handler in router

428

router.rule()

429

.msgType(WxConsts.XmlMsgType.EVENT)

430

.event(WxConsts.EventType.CLICK)

431

.handler(new MenuClickHandler())

432

.end();

433

```

434

435

### Complex Menu Structure

436

437

```java

438

public WxMenu createComplexMenu() {

439

WxMenu menu = new WxMenu();

440

List<WxMenuButton> buttons = new ArrayList<>();

441

442

// Products menu with sub-buttons

443

WxMenuButton productsButton = new WxMenuButton();

444

productsButton.setName("Products");

445

446

List<WxMenuButton> productSubButtons = new ArrayList<>();

447

448

// Product category 1

449

WxMenuButton product1 = new WxMenuButton();

450

product1.setType(WxConsts.MenuButtonType.VIEW);

451

product1.setName("Category A");

452

product1.setUrl("https://www.example.com/category-a");

453

productSubButtons.add(product1);

454

455

// Product category 2

456

WxMenuButton product2 = new WxMenuButton();

457

product2.setType(WxConsts.MenuButtonType.CLICK);

458

product2.setName("Category B");

459

product2.setKey("CATEGORY_B");

460

productSubButtons.add(product2);

461

462

// Product catalog

463

WxMenuButton catalog = new WxMenuButton();

464

catalog.setType(WxConsts.MenuButtonType.MEDIA_ID);

465

catalog.setName("Catalog");

466

catalog.setMediaId("catalog_media_id");

467

productSubButtons.add(catalog);

468

469

productsButton.setSubButtons(productSubButtons);

470

buttons.add(productsButton);

471

472

// Services menu

473

WxMenuButton servicesButton = new WxMenuButton();

474

servicesButton.setName("Services");

475

476

List<WxMenuButton> serviceSubButtons = new ArrayList<>();

477

478

// Customer service

479

WxMenuButton customerService = new WxMenuButton();

480

customerService.setType(WxConsts.MenuButtonType.CLICK);

481

customerService.setName("Customer Service");

482

customerService.setKey("CUSTOMER_SERVICE");

483

serviceSubButtons.add(customerService);

484

485

// Technical support

486

WxMenuButton techSupport = new WxMenuButton();

487

techSupport.setType(WxConsts.MenuButtonType.VIEW);

488

techSupport.setName("Tech Support");

489

techSupport.setUrl("https://support.example.com");

490

serviceSubButtons.add(techSupport);

491

492

// FAQ

493

WxMenuButton faq = new WxMenuButton();

494

faq.setType(WxConsts.MenuButtonType.ARTICLE_VIEW_LIMITED);

495

faq.setName("FAQ");

496

faq.setArticleId("faq_article_id");

497

serviceSubButtons.add(faq);

498

499

servicesButton.setSubButtons(serviceSubButtons);

500

buttons.add(servicesButton);

501

502

// Contact menu

503

WxMenuButton contactButton = new WxMenuButton();

504

contactButton.setName("Contact");

505

506

List<WxMenuButton> contactSubButtons = new ArrayList<>();

507

508

// Phone

509

WxMenuButton phone = new WxMenuButton();

510

phone.setType(WxConsts.MenuButtonType.CLICK);

511

phone.setName("Phone");

512

phone.setKey("CONTACT_PHONE");

513

contactSubButtons.add(phone);

514

515

// Address

516

WxMenuButton address = new WxMenuButton();

517

address.setType(WxConsts.MenuButtonType.LOCATION_SELECT);

518

address.setName("Address");

519

address.setKey("CONTACT_ADDRESS");

520

contactSubButtons.add(address);

521

522

// Mini Program

523

WxMenuButton miniProgram = new WxMenuButton();

524

miniProgram.setType(WxConsts.MenuButtonType.MINIPROGRAM);

525

miniProgram.setName("Mini Program");

526

miniProgram.setUrl("https://www.example.com");

527

miniProgram.setAppid("miniprogram_appid");

528

miniProgram.setPagepath("pages/contact/contact");

529

contactSubButtons.add(miniProgram);

530

531

contactButton.setSubButtons(contactSubButtons);

532

buttons.add(contactButton);

533

534

menu.setButtons(buttons);

535

return menu;

536

}

537

```

538

539

## Menu Limitations

540

541

- Maximum 3 first-level buttons

542

- Maximum 5 sub-buttons per first-level button

543

- Button names: 1-16 characters for first-level, 1-60 characters for sub-buttons

544

- Click event keys: 1-128 characters

545

- URLs: Must be valid HTTP/HTTPS URLs

546

547

## Best Practices

548

549

1. **Clear Naming**: Use descriptive, concise button names

550

2. **Logical Grouping**: Group related functions under the same parent button

551

3. **Event Keys**: Use meaningful, consistent naming conventions for event keys

552

4. **Fallback URLs**: Always provide fallback URLs for mini program buttons

553

5. **Testing**: Test menus with different user segments for conditional menus

554

6. **Regular Updates**: Keep menu content fresh and relevant

555

7. **Analytics**: Track menu usage to optimize structure

556

557

## Error Handling

558

559

```java

560

try {

561

wxService.getMenuService().menuCreate(menu);

562

} catch (WxErrorException e) {

563

int errorCode = e.getError().getErrorCode();

564

565

switch (errorCode) {

566

case 40018:

567

System.err.println("Invalid button name length");

568

break;

569

case 40019:

570

System.err.println("Invalid button key length");

571

break;

572

case 40020:

573

System.err.println("Invalid button URL");

574

break;

575

case 40023:

576

System.err.println("Invalid sub-menu level");

577

break;

578

case 40024:

579

System.err.println("Too many sub-menu buttons");

580

break;

581

case 40025:

582

System.err.println("Too many main menu buttons");

583

break;

584

default:

585

System.err.println("Menu creation failed: " + e.getError().getErrorMsg());

586

}

587

}

588

```