Jump to content

Settings Train (module preview)... all aboard!


Macrura

Recommended Posts

MODULE PREVIEW

This is a new module I'm working on, Settings Train.

Ever needed to setup one or more pages for site settings, need a lot of fields/settings and an easy way to access them in the front end. This module may be of use to you. You can of course either make an editor page using standard fields for settings, but the goal of this module is to allow files within the template folder to define their own 'dependencies' for settings.

Description: this module allows you to create an unlimited number of admin/process pages, and on any process page you can enter the path to a json file that defines the fields to use for the process page.

1.)

59e246bf98823_Edit_Page__News_Settings__localhost.jpg.c37e81cc8aaf9e611c3d0f875dadf96b.jpg

Contents of kitchen-sink.json

[

   {
      "name":"text1",
      "label":"Text Field 1",
      "type":"InputfieldText",
      "width":"100",
      "description":"",
      "collapsed":0,
      "placeholder":"",
      "value":"",
      "columnWidth":50
   },
   {
      "name":"text2",
      "label":"Text Field 2",
      "type":"InputfieldText",
      "width":"100",
      "description":"",
      "collapsed":2,
      "placeholder":"",
      "value":"",
      "columnWidth":50
   },
   {
      "name":"select1",
      "label":"Select Test",
      "type":"InputfieldSelect",
      "width":"100",
      "description":"Description of select 1",
      "options": {
         "default":"Default",
         "blue":"Blue",
         "red":"Red",
         "yellow":"Yellow",
         "dark":"Dark"
      },
      "collapsed":0,
      "placeholder":"",
      "value":"",
      "columnWidth":33
   },
   {
      "name":"checkbox1",
      "label":"Checkbox Test",
      "type":"InputfieldCheckbox",
      "width":"50",
      "description":"Checkbox 1 description",
      "collapsed":0,
      "placeholder":"",
      "value":1,
      "columnWidth":34
   },
   {
      "name":"radios1",
      "label":"Radios Test",
      "type":"InputfieldRadios",
      "width":"50",
      "description":"",
      "options":{
         "black":"Black",
         "white":"White"
      },
      "collapsed":0,
      "placeholder":"",
      "value":"black",
      "columnWidth":33
   },
   {
      "name":"checkboxes1",
      "label":"Checkboxes Test 1",
      "type":"InputfieldCheckboxes",
      "width":"50",
      "description":"Checkboxes 1 Description",
      "options":{
         "address":"Address",
         "phone":"Phone",
         "social":"Social Icons",
         "top_menu":"Top Menu"
      },
      "collapsed":0,
      "placeholder":"",
      "value":"",
      "columnWidth":50
   },
   {
      "name":"checboxes2",
      "label":"Checkboxes Test 1",
      "type":"InputfieldCheckboxes",
      "width":"50",
      "description":"Checkboxes 2 Description",
      "options":{
         "address":"Address",
         "phone":"Phone",
         "social":"Social Icons",
         "top_menu":"Top Menu"
      },
      "collapsed":0,
      "placeholder":"",
      "value":"",
      "columnWidth":50
   },
   {
      "name":"textarea1",
      "label":"Textarea Test",
      "type":"InputfieldTextarea",
      "width":"100",
      "description":"Textarea 1 Description",
      "collapsed":2,
      "value":""
   },
   {
      "name":"pagelistselect1",
      "label":"Page List Select Test",
      "type":"InputfieldPageListSelect",
      "width":"100",
      "description":"Page List Select Test Description",
      "collapsed":0,
      "value":"0",
      "columnWidth":50
   },
   {
      "name":"asm_select1",
      "label":"ASM Select Test",
      "type":"InputfieldAsmSelect",
      "width":"100",
      "description":"ASM Select (templates) - select a template.",
      "options":{
         "43":"Image",
         "59":"Options",
         "61":"Post (post)",
         "62":"Post Index (post-index)"
      },
      "collapsed":0,
      "value":"",
      "columnWidth":50
   },
   {
      "name":"url_test",
      "label":"URL Test",
      "type":"InputfieldURL",
      "width":"100",
      "description":"Enter a URL",
      "noRelative":1,
      "collapsed":0,
      "value":"",
      "columnWidth":33
   },
   {
      "name":"integer_test",
      "label":"Integer Test",
      "type":"InputfieldInteger",
      "width":"100",
      "description":"Enter an Integer",
      "collapsed":0,
      "value":"",
      "columnWidth":34
   },
   {
      "name":"email_test",
      "label":"Email Test",
      "type":"InputfieldEmail",
      "width":"100",
      "description":"Enter an Email Address",
      "collapsed":0,
      "value":"",
      "columnWidth":33
   },
   {
      "name":"ckeditor_test",
      "label":"CK Editor Test",
      "type":"InputfieldCKEditor",
      "width":"100",
      "description":"Some Formatted Text",
      "collapsed":0,
      "value":""
   }
]

