Jump to content

Robin S

Members
  • Posts

    4,906
  • Joined

  • Days Won

    319

Posts posted by Robin S

  1. 2 hours ago, msavard said:

    But seeing all the back end of Processwire will be way too intimidating to them.

    Not sure what you mean here. The ProcessWire admin for non-superusers is the most minimal CMS back-end I've seen. It's just the page tree, which is easily understood even by beginners because it corresponds to the front-end structure. And from the page tree editors can only edit the pages that have the templates you allow for them.

    If the page tree is still too overwhelming you customise it with hooks. If the editors only need to deal with pages in a particular branch of the tree you can conditionally set the top-level parent of the tree.

    $wire->addHookBefore('ProcessPageList::execute', function(HookEvent $event) {
    	/** @var ProcessPageList $ppl */
    	$ppl = $event->object;
    	if($event->wire()->page->process !== 'ProcessPageList') return;
    	if($event->wire()->config->ajax) return;
    	// If the user has the "editor" role...
    	if($event->wire()->user->hasRole('editor')) {
    		// Limit Page List to only show a particular page and its descendants
    		$ppl->id = 1085;
    	}
    });

    image.png.2f6723ce94f8bb523bf22b1d3b99ab5d.png

    Or for more complex situations you can control which pages are "listable" individually:

     

    • Like 2
  2. 3 hours ago, ryan said:

    Great job and thanks for all the great modules Robin S.!

    My pleasure. The hooks and inputfields APIs in ProcessWire make module development an absolute dream. It's very satisfying seeing the results you can get with just a little code, and working on modules provides a motivation to dig into the core code so I learn a lot in the process. Also, another shout out to @adrian's amazing Tracy Debugger, which has been transformative for my coding. I have several more modules in progress so watch this space. 🙂

    • Like 18
    • Thanks 9
  3. 1 hour ago, Flashmaster82 said:

    Not working! I installed the latest update 0.3.3 and then the option to paste url at the image field is gone??

    Sorry, I made a typo in that version. Please upgrade to v0.3.4 and it should be working again.

    • Like 1
  4. 4 minutes ago, bernhard said:

    Looks great.

    Thanks.

    4 minutes ago, bernhard said:

    Wouldn't that be worth a PR?

    That's an unknown. It's not worth the time of making a PR if Ryan doesn't want it as a PR. When it's a module I and everyone else can use it right away. When it's a PR then it's something that maybe becomes usable someday, maybe not...

    • Like 5
  5. Inputfield Dependency Helper

    Adds "Insert field name" and "Insert value" dropdown menus to help with constructing show-if/required-if conditions, aka inputfield dependencies.

    The "Insert field name" menu helps you remember the field names that exist in your site (or exist in the current template) and avoids typos.

    The "Insert value" menu lets you select values for Page Reference or Select Options fields via the human-friendly label whereas the show-if/required-if conditions require those values to be inserted as numerical IDs.

    idh-1

    Insert field name


    When you click the button a dropdown menu appears listing field names, with the field labels in parentheses. When editing a field in template context only the fields that exist in the template are listed, and the field labels are in template context. When editing a field outside of template context all the non-system fields are listed. When you click an item in the list the field name is inserted into the settings field.

    Insert value


    When using a Page Reference or Select Options field value in a show-if/required-if condition you have to enter the numerical ID of the page/option, and this is not so user-friendly – often you have to switch to another tab and go and look up the relevant ID. The "Insert value" button is intended to make this process easier.

    When you click the button a dropdown menu appears listing any Page Reference and Select Options fields that exist in the current template (when editing in template context) or in the site. When you click one of the fields the selectable options for the field are AJAX-loaded into a flyout menu. Clicking one of the selectable options will insert the numerical ID of the option into the settings field.

    Configuration


    In the module config you can set a limit to the number of selectable options shown in the menu, so the menu doesn't get excessively long.

     

    https://github.com/Toutouwai/InputfieldDependencyHelper
    https://processwire.com/modules/inputfield-dependency-helper/

    • Like 7
    • Thanks 1
  6. You probably want to exclude by template for the "Link to URL" autocomplete field too.

    // ProcessPageEditLink > Link to URL: exclude pages by template
    $wire->addHookBefore('InputfieldPageAutocomplete(name=link_page_url)::render', function(HookEvent $event) {
    	$inputfield = $event->object;
    	$exclude_templates = ['basic_page', 'movies'];
    	$inputfield->findPagesSelector .= ', template!=' . implode('|', $exclude_templates);
    });
    
    // ProcessPageEditLink > Select Page / Select Child Page: exclude pages by template
    $wire->addHookAfter('ProcessPageEditLink::execute', function(HookEvent $event) {
    	$exclude_templates = ['basic_page', 'movies'];
    	$css = '';
    	foreach($exclude_templates as $template_name) {
    		// Hide the page list item (and its children)
    		$css .= ".PageListTemplate_$template_name, ";
    		// Or just hide the "Choose page" button, if the child pages should remain selectable
    		// $css .= ".PageListTemplate_$template_name .PageListActionSelect, ";
    	}
    	$css = rtrim($css, ', ');
    	$css .= ' { display:none !important; }';
    	$event->return .= "<style>$css</style>";
    });

     

    • Like 1
  7. @mel47, my fault, there are two bundled modules and I forgot to update the version number of one of them. Plus there was a problem where GitHub didn't pick up the casing change of a subdirectory. If you upgrade to the newly released v0.3.2 it should be fixed.

    • Thanks 1
  8. @szabesz, this is the support thread for Logs JSON Viewer but I think you are talking about the Custom Logs module.

    Custom Logs is working for me here with a log named "my-log", so it would be good to find out why it's not working for you. Do you have a custom log named "my-log" defined in the module config? What do you see if you use Tracy to do this...

    bd($name, "name");
    bd($custom_logs, "custom_logs");

    ...just before this line.

    • Like 1
  9. Search Corrections

    Suggests alternative words for a given input word.

    This can be useful in a website search feature where the given search term produces no results, but an alternative spelling or stem of the term may produce results.

    The module has two methods intended for public use:

    1. findSimilarWords(): this method suggests corrected spellings or similar alternatives for the given word based on words that exist in the website.

    2. stem(): this method returns the stem of the given word, which may give a full or partial match for a word within the website.

    The module doesn't dictate any particular way of using it in a website search feature, but one possible approach is as follows. If a search produces no matching pages you can take the search term (or if multiple terms, split and then loop over each term) and use the module methods to find alternative words and/or the stem word. Then automatically perform a new search using the alternative word(s), and show a notice to the user, e.g.

    Your search for "begining" produced no matches. Including results for "beginning" and "begin".

     

    findSimilarWords()

    This method creates a list of unique words (the "word list") that exist on the pages and fields that you define, and compares those words to a target word that you give it. The method returns an array of words that are sufficiently similar to the target word.

    For multi-language sites, the $user language determines which language populates the word list.

    Similarity

    The method ranks similar words by calculating the Levenshtein distance from the target word.

    Where several results have the same Levenshtein distance from the target word these are ordered so that results which have more letters in common with the target word at the start of the result word are higher in the order.

    Method arguments

    $target (string) The input word.

    $selector (string) A selector string to find the pages that the word list will be derived from.

    $fields (array) An array of field names that the word list will be derived from.

    $options (array) Optional: an array of options as described below.

    • minWordLength (int) Words below this length will not be included in the word list. Default: 4
    • lengthRange (int) Words that are longer or shorter than the target word by more than this number will not be included in the word list. Default: 2
    • expire (int) The word list is cached for this number of seconds, to improve performance. Default: 3600
    • maxChangePercent (int) When the Levenshtein distance between a word and the target word is calculated, the distance is then converted into a percentage of changed letters relative to the target word. Words that have a higher percentage change than this value are not included in the results. Default: 50
    • insertionCost (int) This is an optional argument for the PHP levenshtein() function. See the docs for details. Default: 1
    • replacementCost (int) This is an optional argument for the PHP levenshtein() function. See the docs for details. Default: 1
    • deletionCost (int) This is an optional argument for the PHP levenshtein() function. See the docs for details. Default: 1

    Example of use

    // The input word that may need correcting
    $target = 'dispraxia';
    
    // Get the Search Corrections module
    $sc = $modules->get('SearchCorrections');
    // Define a selector string to find the pages that the word list will be derived from
    $selector = "template=basic-page";
    // Define an array of field names that the word list will be derived from
    $flds = ['title', 'body'];
    // Optional: override any of the default options
    $options = ['maxChangePercent' => 55];
    
    // Get an array of similar words that exist in the pages/fields you defined
    // The return value is in the format $word => $levenshtein_distance
    $results = $sc->findSimilarWords($target, $selector, $flds, $options);

     

    Example result:

    sc-result

     

    stem()

    This method uses php-stemmer to return the stem of the given word. As an example, "fish" is the stem of "fishing", "fished", and "fisher".

    The returned stem may be the original given word in some cases. The stem is not necessarily a complete word, e.g. the stem of "argued" is "argu".

    If using the stem in a search you will probably want to use a selector operator that can match partial words.

    Method arguments

    $word (string) The input word.

    $language (string) Optional: the language name in English. The valid options are shown below. Default: english

    • catalan
    • danish
    • dutch
    • english
    • finnish
    • french
    • german
    • italian
    • norwegian
    • portuguese
    • romanian
    • russian
    • spanish
    • swedish

    Alternatively, you can use the ISO 639 language code for any of the above languages.

    Example of use

    // The input word
    $word = 'fishing';
    // Get the Search Corrections module
    $sc = $modules->get('SearchCorrections');
    // Get the stem of the word
    $stem = $sc->stem($word);

     

    https://github.com/Toutouwai/SearchCorrections
    https://processwire.com/modules/search-corrections/

    • Like 11
    • Thanks 5
  10. v0.3.0 released, which adds some new features such as Custom Search Builder in the datatable, a new "Error responses only" view, and the ability to exclude links from this view by defining URL prefixes, to exclude domains known to give false-positive error responses. See the updated readme for more.

    • Like 2
  11. A new page needs to be saved before you can add files or images to it. So try saving the new repeater page after you create it:

    // ...
    $contentRepeater = $page->content->getNew();
    $contentRepeater->save();
    // ...

    I suggest you install TracyDebugger because it would have shown you a error message that explains the problem when you tried to add a file to an unsaved repeater page.

    • Like 1
  12. @monollonom, the edit button sounds like a generally useful feature so I've built an option for this into v0.3.0. There is also a hookable InputfieldSelectImages::getImageButtons() method if you want to add to or replace the button markup.

    @mel47, the module itself doesn't impose any limit on how many selectable images you can have, but I think it would be poor usability to have more than about 100 images to wade through.

    I don't see anything wrong in your hook code, so if it's timing out perhaps you are returning a very large number of images. The inputfield uses the standard admin image thumbnail, so if you have added images to a page using the API rather than in Page Edit then it can take a while to generate the admin thumbnails the first time they are rendered.

    Probably you should work out a way to present fewer images for selection. For example, you could have a Page Reference field on the page to select a particular meeting page, and then the Select Images field would only show the images on that meeting page.

    $wire->addHookAfter('FieldtypeDynamicOptions::getSelectableOptions', function(HookEvent $event) {
    	// The page being edited
    	$page = $event->arguments(0);
    	// The Dynamic Options field
    	$field = $event->arguments(1);
    	
    	if($field->name === 'image_selection') {
    		if(!$page->selected_meeting->id) return;
    		$options = [];
    		foreach($page->selected_meeting->images as $image) {
    			$options[$image->url] = "{$image->basename}<br>{$image->filesizeStr}";
    		}
    		$event->return = $options;
    	}
    });

     

    • Thanks 1
  13. 10 hours ago, TomPich said:

    I need to retrieve data from an external database (I’m okay with thay), something like an array of id => value.
    I’d like the select options to show the value, and then store the pair id / value in the field.
    Can I do that with this module?

    Yes, you could do that. The fieldtype just needs an array of options returned from a hook to FieldtypeDynamicOptions::getSelectableOptions() and there are no constraints on how that array is generated.

    The fieldtype only stores the value, but if you needed to look up the label that goes with a value you could just run the same code that generates the options array and then get the label for any value. One way you might do this is via a method for a custom Page class that returns the selectable options - that way you don't need to repeat any code. So you would add a method like getDynamicOptions() to the Page class that the Dynamic Options field is used with.

    Your hook would then be:

    $wire->addHookAfter('FieldtypeDynamicOptions::getSelectableOptions', function(HookEvent $event) {
    	// The page being edited
    	$page = $event->arguments(0);
    	// The Dynamic Options field
    	$field = $event->arguments(1);
    	if($field->name === 'your_field_name') {
    		/*
    		 * Get an array of options as $value => $label from the custom Page class method
    		 *
    		 * If you have more than one Dynamic Options field on the page that you need
    		 * to distinguish between then you could pass the field name as an argument to the method
    		 * e.g. $page->getDynamicOptions('your_field_name')
    		 * */
    		$options = $page->getDynamicOptions();
    		// Set that options array as the event return
    		$event->return = $options;
    	}
    });

    And to look up the label for the selected option in the template file:

    // Get the label for the selected option
    $options = $page->getDynamicOptions();
    $label = $options[$page->your_field_name];

    This assumes your field is for single options. If it's for multiple options then you would loop over the field value and look up each label from the $options array.

    • Like 1
  14. 2 hours ago, elabx said:

    Does setting the default value in the field setting help you to set the default selection option? (I am specifically using Radios input)

    I haven't tried that before, but I just tried it now and it does work. For "Default value" you have to enter the value of the dynamic option rather than the label, and the field has to be "Required" as per the default value note.

    P.S. I just released v0.1.8 which fixes a minor config fields bug, so you might like to upgrade.

    • Like 1
  15. 3 hours ago, bernhard said:

    I guess your module could install Page Paths automatically, no?

    I don't think it's good to automatically install modules that aren't bundled as part of the module repository. I believe PagePaths does impact some core functionality when installed (PageFinder results and possibly the $page->path/$page->url properties?) and the fact that it includes a feature to manually rebuild the paths table makes me think that it can potentially get out of sync with the page structure. So I think users need to consciously decide to install it if they want to use the Verify Links module.

    I've updated the readme to mention the required modules and that they are core modules.

    • Like 2
  16. @ryan, thanks for creating this cool module!

    A couple of questions:

    1. Do the subfields have an ID of some sort separate to the name, such that a subfield can be renamed without losing the existing data stored for the subfield?

    2. What happens to stored data if a subfield is removed from the defining file? Does the existing data for the subfield persist in the database, or does the fieldtype detect the removal and do some cleanup to remove the stored data?

    Also, I think there's a typo in the blog post.

    // multi-selection
    foreach($page->custom_field->countries as $value) {
      $label = $page->field->label('countries', $value);
      echo "<li>$value: $label</li>"; // i.e. "USA: United States"
    }

    ...should be...

    // multi-selection
    foreach($page->custom_field->countries as $value) {
      $label = $page->custom_field->label('countries', $value);
      echo "<li>$value: $label</li>"; // i.e. "USA: United States"
    }

     

    • Like 6
  17. 2 hours ago, MarkE said:

    if the string is too long, it gets truncated in the log

    LogsJsonViewer doesn't do any truncating, and doesn't get involved in the saving of log data at all - it just formats what is already in the log.

    Your problem might be due to $maxLineLength in FileLog. There's a FileLog::setMaxLineLength() method, but I'm not sure how you could practically use this unless you write to your log file using FileLog::save() instead of the more convenient WireLog::save(). Instead you probably just have to try and avoid going over $maxLineLength if you are saving JSON, perhaps by doing your own truncation on individual values if they are long, before you save the data.

  18. Process Render File

    A Process module that renders markup from files in /site/templates/ProcessRenderFile/. This provides an easy way to create simple admin screens where it might be overkill to create a dedicated Process module for the purpose.

    Process page


    When you install the module a page with the name "render-file" and the title "Render File" is created under Setup. To change the page name or title, expand Page List to Admin > Setup > Render File and open the page for editing.

    Tip: if you create a new text field with the name "page_icon" and add it to the core "admin" template you can set a custom menu icon for the page by entering the icon name into the field. E.g. enter "smile-o" to use a smiley icon for the page.

    If you want to use ProcessRenderFile for more than one Process page you can create a new page under Setup. Select "admin" for the template, enter a title for the page, and in the next step choose ProcessRenderFile in the Process dropdown.

    Render files for URL segments


    On install the module will create a "ProcessRenderFile" folder in /site/templates/. Any .php files you save to this folder will be rendered as the output of a matching URL segment for Process pages using ProcessRenderFile.

    For example, if you create a file foo.php containing code...

    echo "This is the output of foo.php";

    ...then you'll see this output when you visit /processwire/setup/render-file/foo/ (assuming the default ProcessWire admin page name and the default ProcessRenderFile page name). In the render file you can use all the ProcessWire API variables like $pages, $input, etc, as you would in a template file.

    If you create foo.js and foo.css (or foo.scss if you have ProCache installed) then those assets will be automatically loaded when you visit /processwire/setup/render-file/foo/.

    When a file is rendered the filename will be converted into a capitalised format that's used as a browser title and a headline. If you want to set a custom browser title and/or headline you can do this in your render file:

    $this->wire('processBrowserTitle', 'Custom browser title');
    $this->wire('processHeadline', 'Custom headline');

    Render file for the Process page


    If you create a render file that has the same name as the ProcessRenderFile Process page then this file will be rendered when the Process page is viewed without any URL segment. So for the default ProcessRenderFile page name you would create render-file.php. Note that this will override the default list output described below.

    Configuration


    The module configuration screen lets you select URL segment render files to appear as menu items.

    prf-2

    The selected render files will appear in the flyout menu for the Process page, and also as a list when the Process page is viewed without any URL segment. The list is only shown if you haven't created a render file for the Process page as described above.

    prf-1

    prf-3

    If you've created more than one ProcessRenderFile Process page then you'll see menu options for each page in the module configuration.

     

    https://github.com/Toutouwai/ProcessRenderFile
    https://processwire.com/modules/process-render-file/

    • Like 13
    • Thanks 2
×
×
  • Create New...