Jump to content
horst

Does using dedicated module files help a lazy programmer?

Recommended Posts

Does using dedicated module files help a lazy programmer?

For a private helper module I wanted to built, I decided to use the possibilities of dedicated files (implemented in PW 2.5.5) and not to write all into a single module file. Until now, I totally missed or forgot about this possibility. To my excuse: on introduction I may have thought not to use it early in my modules to keep backward compatibility. And then totally forgot about it. :)

I allready use a tool for postprocessing in my sites. And I'm not familiar with all those popular node/grunt/gulp/npm/bower/and-what-else stuff out there. It looks to me a bit oversized for small to medium websites. But I also wanted not miss a comfortable, easy to use config for less and sass files, especially for those from frameworks like Bootstrap 3 / 4 or UIKit. So, what my toolbox should get added was a preprocessor (compiler) for sass (.scss) files first. I choosed the UIKit for the first shot.

The created files for a configurable module called PreAndPostProcessor and a process module called ProcessPreProcessor were:

  • PreAndPostProcessor.module
  • PreAndPostProcessor.info.json
  • PreAndPostProcessorConfig.php
     
  • ProcessPreProcessor.module
  • ProcessPreProcessor.info.json
  • ProcessPreProcessor.css
  • ProcessPreProcessor.js

As you can read about the differences to the old-schooled style in Ryans blog post, I focus on what I found out to be most useful for me. Starting with the Config file, I decided to use the $this->add() method in the __constructor(). It is the way what needs less code to define your inputfields for a configpage: just a collection of arrays with field or fieldset definitions.

Mandatory definitions are: type, name, label. Others are optional: description, notes, required, columnWidth, collapsed, showIf, ...
And, of course, you need the definitions specific to your fieldtypes (value, options, ...).

To group some fields into a fieldset, add a key called "children" to the fieldset array and add all field definitions to it as collection. Simple!

Spoiler

PreAndPostProcessorConfig.php:


<?php namespace ProcessWire;

class PreAndPostProcessorConfig extends ModuleConfig {

