Search code examples
phppluginstwiggrav

Grav CMS: Hide modular pages in page selection lists


I'm working on a project which uses a lot of modular pages.
So naturally, the dropdown which lists all the pages (e.g. when selecting a parent page when creating a new page) gets very bloated with options you don't really use.

I edited /user/plugins/admin/themes/grav/templates/forms/fields/pages/pages.html.twig to prevent the modular pages from rendering.

Original code (line 12):

{% for page_route, option in pages_list %}
    <option {% if page_route == value or (field.multiple and page_route in value) %}selected="selected"{% endif %} value="{{ page_route }}">{{ option|raw }}</option>
{% endfor %}

My code:

{% for page_route, option in pages_list %}
    {% if page_route|split('/')|last matches '/^(?!_).*/' %}
         <option {% if page_route == value or (field.multiple and page_route in value) %}selected="selected"{% endif %} value="{{ page_route }}">{{ option|raw }}</option>
    {% endif %}
{% endfor %}

So this works pretty well and hides all the modular pages in the dropdown. Unfortunately, I fear this may be overwritten with the next admin plugin update.

I'd love to create a plugin which forces the admin plugin to use my templates instead of messing around in the original ones, but I don't know how to do that. Is it even possible?

Thanks!


Solution

  • I found something: https://github.com/OleVik/grav-plugin-adminidenticons
    It overrides a partial of the admin plugin.

    Step 1: Create a plugin

    There are plenty of tutorials how to do that.
    I have the following file structure inside my plugin folder:

    user/plugins
    -- myplugin
    ---- blueprints.yaml
    ---- myplugin.php
    ---- myplugin.yaml
    

    Step 2: Copy files

    /user/plugins/admin/themes/grav/templates/forms/fields/pages/pages.html.twig to /user/plugins/myplugin/admin/themes/grav/templates/forms/fields/pages/pages.html.twig

    /user/plugins/admin/themes/grav/templates/partials/blueprints-new.html.twig to /user/plugins/myplugin/admin/themes/grav/templates/partials/blueprints-new.html.twig

    Don't forget to add the snippet I posted above into the copied pages.html.twig. You can leave the blueprints-new.html.twig unedited, but you need the partial inside your plugin folder to get Twig to load the local pages.html.twig.

    Step 3: PHP

    Edit myplugin.php

    <?php
    namespace Grav\Plugin;
    
    use Grav\Common\Grav;
    use Grav\Common\Plugin;
    use Grav\Common\Page\Page;
    use RocketTheme\Toolbox\Event\Event;
    
    class MyPluginPlugin extends Plugin
    {
        public static function getSubscribedEvents() {
            return [
                'onPluginsInitialized' => ['onPluginsInitialized', 0],
            ];
        }
    
        public function onPluginsInitialized()
        {
            /** @var Uri $uri */
            $uri = $this->grav['uri'];
            $route = $this->config->get('plugins.admin.route');
    
            if ($route && preg_match('#' . $route . '#', $uri->path())) {
                $this->enable([
                    'onPageInitialized' => ['onPageInitialized', 0],
                    'onAdminTwigTemplatePaths' => ['onAdminTwigTemplatePaths', 0]
                ]);
            }
        }
    
        /**
         * Load custom CSS into backend
         *
         */
        public function onPageInitialized()
        {
            $assets = $this->grav['assets'];
            $assets->addCss('user/plugins/myplugin/style/custom-backend.css', 1);
        }
    
        /**
         * Register templates and page
         *
         * @param RocketTheme\Toolbox\Event\Event $event Event handler
         *
         * @return array
         */
        public function onAdminTwigTemplatePaths($event)
        {
            $event['paths'] = array_merge(
                $event['paths'],
                [__DIR__ . '/admin/themes/grav/templates']
            );
            return $event;
        }
    }
    

    Bonus: Hide unique page templates

    Sometimes, you create page templates which are supposed to be used once on just one page. Just the way Grav works, they will still appear inside the list when creating a new page. Of course, you don't want your editors to get creative with the page templates, so it's best to hide them.

    If you're actually also reading the code you're copy-pasting, you'll notice, that there is a function onPageInitialized(), which loads a CSS file into the backend.

    Update your files:

    user/plugins
    -- myplugin
    ---- style
    ------ custom-backend.scss
    ------ custom-backend.css
    ---- blueprints.yaml
    ---- myplugin.php
    ---- myplugin.yaml
    

    Edit custom-backend.scss

    // hide unique templates
    .selectize-dropdown-content {
        .option {
            $hide_values: "this-template", "home", "that-template";
    
            @each $current_value in $hide_values {
                &[data-value="#{$current_value}"] {
                    display: none;
                }
            }
        }
    }
    

    Set the $hide_values to the page templates you want to hide in the backend. I use CSS, that way you can re-enable them with the browser inspector in case you need them. Of course, don't forget to compile your SCSS.

    I know this turned into a fully fledged tutorial, but having the modular pages littering the page list is actually a problem I had on multiple projects now and I never found something online. Unfortunately, I don't really have a way to publish this properly, so I hope someday someone will stumble upon this Q&A and put it on some webblog, where it belongs.

    Thanks!