The json file can be anywhere (currently limited to the templates folder). For example, if you have a theme folder and that theme requires specific preferences to be set for that theme, you can have the settings page load the fields needed by that theme.

Process Page in Menu:

59e24872f327b_Pages__ProcessWire__localhost.jpg.1eee214e41d176c8d0ed42db6dd6ec1a.jpg

Process Page (editing the settings):

59e24901d5fec_News_Settings__ProcessWire__localhost.thumb.jpg.77ae466221694213430ff6c4fe47728a.jpg

59e249121d2a2_News_Settings__ProcessWire__localhost.jpg.6ae5851bb9867fe96ab847bc78566217.jpg

Then you can access those settings in your front end like this:

$train = $modules->get("SettingsTrain");
$themeSettings = $train->getSettings('news-settings');

the settings are delivered as a WireArray:

59e2496382961_My_Great_Site__The_Best_Site_In_the_Universe.jpg.d38e21898e8c5b3ccc15fcf637f38993.jpg

so you can now do this:

echo $newSettings->url_test; which outputs http://processwire.com

_main_php.jpg.4fab27ea643882ddb11f0f3b753e504e.jpg

For rapid site development, this can save you from having to manually setup fields for new projects settings, especially if you use those same settings a lot.

  • Like 19
Link to comment
Share on other sites

Really cool :lol:. I can see myself using this a lot.

One simple request, can you add support for using regular PHP files for configuration?
https://github.com/mrkrstphr/array-config

Manually typing JSON for building inputs array would get tedious really quick. I'd rather use a PHP file because:

  • I can add logic to my configuration files (and even include other files). This eliminates having to write some parts over and over. I can just write a function to create a text field and use that.
  • I can use my IDE and its tools, autocomplete, intellisense etc
  • Like 4
Link to comment
Share on other sites

4 minutes ago, abdus said:

I can add logic to my configuration files

Agreed! While I love the idea of this module and especially the easy setup of option type fields (checkbox, ASM, etc) without needing to point to somewhere for the source of the options, I would like to be able to define the options via PHP when I want. Maybe the approach I have taken in AdminActions might work ok here as well, eg:

        $fieldOptions = array();
        foreach($this->wire('fields') as $field) {
            if ($field->flags & Field::flagSystem || $field->flags & Field::flagPermanent) continue;
            if(count($field->getFieldgroups()) === 0) $fieldOptions[$field->id] = $field->label ? $field->label . ' (' . $field->name . ')' : $field->name;
        }

        return array(
            array(
                'name' => 'fields',
                'label' => 'Fields',
                'description' => 'Select the fields you want to delete',
                'notes' => 'Note that all fields listed are not used by any templates and should therefore be safe to delete',
                'type' => 'checkboxes',
                'options' => $fieldOptions,
                'required' => true
            )
        );

 

  • Like 2
Link to comment
Share on other sites

18 minutes ago, Zeka said:

What about image field? Is there support for this type of field? 

I haven't tried it with image input, but you are able to use InputfieldImage and InputfieldFile in isolation. I'm using it with one of my modules like this:

[
    'type'            => 'file',
    'name'            => 'recipientListFile',
    'id'              => 'recipientListFile',
    'label'           => $this->_('Recipient Emails File'),
    'description'     => $this->_('The file must contain one record per line'),
    'notes'           => $this->_('First column in CSV files is assumed to be email addresses'),
    'maxFiles'        => 1,
    'extensions'      => 'csv txt',
    'noAjax'          => true,
    'uploadOnlyMode'  => true,
    'destinationPath' => $temp->get(),
    'attr'            => [
        'required' => true,
    ],
    // 'uploadOnlyMode'  => true,
    'overwrite'       => true,
    'icon'            => 'file-text-o',
],

Then save the file using

$temp = $this->files->tempDir($this->className);
$recipientList = (new WireUpload('recipientListFile'))
    ->setDestinationPath($temp->get())
    ->setValidExtensions(['csv', 'txt'])
    ->execute();

As InputfieldImage extends InputfieldFile, it should be quite similar.

  • Like 1
Link to comment
Share on other sites

56 minutes ago, abdus said:

One simple request, can you add support for using regular PHP files for configuration?
https://github.com/mrkrstphr/array-config

Manually typing JSON for building inputs array would get tedious really quick. I'd rather use a PHP file because:

  • I can add logic to my configuration files (and even include other files). This eliminates having to write some parts over and over. I can just write a function to create a text field and use that.
  • I can use my IDE and its tools, autocomplete, intellisense etc

