Precisa incluir um campo personalizado na administração dos menus do WordPress? Adicionar, por exemplo, um checkbox para dizer que um determinado item deveria ser exibido como um botão? A nova action wp_nav_menu_item_custom_fields, incluída na versão 5.4 do WordPress, deixou essa tarefa muito mais fácil. Veja como no post e no vídeo dessa semana 🙂

Como era antes do WordPress 5.4

A exibição dos menus no WordPress normalmente são feitas por walkers, ou seja, classes que vão item por item exibindo o necessário. Para a exibição na tela de administração a classe usada é a Walker_Nav_Menu_Edit e os campos exibidos através do método start_el. O que os plugins e temas faziam antes da nova versão era sobrescrever este método substituindo a classe de alguma forma, normalmente passando uma nova classe através do filtro wp_edit_nav_menu_walker.

O problema dessa abordagem é que só é possível substituir a classe original por uma outra, ou seja, se você precisar incluir dois campos personalizados através de dois plugins diferentes, você vai ter um problema: somente a última classe passada pelo filtro será usada.

A action wp_nav_menu_item_custom_fields do WP 5.4

A nova action incluída na versão 5.4 permite que qualquer código personalizado possa imprimir novos campos na administração dos itens de menu, logo acima dos links para “mover” o item.

Como exibir os campos

Voltando para o nosso exemplo de um checkbox para exibir um item de menu como um botão, o código para inserir o campo seria mais ou menos assim:

function my_wp_nav_menu_item_custom_fields( $item_id, $item, $depth, $args ) {
	// Itens de menu são gravados como posts pelo WP.
	$is_button = (bool) get_post_meta( $item_id, 'is_button', true );

	// Tem post e vídeo sobre nonce aqui no blog também.
	wp_nonce_field( 'nav_menu_edit', 'nav_menu_is_button' );
	?>
	<div>
		<input
			type="checkbox"
			class="nav-menu-is-button"
			name="nav-menu-is-button[<?php echo $item_id; ?>]"
			id="nav-menu-is-button-for-<?php echo $item_id; ?>"
			<?php checked( '1', $is_button ); ?>
			value="1">
		<label for="nav-menu-is-button-for-<?php echo $item_id; ?>">
			<?php _e( 'Exibir como botão', 'text-domain'); ?>
		</label>
	</div>
	<?php
}
add_action( 'wp_nav_menu_item_custom_fields', 'my_wp_nav_menu_item_custom_fields', 10, 4 );

Esse código apenas exibe o campo, como na imagem:

Checkbox para exibir o item como botão

Como salvar o valor do campo

Nós ainda precisamos de uma forma de gravar o seu valor, que será um metadado do item, que é gravado como um post pelo WordPress. Para fazer a gravação, usamos a action wp_update_nav_menu_item. Fica mais ou menos assim:

function my_wp_update_nav_menu_item( $menu_id, $menu_item_db_id ) {
	// Verifica o nonce criado na outra função.
	if ( ! isset( $_POST['nav_menu_is_button'] ) || ! wp_verify_nonce( $_POST['nav_menu_is_button'], 'nav_menu_edit' ) ) {
		return;
	}

	$is_button = ( ! empty( $_POST['nav-menu-is-button'][ $menu_item_db_id ] ) && '1' === $_POST['nav-menu-is-button'][ $menu_item_db_id ] );
	update_post_meta( $menu_item_db_id, 'is_button', $is_button );
}
add_action( 'wp_update_nav_menu_item', 'my_wp_update_nav_menu_item', 10, 2 );

Como usar o valor do campo

Fica faltando então como usar o campo. Neste caso, vamos imaginar que basta colocar uma classe a mais no link se o checkbox foi marcado:

function my_nav_menu_css_class( $classes, $item, $args = array(), $depth = 0 ) {
	$is_button = (bool) get_post_meta( $item->ID, 'is_button', true );
	if ( $is_button ) {
		$classes[] = 'button';
	}
	return $classes;
}
add_filter( 'nav_menu_css_class', 'my_nav_menu_css_class', 10, 4 );

No final, fica assim (meio tosco, mas vale a ideia):

Veja também a dev note, ou seja, o post no Blog make do WordPress, com o anúncio do novo filtro. O código deste post foi baseado neste arquivo. Também é possível fazer funcionar no Personalizar, mas o código teria que ser modificado e ainda seria necessário algum JavaScript. Fica para um próximo post!