    public function __construct() {
        $this->add(array(
            array(
                'type' => 'Fieldset',
                'name' => '_compiler_conf',
                'label' => 'Compiler setup',
                'collapsed' => Inputfield::collapsedNo,
                'children' => array(
                    array(
                        'type' => 'select',
                        'name' => 'site_mode',
                        'label' => 'Set this to the mode how this site is used!',
                        #'description' => '',
                        'notes' => 'In production mode, the compiler ONLY get started if the output CSS-file is MISSING!',
                        'options' => array(
                            'PRODUCTION_MODE' => 'PRODUCTION_MODE',
                            'DEV_MODE' => 'DEV_MODE',
                        ),
                        'required' => true,
                        'columnWidth' => 100,
                    ),
                    array(
                        'type' => 'checkbox',
                        'name' => 'compiler_suppress_debugcomments',
                        'label' => 'Suppress SCSS-Source-Line_Numbers while in Debugmode',
                        'description' => 'When in Debugmode ($config->debug => true), the default behave is Nested output with SCSS-Source-Line_Numbers',
                        'notes' => 'Check this to override the default and select an output format below',
                        'showIf' => 'site_mode=DEV_MODE',
                        'columnWidth' => 100,
                    ),
                    array(
                        'type' => 'select',
                        'name' => 'compiler_output',
                        'label' => 'Select how the CSS should be generated',
                        'description' => '',
                        'notes' => 'default is: Nested',
                        'options' => array(
                            'Expanded' => 'Expanded',
                            'Nested' => 'Nested',
                            'Compact' => 'Compact',
                            'Compressed' => 'Compressed',
                            'Crunched' => 'Crunched'
                        ),
                        'required' => true,
                        'showIf' => 'site_mode=DEV_MODE, compiler_suppress_debugcomments=1',
                        'columnWidth' => 100,
                    ),
                )
            ),
            array(
                'type' => 'Fieldset',
                'name' => '_uikit_conf',
                'label' => 'Kit setup',
                'collapsed' => Inputfield::collapsedNo,
                'children' => array(
                    array(
                        'type' => 'select',
                        'name' => 'kit_type',
                        'label' => 'Select the Kit you are using',
                        #'description' => '',
                        'notes' => 'currently supported: uikit, (planned: bootstrap 4)',
                        'options' => array('uikit' => 'uikit'),
                        'value' => 'uikit',
                        'required' => true,
                        'columnWidth' => 50,
                    ),
                    array(
                        'type' => 'text',
                        'name' => 'kit_fullpath',
                        'label' => 'directory site path to your kits scss sources',
                        'description' => 'starts with "site/...", (your sitesfolder) without leading slash! But with trailing slash!',
                        'notes' => 'e.g.: site/templates/uikit/scss/ | must be writeable by PHP / PW!',
                        'placeholder' => 'site/templates/uikit/scss/',
                        'value' => '',
                        'required' => true,
                        'columnWidth' => 50,
                    ),
                    array(
                        'type' => 'text',
                        'name' => 'kit_variablesfilename',
                        'label' => 'Custom-Variablesfile (basename with extension)',
                        'description' => 'Relative to your scss kit start directory without leading slash!',
                        'notes' => 'e.g.: core/globalpwsettings.scss | must be writeable by PHP / PW!',
                        'placeholder' => 'core/globalpwsettings.scss',
                        'value' => '',
                        'required' => true,
                        'columnWidth' => 50,
                    ),
                    array(
                        'type' => 'text',
                        'name' => 'kit_startfilename',
                        'label' => 'startfile (basename with extension)',
                        'description' => 'Relative to your scss kit start directory without leading slash!',
                        'notes' => 'e.g.: uikit.scss',
                        'placeholder' => 'uikit.scss',
                        'value' => '',
                        'required' => true,
                        'columnWidth' => 50,
                    ),
                    array(
                        'type' => 'text',
                        'name' => 'kit_outputcssfile',
                        'label' => 'CSS-output-file (site path with extension!)',
                        'description' => 'starts with "site/...", (your sitesfolder) without leading slash!',
                        'notes' => 'e.g.: site/templates/styles/uikit.css | must be writeable by PHP / PW!',
                        'placeholder' => 'site/templates/styles/uikit.css',
                        'value' => '',
                        'required' => true,
                        'columnWidth' => 100,
                    ),
                )
            ),
        ));
    }
}

This is the complete config file! No other definitions or methods, also in the main module file are necessary. Unbelievable! :)

 

Another nice thing I discovered, is the use of the *.info.json files. So, this I have used before, but not like here. :)

The behave is like with the *Config.php files, - you write really less code, just arrays with key - value pairs and PW does the rest for you! Only difference here is, that you have to write it in JSON notation.

The ProcessPreProcessor.info.json file contains the neccessary and common parts: title, version, requires. And some others: permission, permissions, page and nav.

Page and nav are specific to Process modules. With page {name, parent, title} you define where PW should create you a page in the admin, and with nav, you can define a complete submenu for this page.

For those who are yet not familiar with the internal structure of Processmodules: you can navigate to a submenu entry by calling it: {pw-admin-url}/{main-module-url}/{submenu-url}/.

Calling the main menu url invokes the ___execute() method of the module. Calling a submenu url invoke the ___executeSubmenu() method. This all is really simple and straight forward. And it is really really helpful in cases like with the new toy for my toolbox. :)

The nav is a collection of arrays, each holding at least an url and a label. Thats enough for PW to implement the menu and submenu for you in the admin. But you also may define an icon too. Aaaand, you also can add your own custom key / value pairs to it. PW does not complain on it.

I have added a description. The nav was generated by parsing all core distribution scss files from the UIKit. They have a name and description in their first two lines. I programatically read this out and generated this nav notation for the info.json file:

