Jump to content
Macrura

Settings Factory

Recommended Posts

sf_logo.png.273967076f19a5f3601ac83abc3cef49.png

This is the new topic for the Settings Factory module (formerly known as Settings Train).

Repo:

https://github.com/outflux3/SettingsFactory

I'm not sure what versions this is compatible with, it has only been tested on 3.x branch;
it is not namespaced, and i'm not sure if namespacing is necessary or a benefit for this module; if any namespace or module gurus can weigh in on this, let me know. I'm also not sure if there needs to be a minimum php version;

I have one live site using this now and it's working great; But before submitting to mods directory, would be better if there was some additional testing by other users.

  • Like 11

Share this post


Link to post
Share on other sites

Hi Marc

Much prefer this name - makes more sense. Will test it out (functionality-wise) today.

You don't need to namespace it if you're maintaing compatibility with PW-legacy. I don't namespace my module files, but only everything outside of them. For example, Typographer uses two namespaces: Rockett and Typographer, both of which are imported via the PW class loader. Everything should work fine in legacy, so long as you don't use any features that are only available after 3.0.62 as legacy will probably only be brought up to speed when the next 3.x stable comes out. 

In terms of PHP compatibility, I make it a rule to support only 5.6+, as it is currently the oldest version with security support. With that said, my phpfmt (mentioned below) is configured to use PHP 5.4-style arrays.

Some other recommendations from my side:

  1. Be consistent with spaces/tabs. Tabs are generally frowned upon on the PSR side of things, but it's really up to you, provided it's consistent. I use four spaces for indentation, and I also use phpfmt in Sublime to automatically format my code.
  2. in processForm(), you're pulling in the page title within the walls of a translation helper. As far as I know, this doesn't work, so you'll need to use sprintf to import the page title: sprintf($this->_('Saved: %s'), $this->wire('page')->title)
  3. wire is imported into the Process, so can use $this->wire(…) everywhere that doesn't have a static scope, instead of the wire() helper.

Hope that helps. 😊

  • Like 4

Share this post


Link to post
Share on other sites

Thanks @Mike Rockett!

5 hours ago, Mike Rockett said:

Be consistent with spaces/tabs. Tabs are generally frowned upon on the PSR side of things, but it's really up to you, provided it's consistent. I use four spaces for indentation, and I also use phpfmt in Sublime to automatically format my code.

currently as far as i know/can see in Sublime, the module follows the PW coding guide, so only uses tabs

I fixed all the other items according to your recommendations, commit after testing..

Share this post


Link to post
Share on other sites

You're welcome.

25 minutes ago, Macrura said:

currently as far as i know/can see in Sublime, the module follows the PW coding guide, so only uses tabs

The GH editor is showing me spaces in some places, and so the indentation appears inconsistent. 

I wasn't actually aware of a style guide for PW (I've now seen it). I tend to stick to PSR1 and 2 along with the following configuration:

Spoiler

[
	"AddMissingParentheses",
	"AutoSemicolon",
	"ClassToSelf",
	"DocBlockToComment",
	"DoubleToSingleQuote",
	"EchoToPrint",
	"GeneratePHPDoc",
	"IndentTernaryConditions",
	"MergeElseIf",
	"NewLineBeforeReturn",
	"OrderMethod",
	"OrganizeClass",
	"PrettyPrintDocBlocks",
	"PSR2EmptyFunction",
	"ReindentSwitchBlocks",
	"RemoveSemicolonAfterCurly",
	"RemoveUseLeadingSlash",
	"ReplaceIsNull",
	"ReturnNull",
	"ShortArray",
	"StripNewlineAfterCurlyOpen",
	"StripSpaceWithinControlStructures",
	"WrongConstructorName"
],

 

 

  • Like 2

Share this post


Link to post
Share on other sites

Oh, and just to follow up on the PHP compatibility. It's currently compatible with 5.4+. If the square array notation is changed in both files (three small occurrences in total), then it supports 5.2+.

  • Like 1

Share this post


Link to post
Share on other sites

By strange coincidence, I was just thinking that maybe PW should have a standard EditorConfig file as part of the suite. Whilst it does not address all of the code styling issues raised above, it would allow us to all get the tabs/spaces/line endings/whitespace trimming right for this project by just using an editor that either supports EditorConfig out of the box, or via a plugin. I've started using it on my current project and it seems to work quite well.

  • Like 4

