Jump to content

Robin S

  • Content Count

  • Joined

  • Last visited

  • Days Won


Posts posted by Robin S

  1. Hi @adrian,

    Is it possible to switch into a user with the guest role only using the User Switcher panel? I didn't see the default guest user available there so I created a new user with only the guest role but it doesn't appear either.

    Or do you know of another way to get the debug bar to appear on a remote site when not logged in? (of course you would never to this on a live site - my site isn't publicly accessible)

  2. 5 hours ago, snck said:

    After updating this installation to 3.0.148

    What version did you update from? I think it hasn't been possible to set access controls on fieldsets for some time, maybe years.

    I think there might be a couple of reasons for why you can't set access controls on fieldsets:

    1. Edit access (in Page Edit) for a fieldset is meaningless because a fieldset doesn't store any user-editable data.

    2. Generally speaking fields do not "know" that they belong to a fieldset. You can run your own logic like this...

    ...but there is no simple property of a field A that indicates that it is within fieldset B. So setting view/edit access on a fieldset doesn't actually set view/edit access for fields within that fieldset. Back when it was possible to set access controls on a fieldset it might have appeared that there was access control in that maybe the inputfields didn't get rendered, but I doubt that this was proper access control/security on the fields within the fieldset. So my guess is that Ryan removed that option so devs wouldn't get the wrong impression that they are setting access control on fields by setting it on a parent fieldset.

    So I think your options are...

    1. Set access control on the fields within your fieldset.

    2. So long as you know and are comfortable with the fact that it isn't proper access control, you could remove the fieldset using a hook:

    $wire->addHookAfter('ProcessPageEdit::buildFormContent', function (HookEvent $event) {
    	/* @var InputfieldWrapper $wrapper */
    	$wrapper = $event->return;
    	// Do some test based on roles
    	if($event->wire('user')->hasRole('some_role')) {
    		// Remove fieldset
    		$fs = $wrapper->getChildByName('your_fieldset_name');


    • Like 1

  3. 5 hours ago, Pixrael said:

    But if you check that js code, in the "ui.createComponent" there is an element ID that corresponds to the product ID in Shopify

    Do you know if there's a way to query some Shopify API to get all the IDs and titles of products that exist in the Shopify store? So that a client only needs to maintain products in Shopify but the PW site could run a cron job where every day it gets all the product IDs and titles and automatically creates pages for them?

    • Like 2

  4. 1 hour ago, bernhard said:

    Every Inputfield consists of this markup:

    <li class="Inputfield">
      <label class="InputfieldHeader"></label>
      <div class="InputfieldContent ..."></div>

    This markup actually belongs to InputfieldWrapper rather than individual inputfield renders.

    There is the InputfieldWrapper::setMarkup method that you can use to customise the markup that is rendered by InputfieldWrapper. See the defaultMarkup property as a starting point for what can be customised:

     * Markup used during the render() method - customize with InputfieldWrapper::setMarkup($array)
    static protected $defaultMarkup = array(
    	'list' => "<ul {attrs}>{out}</ul>",
    	'item' => "<li {attrs}>{out}</li>", 
    	'item_label' => "<label class='InputfieldHeader ui-widget-header{class}' for='{for}'>{out}</label>",
    	'item_label_hidden' => "<label class='InputfieldHeader InputfieldHeaderHidden ui-widget-header{class}'><span>{out}</span></label>",
    	'item_content' => "<div class='InputfieldContent ui-widget-content{class}'>{out}</div>", 
    	'item_error' => "<p class='InputfieldError ui-state-error'><i class='fa fa-fw fa-flash'></i><span>{out}</span></p>",
    	'item_description' => "<p class='description'>{out}</p>", 
    	'item_head' => "<h2>{out}</h2>", 
    	'item_notes' => "<p class='notes'>{out}</p>",
    	'item_detail' => "<p class='detail'>{out}</p>", 
    	'item_icon' => "<i class='fa fa-fw fa-{name}'></i> ",
    	'item_toggle' => "<i class='toggle-icon fa fa-fw fa-angle-down' data-to='fa-angle-down fa-angle-right'></i>", 
    	// ALSO: 
    	// InputfieldAnything => array( any of the properties above to override on a per-Inputifeld basis)

    But this applies to the whole InputfieldWrapper. In terms of making it more targeted you can set markup for individual inputfield types by using the inputfield class name as a key:

    	'InputfieldText' => [
    		'item' => '<li {attrs}><p>Markup before</p>{out}<p>Markup after</p></li>',

    But you can't target individual inputfields by name or something like that.

    LoginRegisterPro has a similar setMarkup() method but has the added feature of letting you use "name=some_inputfield_name" as a key: https://processwire.com/store/login-register-pro/docs/#customizing-markup-and-or-class-attributes-html

    It would be cool if a feature like that was added to the core InputfieldWrapper::setMarkup method.

    • Like 3
    • Thanks 1

  5. I can see why it's awkward for your use case, but the getMarkup() and getText() methods are working as per their documentation as I understand it.

    The argument can be one of two things: "field name" or "markup string with field {name} tags in it". The method has to distinguish between those two possibilities and it does that by looking for the presence of "{" and "}" - if those characters are not found it treats the string as a field name.

    Basically you're requesting a new feature which is a third possible argument to these methods, namely a string that isn't a field name and doesn't have {name} tags in it. I'm sure Ryan would consider that if you raise it in the requests repo, but given how many existing requests there are you'll probably want to come up with a workaround in the meantime.

    You could do this...

    echo $page->getMarkup($modules->get('MyModule')->MyTextFormatSetting) ?: $modules->get('MyModule')->MyTextFormatSetting;
    echo $page->getText($modules->get('MyModule')->MyTextFormatSetting) ?: $modules->get('MyModule')->MyTextFormatSetting;

    ...or in the case of getMarkup() the method is hookable so you could do this...

    $wire->addHookAfter("Page::getMarkup", function(HookEvent $event) {
    	$key = $event->arguments(0);
    	if(!$event->return) $event->return = $key;


    • Like 3

  6. 1 hour ago, Tyssen said:

    I'd like to change it so that each member group has its own images field and each field has the upload limit set to the limit for that group.

    I suggest setting the maxFiles setting of the inputfield dynamically with a hook.

    There are many different methods you could potentially hook - I don't know if you're talking about Page Edit, ProcessProfile, ProcessUser, or some form on the front-end, and I don't know if by "group" you mean "role". But here is something that you can adapt to suit:

    $wire->addHookBefore("InputfieldImage::render", function(HookEvent $event) {
    	/* @var InputfieldImage $inputfield */
    	$inputfield = $event->object;
    	$field = $inputfield->hasField;
    	if(!$field || $field->name !== 'images') return;
    	$user = $event->wire('user');
    	if($user->hasRole('foo')) {
    		$inputfield->maxFiles = 1;
    		$inputfield->description = 'You may upload a maximum of 1 image.';
    	} elseif($user->hasRole('bar')) {
    		$inputfield->maxFiles = 2;
    		$inputfield->description = 'You may upload a maximum of 2 images.';
    	} else {
    		$inputfield->maxFiles = 0; // No limit


    • Like 2

  7. @maddmac, I tested here inside a repeater and it's working correctly.

    You might need to clear cached files from your browser to get the updated CKEditor plugins that are included in the module. As far as I know plugins don't get automatic cache busting in CKEditor and I don't know any way to do this manually due to the way external plugins are loaded.

    If you do a hard refresh in Page Edit it should fix things.

    • Like 1

  8. 8 hours ago, ryan said:

    But it sounds like you've had use cases for it which means others likely have too, and that's plenty good reason for me. I'll go ahead and add getID() it as an alias of has().


    I use findIDs() when I'm using the PW API in conjunction with SQL queries where I only need the page IDs in the query. Sometimes I only need a single page ID and so having a getID() makes that simpler and corresponds to the find() and get() methods. 

    • Like 3

  9. 1 hour ago, Macrura said:

    i know of some other devs that do use it on live sites so i think it's still risky to autoload scripts or styles on a module without just loading the assets where you need them

    The thing is, it's a risk that's carried by the site developer rather than the module developer. If an autoload module adds scripts and styles to $config->scripts and $config->styles it's your site that's at risk of breaking, not the module. Personally I'd never want to take that risk.

    The simple solution is to create your own custom FilenameArray in $config that is reserved for front-end usage. This old post from @Soma explains how:


    • Like 1

  10. 12 hours ago, LMD said:

    I have a wishlist suggestion - as well as the fixed ratios, would it be feasible/possible to also include a minimum size for the crop area?

    As far as I can see this isn't possible/practical. Although the cropper library does allow for "minCropBoxWidth" and "minCropBoxHeight" options these can only be set when the cropper is initialised. To change the options you have to destroy the existing cropper and reinitialise it with complete new options, but the library provides no ability to get the existing options (as supplied by the PW core) before destroying the old cropper. And I don't want to duplicate and maintain ProcessPageEditImageSelect.js to be able to recreate all the options.

    The options that can be updated dynamically are very limited - only setAspectRatio() and setDragMode() methods are available. If anyone can see a way to set minCropBoxWidth and minCropBoxHeight dynamically then let me know.

    So as @horst suggested, use CroppableImage instead if you need to set minimum crop sizes.

  11. v0.3.0 released.

    Adds support for PageListSelect and PageListSelectMultiple inputfield types. Also adds support for PageAutocomplete inputfield type but only when used via a HannaCodeDialog::buildForm hook. From the module readme:


    For selecting pages you can use pagelistselect or pagelistselectmultiple. You don't supply select options for these inputfield types.


    PageAutocomplete inputfield type

    The PageAutocomplete inputfield type can only be used via a HannaCodeDialog::buildForm hook. See the PhpDoc documentation for the list of inputfield properties that may be set. Particularly findPagesSelector for limiting the pages that may be selected and maxSelectedItems for allowing only a single page selection.


    10 hours ago, maddmac said:

    Is is possible to use the InputfieldSelectorSelectID module with the Hannacode dialog to make a page selector?

    @maddmac, I think you must be referring to PageListSelect which is used in InputfieldSelectorSelectID rather than that module as a whole. In v0.3.0 you can now use PageListSelect with HannaCodeDialog, either by setting a "attributename__type=pagelistselect" attribute in the tag settings or by using a HannaCodeDialog::buildForm hook.

    • Like 3

  12. 2 hours ago, eydun said:

    Would it be possible to add the Config class as a variable?

    I have tried:

    /** @var tpl_config $config */

    But it does not work.

    That's not how this module works. It's just gives you code completion for fields that belong to the template of the current page - $config is an API variable so is something totally different.

    But you can add type hints for the API variables that PW makes available to template files in a DocBlock at the top of your template files. More info:


    • Like 1
    • Thanks 1

  13. On 3/17/2020 at 8:50 AM, horst said:

    Do you know a way how to make the labels multilanguage aware?

    Sorry, I never get to work on multi-language sites here in NZ so I don't know about multi-language features.

    • Like 1

  14. 17 minutes ago, Macrura said:

    PHP_EOL should be the standard for cross platform

    As I understand it, PHP_EOL means "the end of line character for the current system". So when the code executes on Windows it equates to "\r\n" and when it executes on *nix it equates to "\n".

    It's cross-platform when it comes to outputting a line-break character, but not when it comes to looking for line-break characters in user input from Windows and *nix.

    I usually do this...

    $lines = explode("\n", str_replace("\r", "", $input));

    ...which is faster than regex.

    • Like 3

  15. Inspired by a recent question.

    Image Crop Ratios

    Allows preset aspect ratios to be defined per image field for the ProcessWire image crop tool.

    The module adds a select dropdown to the crop tool. Choose an aspect ratio and the crop area will be fixed to that ratio.




    Install the Image Crop Ratios module.


    • Default aspect ratios for all image fields can be defined in the module config.
    • Aspect ratios for specific image fields can be defined on the Input tab of the field settings.
    • You can override the ratio settings in template context if needed.
    • Insert a hyphen as the first item in the ratio settings unless you want to force a ratio to be applied to the crop tool. The hyphen represents a blank option that allows a free crop area to be drawn.


    1. Click the "Crop" link on the details view of an image thumbnail.
    2. Click the "Crop" icon at the top of the editor window.
    3. Choose an option from the "Ratio" select dropdown.



    • Like 15

  16. You could add the datalist to a normal text field using a hook in /site/ready.php:

    $wire->addHookBefore('InputfieldText::render', function(HookEvent $event) {
    	/* @var InputfieldText $inputfield */
    	$inputfield = $event->object;
    	$field = $inputfield->hasField;
    	if($field && $field->name === 'my_field') {
    		$inputfield->attr('list', 'my-list');
    		$inputfield->appendMarkup = <<<EOT
    <datalist id="my-list">
      <option value="One">
      <option value="Two">
      <option value="Three">


    • Like 2

  17. This seems to do the job:

    $wire->addHookAfter('ProcessPageEdit::buildFormContent', function(HookEvent $event) {
    	/* @var InputfieldWrapper $wrapper */
    	$wrapper = $event->return;
    	// Do some check on user role
    	if($event->wire('user')->isSuperuser()) {
    		$inputfields = $wrapper->getAll();
    		foreach($inputfields as $inputfield) {
    			$inputfield->required = 0;


    • Thanks 1

  18. You could use a hook...

    $wire->addHookBefore('ProcessPageList::find', function(HookEvent $event) {
    	$selector = $event->arguments(0);
    	/* @var Page $page */
    	$page = $event->arguments(1);
    	if($page->template == 'your_parent_template') {
    		$selector .= ", sort=date, sort=title";
    		$event->arguments(0, $selector);

    ...or this module: https://modules.processwire.com/modules/process-page-list-multiple-sorting/

    • Like 4
    • Thanks 1

  19. 3 minutes ago, matjazp said:

    What I would be interested in if someone with ProCache would explain how it works and how ProCache knows all that details if PW (or even) php isn't touched at all?

    ProCache serves up a cached static HTML file using mod_rewrite rules in .htaccess

    It checks if...

    • the request method is not POST
    • there is no query string
    • there is no wire_challenge or wires_challenge cookie
    • a cached HTML file exists for the requested URL

    ...and if all of this is true it serves the HTML file.

    I recently opened a support topic asking for help using ProCache in conjunction with template cache (my site has a lot of logged-in users that I'd like to serve cached pages to). When Ryan replies over the weekend I'll mention the discussion here and ask if he'd consider improving the template cache using the principle you're experimenting with.

  • Create New...