Adicionando campos aos itens do menu WordPress – Plugin personalizado

Publicados: 2021-05-19

Em um artigo anterior, vimos como você pode adicionar seu próprio campo personalizado aos itens de menu usando o gancho de ação wp_nav_menu_item_custom_fields que foi introduzido no WordPress 5.4. Detalhamos duas rotas para conseguir isso; adicionando algum código personalizado ao functions.php ou usando um plugin do WordPress.

Neste artigo, vamos recriar o mesmo campo, mas desta vez faremos isso criando nosso próprio plugin do zero.

Vamos começar.

Criação de plug-ins

Não entraremos nos detalhes básicos da criação de um plug-in do WordPress, pois isso foi abordado em nosso artigo aprofundado 'Como construir seu primeiro plug-in do WordPress. Um guia passo a passo'. Vamos pular adiante para criar nossa pasta de plugins na pasta wp-content/plugin/ . Em seguida, nomearemos nossa pasta de plugins personalizada como “menu-item-field-creator” e dentro dela criaremos um arquivo chamado menu-item-field-creator.php .

Após isso vamos abrir este arquivo com nosso editor de texto favorito e adicionar o código abaixo. Este código tem o efeito de introduzir o plugin no núcleo do WordPress.

 <?php /* Plugin Name: Menu Item Field Creator Description: My custom plugin to create menu item fields */

Como você pode notar, definimos o nome e a descrição do plug-in como queremos que sejam exibidos na área de plug-in do administrador. Por causa deste exemplo, não definiremos nenhum outro campo de cabeçalho.

Com essas etapas concluídas, vamos para nossa seção Plugins na área Admin e verifique se o plug-in é exibido corretamente.

Em seguida, inseriremos nosso primeiro código funcional que estabelecerá nossa classe principal e algumas funções.

A maneira simples

A maneira mais simples de fazer este plugin funcionar é inserir o código que escrevemos em nosso artigo anterior no arquivo PHP principal do plugin para que o conteúdo final fique assim:

 <?php /* Plugin Name: Menu Item Field Creator Description: My custom plugin to create menu item fields */ /** * Add the field. */ function pr_menu_item_sub( $item_id, $item ) { $menu_item_sub = get_post_meta( $item_id, '_menu_item_sub', true ); ?> <div> <span class="subtitle"><?php _e( 'Subtitle', 'menu-item-sub' ); ?></span><br /> <input type="hidden" class="nav-menu-id" value="<?php echo $item_id; ?>" /> <div class="logged-input-holder"> <input type="text" name="menu_item_sub[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $menu_item_sub ); ?>" /> </div> </div> <?php } add_action( 'wp_nav_menu_item_custom_fields', 'pr_menu_item_sub', 10, 2 ); /** * Save input. */ function save_menu_item_sub( $menu_id, $menu_item_db_id ) { if ( isset( $_POST['menu_item_sub'][ $menu_item_db_id ] ) ) { $sanitized_data = sanitize_text_field( $_POST['menu_item_sub'][ $menu_item_db_id ] ); update_post_meta( $menu_item_db_id, '_menu_item_sub', $sanitized_data ); } else { delete_post_meta( $menu_item_db_id, '_menu_item_sub' ); } } add_action( 'wp_update_nav_menu_item', 'save_menu_item_sub', 10, 2 ); /** * Show the Menu Field Value. */ function show_menu_item_sub( $title, $item ) { if ( is_object( $item ) && isset( $item->ID ) ) { $menu_item_sub = get_post_meta( $item->ID, '_menu_item_sub', true ); if ( ! empty( $menu_item_sub ) ) { $title .= '<p class="menu-item-sub">' . $menu_item_sub . '</p>'; } } return $title; } add_filter( 'nav_menu_item_title', 'show_menu_item_sub', 10, 2 );

Neste ponto, se você ativar o plug-in, verá que ele funciona bem. No entanto, existe uma maneira de obter os mesmos resultados usando um estilo de codificação diferente.

Usando Programação Orientada a Objetos

Para obter os mesmos resultados em uma abordagem mais orientada a objetos, conforme descrevemos em nosso artigo relacionado, siga as instruções abaixo.

Para começar, esvazie o conteúdo do arquivo PHP principal do seu plugin, exceto o comentário do cabeçalho e insira estas linhas:

 class MyCP_Menu_Item_Field_Creator { } $mycp_menu_item_field_creator = new MyCP_Menu_Item_Field_Creator();

O que fizemos com este código até agora foi definir a classe wrapper MyCP_Menu_Item_Field_Creator que conterá toda a funcionalidade. Por fim, instanciamos um objeto.

