How to reuse a complete modular section (layout, media, fields) across multiple pages?

Plugin only allows to select another module and does not include any content or custom fields from that selected module. It only has a single select field.

Having said that…

IIRC Grav supports some kind of plugin extensibility, but wouldn’t that defeat the purpose of module reuse? I mean, if you want to change some fields of the selected module, wouldn’t it be better to just create a module of that needed type? :thinking:

In our case, the custom fields (like “Show in page jump menu” and some toggles for background or layout options) are actually general options that we want available for all module pages—not unique content per instance, but things that control how modules behave or are displayed on the site.

So technically, I would just need to extend the YAML blueprint that the plugin uses for mirrored modules, adding our custom fields from our general module_item.yaml blueprint. That way, those options would show up in the admin for both regular and mirrored modules.

Of course, this would mean modifying the plugin’s blueprint file directly—which could get overwritten with updates.

Is there a recommended way in Grav to override or extend a plugin blueprint (like via blueprints:// or another mechanism) without directly editing the plugin files? Or is patching the plugin YAML the only option for now

I assume it should be possible, when you select a module, to choose which fields to extend. But template would also need to be updated to merge both page configs :thinking: I might look into this, but no promises

@Karmalakas My idea is to add a configuration option that allows users to specify a custom blueprint file (e.g. theme://blueprints/module-reuse.yaml).
If set, the plugin would use that blueprint instead of the default one.
This way, site owners can add their own custom fields and tabs for module reuse—without having to modify the plugin directly.
If the option is empty, the plugin just falls back to its own blueprint.

user/plugins/module-reuse/blueprints.yaml

name: Module Reuse
slug: module-reuse
type: plugin
version: 0.1.0
description: Reuse any module in a modular page
icon: plug
author:
  name: Karmalakas
homepage: https://github.com/karmalakas/grav-plugin-module-reuse
#demo: http://demo.yoursite.com
keywords: modular, module, duplicate
bugs: https://github.com/karmalakas/grav-plugin-module-reuse/issues
docs: https://github.com/karmalakas/grav-plugin-module-reuse/blob/develop/README.md
license: MIT

dependencies:
  - { name: grav, version: '>=1.7.0' }

form:
  validation: loose
  fields:
    enabled:
      type: toggle
      label: PLUGIN_ADMIN.PLUGIN_STATUS
      highlight: 1
      default: 0
      options:
        1: PLUGIN_ADMIN.ENABLED
        0: PLUGIN_ADMIN.DISABLED
      validate:
        type: bool
    root:
      type: pages
      label: Start in
      show_all: true
      show_modular: false
      description: Root page to start the tree for module selection
    custom_blueprint:
      type: text
      label: 'Custom module blueprint path'
      description: >
        Specify the path to your custom module blueprint. The file name must be 'module-reuse.yaml'.
        This will replace the default blueprint for module reuse modules.  
        Make sure your blueprint includes the required fields (like 'header.module').
      default: ''


Then you put your custom file in your theme blupeprint modular folder, e.g. user/themes/my-theme/blueprints/modular/module-reuse.yaml

Maybe somethingl like this in plugins user/plugins/module-reuse/module-reuse.php. I have not testet it yet:

 /**
     * Extend page blueprints with additional configuration options.
     *
     * @param Event $event
     */
    public function onGetPageBlueprints($event)
    {
        $locator = Grav::instance()['locator'];

        // Load Plugin Blueprint
       $event->types->scanBlueprints($locator->findResource('plugin://' . $this->name . '/blueprints'));

        // Load custom Blueprint (if set, it overwrites the plugin's own)
        $customBlueprint = $this->config->get('plugins.module-reuse.custom_blueprint');
        if ($customBlueprint) {
            $customBlueprintPath = $locator->findResource($customBlueprint, true, true);
            if ($customBlueprintPath && file_exists($customBlueprintPath)) {
                $event->types->scanBlueprints(dirname($customBlueprintPath));
            }
            else {
                $this->grav['log']->warning("[Module Reuse] Custom blueprint not found at: $customBlueprint");
            }
        }
    }

By the way, another great effect of this approach is that you can also override the Twig template for module-reuse simply by placing a module-reuse.html.twig file in the corresponding templates/modular/ directory of your theme. Grav will automatically use the theme’s template instead of the plugin’s, so no further changes are required—customizing the frontend becomes super easy!

I’ll answer here in short, but let’s move to repo discussions if you feel there’s a need for more :slight_smile:

So my approach to most software - make it reasonably flexible. I don’t want to add your proposed option, because that would limit config to a single type of module. My idea is to make fields for override available depending on the selected module to reuse on the page level

If you’re doing this on a single project, I guess it’s fine, but as a plugin, that would cause more issues in the future I suppose (if/when more users start using it to reuse different types of modules)

@Karmalakas Thanks for your feedback!
I totally understand your point about not wanting to limit configuration to a single module type, especially with the plugin’s potential for broader use. Our changes were indeed focused on our own project needs, where a unified custom blueprint and template make things much easier for editors and consistent for our content structure.

Your approach for per-module-type field overrides makes a lot of sense for the general case, especially as more people start using the plugin in different setups. If you develop something in that direction, we’d be interested in testing or providing feedback.

For now, we’ll continue with our local customization, but we’ll keep an eye on the plugin’s progress!

Thanks for the great work and the open discussion.