Share this post


Link to post
Share on other sites
26 minutes ago, netcarver said:

By strange coincidence, I was just thinking that maybe PW should have a standard EditorConfig file as part of the suite. Whilst it does not address all of the code styling issues raised above, it would allow us to all get the tabs/spaces/line endings/whitespace trimming right for this project by just using an editor that either supports EditorConfig out of the box, or via a plugin. I've started using it on my current project and it seems to work quite well.

Didn't know there was some sort of universal config like that. Tried it out in Sublime, works well!

Share this post


Link to post
Share on other sites
13 hours ago, Mike Rockett said:

Tabs are generally frowned upon on the PSR side of things

Tabs 4 Life, brah! There is no more definitive authority than Richard Hendricks:

(I've posted that before but could not resist)

But seriously, the PW code style gets things so right. The braces style too. Some reasoned argument:
https://github.com/php-fig-rectified/fig-rectified-standards/blob/master/Reasoning-Tabs-vs-Spaces.md
https://github.com/php-fig-rectified/fig-rectified-standards/blob/master/Reasoning-Brace-Styles.md

 

  • Like 1
  • Haha 2

Share this post


Link to post
Share on other sites

I would have taken an exception in this particular case :)

  • Like 1

Share this post


Link to post
Share on other sites

@Robin S They make some valid arguments, though I'm used to fig. On the flip side, their readmes use spaces for indentation, even in code blocks that state that a tab should be used instead. ;-) Good video though - hadn't seen that before.

Edit: Anyways, let's not hijack the thread - we could always open up a new one to discuss these things. (Sorry, Marc...)

Share this post


Link to post
Share on other sites
8 minutes ago, adrianromega said:

Interesting module, but how are you suppose to access all the defined fields in the front-end ?

I'm working on the github wiki which will include those instructions, but here it is in a nutshell:

Once you have created the process page for the settings, those settings are available using the process name, so if you made a page with the name theme-settings, you would do this:

$factory = $modules->get("SettingsFactory");
$themeSettings = $factory->getSettings('theme-settings');

