sanitizer = $sanitizer; $this->fields = $fields; } /** * Registers hooks. * * @return void */ public function register(): void { add_action( 'wp_nav_menu_item_custom_fields', array( $this, 'render' ) ); add_action( 'wp_update_nav_menu_item', array( $this, 'save' ), 10, 2 ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ) ); } /** * Loads the fields script and styles on Appearance → Menus. * * @param string $hook_suffix Current admin page. * @return void */ public function enqueue( string $hook_suffix ): void { if ( 'nav-menus.php' === $hook_suffix ) { AdminApp::enqueue( 'rule-fields', array() ); } } /** * Saves a menu item's rule when Appearance → Menus is saved. * * Only runs when our fields for this item were submitted, so menu items * saved elsewhere (Customizer, REST API, imports) keep their rule. * * @param int $menu_id Menu ID. * @param int $menu_item_db_id Menu item ID. * @return void */ public function save( $menu_id, $menu_item_db_id ): void { $item_id = (int) $menu_item_db_id; // phpcs:disable WordPress.Security.NonceVerification.Missing -- Verified just below. if ( ! isset( $_POST[ self::FIELD ][ $item_id ], $_POST[ self::NONCE_FIELD ] ) ) { return; } // phpcs:enable $nonce = sanitize_text_field( wp_unslash( $_POST[ self::NONCE_FIELD ] ) ); if ( ! wp_verify_nonce( $nonce, self::NONCE_ACTION ) || ! current_user_can( 'edit_theme_options' ) ) { return; } // Sanitized by RuleSanitizer::sanitize(). $raw = wp_unslash( $_POST[ self::FIELD ][ $item_id ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $rule = $this->sanitizer->sanitize( $raw ); if ( empty( $rule['groups'] ) ) { delete_post_meta( $item_id, ClassicMenuFilter::META_KEY ); return; } update_post_meta( $item_id, ClassicMenuFilter::META_KEY, $rule ); } /** * Renders the fields for one menu item. * * @param int|string $item_id Menu item ID. * @return void */ public function render( $item_id ): void { $item_id = (int) $item_id; $rule = $this->sanitizer->sanitize( get_post_meta( $item_id, ClassicMenuFilter::META_KEY, true ) ); // One nonce field per item (items can be added by Ajax), so no id attribute: IDs must be unique. echo ''; $this->fields->render( self::FIELD . '[' . $item_id . ']', (string) $item_id, $rule, array( 'toggle' => __( 'Change menu item visibility', 'yangra-conditional' ), 'action' => __( 'this menu item when all of these conditions match:', 'yangra-conditional' ), 'tips' => array( __( 'Hidden menu items only remove the link: the page is still reachable by its URL. Rules apply to administrators too. Hiding an item also hides all of its sub-items.', 'yangra-conditional' ), ), ) ); } }