should be really easy, you'd just need create a php file that returns an array of inputfields;  DO you think i should try and integrate that array-config, or just allow the php file to return an array, like in Adrian's example?

right now i just feed the array converted from json right into the form; the values are almost all automatically read from the module config except for checkbox that takes some special handling..
 

        // ------------------------------------------------------------------------
        // USER DEFINED FIELDS
        // ------------------------------------------------------------------------
        if(wire('page')->st_filepath) {
            $path = wire('config')->paths->templates .  wire('page')->st_filepath;
            $settingsKey = $this->wire('page')->name;
            $modData = $this->modules->getConfig('SettingsTrain');
            $thisData = isset($modData[$settingsKey]) ? $modData[$settingsKey] : null;
            if(file_exists($path)) {
                $json = file_get_contents($path);
                $fArray = json_decode($json, true);
                // update values
                foreach($fArray as $key => $cField) {
                    $name = $cField['name'];
                    $cField['value'] = $thisData ? $thisData[$name] : ''; // or get default value in json file?

                    if($cField['type'] == 'InputfieldCheckbox' && $cField['value'] == 1) {
                        $cField['checked'] = 'checked';
                    }

                    $fArray[$key] = $cField;
                }
                $form->add($fArray);
            }
        }

 

i started building it on Thursday night, and have probably like 7 hrs on it, mostly figuring out the logic of the process pages each saving their unique data to the main module that extends wiredata...

this also might need someone else to have a look at; i do have it working fine, but there could most likely be some places where the code could be tightened up.

55 minutes ago, adrian said:

Agreed! While I love the idea of this module and especially the easy setup of option type fields (checkbox, ASM, etc) without needing to point to somewhere for the source of the options, I would like to be able to define the options via PHP when I want. Maybe the approach I have taken in AdminActions might work ok here as well, eg:

yeah, i was wondering how that was going to work with this; for some people they may want to use the json system, but it should also support php; So in your example if the file ending is php, then the process module would do this:

$fArray = wireRenderFile($path);

instead of this:

$json = file_get_contents($path);
$fArray = json_decode($json, true);
52 minutes ago, tpr said:

Sounds awesome, thanks! How about changing the name to Settings Factory? Train doesn't sound proper to me.

ok possibly, yeah i couldn't come up with anything and needed to start building it with some name... the FA train icon does look cool though! How about a vote on what to call it?... Settings Factory could be a good option...

49 minutes ago, Zeka said:

What about image field? Is there support for this type of field? 

I do understand that this is a downside of using a process module for this; so usually i setup a media type page with 1 image and then i let the users upload the images to their media library; then i let them choose the page (image) from this module, somethings using Selectize, or just a plain page select.. not ideal; once i have the code on github, anyone is certainly welcome to insert some code into the logic somewhere to allow images to work, would be cool..

  • Like 1
Link to comment
Share on other sites

14 minutes ago, Macrura said:

DO you think i should try and integrate that array-config

There's nothing to integrate, array-config is a joke repository :), it's just there to show that you can you can return variables from files and use them with include statement, instead of dealing with parsing, validation of JSON/YAML etc.

I want the same thing with @adrian, which is essentially how getModuleConfigArray() method of ConfigurableModule interface works.

public function getModuleConfigArray() {
    return [
        'colors' => [
            'type' => 'radios',
            'label' => $this->_('Color Set'),
            'options' => [
                'classic' => $this->_('Classic'),
                'warm' => $this->_('Warm'),
                'modern' => $this->_('Modern'),
                'futura' => $this->_('Futura')
            ],
            'value' => 'classic',
            'optionColumns' => 1
        ]
    ];
}
15 minutes ago, Macrura said:

So in your example if the file ending is php, then the process module would do this:


$fArray = wireRenderFile($path);

Exactly.

Also, I agree with @tpr and @szabesz on the naming. While fa-train looks really smooth, fa-industry or fa-wrench isn't too bad either.

We really should switch to Material Icons, though. There's an icon for everything, and every icon is crafted with top notch attention to detail. FA looks quite rough in comparison. Small list of Font Awesome icons can be replaced with their Material counterparts, or both can be combined

  • Like 6
Link to comment
Share on other sites

OK, php defined settings are working:

1) process page config:

59e26f5ccd806_Edit_Page__PHP_Defined_Settings_Test__localhost.jpg.a8cc5aea9067c4739d1412c1f689f5fc.jpg

2) contents of example.php

<?php namespace ProcessWire;


$fieldOptions = array();
foreach(wire('fields') as $field) {
    if ($field->flags & Field::flagSystem || $field->flags & Field::flagPermanent) continue;
    if(count($field->getFieldgroups()) === 0) $fieldOptions[$field->id] = $field->label ? $field->label . ' (' . $field->name . ')' : $field->name;
}