the settings are delivered as a WireArray (or can be delivered as a plain array getSettingsArray('name-of-process); Here is the bar dump of those settings, using default wireArray;

59e2496382961_My_Great_Site__The_Best_Site_In_the_Universe.jpg.d38e21898e8c5b3ccc15fcf637f38993.jpg

In some scenarios i'm getting the raw array and merging it with some other hardcoded array, like for outputting JSON-LD schema:

Person.schema.php:

<?php namespace ProcessWire;

if(empty($item)) $item = $page;
if(!isset($tag)) $tag = true;

$jsonld = array(
	"@context" 		=> $tag ? "http://schema.org/" : '',
	'@type'			=> 'Person',
	'mainEntityOfPage' => array(
		'@type' => "WebPage",
		'@id'	=> $pages->get(1)->httpUrl,
	)
);

$factory = $modules->get('SettingsFactory');
$personSchema = $factory->getSettingsArray('schema-person');
$jsonld = array_merge($jsonld, $personSchema);

// add image here...
$profileMedia = wire('pages')->get("template=media, media_roles.name=schema-profile, images.count>0");
if($profileMedia->id) {
	$image = $profileMedia->images->first()->width(696);
	$jsonld['image']		= array(
		"@type" => "ImageObject",
		'url'	=> $image->httpUrl,
		'height'=> $image->height,
		'width' => $image->width
	);
}

$jsonld = array_filter($jsonld);
if(!$tag) {
	return $jsonld;
} else {
	if($user->isLoggedin()) {
		$jsonld = json_encode($jsonld, JSON_PRETTY_PRINT);
	} else {
		$jsonld = json_encode($jsonld);
	}
	echo '<script type="application/ld+json">' . $jsonld . '</script>';
}

 

 

  • Like 2

Share this post


Link to post
Share on other sites

Thanks for info, now is all clear.

Using your module you can define all kind of fields, except for InputfieldImage and InputfieldFile.... what is your suggestion to have in "settings"  fields for images or files (for logoes, backgound image, etc) ?

I hope you understand what I mean....

 

Share this post


Link to post
Share on other sites
On 10/23/2017 at 12:02 PM, adrianromega said:

what is your suggestion to have in "settings"  fields for images or files (for logoes, backgound image, etc) ?

Since i typically maintain separate pages for those types of media (in a media library for every site), it is just a matter of setting up page select field. I use selectize so that the user can see what they are selecting. Also if i use a page for logo, then they can update the logo from the media library without having to change the setting; or they can add several logos to the media library and then select which one to use on the settings page.

I don't yet know how to support image/file fields natively in this module, although since the settings pages themselves are pages of template admin, it might be possible. I was actually able to use both image and file fields and upload an image, however there are still errors with the value of the inputfield not yet working...

In other news, here are some new screenshots of settings panels using UiKit theme, including a working example of using  WireTabs:

59f4d949123a1_Theme_Settings__ProcessWire__localhost.thumb.jpg.bfb1461cded2a615e778a50d8bea6833.jpg

59f4d950c8e71_WireTabs_Testing__ProcessWire__localhost.thumb.jpg.13ddd192e24c657e684b2a01e9e95db0.jpg

 

 

 

  • Like 5

Share this post


Link to post
Share on other sites

thanks for your reply.

I have tried also the new version with support for InputfieldWrapper.

Based on your example, wiretabs-example.php, I have tried to use 2 InputfieldFieldsets inside first wiretab (InputfieldWrapper inside InputfieldWrapper), the display of fields is fine, but it is not saving values of fields properly...depends on the position of the nested InputfieldWrappers, some values are saved, some are not. With only one InputfieldWrapper inside another InputfieldWrapper, all is fine, but with more nested InputfieldWrappers, something is wrong.

for the config below for example, is not saving the field values form the first InputfieldFieldset.

 

<?php

/**
 * since you can only return 1 array to the module, you have to wrap 
 * the tabs in an inputfield wrapper
 */
$inputfields = new InputfieldWrapper();

//---------------------------------------------------
$general = [
    [
        'name' => 'site_name',
        'label' => __('Site Name'),
        'type' => 'InputfieldText',
        'value' => ''
    ],
    [
        'name' => 'email_address',
        'label' => __('E-mail'),
        'type' => 'InputfieldEmail',
        'value' => ''
    ],
    [
        'name' => 'telephone',
        'label' => __('Telephone'),
        'type' => 'InputfieldText',
        'value' => ''
    ],
    [
        'name' => 'fax',
        'label' => __('Fax'),
        'type' => 'InputfieldText',
        'value' => ''
    ],
];



$general2 = [
    [
        'name' => 'set_1',
        'label' => __('Setting 1'),
        'type' => 'InputfieldText',
        'value' => ''
    ],
    [
        'name' => 'set_2',
        'label' => __('Setting 2'),
        'type' => 'InputfieldText',
        'value' => ''
    ]
];

$general3 = [
    [
        'name' => 'set_3',
        'label' => __('Setting 3'),
        'type' => 'InputfieldText',
        'value' => ''
    ],
    [
        'name' => 'set_4',
        'label' => __('Setting 4'),
        'type' => 'InputfieldText',
        'value' => ''
    ] 
];



$tab = new InputfieldWrapper();
$tab->attr('title', 'General');
$tab->attr('class', 'WireTab');




$advanced = new InputfieldFieldset();
$advanced->label = __('Advanced Settings');
$advanced->description = __('These settings are not required');
$advanced->columnWidth = 50;
$advanced->add($general2);
$tab->add($advanced);



$advanced = new InputfieldFieldset();
$advanced->label = __('Advanced Settings');
$advanced->description = __('These settings are not required');
$advanced->columnWidth = 50;
$advanced->add($general3);
$tab->add($advanced);



$tab->add($general);

$inputfields->append($tab);

//---------------------------------------------------
$location = [
    [
        'name' => 'address',
        'label' => __('Address'),
        'type' => 'InputfieldText',
        'required' => true,
        'value' => ''
    ],
    [
        'name' => 'postal_code',
        'label' => __('Postal code'),
        'type' => 'InputfieldText',
        'required' => true,
        'value' => '',
        'columnWidth' => 33
    ],
    [
        'name' => 'city',
        'label' => __('City'),
        'type' => 'InputfieldText',
        'required' => true,
        'value' => '',
        'columnWidth' => 67
    ],
];

$tab = new InputfieldWrapper();
$tab->attr('title', 'Location');
$tab->attr('class', 'WireTab');
$tab->add($location);
$inputfields->append($tab);

//---------------------------------------------------


return $inputfields;

 

  • Like 1

Share this post


Link to post
Share on other sites

ok i think i have fixed this, and improved the extraction process for the inputfields. Can you try the latest version?

Share this post


Link to post
Share on other sites

@adrianromega - thanks for taking it for a test drive, and identifying that problem!

I ended up rewriting the method that extracts the inputfields and now it should work a lot better thanks to your testing of that scenario.

 

Share this post


Link to post
Share on other sites

@Macrura Great module. Thank you for your work. Just curious is there some limitation of input field types? 

Share this post


Link to post
Share on other sites
1 hour ago, Zeka said:

Great module. Thank you for your work. Just curious is there some limitation of input field types? 

It is probably limited to the types of fields you can use generally in module configs, and currently there is no way to handle custom processing of form data, it uses the default $form->process() function from the core; If there are any specific fields you want to test let me know and i'll give them a go; The obvious ones that won't work are files and images, as well as any profileds like tables, repeaters and stuff like that;

Share this post


Link to post
Share on other sites

Actually I was thinking about Profields ( tables, multiplier). So there are no repeatable field types that we can use with the module. 

Share this post


Link to post
Share on other sites
3 hours ago, Zeka said:

So there are no repeatable field types that we can use with the module. 

Yeah, i haven't found any way to do repeatable content yet, but it could be possible to roll your own multiplier field using text inputs and some javascript. If i get around to that i will post how it is done..

Share this post


Link to post
Share on other sites

the input form is all native PW; so you just supply your array of field definitions using the correct keys for that inputfield type;

no graphical ui would be possible, but there is a kitchen sink file where you just grab the type of inputfield you want, paste it in to your fields array, change the settings and bob's your uncle.

  • Like 2

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 hellerdruck
      Hi all
      I need to export all the texts from a website to a translation company (as json or csv or txt...). How can this be done? Of course manually, but this website is huge and it would take me years...
      Also, as a second step, importing the translation ...
      Any ideas anyone? Tutorials? Plugins?
      Thanks for your help.
    • By jonatan
      So... I thought (for some stupid reason I can't even recall now no wait now I remember.. I wanted to hide the "Trash" for "editor" role users) that it'd be super duper smart to "Enable access control" for the field "process" on the admin template.... Really really stupid.... Now all I get is:

       
       
       
      – when I go to mywebsitedomain.com/admin
      but.... my website domain.com and all its subpages works perfectly fine! So it's ONLY the /admin (processwire) which throws a 503 at me. 
      🥵🤯☠️💩😭😱
      S.O.S.
    • By Ivan Gretsky
      Most of us know and use site/config-dev.php file. If present, it is used instead of site/config.php, so it is easy to set database connection and debug mode for local development, not touching the production config. It is also very useful when working with git. You can simply ignore it in the .gitignore file, so local settings won’t end up in the repo.
      But sometimes you need to add code to site/ready.php or site/init.php just for the dev environment. For example, to add ryan’s super cool on demand images mirrorer. I can’t live without it when working with big sites, which have more assets then I want to download to my desktop.
      It would be great if there was something like site/ready-dev.php for this. Not out-of-the-box, but it’s pretty easy to achieve. Unlike site/config-dev.php, site/ready.php is not hardcoded. It’s name is set with a special config setting:
      // wire/config.php $config->statusFiles = array( 'boot' => '', 'initBefore' => '', 'init' => 'init.php', 'readyBefore' => '', 'ready' => 'ready.php', 'readySite' => '', 'readyAdmin' => '', 'render' => '', 'download' => '', 'finished' => 'finished.php', 'failed' => '', ); As you can see, we can not only define, which files are loaded on init, ready and finished runtime states, but probably even add more if we need to.
      So we override this setting in site/config-dev.php like this:
      // site/config-dev.php // Change ready.php to ready-dev.php $temp = $config->statusFiles; $temp['ready'] = 'ready-dev.php'; $config->statusFiles = $temp; For some reason we can’t just do
      $config->statusFiles['ready'] = 'ready-dev.php'; and have to override the whole array. Maybe you PHP gurus can explain this in the comments.
      Now we can create the site/ready-dev.php file and place all the dev-only code there. Important thing is to include the main site/ready.php.
      // site/ready-dev.php include 'ready.php'; // DEV HOOK TO MIRROR ASSETS ON DEMAND $wire->addHookAfter('Pagefile::url, Pagefile::filename', function($event) { $config = $event->wire('config'); $file = $event->return; if($event->method == 'url') { // convert url to disk path $file = $config->paths->root . substr($file, strlen($config->urls->root)); } if(!file_exists($file)) { // download file from source if it doesn't exist here $src = 'https://mysite.com/site/assets/files/'; $url = str_replace($config->paths->files, $src, $file); $http = new WireHttp(); try { $http->download($url, $file); } catch (\Exception $e) { bd($file, "Missing file"); } } }); Do not forget to replace "mysite.com" if you’re copypasting this))
      Now, add the newly created file to the `.gitignore` and we’re done.
       
      # .gitignore # Ignore dev files site/config-dev.php site/ready-dev.php Thanks for reading!
       
    • By MoritzLost
      Sorry for the convoluted title. I have a problem with Process modules that define a custom page using the page key through getModuleInfo (as demonstrated in this excellent tutorial by @bernhard). Those pages are created automatically when the module is installed. The problem is that the title of the page only gets set in the current language. That's not a problem if the current language (language of the superuser who is installing the module) is the default language; if it isn't, the Process page is missing a title in the default language. This has the very awkward effect that a user using the backend in the default language (or any other language) will see an empty entry in the setup menu:

      This screenshot comes from my Cache Control module which includes a Process page. Now I realize the description sounds obscure, but for us it's a common setup: We a multiple bilingual sites where the default language is German and the second language is English. While the clients use the CMS in German, as a developer I prefer the English interface, so whenever I install a Process module I get this problem.
      As a module author, is there a way to handle this situation? I guess it would be possible to use post-installation hooks or create the pages manually, but I very much prefer the declarative approach. The page title is already translatable (through the __ function), but of course at the time of installation there is no translation, and as far as I'm aware it's not possible to ship translations with a module so they are used automatically. Could this situation be handled better in the core? I would prefer if the module installation process would always set the title of the Process page in the default language, instead of the language of the current user.
    • By MoritzLost
      Process Cache Control
      This module provides a simple solution to clearing all your cache layers at once, and an extensible interface to perform various cache-related actions.
      The simple motivation behind this module was that I was tired of manually clearing caches in several places after deploying a change on a live site. The basic purpose of this module is a simple Clear all caches link in the Setup menu which clears out all caches, no matter where they hide. You can customize what exactly the module does through it's configuration menu:
      Expire or delete all cache entries in the database, or selectively clear caches by namespace ($cache API) Clear the the template render cache. Clear out specific folders inside your site's cache directory (/site/assets/cache) Clear the ProCache page render cache (if your site is using ProCache) Refresh version strings for static assets to bust client-side browser caches (this requires some setup, see the full documentation for details). This is the basic function of the module. However, you can also add different cache management action through the API and execute them through the module's interface. For this advanced usage, the module provides:
      An interface to see all available cache actions and execute them. A system log and logging output on the module page to see verify what the module is doing. A CacheControlTools class with utility functions to clear out different caches. An API to add cache actions, execute them programmatically and even modify the default action. Permission management, allowing you granular control over which user roles can execute which actions. The complete documentation can be found in the module's README.
      Plans for improvements
      If there is some interest in this, I plan to expand this to a more general cache management solution. I particular, I would like to add additional cache actions. Some ideas that came to mind:
      Warming up the template render cache for publicly accessible pages. Removing all active user sessions. Let me know if you have more suggestions!
      Links
      https://github.com/MoritzLost/ProcessCacheControl ProcessCacheControl in the Module directory CHANGELOG in the repository Screenshots


×
×
  • Create New...