Show only published posts in menu loop

Here’s some code I’m using to display a menu of all items below a parent item.

I’m wondering how I can get it to only display published posts?

<Loop type="menu" menu="Primary Menu" status=publish>

doesn’t seem to work.

<Set current-url><Field url /></Set>
<ul class="shortcode-menu">
  <Loop type="menu" menu="Primary Menu"  status=publish field="id" field_value="{Get local=parent /}">
    <li class="menuid-{Field id /}"><a href="{Field url}"><Field title /></a></li>
    <If field=children>
      <ul class="child-menu">
        <Loop field="children">
          <If variable=current-url is value="{Field url}">
            <li class="menuid-{Field id /} parentid-{Field parent_id} current"><a href="{Field url}"><Field title /></a></li>
            <Else />
            <li class="menuid-{Field id /} parentid-{Field parent_id}"><a href="{Field url}"><Field title /></a></li>
          </If>
        </Loop>
      </ul>
    </If>
  </Loop>
</ul>

I’m a bit confused about what you’re trying to do here. As far as I’m aware, draft menus or menu items aren’t a thing in WordPress, right? I just tried myself and I’m only able to add published posts to a menu. You’ve got a menu loop (which loops through menu items) but you’re asking about displaying posts, which sounds a bit contradictory.

Are you trying to manually create a menu using L&L byh looping through posts? If so, you wouldn’t want to use the menu loop, you’d just use a regular post loop, which does work with status=publish.

Let me know if you can clarify what you’re trying to achieve and what kind of data you’re intending to loop through.

Yeah I wasn’t aware of that but can confirm you can’t add draft pages to a menu.

You can have a published page in a menu and change it to draft and it will still display in the menu but that looks like default behaviour for WP generated menus as well. I could have sworn that wasn’t default behaviour and the menu item was removed for users who don’t have access to drafts eg anon users. I might have imagined that or had some plugin activated that handled it.

I guess I could probably get the post_id of the menu item and run an if statement to check if it’s published.

Oh interesting, I hadn’t thought to try that. In that case, since menu loops have a post field that allows us to get a “Loop instance of item as post,” I imagined we should be able to get actual post fields from the menu item with <Loop field=post>. I gave the template below a try:

<ul>
  <Loop type=menu menu="My Menu">
    <li>
      <Field title />
      <Loop field=post>(<Field status />)</Loop>
    </li>
  </Loop>
</ul>

Interestingly, on published posts, I’m able to get their status (“publish”) but on draft posts, I’m not even able to loop through the post field. The WordPress docs seem pretty clear that it expects you to only put “currently published” items in a menu, so I wouldn’t be surprised if some core bit of WordPress just isn’t allowing menus to work with draft items. L&L is just piggybacking off core WP functions for the most part so I doubt this is a unique limitation of L&L.

That being said, it’s still possible to get other menu fields, such as post_id, which gave me an idea:

<ul>
  <Loop type=menu menu="My Menu">
    <Set status><Loop post_type=page id="{Field post_id}" status=publish,draft><Field status /></Loop></Set>
    <If variable=status is value=publish>
      <li>
        <Field title />
      </li>
    </If>
  </Loop>
</ul>

This works and only displays items that are published. The downside is that it results in an extra query for each menu item when theoretically that data should already be accessible. Even though this does seem like L&L is just mirroring the regular WordPress way of doing things, I wonder if we’d be able to get that post field even for draft posts. It wouldn’t be the first time we’ve made L&L get around the limitations of core WP. I expect we’ll need to make some changes to the menu loop for block theme menus anyway, so I’ll make a note to have a dev check to see what we can do about this. In any case, hopefully, the suggestion above works for you for now.

Oh hold up, I just realized that while my post above was correct in that it doesn’t seem possible to use <Loop field=post> on draft menu items, I’ve realized that that’s not necessary since we can just check which posts are published and only display those. So this would be the best approach to achieve what you’re looking for:

<ul>
  <Loop type=menu menu="My Menu">
    <If check="{Loop field=post}{Field status /}{/Loop}" value=publish>
      <li>
        <Field title />
      </li>
    </If>
  </Loop>
</ul>

Hope that helps!

3 Likes

That’s perfect, thanks!

1 Like