Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating new menu item - Wordpress

I'm looking for a way to create a new item that can be added to a menu.

Here are the details of my problem: I use WPML. WPML have that nice feature that you can add the switcher to a menu, automatically. It adds it at the end of the menu, no control on that.

Thing is, I want my language switcher to be element 4 out of 6. That feature to automatically add the element at the end doesn't fit my needs.

So I want to create a new element that can be used in apparence->menu to put my language switcher exactly at the spot I want it.

Is there any way to do that?

TLDR: I want to be able to push custom HTML/PHP code in a menu element (Apparence->Menu). Any functions to do so?

like image 551
Fredy31 Avatar asked Nov 06 '15 17:11

Fredy31


People also ask

How do I add menu items to WordPress admin panel?

Creating menu –add_action('admin_menu', 'custom_menu'); add_action('admin_menu', 'custom_menu'); In above line of code, first parameter is the hook we discuss about, Second parameter is name of callback function. In callback function you have to write what you want to alter in admin menu.

How do I create a menu in WordPress 2022?

In order to create a WordPress menu dropdown in the 2022 WordPress theme, you will need to click on the specific menu item for which you want to create a dropdown. You can add the submenu using the 'submenu' block icon.

How do I create a custom menu in WordPress without Plugin?

To do this go to Appearance >Menus and start creating a new menu. Give the menu the title “Secondary Menu”, select “My Custom Menu” for a location and then hit the “Create Menu” button. Finally add some items to the menu (for example Menu item 1, Menu item 2, Menu item 3) and then save the menu.


2 Answers

From wp-includes/nav-menu-template.php, in Walker_Nav_Menu::start_el:

/**
 * Filter a menu item's starting output.
 *
 * The menu item's starting output only includes `$args->before`, the opening `<a>`,
 * the menu item's title, the closing `</a>`, and `$args->after`. Currently, there is
 * no filter for modifying the opening and closing `<li>` for a menu item.
 *
 * @since 3.0.0
 *
 * @param string $item_output The menu item's starting HTML output.
 * @param object $item        Menu item data object.
 * @param int    $depth       Depth of menu item. Used for padding.
 * @param array  $args        An array of {@see wp_nav_menu()} arguments.
 */
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );

Which means you can append to individual nav menu item HTML contents (right before the last li tag) using that filter. $item_output contains the HTML generated for the item so far. Example:

<?php

add_filter('walker_nav_menu_start_el', function ($item_output) {
    return $item_output . '<span>hello world</span>';
});

That would append <span>hello world</span> to each nav menu item HTML. A closing li tag will be appended after this filter. You can use the 4th argument ($args) to validate the currently rendering navigation menu.

like image 200
ojrask Avatar answered Oct 02 '22 14:10

ojrask


All right, I have temporary solution.

