• All I am trying to do is dynamically add the latest post to my nav menu.

    That’s it.

    I am wanting to do this programmatically because I don’t want to be reliant upon third parties and plugins in the operation of my site beyond that which is minimally required to have a self-hosted site on WordPress.

    I am using a custom barebones theme which I have used elsewhere for about 20 years now. I modified my HTML/CSS as necessary to get it to work in the WordPress ecosystem. My site works perfectly otherwise and it looks exactly how I want it to look.

    The current menu on my public site is 100% static HTML/CSS. I’ve manually input the ~300 links to the blog posts in the menu by hand all because WordPress doesn’t have a functional, native menu built in.

    WHERE I’M AT:

    -I’ve successfully registered my custom menu.

    -I’ve got code in my functions.php file which can indeed dynamically insert the latest post title and URL into the menu.

    THE PROBLEM:

    -All code I can find overwrites the existing most recent menu item.

    I’ve actually got a couple of very different codes which do manage to output the latest post to my “wp_nav_menu”‘s “theme_location” but they all overwrite the previous/existing entry.

    I must be missing some magic line of PHP code which makes it actually append to the existing code instead of overwriting.

    I can provide examples of the codes I’m using, but all I need is someone who knows PHP who can tell me “hey idiot, to append the results of the array, use the ‘”‘soilent_green’ argument”.

    All I want is to dynamically add the latest entry onto the menu. It must be common knowledge to any PHP wizard.

    <rant>
    I have spent two full 8-hour days sweatily experimenting/googling/breaking things to no avail. What I’m attempting to do should not only be easy but it should be a baked-in, on-by-default setting. Users shouldn’t even have to think about this because it should be on by default, like every other blogging platform I’ve ever seen works. Incredibly, maddeningly, WordPress DOES have this functionality built in… for PAGES. But WordPress is fundamentally a blogging platform, is it not? Then why is this functionality not available for POSTS? I can’t believe how much time I’ve wasted trying to find an answer to this very, very basic problem.
    </rant>


    Here’s an example of my functions.php file with one of the several codes I’ve found which all DO dynamically add the latest post to the menu, but which all overwrite the existing menu items. I don’t want them to overwrite, I want them to be added onto the menu. Like, the basic function of any blog navigation menu anywhere. Arguably, the most basic functionality.

    add_theme_support('menus');


    register_nav_menus(
    array('sidebar-menu' => 'sidebar Menu Location',

    )
    );


    // Front end only, to avoid issues in the admin menu editor
    if ( ! is_admin() ) {
    add_filter( 'wp_get_nav_menu_items', 'replace_placeholder_nav_menu_item_with_latest_post', 10, 3 );
    }

    /**
    * Replaces a custom URL placeholder with the URL to the latest post.
    *
    * @param array $items The menu items.
    * @param object $menu The menu object.
    * @param object $args The menu arguments.
    * @return array The modified menu items.
    */
    function replace_placeholder_nav_menu_item_with_latest_post( $items, $menu, $args ) {
    foreach ( $items as $item ) {
    if ( '#latestpost' != $item->url ) {
    continue;
    }

    $latest_post = get_posts( array(
    'numberposts' => 1,
    'post_status' => 'publish'
    ) );

    if ( empty( $latest_post ) ) {
    continue;
    }
    $appended_html = sprintf(
    '<li><a href="'. esc_url( get_permalink( $latest_post[0]->ID ) ) .'">'. esc_html( get_the_title() ) .'</a></li>',
    get_permalink()
    );

    echo $appended_html;



    }

    return $items;
    }

    The page I need help with: [log in to see the link]

