Jump to content
Esther E.

IC5: Menus

Action and Moderation Menus can be one of the most tedious development tasks, while also being critical to user experience.

For example, we may add support for pinning/unpinning content, then we need to remember to include the ability to pin/unpin that content in all the HTML templates. 3rd party developers add screens inside their applications, and then they need to add a link to the User Menu to make that accessible.

With Invision Community 4, this would require a template hook targeting fairly complex classes and children that was susceptible to structural changes to templates between versions.

In Invision Community 5, we have made significant changes to menu creation in order to streamline the process, and also to allow 3rd party developers better accessibility.

 

New Helper Classes

Menus are now built using helper classes, rather than relying on lengthy HTML templates. A menu is created by initializing a new Menu object.

$menu = new Menu( 'AccountMenu' );

We can then add elements to the menu.

$menu->addTitleField( 'menu_content' );
$menu->add( new Link( $member->url(), 'menu_profile', icon:'fa-solid fa-user' ) );
$menu->addSeparator();
$menu->add( new Link( Url::internal( "app=core&module=system&controller=markread", "front", "mark_site_as_read" )->csrf()->addRef( Request::i()->url() ), 'mark_site_read', dataAttributes: [
			'data-action' => 'markSiteRead',
			'data-controller' => 'core.front.core.markRead'
		], icon: 'fa-solid fa-eye' ) );

The most common menu element is the Link. This will generate the appropriate <li> element within the menu. You can define the URL, CSS class (default is ipsMenu_item), data attributes, icon, title, among other properties.

Titles and Separators are added using the Menu::addTitleField() and Menu::addSeparator() methods respectively.

You can also insert custom HTML into the menu using the Menu::addHtml() method.

In your HTML template, you would then simply display the menu object as a string.

{{if $menu->hasContent()}}
{$menu|raw}
{{endif}}

The menu templates will include the link that opens the menu, as well as the menu itself.

You'll notice that the above contains a call to the hasContent() method. This method will check if the menu object has any elements inside; if a user does not have permission to any of the elements, nothing will be displayed.

 

Content Menus

Almost all content items and comments (and reviews) require some kind of menu for moderation. Previously, this meant creating large chunks of redundant HTML code throughout the codebase. We've implemented \IPS\Content\Item::menu() and \IPS\Content\Comment::menu() to build these menus in a central location. The new methods include checks for whether a feature is in use and whether the user has permission to perform this action.

Example:

if( IPS::classUsesTrait( $this, 'IPS\Content\Pinnable' ) AND $this->canPin( $member ) )
{
	$links['pin'] = new ContentMenuLink( $this->url()->csrf()->setQueryString( array( 'do' => 'moderate', 'action' => 'pin' ) ), 'pin'  );
}

Now, the HTML template simply contains:

{$entry->menu()|raw}

(Note: Yes, these content menus can be extended using... you guessed it. UI Extensions.)

 

Other Menus

We have also migrated the following menus to the new structure:

  • User Menu
  • Mobile Menu
  • Create Menu

 

Badges

Another area with redundant HTML was our content badges. For example, pinned topics will display an icon on both the topic list and the topic header. We have created helper classes for badges and badge icons to centralize this logic. Within the new Item::badges() method, we build an array of icons that will be shown.

if( IPS::classUsesTrait( $this, Featurable::class ) AND $this->isFeatured() )
{
	$return['featured'] = new Icon( Badge::BADGE_POSITIVE, 'fa-solid fa-star', Member::loggedIn()->language()->addToStack( 'featured' ) );
}

The above generates a badge icon with the badge type ipsBadge--positive (constants have been declared for all common types, but any class can be used), the star icon, and the "featured" language string as the tooltip.

In our template HTML, we now have

<div class='ipsBadges'>
	{{foreach $entry->badges() as $badge}}{$badge|raw}{{endforeach}}
</div>

 

UserMenu Extension

Now that we've moved the menus into the codebase and out of the templates, we needed a way to allow 3rd party developers to insert their own menu items. We've introduced a new extension called UserMenu.

