Skip to content

Combining with a module that adds custom items #143

Open
@JayBox325

Description

@JayBox325

Question

I have got a unique multi-site setup where each site has a different 'homepage' single, but my platform could end up with 15/20 or more sites, so in an attempt to limit how complex my permissions management could get and to try to simplify the onboarding process of a new site, I have written a module that automates adding a link to the singles associated with that site to the global sidebar.

Your 'Expanded Singles' plugin didn't work for me as we're not using the secondary sidebar, and hosting everything in the global sidebar.

The benefits of this module mean I can have just one 'outlets' Navigation layout that is associated with one 'outlet' user group, whereas if I don't use my module.

In order to get the AX I'm looking for, I'd need to create a new site, a new user group, a new single and a new navigation layout for each outlet which will become hard to maintain, whereas if I can just dynamically add the singles to the top, this will save a lot of work. Here is my module that finds the singles for the current site and adds them to the sidebar, but when I enable the Navigation plugin, it replaces this item, too. Is it going to be possible to combine them?

<?php

namespace sidebarsingle;

use Craft;
use craft\events\RegisterCpNavItemsEvent;
use craft\models\Section;
use yii\base\Event;
use craft\elements\Entry;

class Module extends \yii\base\Module
{
    public function __construct($id, $parent = null, array $config = [])
    {
        parent::__construct($id, $parent, $config);

        // Attach the event handler when the module is initialized
        Craft::$app->onInit(function () {
            $this->registerEventHandlers();
        });
    }

    private function registerEventHandlers()
    {
        // Listen for the CP navigation item registration event
        Event::on(
            \craft\web\twig\variables\Cp::class,
            \craft\web\twig\variables\Cp::EVENT_REGISTER_CP_NAV_ITEMS,
            function (RegisterCpNavItemsEvent $event) {
                // Fetch all singles for the current site
                $singles = $this->getCurrentSiteSingles();

                // Add a navigation item for each single
                foreach ($singles as $single) {
                    array_unshift($event->navItems, [
                        'url' => 'entries/' . $single->section->handle . '/' . $single->id . '-' . $single->slug, // URL for the single
                        'label' => 'Landing Page',
                        'icon' => '@appicons/house.svg', // Optional icon
                    ]);
                };

            }
        );
    }

    /**
     * Fetch all singles for the current site
     *
     * @return array The singles for the current site
     */
    private function getCurrentSiteSingles()
    {
        // Get the currently active site
        $currentSiteHandle = Craft::$app->getRequest()->getParam('site', Craft::$app->getSites()->getCurrentSite());
        $currentSite = Craft::$app->getSites()->getSiteByHandle($currentSiteHandle);

        if ($currentSite) {
            // Get the current site's ID
            $currentSiteId = $currentSite->id;

            // Fetch all singles
            $singles = Craft::$app->entries->getSectionsByType(Section::TYPE_SINGLE);

            // Find the single for the current site and return it
            $singlesForCurrentSite = array_filter($singles, function ($single) use ($currentSiteId) {
                return in_array($currentSiteId, $single->getSiteIds());
            });

            // Fetch the associated entries to get the slugs
            $entries = [];
            foreach ($singlesForCurrentSite as $single) {
                $entry = Entry::find()
                    ->sectionId($single->id) // Filter by the section ID
                    ->siteId($currentSiteId) // Ensure it's for the current site
                    ->one();

                if ($entry) {
                    $entries[] = $entry;
                }
            }

            return $entries;

        } else {
            echo 'Error: Active site not found.';
            return [];
        }
    }
}

Thanks!

Additional context

No response

Activity

engram-design

engram-design commented on Jan 29, 2025

@engram-design
Member

So that's going to be tricky, as we're essentially competing over the Cp::EVENT_REGISTER_CP_NAV_ITEMS event. We'll probably need to introduce our own event that while similar, allows you to modify CP Nav's overridden navigations.

JayBox325

JayBox325 commented on Jan 29, 2025

@JayBox325
Author

Ok, that makes sense. This probably means I'll need to stick with the default navigation to allow this feature, which is a shame. Unless there'd be a way for me to use my module to update the URL of the Landing Page item to configure it to be that Site's "homepage" single dynamically, which isn't perfect, but may be the solution for now.

I have tried to just replace the first item in the navigation with my desired URL, but no dice:

if ($landingSingle && !empty($event->navItems)) {
    // Modify the first nav item
    $event->navItems[0]['url'] = 'entries/' . $landingSingle->section->handle . '/' . $landingSingle->id . '-' . $landingSingle->slug;
}

UPDATE: I have resolved this for now, by adding the desired single URL to the body tag as a data attribute, then using the Control Panel JS plugin, I'm just taking the contents of this attribute and using them as the Landing Page navigation item set by the CP Nav plugin. So this works for now... but if there was a way to dynamically override items from within the CP Nav that would be amazing to have it all done server-side.

This means my admin now looks like this:

Image

This could potentially be a plugin idea to remove the potentially needless second sidebar navigation within Entries, as almost everything in the CraftCMS eco-system is an entry now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Combining with a module that adds custom items · Issue #143 · verbb/cp-nav