add_new_item_to_menu used count($menu_items) for the new item's menu_order. When existing items did not have perfectly sequential orders, this produced a value already taken by another item, causing MySQL's tie-breaking to return items out of depth-first sequence and breaking get_nested_menu nesting. Changed to max(menu_order) + 1 so the new item always lands after every existing item.
Files changed:
proudcity-quick-menu.php
Changes:
add_new_item_to_menu():menu_ordernow usesmax( wp_list_pluck( $menu_items, 'menu_order' ) ) + 1update_menu_items(): removed unused$menu_to_updateand$updated_itemsparameters (AJAX handler reads from$_POSTdirectly; parameters were never passed by the hook)sanitize_array_of_css_classes(): removed unused$key =>from foreachwp_quick_menu_meta_box_call_back(): renamed$post→$_post(required by hook, intentionally unused)
References: proudcity/wp-proudcity#2776
Identified and fixed three bugs that could cause the menu display to break after using the quick-menu metabox, matching the symptom where opening the WP menu editor and saving without changes would restore the layout.
Bug 1 (primary cause): $nav_menu_item was overwritten on every loop iteration after $in_menu became true, ending up as the last menu item's db_id instead of the current post's. When changing menus, the wrong nav_menu_item was passed to maybe_remove_old_menu_entry and deleted, leaving its children with stale _menu_item_menu_item_parent values pointing to a nonexistent post. Those orphaned children became invisible in the menu display.
Bug 2: add_new_item_to_menu never set _menu_item_menu_item_parent on newly created nav_menu_items. WordPress expects this meta to be present (set to 0 for top-level items) for correct nesting queries.
Bug 3: get_current_item rendered the newly added item's <li> without a data-menu-item-parent-id attribute, unlike all other items rendered by get_single_item. Added data-menu-item-parent-id="0" to match.
References: proudcity/wp-proudcity#2776
Files changed:
proudcity-quick-menu.php
The quick menu metabox was registered for all users who could edit posts, exposing the admin UI to users who lack menu editing capability. Added a current_user_can('manage_categories') check at the top of wp_quick_menu_add_meta_box() to match the capability check already in place on all AJAX handlers.
Files changed:
proudcity-quick-menu.php
Changes:
wp_quick_menu_add_meta_box(): returns early if the current user cannotmanage_categories
References: proudcity/wp-proudcity#2784
Added transient-based rate limiting to all four AJAX handlers to prevent DoS abuse by logged-in users.
Files changed:
proudcity-quick-menu.php
Changes:
- Added
const RATE_LIMIT_WINDOW = 10class constant for the throttle window (seconds) - Added
check_rate_limit( $action, $limit )private static helper using a per-user, per-action transient counter - Applied rate limiting to all four AJAX handlers after nonce and capability checks:
edit_menu_item()— 2 per 10sdelete_menu_item()— 2 per 10sget_menu_items()— 5 per 10supdate_menu_items()— 10 per 10s
- Added docblock to
edit_menu_item()
References: proudcity/wp-proudcity#2784
Added client-side validation before AJAX submission to prevent malformed or manipulated DOM data from reaching the server.
Files changed:
js/pc-quick-menu-script.js
Changes:
- Added
pcq_valid_id()helper to validate positive integer IDs from data attributes pcq_setup_menu_data(): skips menu items with missing/invalidmenu-item-db-id; validatesmenu-item-menu-orderwith fallback to DOM index- Delete handler: validates
menu-item-db-idbefore firing AJAX; shows user feedback and bails if invalid - Edit handler: validates
menu-item-object-idand rejects empty title before firing AJAX; shows user feedback for both failure cases
References: proudcity/wp-proudcity#2784