Spoiler

ProcessPreProcessor.info.json:


{
    "title": "Process Pre-Processor",
    "summary": "",
    "version": 1,
    "author": "Horst Nogajski",
    "href": "",
    "icon": "",
    "requires": "ProcessWire>=3.0.18, PHP>=5.4.0, PreAndPostProcessor",
	"permission": "preprocessor",
	"permissions": {"preprocessor":"Run the Pre-Processor Config"},
	"page": {"name": "preprocessor", "parent": "setup", "title": "Pre-Processor"},
	"nav": 	[
                {"url":"globalpwsettings\/","label":"GlobalPWsettings","icon":"code","description":"Defines Sitewide Settings, also for other modules (LazySizes, etc)"},
                {"url":"alert\/","label":"Alert","icon":"code","description":"Defines styles for alert messages"},
                {"url":"animation\/","label":"Animation","icon":"code","description":"Provides a useful set of keyframe animations"},
                {"url":"article\/","label":"Article","icon":"code","description":"Defines styles for articles within your page"},
                {"url":"badge\/","label":"Badge","icon":"code","description":"Defines styles for badges"},
                {"url":"base\/","label":"Base","icon":"code","description":"Sets default values for HTML elements"},
                {"url":"block\/","label":"Block","icon":"code","description":"Defines styles to create horizontal layout blocks"},
                {"url":"breadcrumb\/","label":"Breadcrumb","icon":"code","description":"Defines styles for a breadcrumb navigation"},
                {"url":"button\/","label":"Button","icon":"code","description":"Defines styles for buttons"},
                {"url":"close\/","label":"Close","icon":"code","description":"Defines styles for a close button"},
                {"url":"column\/","label":"Column","icon":"code","description":"Provides a responsive, fluid and nestable columns for text and inline elements"},
                {"url":"comment\/","label":"Comment","icon":"code","description":"Defines styles for comment threads"},
                {"url":"contrast\/","label":"Contrast","icon":"code","description":"Utility class to adjust colors for dark or colored blocks"},
                {"url":"cover\/","label":"Cover","icon":"code","description":"Defines styles for images and videos to cover their container in a centered position"},
                {"url":"descriptionlist\/","label":"Descriptionlist","icon":"code","description":"Defines styles for description lists"},
                {"url":"dropdown\/","label":"Dropdown","icon":"code","description":"Defines styles for a toggleable dropdown"},
                {"url":"flex\/","label":"Flex","icon":"code","description":"Defines styles to create layouts with flexbox"},
                {"url":"form\/","label":"Form","icon":"code","description":"Defines styles for forms"},
                {"url":"grid\/","label":"Grid","icon":"code","description":"Provides a responsive, fluid and nestable grid"},
                {"url":"icon\/","label":"Icon","icon":"code","description":"Defines styles for icons"},
                {"url":"list\/","label":"List","icon":"code","description":"Defines styles for ordered and unordered lists"},
                {"url":"modal\/","label":"Modal","icon":"code","description":"Defines styles for modal dialogs"},
                {"url":"nav\/","label":"Nav","icon":"code","description":"Defines styles for list navigations"},
                {"url":"navbar\/","label":"Navbar","icon":"code","description":"Defines styles for the navigation bar"},
                {"url":"offcanvas\/","label":"Offcanvas","icon":"code","description":"Defines styles for an off-canvas sidebar that slides in and out of the page"},
                {"url":"overlay\/","label":"Overlay","icon":"code","description":"Defines styles for image overlays"},
                {"url":"pagination\/","label":"Pagination","icon":"code","description":"Defines styles for a navigation between pages"},
                {"url":"panel\/","label":"Panel","icon":"code","description":"Defines styles for reusable content areas"},
                {"url":"print\/","label":"Print","icon":"code","description":"Optimize page for printing"},
                {"url":"subnav\/","label":"Subnav","icon":"code","description":"Defines styles for the sub navigation"},
                {"url":"switcher\/","label":"Switcher","icon":"code","description":"Defines styles for the switcher"},
                {"url":"tab\/","label":"Tab","icon":"code","description":"Defines styles for a tabbed navigation"},
                {"url":"table\/","label":"Table","icon":"code","description":"Defines styles for tables"},
                {"url":"text\/","label":"Text","icon":"code","description":"Collection of useful text utility classes to style your content"},
                {"url":"thumbnail\/","label":"Thumbnail","icon":"code","description":"Defines styles for image thumbnails"},
                {"url":"thumbnav\/","label":"Thumbnav","icon":"code","description":"Defines styles for a thumbnail navigation"},
                {"url":"utility\/","label":"Utility","icon":"code","description":"Collection of useful utility classes to style your content"}
    ]
}

 