return [
    'colors' => [
        'name'  => 'radiostest2',
        'type' => 'radios',
        'label' => $this->_('Color Set'),
        'options' => [
            'classic' => $this->_('Classic'),
            'warm' => $this->_('Warm'),
            'modern' => $this->_('Modern'),
            'futura' => $this->_('Futura')
        ],
        'value' => 'classic',
        'optionColumns' => 1
    ],
    [
        'name' => 'fields',
        'label' => 'Fields',
        'description' => 'Select the fields you want to delete',
        'notes' => 'Note that all fields listed are not used by any templates and should therefore be safe to delete',
        'type' => 'checkboxes',
        'options' => $fieldOptions,
        'required' => true
    ]
];

3) result:

59e27080ab9d7_PHP_Defined_Settings_Test__ProcessWire__localhost.thumb.jpg.0f11236eb21ef08dedc5e3800590b48f.jpg

  • Like 3
  • Thanks 1
Link to comment
Share on other sites

i'm not a fan of the fa-industry icon, any other ideas for icons?

wrench is kind of over used... might just keep the train icon, even if the name changes to Settings Factory, but still Settings Train is more catchy...

Link to comment
Share on other sites

41 minutes ago, adrian said:

Wow - I totally agree - they are beautiful. Lots of the FA ones really are pretty poor.

Do you think FA version 5 is an improvement? I have noticed that i like the V5 icons a lot better (using them in the admin via the FontAwesomePro module) a lot more icons also

Link to comment
Share on other sites

52 minutes ago, abdus said:

We really should switch to Material Icons, though.

If you mean PW in general, then...

Add Material Icons: yes
Replace FA with Material icons: no

While that long list of Material Icons looks nice at first (and I use them often) there is a heap of essential things missing. A couple of random examples: Facebook, external link.

  • Like 4
Link to comment
Share on other sites

I ended up going with Settings Factory, since it may just make more sense in the long run. The module is really more of a facilitator to the display of inputfields related to settings, and their subsequent storage and retrieval, so not sure there is any good metaphor that could be used...

  • Like 3
Link to comment
Share on other sites

Cool looking module. I have a question based on my take on PW philosophy. Also, I just had to do some work on a WP site and it took me forever to find some content as it was buried in the Theme admin not WP admin.  So, my question is: Is it a good idea to put client editable content outside of the PW database? Now, I and anyone else who is unfortunate enough to have to work on a PW site I create, must know that there is some data in the DB and some in some JSON or PHP files in the template folder... Plus, it does not get backed up with the rest of the data... 

This is just a question. I go through the process of creating a Settings Page every site, so I do love the idea of something that makes it easier.

Keep up the great work!

Link to comment
Share on other sites

The module evolved from a couple of separate ideas/needs and other modules;

First there was the General Settings module, which I used on a few sites and worked well. But that has some problems/caveats/gotchas:
1) by default it uses a $settings global variable that overwrites the Lister Pro settings global $settings;
2) it has limited support for inputfield types (thus why my forked version added support for more field types, collapsed status etc.);
3) you could only have 1 settings page with that module
4) you had to use the module's interface for setting up the fields.

So the overall the idea of defining settings fields with json and storing the data inside the module config was inspired by PGS (process general settings).

2 hours ago, artaylor said:

So, my question is: Is it a good idea to put client editable content outside of the PW database?

The settings values are stored in the database, in the module config of the main (non process) module.

2 hours ago, artaylor said:

must know that there is some data in the DB and some in some JSON or PHP files in the template folder

No, no data is stored in the template folder; only the field definitions; this is a feature, not a caveat/limitation.

Settings Factory itself is part Warehouse, part Factory, and part Delivery Service..

Factory in that it takes raw materials (the json and php files you have created) and turns those into process pages where you use those inputfields...
Warehouse in that it stores those settings values for you, each in it's own array named after your process page.
Delivery Service in that is facilitates the retrieval of those settings as a WIreArray or Plain Array (depending on your needs) to the templates;

One recent use case of this module is for defining Schema.org values for various Schema types;  In this use case, all of the fields are defined in the json field definition file, and then the process module displays the input fields; the Schema rendering function/file reads the SettingsFactory data array straight into the schema (json-ld) since the keys are matching the Schema.org properties; So if you are doing a company site, you can give them a few pages of schema fields to fill out and then create your json-ld from those various arrays..

I think the use case for this module is pretty clear, and really comes down to 1 field, 1 value config settings, or definitions of things like Schema properties; as opposed to real fields that can contain values for that field on multiple pages.

 

  • Like 1
Link to comment
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.
×
×
  • Create New...