Viewing 6 replies - 1 through 6 (of 6 total)


  • This solution permanently appends each post to your WordPress nav menu at publish time, so nothing gets overwritten. It uses transition_post_status to detect when a post is published for the first time, finds the menu assigned to the sidebar-menu theme location, checks for duplicates, and then saves a real menu item via wp_update_nav_menu_item().

    Requirement: In WP Admin → Appearance → Menus, make sure you have a menu assigned to the Sidebar Menu Location (sidebar-menu). Otherwise, WordPress has no menu ID to insert into.

    <?php
    /**
    * Single solution: Automatically append each newly published post to your assigned menu
    * (persistent in the database; does not overwrite existing menu items).
    */

    add_action('after_setup_theme', function () {
    add_theme_support('menus');

    register_nav_menus([
    'sidebar-menu' => 'Sidebar Menu Location',
    ]);
    });

    /**
    * When a post is published for the first time, add it to the menu assigned to 'sidebar-menu'.
    */
    add_action('transition_post_status', function ($new_status, $old_status, $post) {

    // Only run when transitioning INTO 'publish' for the first time
    if ($new_status !== 'publish' || $old_status === 'publish') {
    return;
    }

    // Only standard posts (change if you need a custom post type)
    if (empty($post->post_type) || $post->post_type !== 'post') {
    return;
    }

    // Ignore autosaves and revisions
    if (wp_is_post_autosave($post->ID) || wp_is_post_revision($post->ID)) {
    return;
    }

    // Get the menu ID assigned to this theme location
    $locations = get_nav_menu_locations();
    if (empty($locations['sidebar-menu'])) {
    return; // No menu assigned to this location
    }
    $menu_id = (int) $locations['sidebar-menu'];

    // Prevent duplicates: if this post is already in the menu, do nothing
    $existing_items = wp_get_nav_menu_items($menu_id);
    if (!empty($existing_items)) {
    foreach ($existing_items as $item) {
    if (
    isset($item->object, $item->object_id) &&
    $item->object === 'post' &&
    (int) $item->object_id === (int) $post->ID
    ) {
    return;
    }
    }
    }

    // Append a new menu item pointing to this post
    wp_update_nav_menu_item($menu_id, 0, [
    'menu-item-title' => get_the_title($post->ID),
    'menu-item-object' => 'post',
    'menu-item-object-id' => $post->ID,
    'menu-item-type' => 'post_type',
    'menu-item-status' => 'publish',
    ]);

    }, 10, 3);
    Thread Starter sublunar

    (@sublunar)

    That works!

    Only issue is that it adds it to the bottom of the menu, but everything is in reverse chronological order. So it just needs to be sorted in the opposite order as displayed.

    Do you know where I would add the sort (or rsort) command into the code?

    THANK YOU for the help! I was not going to figure that out on my own. Still a noob but trying to learn.

    Thread Starter sublunar

    (@sublunar)

    Anyone know how to change the order of the menu as it is displayed at the “theme_location”

    I’ve tried all sorts of things but cannot get anything to affect the output of yemlihakorkmaz‘s code.

    Thread Starter sublunar

    (@sublunar)

    shahzadmalik69

    your solution does add it to the menu successfully, but the menu is being displayed in reverse chronological order.

    Do you know how to sort the menu such that the more recent posts are on top instead of the bottom?

    I’ve tried all kinds of different sorting methods but nothing seems to affect it.

    I’ve tried adding things like: 'orderby' => 'date', in my wp_nav_menu code but nothing seems to affect the actual order of the menu items

    Thread Starter sublunar

    (@sublunar)

    well, thanks anyway, I guess.

    • This reply was modified 3 months, 1 week ago by sublunar.
    Moderator bcworkz

    (@bcworkz)

    wp_nav_menu() doesn’t support ordering because most menus are manually constructed. There’s a “menu_order” value that can be set, but using it for dynamically generated menu items is not the best approach.

    wp_nav_menu() uses get_posts() to get menu items in the same way we’d get posts, except the post type is “nav_menu_item”. Thus you can use the “pre_get_posts” action hook to alter ordering or any other query parameter you might desire. Your callback needs to first verify it’s operating on the correct query. Checking the “post_type” value should be adequate. Then set the “order” parameter to 'DESC'.

Viewing 6 replies - 1 through 6 (of 6 total)

You must be logged in to reply to this topic.