The (main) ___execute() method of the ProcessPreProcessor.module should present a submenu list with file infos. This now could be done by parsing the info.json file:

    public function ___execute() {
        // generate a navigation
        $dump = json_decode(file_get_contents(dirname(__FILE__) . '/' . basename(__FILE__, '.module') . '.info.json'));
        $nav  = $dump->nav;
        $out  = "\t\t\t<dl class='nav hnpp'>\n";
        foreach($nav as $obj) {
            $out .= "\t\t\t\t<dt><a href='./{$obj->url}'>{$obj->label}</a> ></dt>\n";
            $out .= "\t\t\t\t<dd>{$obj->description}</dd>\n";
        }
        $out .= "\t\t\t</dl>\n";
        return $out;
    }

 

To make it even more friendly for lazy devs, :), I created one method that is called from all sub-execute methods by simply passing their own name over into this function that loads and parse the scss file and displays its config page:

Spoiler

    public function ___executeGlobalPWsettings()  { return $this->run(__FUNCTION__); }  // Defines sitewide settings, also for other modules (LazySizes, etc)
    public function ___executeAlert()             { return $this->run(__FUNCTION__); }  // Defines styles for alert messages
    public function ___executeAnimation()         { return $this->run(__FUNCTION__); }  // Provides a useful set of keyframe animations
    public function ___executeArticle()           { return $this->run(__FUNCTION__); }  // Defines styles for articles within your page
    public function ___executeBadge()             { return $this->run(__FUNCTION__); }  // Defines styles for badges
    public function ___executeBase()              { return $this->run(__FUNCTION__); }  // Sets default values for HTML elements
    public function ___executeBlock()             { return $this->run(__FUNCTION__); }  // Defines styles to create horizontal layout blocks
    public function ___executeBreadcrumb()        { return $this->run(__FUNCTION__); }  // Defines styles for a breadcrumb navigation
    public function ___executeButton()            { return $this->run(__FUNCTION__); }  // Defines styles for buttons
    public function ___executeClose()             { return $this->run(__FUNCTION__); }  // Defines styles for a close button
    public function ___executeColumn()            { return $this->run(__FUNCTION__); }  // Provides a responsive, fluid and nestable columns for text and inline elements
    public function ___executeComment()           { return $this->run(__FUNCTION__); }  // Defines styles for comment threads
    public function ___executeContrast()          { return $this->run(__FUNCTION__); }  // Utility class to adjust colors for dark or colored blocks
    public function ___executeCover()             { return $this->run(__FUNCTION__); }  // Defines styles for images and videos to cover their container in a centered position
    public function ___executeDescriptionlist()   { return $this->run(__FUNCTION__); }  // Defines styles for description lists
    public function ___executeDropdown()          { return $this->run(__FUNCTION__); }  // Defines styles for a toggleable dropdown
    public function ___executeFlex()              { return $this->run(__FUNCTION__); }  // Defines styles to create layouts with flexbox
    public function ___executeForm()              { return $this->run(__FUNCTION__); }  // Defines styles for forms
    public function ___executeGrid()              { return $this->run(__FUNCTION__); }  // Provides a responsive, fluid and nestable grid
    public function ___executeIcon()              { return $this->run(__FUNCTION__); }  // Defines styles for icons
    public function ___executeList()              { return $this->run(__FUNCTION__); }  // Defines styles for ordered and unordered lists
    public function ___executeModal()             { return $this->run(__FUNCTION__); }  // Defines styles for modal dialogs
    public function ___executeNav()               { return $this->run(__FUNCTION__); }  // Defines styles for list navigations
    public function ___executeNavbar()            { return $this->run(__FUNCTION__); }  // Defines styles for the navigation bar
    public function ___executeOffcanvas()         { return $this->run(__FUNCTION__); }  // Defines styles for an off-canvas sidebar that slides in and out of the page
    public function ___executeOverlay()           { return $this->run(__FUNCTION__); }  // Defines styles for image overlays
    public function ___executePagination()        { return $this->run(__FUNCTION__); }  // Defines styles for a navigation between pages
    public function ___executePanel()             { return $this->run(__FUNCTION__); }  // Defines styles for reusable content areas
    public function ___executePrint()             { return $this->run(__FUNCTION__); }  // Optimize page for printing
    public function ___executeSubnav()            { return $this->run(__FUNCTION__); }  // Defines styles for the sub navigation
    public function ___executeSwitcher()          { return $this->run(__FUNCTION__); }  // Defines styles for the switcher
    public function ___executeTab()               { return $this->run(__FUNCTION__); }  // Defines styles for a tabbed navigation
    public function ___executeTable()             { return $this->run(__FUNCTION__); }  // Defines styles for tables
    public function ___executeText()              { return $this->run(__FUNCTION__); }  // Collection of useful text utility classes to style your content
    public function ___executeThumbnail()         { return $this->run(__FUNCTION__); }  // Defines styles for image thumbnails
    public function ___executeThumbnav()          { return $this->run(__FUNCTION__); }  // Defines styles for a thumbnail navigation
    public function ___executeUtility()           { return $this->run(__FUNCTION__); }  // Collection of useful utility classes to style your content

 

 

