Great Schema - horrible widget. Advice?

I have a tendency to over-engineer or oversimplify or even miss obvious solutions.

The problem with the solution I provide is that the front end, UX, TTW config is absolutely horrendous and needs to be shot, burned, buried, and removed from history books so younger generations won't be poisoned by dangerous ideas. Please help.


Here's the request:

I want navigation on my header such that:

  1. I can have sub-navigation under main navigation.
  2. navigation is NOT driven by content
    (no queries for folders and 'exclude from nav' and navigation depth and all that slowness)
  3. navigation is NOT driven by objects in the database - some navigation items may actually go off-domain and link to other sites.
  4. I want to configure it. (basically, I don't want to write HTML, so this must be TTW)

Solution: Drop Plone's navigation completely and design my own control panel config:

My schema - as simple as possible, is a single list (main naviation) of lists (sub navigations) of 'Header elements" (a structure containing a title and a url)

class IHeaderElement(Interface):

    name = field.TextLine(
        title="Link Name",
        required=True
    )

    url = schema.ASCIILine(
        title="Link URL",
        description=u'A tales string expression (string:) producing the called URL. '
                    u'Example: ${navigationRootUrl}/page'
                    u'see header.pt for available variables.',
        required=True,
    )


class INavigationSettings(Interface):

    main_navigation_items = field.List(
        title="Navigation Items",
        description="""The First element in each list is the 'Section' Navigation Column Header.
                    Additional elements are additional 'sub-sections' under that header """,
        required=True,
        value_type=field.List(
            title="Navigation Column",
            value_type=PersistentObject(IHeaderElement),
            required=False,
        ),
    )

There's a lot of other code required to get 'value_type = object' to work that I'm ignoring for the moment.


Then just throw this at plone.app.registry (z3c.form undereath, I think) and "Make Me A Form, Damnit!"

I'm on a K.I.S.S. kick now and really trying to avoid going down the rabbit hole.

class NavigationSettingsEditForm(RegistryEditForm):
    """
    Define form logic
    """
    schema = INavigationSettings
    label = "Site Settings - Navigation"

class NavigationSettingsView(ControlPanelFormWrapper):
    form = NavigationSettingsEditForm
    <configlet
        title="Navigation Settings"
        action_id="myslte.settings.navigation"
        appId="mysite.settings"
        category="Products"
        condition_expr=""
        url_expr="string:${portal_url}/@@rfa-navigation-settings"
        icon_expr=""
        visible="True"
        i18n:attributes="title">
            <permission>Manage portal</permission>
    </configlet>

Honestly, I spent too long on this problem with trying different approaches and throwing them away, and ran out of time to provide a solution I like, so here we are.


Now, if you want to configure your navigation, you end up with this horrible interface:

sucky-form-2-resize

You can't really tell if you're adding a column or a row (a main nav or subnav)
You can't re-order things. Want to put a column between navigation columns 3 and 4? HA HA HA HA!
you can't tell what checkbox is next to what object...


So, in running out of time, this is what got delivered, and I'm really upset about it. Lists should have order and insert operations, but the widget used is just dumb about it.

Does anybody have a quick idea how to make this form look better? do I have to design my own custom form and custom javascript to maintain a list of lists of objects?

Does anyone know what username Annette Lewis hides behind? (send me a PM, I'll keep you anonymous, I promise.)

If you used data grid field, you could reorder.
If not: maybe add a 'importance' int field (sort on) , so you could change the numbers to move something up or down ?

personally, I would add a UI for adding a) Content type or b) Custom url. Then use javascript to reorder. So probably something similar to how Wordpress does it (with 'one button for adding' and another area for 'dragging things around' )

@abl123

I don't have a good solution for fixing that interface you have there...

But the solution I built for a site once was to keep the navigation built on objects, but only specific objects.

So the top level folders all start with the id megamenu-, and only objects that start with this id will show in the top level navigation. There are subfolders inside of those (one for each column of links), then the actual links use the Link content type, which usually points to a specific page in the site, but sometimes also goes to external sites.

Yep. This is what I want too. Unfortunately, I didn't want to dive down the custom widget path or the custom form path.

But I think this is the only path.

There is no nice little widget in plone that can work with this schema. It's going to use z3c form multi widget Multi Widget — z3c.form 4.3.dev0 documentation.

Idea: Use folderish link objects?

Not too sure about "all that slowness" - we extended the widget to display related items. Site structure still guides the main navigation, but editors add links to content in other places (inclding external). In the top and regular sub navigation, external links were done exactly like @jensens already suggested. - but I just noticed that those have now been replaced by summaries on our own site.

The layout is not 100% optimal yet, but you get the idea here:
https://www.pnz.de/en/manufactory

Editors see this:
Screenshot from 2021-11-20 09-21-27

1 Like

Btw, this is not slow anymore since Plone 5.2 (global tabs code).

Can't you just use portal actions? Very simple, you can use also an advanced UI in ZMI with all the settings.

Yep, we were using portal actions in our previous design that was a flat navigation.

When the new "sub nav" requirement came in, that's when portal actions wasn't feature rich enough.

It seems natural to use the content tree to do navigation - and use folderish link objects for external links. We were burnt with this in the past because of the inefficiency of computing the navigation. When we did our performance tweaking, navigation was the biggest offender by far. 30%-40% of the time Plone was crunching on navigation. We went to portal tabs and that made the load time drop considerably.

This was Plone 5.2.

Back in plone 4 the "exclude from navigation" was giving poltergeist like behavior because of an arcane bug with ZCatalog's bool index. Boolean Index query result is incorrect when inverted+resultset · Issue #28 · zopefoundation/Products.ZCatalog · GitHub (fixed in Products.ZCatalog 4.0.1).

So, going back to using a query-based navigation is worth considering, but it's got a bad taste right now with my customer.

Can you elaborate on this?

I'd prefer not to use the ZMI as we should end up granting some kind of senior editor the permission to change the navigation, so keeping it inside Plone would be preferable.

You don't have to go the ZMI, there is an actions controlpanel :wink:

Yep. Actions Control panel / Portal Tabs is flat navigation - no ability to add sub navigation. I hope I'm wrong - you're the second to mention Portal Tabs. If Portal Tabs can do sub-navigation then my problem is solved.

Maybe... maybe that's what plone needs? (without compromising the simple and easy interface portal tabs already provides)

An idea can be to use collective.taxonomy to build your tree, just use the url as "value" of the taxon (or item) and the title as the navigation item label.

Drupal, Wordpress has the navigation based on taxonomies (or, more precisely, classifications), for example.
https://www.drupal.org/docs/user_guide/en/menu-link-from-content.html

here collective.taxonomy:

I didn't know about this. Thanks!

Maybe look here, too: Display vocabulary term title for fields value in custom view

Plone Foundation Code of Conduct