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
```