É muito importante lembrar que o nome da classe principal que você definir estará disponível globalmente e, portanto, você deve certificar-se de que é único e que não há chance de qualquer outro plugin ou tema usar o mesmo nome. É por isso que é recomendado que você use um prefixo personalizado como o MyCP_ que usamos acima.

Dentro da classe, agora adicionaremos algumas funcionalidades. O conteúdo final do nosso arquivo PHP principal do plugin ficará assim:

 <?php /* Plugin Name: Menu Item Field Creator Description: My custom plugin to create menu item fields */ class MyCP_Menu_Item_Field_Creator { public function __construct() { add_action( 'wp_nav_menu_item_custom_fields', array( $this, 'menu_item_sub' ), 10, 2 ); add_action( 'wp_update_nav_menu_item', array( $this, 'save_menu_item_sub' ), 10, 2 ); add_action( 'nav_menu_item_title', array( $this, 'show_menu_item_sub' ), 10, 2 ); } public function menu_item_sub( $item_id, $item ) { $menu_item_sub = get_post_meta( $item_id, '_menu_item_sub', true ); ?> <div> <span class="subtitle"><?php _e( 'Subtitle', 'menu-item-sub' ); ?></span><br /> <input type="hidden" class="nav-menu-id" value="<?php echo $item_id; ?>" /> <div class="logged-input-holder"> <input type="text" name="menu_item_sub[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $menu_item_sub ); ?>" /> </div> </div> <?php } public function save_menu_item_sub( $menu_id, $menu_item_db_id ) { if ( isset( $_POST['menu_item_sub'][ $menu_item_db_id ] ) ) { $sanitized_data = sanitize_text_field( $_POST['menu_item_sub'][ $menu_item_db_id ] ); update_post_meta( $menu_item_db_id, '_menu_item_sub', $sanitized_data ); } else { delete_post_meta( $menu_item_db_id, '_menu_item_sub' ); } } public function show_menu_item_sub( $title, $item ) { if ( is_object( $item ) && isset( $item->ID ) ) { $menu_item_sub = get_post_meta( $item->ID, '_menu_item_sub', true ); if ( ! empty( $menu_item_sub ) ) { $title .= '<p class="menu-item-sub">' . $menu_item_sub . '</p>'; } } return $title; } } $mycp_menu_item_field_creator = new MyCP_Menu_Item_Field_Creator();

Removemos os prefixos dos nomes dos métodos, pois agora temos um prefixo de classe.

Na função __construct definimos os ganchos que usamos junto com suas funções de retorno de chamada que serão executadas. Em seguida, introduzimos a função de retorno de chamada menu_item_sub que exibirá o campo de entrada onde o usuário admin pode preencher a legenda do item.

Depois disso, salvamos a entrada com o método save_menu_item_sub e, finalmente, com o callback show_menu_item_sub , mostramos os valores, se disponíveis, no menu front-end.

Expandindo o Andarilho

No exemplo acima, incluímos o campo de menu personalizado dentro do título do item de menu, sem alterar a saída HTML dos dados da árvore do menu. Mas e se quisermos adicionar o campo subtitle como um elemento HTML separado, como um elemento <div> fora do link do elemento title?

É aqui que temos que trabalhar mais uma vez com a classe Walker. Como vimos em nosso artigo 'Conhecendo a classe WordPress Walker', ao estender o Walker você pode personalizar a estrutura de dados em forma de árvore. Neste caso, este será o menu.

