Jump to content

Robin S

Members
  • Posts

    4,994
  • Joined

  • Days Won

    329

Posts posted by Robin S

  1. Show Image Custom Field Errors

    Makes custom fields for images visible when there is an error, e.g. empty required fields.

    Purpose

    Image fields have three view modes: square grid, proportional grid, and vertical list. In square grid and proportional grid modes only the thumbnail is visible and custom fields for an image are hidden until the thumbnail is clicked.

    This can cause an issue when any of the custom fields is an error state (e.g. a required field that has been left empty) because the relevant field will not be visible in the Page Edit interface, making it more difficult for the user to locate the field that needs attention.

    The Show Image Custom Field Errors module forces image fields into vertical list mode when there is an error in a custom field. When the error is resolved the image field is returned to the view mode that was in use before the error occurred.

    e3af5c10-8baa-4c33-ba77-7f205cc0d5f9

     

    https://github.com/Toutouwai/ShowImageCustomFieldErrors
    https://processwire.com/modules/show-image-custom-field-errors/

    • Like 13
  2. Hi @ryan,

    This new version of WireRequestBlocker has a breaking change relative to the previous version in that it now requires PHP >= v8, due to the use of str_starts_with().

    Because pro modules are not upgradable via the PW admin users don't see notices about requirements before upgrading (and the PHP 8 requirement isn't stated in getModuleInfo() in any case). Could you please highlight the PHP 8 requirement somehow, or change the code so it has the same requirements as previous versions of the module?

    Thanks.

    • Like 1
  3. @Stefanowitsch asked about using the File Mover module with a "media library" page that is accessed via a modal. I thought I would share some hook code publicly in case it's useful for others too.

    // Add a button to file and image fields to open a media library page in a modal
    // Hook InputfieldFile::render to affect file and image fields,
    // or InputfieldImage::render to affect only image fields
    $wire->addHookAfter('InputfieldFile::render', function(HookEvent $event) {
    	$inputfield = $event->object;
    	// The field associated with the inputfield (if any)
    	$field = $inputfield->hasField;
    	// The page containing the inputfield (if any)
    	$page = $inputfield->hasPage;
    
    	// Don't add the button to fields on the media library page
    	// as we don't want the possibility of nested modals
    	if($page && $page->template == 'media_library') return;
    
    	// You can also check the field name if the button should only be added to a specific field, e.g.
    	// if($field && $field->name !== 'article_images') return;
    
    	// Get the media library page
    	$media_library = $event->wire()->pages->get("template=media_library");
    
    	// Construct the URL to edit the media library page
    	$url = $media_library->editUrl;
    	// Add &modal=1 so the admin header isn't shown
    	$url .= '&modal=1';
    	// We don't need other tabs or fields besides the image/file field(s),
    	// so specify the field name(s) in the URL
    	// Unfortunately there is this layout bug: https://github.com/processwire/processwire-issues/issues/1972
    	$url .= '&field=images,files';
    
    	/** @var InputfieldButton $f */
    	$f = $event->wire()->modules->get('InputfieldButton');
    	$f->href = $url;
    	$f->value = 'Open media library';
    	$f->icon = 'picture-o';
    	// Add pw-modal class so the button link opens in a modal
    	$f->addClass('pw-modal');
    	// Make it a large modal
    	$f->addClass('pw-modal-large');
    	// Add a bit of space above the button
    	$f->attr('style', 'margin-top: 10px;');
    
    	// Append the rendered button to the inputfield
    	$event->return .= $f->render();
    });

    image.thumb.gif.6c208089b25cbf77d95761c0f5048a72.gif

    • Thanks 4
  4. @biber, you could of course create several different images fields with different sets of custom fields.

    But if there's an advantage to you of just dealing with a single images field then in your custom fields setup add all the different fields (ingredients, places, etc) you need across all the different templates the field is added to (recipe, plant, etc). Then you can use the Custom Inputfield Dependencies module to only show certain fields depending on the template of the page that's open in Page Edit.

    image.thumb.png.beaecef32b18e73fc7093c960395b5f0.png

    • Like 4
  5. 11 hours ago, gornycreative said:

    I think this module may be broken with the new site? I tried refreshing the modules list and got no dropdown.

    It's working for me, so might have been a temporary outage at the modules directory. Or if it's a recurring issue for you please add some more detailed steps to reproduce on a clean installation.

  6. I wasn't sure if this module would be of much general interest but Teppo has mentioned it a couple of times in recent issues of PW Weekly so I'm adding it to the modules directory and creating a support topic for it.

    Page Action: Include File

    A generic action for Lister Pro allowing the selection of a PHP file containing the action code.

    This can be useful for quickly applying API processing to pages without going to the trouble of creating a custom Page Action module for the purpose. Large quantities of pages can be processed thanks to Lister Pro's feature that splits the pages into chunks.

    Usage

    The module creates a folder at /site/templates/PageActionIncludeFile/ on install. Place your PHP files inside this folder. Within each file, the $item variable refers to the page that is currently being processed. There is no need to save the page within your code because Lister Pro does this automatically.

    Example action file: append_foo_to_page_title.php

    <?php namespace ProcessWire;
    /** @var Page $item */
    
    // Append " foo" to page title
    $item->title .= " foo";

    Enable the PageActionIncludeFile action in the config of one or more Lister Pro instances.

    PageActionIncludeFile image 1

    In the Lister Pro instance, set the filters or select the pages as needed and then choose the "Include File" action. Use the select field to choose a file you have added to /site/templates/PageActionIncludeFile/.

    PageActionIncludeFile image 2

    Click "Execute" to apply the action.

     

    https://github.com/Toutouwai/PageActionIncludeFile
    https://processwire.com/modules/page-action-include-file/

    • Like 2
  7. @AAD Web Team, the issue of if PW is not doing something it should isn't something we can resolve in the forum as it's a question for Ryan and he doesn't routinely read all topics. To get an answer on that you'll need to raise an issue in the Issues or Requests repos, depending on if you think it's a bug or rather a feature you would like to have.

    But to solve your immediate problem you can use the hookable method I mentioned. You use whatever custom code you have to get a username back from the supplied email address and then use that with the supplied password to attempt a login.

    $wire->addHookBefore('ProcessLogin::loginFailed', function(HookEvent $event) {
    	$session = $event->wire()->session;
    	$username_or_email = $event->arguments(0);
    	// Maybe return early if not dealing with an email address
    	if(strpos($username_or_email, '@') === false) return;
    	// Dummy function indicating where you get the username from an email address using your custom code
    	$username = getUsernameFromEmail($username_or_email);
    	$password = $event->wire()->input->post('login_pass');
    	$u = $session->login($username, $password);
    	if($u) {
    		// Login was successful for the given username and password
    		// Redirect to admin
    		$session->redirect($event->wire()->config->urls->admin);
    	}
    });

     

    • Like 2
  8. 45 minutes ago, adrian said:

    Sorry, now I am seeing: Deprecated: strip_tags(): Passing null to parameter #1 ($string) of type string is deprecated

    I'm surprised a textarea field value can be null rather than an empty string. Maybe something to do with multi-language.

    I'm casting $text to string in v0.1.3 so hopefully fixed. Thanks for the report.

    • Like 2
  9. 6 minutes ago, adrian said:

    So, I added $text = strip_tags($text) and now I get the same 50.4 that the demo on readable.com does.

    Do you think it makes sense to add that?

    Good idea, I've done that in v0.1.2

    • Like 2
  10. @adrian, I've added most of your requests in v0.1.1. But not the colour-coding because the results don't fall into universal good or bad categories - it depends on the intended audience, e.g. you would expect a high grade level on a website for an academic journal.

    • Like 1
  11. Text Readability

    A module that uses the PHP Text Statistics class to evaluate the readability of English text in textarea fields according to various tests.

    The available readability tests are:

    The results of the enabled tests are displayed at the bottom of textarea fields – either when the "book" header icon is clicked, or at all times, depending on the option selected in the module configuration. An interpretive tooltip appears when you hover any of the result values.

    Requires ProcessWire >= 3.0.246 and PHP >= 7.2.0

    Image

    Why is readability important?


    Readable.com says:

    Readability is partly important because Google considers it a key ranking factor. This is based on human behaviour on websites. If the average person finds website content too difficult to read, they’ll click elsewhere. Google loves readability because it improves UX. Content which is easier to understand will be easier to navigate. This will encourage readers to stay on your page. Which, in turn, improves bounce rates.

    And:

    A good score to work for, for the public, is a Flesch Kincaid grade level of 8. This is adequate for 85% of the public to easily understand.

    The Wikipedia article on readability has useful information too.

    Module configuration


    • Select which readability tests you want to enable. For each test there is an "about" link to information about the test.
    • Select whether the results of the enabled readability tests should be shown only when the header action icon is clicked (default), or if the results should always be shown.
    • For multi-language sites, select which ProcessWire language represents English (as the tests are only intended for English text).

    Advanced


    If you want to disable the readability test results for a particular textarea field you can hook TextReadability::allowReadabilityResults. Example:

    $wire->addHookAfter('TextReadability::allowReadabilityResults', function(HookEvent $event) {
        $field = $event->arguments(0);
        $page = $event->arguments(1);
        // Disable readability results for the "body" field on the "home" page
        if($field->name === 'body' && $page->template == 'home') $event->return = false;
    });

     

    https://github.com/Toutouwai/TextReadability
    https://processwire.com/modules/text-readability/

    • Like 12
    • Thanks 2
  12. 36 minutes ago, jploch said:

    Just adding this here as note for me and others. There is also a much simpler way to add custom markup to an inputfield:

    $field->appendMarkup('<div class="test">Hello</div>');

    Which approach to take depends on where you want the added markup to appear, relative to things like description and notes.

    Demo:

    $wire->addHookBefore('InputfieldText::render', function(HookEvent $event) {
    	/** @var InputfieldText $inputfield */
    	$inputfield = $event->object;
    	if($inputfield->name !== 'text_1') return;
    	$inputfield->prependMarkup('<div>prependMarkup</div>');
    	$inputfield->appendMarkup('<div>appendMarkup</div>');
    });
    
    $wire->addHookAfter('InputfieldText::render', function(HookEvent $event) {
    	/** @var InputfieldText $inputfield */
    	$inputfield = $event->object;
    	if($inputfield->name !== 'text_1') return;
    	$event->return = '<div>before render</div>' . $event->return . '<div>after render</div>';
    });

    image.png.ad183d98c135132beddbce4ca55cf740.png

    Related request: https://github.com/processwire/processwire-requests/issues/536

    • Like 4
  13. @Morphosis, the value of a populated "single" Page Reference field...

    image.png.716832e1e9805462b3531184a6c1869e.png

    ...is a Page object. So it's redundant to get the ID of the Page Reference field value and then get the Page object from the ID, because you already have the Page object.

    So you probably want something like this:

    // If the Page Reference field is populated (i.e. its value is not a NullPage having an ID of zero)
    // and there are some images uploaded to the selected page
    if($page->gallery_cta_source->id && $page->gallery_cta_source->gallery_images->count) {
    	// Then output the images
    	foreach($page->gallery_cta_source->gallery_images as $image) {
    		// ...
    	}
    }

     

    • Like 2
  14. Assuming that the field would be changed in Page Edit rather than as result of some other API code, you can validate the user input in a hook to InputfieldText::processInput.

    Example:

    $wire->addHookBefore('InputfieldText::processInput', function(HookEvent $event) {
    	$inputfield = $event->object;
    	$input = $event->arguments(0);
    	$field = $inputfield->hasField;
    	$page = $inputfield->hasPage;
    	// For a particular field name and template name
    	if($field && $field->name === 'text_1' && $page && $page->template == 'events') {
    		$old_value = $page->getUnformatted('text_1');
    		// Return early if the old value is empty
    		if(!$old_value) return;
    		$new_value = $input[$inputfield->name];
    		// If the first three characters have changed
    		if(substr($new_value, 0, 3) !== substr($old_value, 0, 3)) {
    			// Show an error message
    			$inputfield->error('You are not allowed to change the first three characters of the "Text 1" field.');
    			// Replace the hooked method so the new value won't be saved to the field
    			$event->replace = true;
    		}
    	}
    });

    image.png.a6deb3d81cd908159a6d441a65eb4e3d.png

    • Like 5
    • Thanks 1
  15. 17 hours ago, Flashmaster82 said:

    Would it be possible to have like a batch that moves all images from one field to another field.

    No, because this module is a helper for the admin interface. Doing bulk operations on a set of pages is what the PW API is for. The key method you would use for this is Pageimages::add().

    The basic idea assuming two different pages are involved:

    // Get the first page in whatever way you like
    $p_1 = $pages(1234);
    // Turn off output formatting
    $p_1->of(false);
    // Get the image from the image_1 field
    // The first() method is used because the value of an image field
    // is always a Pageimages object when output formatting is off
    $image = $p_1->image_1->first();
    
    // Get the second page in whatever way you like
    $p_2 = $pages(1235);
    // Turn off output formatting because you are about to change a field value
    $p_2->of(false);
    // Add the image to the image_2 field on the second page
    // This is an example of Pageimages::add()
    $p_2->image_2->add($image);
    // Save the change to the second page
    $p_2->save('image_2');
    
    // Now perhaps you want to remove the image from the first page?
    $p_1->image_1->remove($image);
    $p_1->save('image_1');

    If you are copying between two fields on the same page you'll have to work around this issue: https://github.com/processwire/processwire-issues/issues/1863

    In FileMover I deal with this by calling Pagefile::install()https://github.com/Toutouwai/FileMover/blob/0020e365557730e59bad87286548e69f562be0d8/FileMover.module.php#L165-L166

    The filename will then be automatically incremented. The incremented filename is something you'll want to consider if anything is linking directly to the image as the link will be broken once you remove the original image.

    Of course you'll want to test everything carefully in a safe environment before you do any bulk operation on a live site. If it all sounds too difficult or risky, then consider if it's even necessary. Why not just keep two different image fields instead of consolidating them into one?

    • Like 2
  16. I'm not sure what the technical reason is for the 404 not being handled from ready.php, but as a workaround you could set a custom property on the $page object to indicate that a 404 should be thrown and then throw the 404 later, e.g. from a template file or from _main.php.

    // Your conditional in ready.php
    if($foo === 'bar') $page->throw404 = true;

     

    // In template file or _main.php
    if($page->throw404) wire404();
    • Like 2
  17. On 4/6/2025 at 6:53 PM, planmacher said:

    Hello, is this module still necassary with newest PW ?

    I'm not aware of anything changing that would make this module redundant, but it will be easy for you to check and find out.

    On 4/6/2025 at 6:53 PM, planmacher said:

    What ist actually the best way to show a text input field only if an image field ist populated? This image field is set to "single file if populated, null if not".

    When using the Image & File Dependencies module, if your image field is named "image" you would use the selector string:

    _image>0

     

  18. The docs for the feature say:

    Quote

    Lets assume that the path /products/tools/hammer/ resolved to an actual page in our site when accessed at that URL. But lets say that we accessed the URL /products/tools/hammer/photos/ and the /photos/ portion at the end does not resolve to a page. Because "photos" did not resolve to a page, ProcessWire considers this a URL segment for the "hammer" page.

    So if the URL being loaded is the URL for an actual page (regardless of whether it has a template file or not) then no URL Segment is going to apply.

    And if the URL resolves to a "car" page then the template file that's rendered won't actually be "car-maker.php" where your URL Segment code exists. If there's a car template file then it will be "car.php" that's rendered, and if there's no car template file then it will be whatever template file applies to your "404 Not Found" page.

    • Thanks 1
  19. 23 minutes ago, taotoo said:

    Thanks for another great module Robin.

    Thanks.

    23 minutes ago, taotoo said:

    I wonder if the icons might be inverted, e.g. so that an eye means the page is visible, and an eye with a strike through means it's hidden.

    No, because the icons are in a column labelled "Actions", with each icon representing an action you can take rather than a status that the PageTable item has. Plus the module has had its conventions for 8 years now and it would be pretty confusing for existing users if the icons suddenly reversed their meanings.

    • Like 1
×
×
  • Create New...