The first version work out nicely. Here is a screenshot of it:

 

uikit-configurator2.gif

 

... and to answer the initial question: Yes, it does!  :)

 

  • Like 17

Share this post


Link to post
Share on other sites

So we could build some profiles based on a supported frameworks  - ie: uiKit here - bundled with the module and play with it directly from PW ?

 

oh and WOW ! :o

  • Like 1

Share this post


Link to post
Share on other sites

thank you horst for the detailed insights!

how to you do all the scss compilation? any code snippets for that part? :)

  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By d'Hinnisdaël
      Format Datetime fields as Carbon instances.
      You can find the latest release and the complete readme on Github.
      Installation
      composer require daun/datetime-carbon-format Usage
      All Datetime fields will now be formatted as Carbon instances instead of strings. Some examples:
      // $page->date is a Datetime field // Output format: j/n/Y echo $page->date; // 20/10/2020 echo $page->date->add('7 days'); // 27/10/2020 echo $page->date->format('l, F j'); // Monday, October 20 echo $page->date->year; // 2020 echo $page->date->diffForHumans(); // 28 minutes ago Frontend only
      The ProcessWire admin seems to expect datetime fields to be strings. This module will only return Carbon instances on frontend page views.
      Date output format
      When casting a Carbon instance to a string (usually when outputting the field in a template), the field's date output format will be respected.
      Links
      GitHub • Readme • Carbon docs
       
       
      PS. I remember reading about a Carbon module in a recent newsletter, but couldn't find it anywhere. Was that you, @bernhard?
    • By jploch
      Hey folks,
      Iam working on a module that extends InputfieldPageTable. I use PageTableExtended as a starting point and all went well so far, except I can't access my config values outside of the module file. The config values allways return the defaults, and not the values in the pw field settings. 

      Here is the code that sets the defaults inside my inputfield module file:
      public function init() { parent::init(); // defaults $this->set('gridMaxWidth', '1600'); $this->set('gridColumns', '12'); } Here is how I add the config field:
      public function ___getConfigInputfields() { $inputfields = parent::___getConfigInputfields(); $fieldsetGrid = $this->modules->get('InputfieldFieldset'); $fieldsetGrid->label = $this->_('Default Grid Settings'); $f = $this->wire('modules')->get('InputfieldText'); $f->attr('name', 'gridMaxWidth'); $f->attr('value', $this->gridMaxWidth); $f->label = $this->_('Container max width'); $f->description = $this->_('Grid container max width in px'); // page name format description $f->notes = $this->_('default is 1600'); // page name format notes $fieldsetGrid->append($f); $inputfields->append($fieldsetGrid); return $inputfields; } Accessing the values outside my module files like this (this gives me the default: 1600, even if I insert another value in the backend field settings):
      $default = $this->wire('modules')->get('InputfieldPageGrid'); $default->gridMaxWidth; Any Ideas?
    • By MoritzLost
      TrelloWire
      This is a module that allows you to automatically create Trello cards for ProcessWire pages and update them when the pages are updated. This allows you to setup connected workflows. Card properties and change handling behaviour can be customized through the extensive module configuration. Every action the module performs is hookable, so you can modify when and how cards are created as much as you need to. The module also contains an API-component that makes it easy to make requests to the Trello API and build your own connected ProcessWire-Trello workflows.
      Warning: This module requires ProcessWire 3.0.167 which is above the current stable master release at the moment.
      Features
      All the things the module can do for you without any custom code: Create a new card on Trello whenever a page is added or published (you can select applicable templates). Configure the target board, target list, name and description for new cards. Add default labels and checklists to the card. Update the card whenever the page is updated (optional). When the status of the card changes (published / unpublished, hidden / unhidden, trashed / restored or deleted), move the card to a different list or archive or delete it (configurable). You can extend this through hooks in many ways: Modifiy when and how cards are created. Modify the card properties (Target board & list, title, description, et c.) before they are sent to Trello. Create your own workflows by utilizing an API helper class with many convenient utility methods to access the Trello API directly. Feedback & Future Plans
      Let me know what you think! In particular:
      If you find any bugs report them here or on Github, I'll try to fix them. This module was born out of a use-case for a client project where we manage new form submissions through Trello. I'm not sure how many use-cases there are for this module. If you do use it, tell me about it! The Trello API is pretty extensive, I'll try to add some more helper methods to the TrelloWireApi class (let me know if you need anything in particular). I'll think about how the module can support different workflows that include Twig – talk to me if you have a use-case! Next steps could be a dashboard to manage pages that are connected to a Trello card, or a new section in the settings tab to manage the Trello connection. But it depends on whether there is any interest in this 🙂 Links
      Repository on Github Complete module documentation (getting started, configuration & API documentation) TrelloWire in the modules directory Module configuration

    • By David Karich
      ProcessWire InputfieldRepeaterMatrixDuplicate
      Thanks to the great ProModule "RepeaterMatrix" I have the possibility to create complex repeater items. With it I have created a quite powerful page builder. Many different content modules, with many more possible design options. The RepeaterMatrix module supports the cloning of items, but only within the same page. Now I often have the case that very design-intensive pages and items are created. If you want to use a content module on a different page (e.g. in the same design), you have to rebuild each item manually every time.
      This module extends the commercial ProModule "RepeaterMatrix" by the function to duplicate repeater items from one page to another page. The condition is that the target field is the same matrix field from which the item is duplicated. This module is currently understood as proof of concept. There are a few limitations that need to be considered. The intention of the module is that this functionality is integrated into the core of RepeaterMatrix and does not require an extra module.
      Check out the screencast
      What the module can do
      Duplicate multible repeater items from one page to another No matter how complex the item is Full support for file and image fields Multilingual support Support of Min and Max settings Live synchronization of clipboard between multiple browser tabs. Copy an item and simply switch the browser tab to the target page and you will immediately see the past button Support of multiple RepeaterMatrix fields on one page Configurable which roles and fields are excluded Configurable dialogs for copy and paste Duplicated items are automatically pasted to the end of the target field and set to hidden status so that changes are not directly published Automatic clipboard update when other items are picked Automatically removes old clipboard data if it is not pasted within 6 hours Delete clipboard itself by clicking the selected item again Benefit: unbelievably fast workflow and content replication What the module can't do
      Before an item can be duplicated in its current version, the source page must be saved. This means that if you make changes to an item and copy this, the old saved state will be duplicated Dynamic loading is currently not possible. Means no AJAX. When pasting, the target page is saved completely No support for nested repeater items. Currently only first level items can be duplicated. Means a repeater field in a repeater field cannot be duplicated. Workaround: simply duplicate the parent item Dynamic reloading and adding of repeater items cannot be registered. Several interfaces and events from the core are missing. The initialization occurs only once after the page load event Attention, please note!
      Nested repeaters cannot be supported technically. Therefore a check is made to prevent this. However, a nested repeater can only be detected if the field name ends for example with "_repeater1234". For example, if your MatrixRepeater field is named like this: "content_repeater" or "content_repeater123", this field is identified as nested and the module does not load. In version 2.0.1 the identification has been changed so that a field ending with the name repeater is only detected as nested if at least a two-digit number sequence follows. But to avoid this problem completely, make sure that your repeater matrix field does NOT end with the name "repeater".
      Changelog
       
      2.0.1
      Bug fix: Thanks to @ngrmm I could discover a bug which causes that the module cannot be loaded if the MatrixRepeater field ends with the name "repeater". The code was adjusted and information about the problem was provided 2.0.0
      Feature: Copy multiple items at once! The fundament for copying multiple items was created by @Autofahrn - THX! Feature: Optionally you can disable the copy and/or paste dialog Bug fix: A fix suggestion when additional and normal repeater fields are present was contributed by @joshua - THX! 1.0.4
      Bug fix: Various bug fixes and improvements in live synchronization Bug fix: Items are no longer inserted when the normal save button is clicked. Only when the past button is explicitly clicked Feature: Support of multiple repeater fields in one page Feature: Support of repeater Min/Max settings Feature: Configurable roles and fields Enhancement: Improved clipboard management Enhancement: Documentation improvement Enhancement: Corrected few typos #1 1.0.3
      Feature: Live synchronization Enhancement: Load the module only in the backend Enhancement: Documentation improvement 1.0.2
      Bug fix: Various bug fixes and improvements in JS functions Enhancement: Documentation improvement Enhancement: Corrected few typos 1.0.1
      Bug fix: Various bug fixes and improvements in the duplication process 1.0.0
      Initial release Support this module
      If this module is useful for you, I am very thankful for your small donation: Donate 5,- Euro (via PayPal – or an amount of your choice. Thank you!)
      Download this module (Version 2.0.1)
      > Github: https://github.com/FlipZoomMedia/InputfieldRepeaterMatrixDuplicate
      > PW module directory: https://modules.processwire.com/modules/inputfield-repeater-matrix-duplicate/
      > Old stable version (1.0.4): https://github.com/FlipZoomMedia/InputfieldRepeaterMatrixDuplicate/releases/tag/1.0.4
    • By picarica
      so i am trying to put CustomHooksForVariations.module, a custom module, i am placing it into site/modules direcotry yet my modules page in admin panel gives me errors
      so this is the screen show when i refresh modules, i dont know why the shole hook is written on top of the page :||

      and this next image is when i try to install it, i saw that it is not defiuned modules.php but it shouldnt need to be ?, any ways i dont want to edit site's core just to make one moulde work there has to be a way

×
×
  • Create New...