Isso significa, é claro, que só precisamos alterar nosso código relacionado à exibição de front-end do nosso campo personalizado. Então vamos substituir todo o código por este:

 <?php /* Plugin Name: Menu Item Field Creator Description: My custom plugin to create menu item fields */ class MyCP_Menu_Item_Field_Creator { public function __construct() { add_action( 'wp_nav_menu_item_custom_fields', array( $this, 'menu_item_sub' ), 10, 2 ); add_action( 'wp_update_nav_menu_item', array( $this, 'save_menu_item_sub' ), 10, 2 ); add_filter( 'wp_nav_menu_args', array( $this, 'menu_item_sub_custom_walker' ) ); } public function menu_item_sub( $item_id, $item ) { $menu_item_sub = get_post_meta( $item_id, '_menu_item_sub', true ); ?> <div> <span class="subtitle"><?php _e( 'Subtitle', 'menu-item-sub' ); ?></span><br /> <input type="hidden" class="nav-menu-id" value="<?php echo $item_id; ?>" /> <div class="logged-input-holder"> <input type="text" name="menu_item_sub[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $menu_item_sub ); ?>" /> </div> </div> <?php } public function save_menu_item_sub( $menu_id, $menu_item_db_id ) { if ( isset( $_POST['menu_item_sub'][ $menu_item_db_id ] ) ) { $sanitized_data = sanitize_text_field( $_POST['menu_item_sub'][ $menu_item_db_id ] ); update_post_meta( $menu_item_db_id, '_menu_item_sub', $sanitized_data ); } else { delete_post_meta( $menu_item_db_id, '_menu_item_sub' ); } } public function menu_item_sub_custom_walker( $args ) { if ( class_exists( 'My_Custom_Nav_Walker' ) ) { $args['walker'] = new My_Custom_Nav_Walker(); } else { echo 'DOES NOT EXIST'; } return $args; } } $mycp_menu_item_field_creator = new MyCP_Menu_Item_Field_Creator(); if ( ! class_exists( 'My_Custom_Nav_Walker' ) ) { class My_Custom_Nav_Walker extends Walker_Nav_Menu { public function start_el( &$output, $item, $depth=0, $args=[], $id=0 ) { $menu_item_sub = get_post_meta( $item->ID, '_menu_item_sub', true ); $output .= '<li class="' . implode( ' ', $item->classes ) . '">'; if ( $item->url && $item->url != '#' ) { $output .= '<a href="' . $item->url . '">'; } else { $output .= '<span>'; } $output .= $item->title; if ( $item->url && $item->url != '#' ) { $output .= '</a>'; } else { $output .= '</span>'; } if ( ! empty( $menu_item_sub ) ) { $output .= '<div class="menu-item-sub">' . $menu_item_sub . '</div>'; } } } }

Você deve ter notado que excluímos o método show_menu_item_sub e trabalhamos com a estrutura de itens de menu front-end de forma diferente. Introduzimos nossa classe Walker personalizada My_Custom_Nav_Walker fora de nossa classe principal e através do nosso método menu_item_sub_custom_walker alteramos o valor padrão do argumento 'walker' para My_Custom_Nav_Walker . Dessa forma, a saída HTML do menu que fornecemos em nosso Walker personalizado será aplicada em nosso front-end.

Vamos verificar os resultados.

Como podemos ver, nossa descrição desta vez é colocada fora do link href do item de menu como pretendíamos.

Levando mais longe

Antes de encerrarmos, vale a pena mencionar que usamos deliberadamente o exemplo “Legenda” porque é simples de fazer e entender.

Se você quiser se esforçar, sugerimos que você crie seus próprios cenários para experimentar. Tente, por exemplo, criar uma saída diferente que permita ao usuário Admin definir qual função de usuário tem permissão para visualizar o item de menu.

Como dica inicial, forneceremos a saída. Substitua o método de saída atual (mostrado abaixo)

 function menu_item_sub( $item_id, $item ) { $menu_item_sub = get_post_meta( $item_id, '_menu_item_sub', true ); ?> <div> <span class="subtitle"><?php _e( 'Subtitle', 'menu-item-sub' ); ?></span><br /> <input type="hidden" class="nav-menu-id" value="<?php echo $item_id; ?>" /> <div class="logged-input-holder"> <input type="text" name="menu_item_sub[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $menu_item_sub ); ?>" /> </div> </div> <?php }

com este:

 function PREFIX_Menu_Item_Roles() { global $wp_roles; $display_roles = apply_filters( 'nav_menu_roles', $wp_roles->role_names ); if ( ! $display_roles ) return; ?> <p class="field-nav_menu_logged_in_out nav_menu_logged_in_out nav_menu_logged_in_out-thin"> <fieldset> <legend><?php _e( 'Display Mode', 'nav-menu-roles' ); ?></legend> <label for="edit-menu-item-role_logged_in"> <input type="radio" class="edit-menu-item-logged_in_out" value="in" name="menu-item-role_logged_in" /> <?php _e( 'Logged In Users', 'nav-menu-roles' ); ?><br/> </label> <label for="edit-menu-item-role_logged_out"> <input type="radio" class="edit-menu-item-logged_in_out" value="out" name="menu-item-role_logged_out" /> <?php _e( 'Logged Out Users', 'nav-menu-roles' ); ?><br/> </label> <label for="edit-menu-item-role_everyone"> <input type="radio" class="edit-menu-item-logged_in_out" value="" name="menu-item-role_everyone" /> <?php _e( 'Everyone', 'nav-menu-roles' ); ?><br/> </label> </fieldset> </p> <?php }

Agora tente criar um método que salve as alterações junto com um que exiba o valor atual/salvo usando os ganchos corretos.

Conclusão

Personalizar um menu do WordPress pode ser frustrante até que você conheça as ferramentas disponíveis para fazer isso. Espero que este artigo tenha lhe dado algumas dicas sobre o que é possível alcançar e as maneiras pelas quais você pode implementar tarefas como essa.

Veja também

  • Adicionando campos personalizados aos itens de menu do WordPress