The UserMenu extension contains the following methods:

  • accountMenu
    This method allows you to add menu elements to the user menu. The method includes a parameter to allow you to add elements in one of 3 places within the menu: content, settings, or logout.
  • mobileMenu
    Allows you to add elements to the mobile navigation menu. All elements are inserted before the "sign out" option.
  • createMenu
    Replaces the CreateMenu extension, which has been deprecated.
  • accountSettingsLinks
    Allows you to add links to the inner sidebar in the Account Settings overview tab (under the link for Notification Settings).

Note: No, this does not add tabs to the Account Settings page, but fear not, that's coming. (Not in the UI Extension.)

  • userNav
    This method will insert HTML in the user bar, to the left of the Create Menu.
  • mobileNav
    Similar to the userNav method, but inserts HTML into the mobile navigation header.

 

What do you think of our changes to the Menus? Let us know in the comments below.

Comments

Recommended Comments

Am I able to add a new entry in any position in the content item menu or only in the first/last position? See this example:

LOcBi53.png

It wouldn't make much sense to add this specific links after the Moderator History.

Link to comment
Share on other sites

5 minutes ago, Adriano Faria said:

Am I able to add a new entry in any position in the content item menu or only in the first/last position? See this example:

LOcBi53.png

It wouldn't make much sense to add this specific links after the Moderator History.

At the moment it's only first or last but we've been discussing this internally.

Link to comment
Share on other sites

14 minutes ago, Daniel F said:

But for other applications, where you'll have to use the UIItem Extension, you're able to place it at the beginning or end

So I assume this check:

{{if ( $topic->canPin() or $topic->canUnpin() or $topic->canFeature() or $topic->canUnfeature() or $topic->canHide() or $topic->canUnhide() or $topic->canMove() or $topic->canLock() or $topic->canUnlock() or $topic->canDelete() or $topic->availableSavedActions() or $topic->canMerge() or $topic->canUnarchive() or $topic->canRemoveArchiveExcludeFlag() or \IPS\Member::loggedIn()->modPermission('can_view_moderation_log') or $topic->canToggleItemModeration() ) or ( $topic->isFutureDate() and $topic::canFuturePublish( NULL, $topic->container() ) ) or ( $topic->hidden() == -2 AND \IPS\Member::loggedIn()->modPermission('can_manage_deleted_content') )}}

for topics, for example, won't be necessary anymore as I can make the checking for each entry in the extension, right?

This is a limitation that prevents us from adding links in the Action menu.

Link to comment
Share on other sites

1 minute ago, Adriano Faria said:

So I assume this check:

{{if ( $topic->canPin() or $topic->canUnpin() or $topic->canFeature() or $topic->canUnfeature() or $topic->canHide() or $topic->canUnhide() or $topic->canMove() or $topic->canLock() or $topic->canUnlock() or $topic->canDelete() or $topic->availableSavedActions() or $topic->canMerge() or $topic->canUnarchive() or $topic->canRemoveArchiveExcludeFlag() or \IPS\Member::loggedIn()->modPermission('can_view_moderation_log') or $topic->canToggleItemModeration() ) or ( $topic->isFutureDate() and $topic::canFuturePublish( NULL, $topic->container() ) ) or ( $topic->hidden() == -2 AND \IPS\Member::loggedIn()->modPermission('can_manage_deleted_content') )}}

for topics, for example, won't be necessary anymore as I can make the checking for each entry in the extension, right?

This is a limitation that prevents us from adding links in the Action menu.

The entry explains it already;)

The menu templates will include the link that opens the menu, as well as the menu itself.

You'll notice that the above contains a call to the hasContent() method. This method will check if the menu object has any elements inside; if a user does not have permission to any of the elements, nothing will be displayed.

 

 

Link to comment
Share on other sites

Hello,

I don't think my question is related to Menus or if there will be a new blog entry to cover it. I'll ask anyways.

Will we be able to add buttons to the items view, like in the topic view (red area)?

GcQUnt1.png

Thank you.

Edited by Adriano Faria
Link to comment
Share on other sites

53 minutes ago, Adriano Faria said:

Hello,

I don't think my question is related to Menus or if there will be a new blog entry to cover it. I'll ask anyways.

Will we be able to add buttons to the items view, like in the topic view (red area)?

GcQUnt1.png

Thank you.

Probably with the new template hooks (which we haven't blogged about yet), but I confess I don't remember all the hook points offhand. 

Link to comment
Share on other sites


×
×
  • Create New...