These are steps:

  1. Open \wp-content\plugins\sitepress-multilingual-cms\inc\language-switcher.php
  2. Go somewhere around line 786, where is function wp_nav_menu_items_filter($items, $args){
  3. Add this right after first {:

    $tempitems = $items;  
    $tempitemsexplode = explode("\n", $tempitems);  
    $items = "";  
    $id = 2; //This is where widget will be located: example, if you want it to be at place 4, write 5
    
  4. Right before if ( $abs_menu_id == $settings_menu_id || false === $abs_menu_id ) { add this:

    $id = 2;  
    for ($i = 0; $i < $id; $i++){  
        $items .= $tempitemsexplode[$i];  
    }  
    for($i = 0; $i < count($tempitemsexplode); $i++){  
        If ($i == $id){  
    
  5. Go to bottom of function and before:
    }
    return $items;
    Add: }}

  6. Now, before return $items; Add:

    for ($i = $id; $i < count($tempitemsexplode); $i++){  
        $items .= $tempitemsexplode[$i];  
    }
    

If you get stuck here is how that whole function looks for me:

function wp_nav_menu_items_filter($items, $args){
    $tempitems = $items;
    $tempitemsexplode = explode("\n", $tempitems);
    $items = "";
    global $sitepress_settings, $sitepress;

    $current_language = $sitepress->get_current_language();
    $default_language = $sitepress->get_default_language();
    // menu can be passed as integer or object
    if(isset($args->menu->term_id)) $args->menu = $args->menu->term_id;

    $abs_menu_id = icl_object_id($args->menu, 'nav_menu', false, $default_language );
    $settings_menu_id = icl_object_id( $sitepress_settings[ 'menu_for_ls' ], 'nav_menu', false, $default_language );

    $id = 2;
    for ($i = 0; $i < $id; $i++){
        $items .= $tempitemsexplode[$i];
    }

    for($i = 0; $i < count($tempitemsexplode); $i++){
        If ($i == $id){
            if ( $abs_menu_id == $settings_menu_id  || false === $abs_menu_id ) {

                $languages = $sitepress->get_ls_languages();


                $items .= '<li class="menu-item menu-item-language menu-item-language-current">';
                if(isset($args->before)){
                    $items .= $args->before;
                }
                $items .= '<a href="#" onclick="return false">';
                if(isset($args->link_before)){
                    $items .= $args->link_before;
                }

                $language_name = '';
                if ( $sitepress_settings[ 'icl_lso_native_lang' ] ) {
                    $language_name .= $languages[ $current_language ][ 'native_name' ];
                }
                if ( $sitepress_settings[ 'icl_lso_display_lang' ] && $sitepress_settings[ 'icl_lso_native_lang' ] ) {
                    $language_name .= ' (';
                }
                if ( $sitepress_settings[ 'icl_lso_display_lang' ] ) {
                    $language_name .= $languages[ $current_language ][ 'translated_name' ];
                }
                if ( $sitepress_settings[ 'icl_lso_display_lang' ] && $sitepress_settings[ 'icl_lso_native_lang' ] ) {
                    $language_name .= ')';
                }



                $alt_title_lang = esc_attr($language_name);

                if( $sitepress_settings['icl_lso_flags'] ){
                    $items .= '<img class="iclflag" src="' . $languages[ $current_language ][ 'country_flag_url' ] . '" width="18" height="12" alt="' . $alt_title_lang . '" title="' . esc_attr( $language_name ) . '" />';
                }

                $items .= $language_name;

                if(isset($args->link_after)){
                    $items .= $args->link_after;
                }
                $items .= '</a>';
                if(isset($args->after)){
                    $items .= $args->after;
                }

                unset($languages[ $current_language ]);
                $sub_items = false;
                $menu_is_vertical = !isset($sitepress_settings['icl_lang_sel_orientation']) || $sitepress_settings['icl_lang_sel_orientation'] == 'vertical';
                if(!empty($languages)){
                    foreach($languages as $lang){
                        $sub_items .= '<li class="menu-item menu-item-language menu-item-language-current">';
                        $sub_items .= '<a href="'.$lang['url'].'">';

                        $language_name = '';
                        if ( $sitepress_settings[ 'icl_lso_native_lang' ] ) {
                            $language_name .= $lang[ 'native_name' ];
                        }
                        if ( $sitepress_settings[ 'icl_lso_display_lang' ] && $sitepress_settings[ 'icl_lso_native_lang' ] ) {
                            $language_name .= ' (';
                        }
                        if ( $sitepress_settings[ 'icl_lso_display_lang' ] ) {
                            $language_name .= $lang[ 'translated_name' ];
                        }
                        if ( $sitepress_settings[ 'icl_lso_display_lang' ] && $sitepress_settings[ 'icl_lso_native_lang' ] ) {
                            $language_name .= ')';
                        }
                        $alt_title_lang = esc_attr($language_name);

                        if( $sitepress_settings['icl_lso_flags'] ){
                            $sub_items .= '<img class="iclflag" src="'.$lang['country_flag_url'].'" width="18" height="12" alt="'.$alt_title_lang.'" title="' . $alt_title_lang . '" />';
                        }
                        $sub_items .= $language_name;

                        $sub_items .= '</a>';
                        $sub_items .= '</li>';

                    }
                    if( $sub_items && $menu_is_vertical ) {
                        $sub_items = '<ul class="sub-menu submenu-languages">' . $sub_items . '</ul>';
                    }
                }

                if( $menu_is_vertical ) {
                    $items .= $sub_items;
                    $items .= '</li>';
                } else {
                    $items .= '</li>';
                    $items .= $sub_items;
                }
            }
        }
    }

    for ($i = $id; $i < count($tempitemsexplode); $i++){
        $items .= $tempitemsexplode[$i];
    }

    return $items;

}

I will try to make it easier to change where you want to place widget.
Comment if you have problems. Good luck!

Edit: Explanation what this modified function does.
This function is used to add language switcher to menu.
When this function is called, we have $items string containing all menu items.
I transferred all menu items from $items to $tempitems and set $items to empty string.
Why? Because now we can insert widget as first menu item or between some menu items.

Then we explode that $tempitems string so we could use another order.

When you now specify $id this becomes our offset.

And now in first loop, with help of $id, we add some temp items to empty $items string, and then language widget and at the end remaining menu items.

like image 41
Nikola Miljković Avatar answered Oct 02 '22 14:10

Nikola Miljković