-
Posts
5,034 -
Joined
-
Days Won
340
Everything posted by Robin S
-
An inputfield module that brings EasyMDE Markdown editor to ProcessWire. EasyMDE is a fork of SimpleMDE, for which there is an existing PW module. Inputfield EasyMDE has a few advantages though: EasyMDE seems to be more actively developed than SimpleMDE, which hasn't seen any updates for several years. You can define options for Inputfield EasyMDE. Inputfield EasyMDE can be used in Repeater fields and in custom fields for File/Image fields. Inputfield EasyMDE EasyMDE (Easy Markdown Editor) as an inputfield for ProcessWire. EasyMDE is a Markdown editor with some nice features, allowing users who may be less experienced with Markdown to use familiar toolbar buttons and shortcuts. More information is at the EasyMDE website. Installation Install the Inputfield EasyMDE module. Usage Create a new textarea field, and in the "Inputfield Type" dropdown choose "EasyMDE". Save the field and if you like you can then configure the EasyMDE options for the field as described below. To convert Markdown to HTML you can install the core TextformatterMarkdownExtra module and apply the textformatter to the field. Alternatively you can use $sanitizer->entitiesMarkdown() on the field value, e.g. echo $sanitizer->entitiesMarkdown($page->your_field_name, ['fullMarkdown' => true]); Configuration On the "Input" tab of the field settings you can define EasyMDE options for the field in JSON format. Refer to the EasyMDE documentation for the available options. Keys in the JSON must be surrounded with double quotes. Example: "toolbar": ["bold", "italic", "heading", "|", "side-by-side"], "sideBySideFullscreen": false https://github.com/Toutouwai/InputfieldEasyMDE https://processwire.com/modules/inputfield-easy-mde/
-
Redirecting 404 error, URLsegments and PagePathHistory
Robin S replied to asbjorn's topic in API & Templates
FYI, there is an open issue on this topic: https://github.com/processwire/processwire-issues/issues/1116 Here is a hook you can try in /site/init.php: $wire->addHookAfter('ProcessPageView::pageNotFound', function(HookEvent $event) { $url = $event->arguments(1); $pages = $event->wire()->pages; // Explode the URL to pieces, with an upper limit of 10 $pieces = explode('/', trim($url, '/'), 10); $redirect_page = $pages->newNullPage(); $segments = []; // Find closest real page, utilising PagePathHistory while($pieces && !$redirect_page->id) { $segments[] = array_pop($pieces); $path = '/' . implode('/', $pieces) . '/'; $redirect_page = $pages->getByPath($path, ['useHistory' => true]); } // If a page is found and the page's template allows URL segments // then redirect to it, adding back the potential URL segments if($redirect_page->id && $redirect_page->template->urlSegments) { $redirect_path = $redirect_page->url . implode('/', $segments) . '/'; $event->wire()->session->redirect($redirect_path); } });- 1 reply
-
- 3
-
-
I know very little about multi-language development in PW, but just to confirm: are you using the FieldtypeURLLanguage module? It's created by Ryan but is different from the core FieldtypeURL module.
-
WireArray::not() takes a selector argument, not a PageArray. So you could do... if (count($resultsToRemove)) $results = $results->not("id=$resultsToRemove"); ...but wouldn't it be better not to have to remove any results? It's not clear to me why you are doing the unusual thing of searching repeater pages directly instead of the usual thing of searching pages that contain the repeater, e.g. repeater_field_name.subfield_name%=$searchQuery
-
New blog: About the new ProFields Combo field
Robin S replied to ryan's topic in News & Announcements
Thanks for the new module @ryan, it sounds great! Could you say something about any potential downsides to this way of storing field data? E.g. situations where it wouldn't be optimal to use it. Or to put the question another way: why isn't all field data for every template stored this way by default in PW? -
-
You could get the field without going via the template fieldgroup, but to get the inputfield and selectable pages I think it's compulsory to supply a Page object. In the case of selectable pages, it's quite common for the selectable pages to change depending on the current page which is perhaps why it's a compulsory argument to getSelectablePages(). I guess you could get the inputfield settings that determine the selectable pages (i.e. parent_id, template_id, findPagesCode, findPagesSelect or findPagesSelector) and then use that to build a $pages->find() selector but that seems like more trouble than supplying a $page argument. For a Page Reference field that isn't in a repeater I think the simplest way is: $options = $page->getInputfield('my_page_ref_field')->getSelectablePages($page); But a Page Reference field inside a repeater is a special case because where the selectable pages depend on the current page, the current page is interpreted as the editable page that contains the repeater, not the repeater page that contains the inputfield. There is discussion about this here: https://github.com/processwire/processwire-issues/issues/479 So you might do something like this: $options = $fields->get('my_page_ref_field')->getInputfield(new Page())->getSelectablePages($page);
-
I can see why that isn't optimal and I agree that it would be good to be able to selectively disable particular textformatters when outputting. The Hanna Code Dialog module depends on Hanna Code and isn't intended to be used independently of it. The way you're using it is unusual so although I don't want to make changes to the module that I think could compromise the experience for typical users you could use a custom hook/module that would load the Hanna Code Dialog CKE plugins to suit your circumstances. So you'd create your own custom version of HannaCodeDialog::afterCkeRenderReady(). $wire->addHookAfter('InputfieldCKEditor::renderReadyHook', function (HookEvent $event) { $inputfield = $event->object; $field = $inputfield->hasField; // For your field name(s)... if(!$field || $field->name !== 'body') return; $config_name = "InputfieldCKEditor_{$field->name}"; $config_name_matrix = "InputfieldCKEditor_{$field->name}_matrix"; $config = $this->wire('config'); $js_config = $config->js(); foreach($js_config as $key => $value) { if($key === $config_name || strpos($key, $config_name_matrix) === 0) { $js_config[$key]['extraPlugins'] .= ',hannadropdown,hannadialog'; $config->js($key, $js_config[$key]); } } });
-
I'm reluctant to do that because the presence of the Hanna Code textformatter is how the module knows whether it should be interfering with the CKEditor field by loading plugins that will widgetise strings surrounded by the Hanna Code delimiters. Although it wouldn't be a common scenario, it ought to be possible for someone to use the Hanna Code delimiters for some other purpose within a field that isn't configured for Hanna Code without Hanna Code Dialog messing with it. You situation sounds like a fringe case. If the objective is to use unformatted field content in the repeater label could you use a hook instead? E.g. $wire->addHookAfter('InputfieldRepeater::renderRepeaterLabel', function (HookEvent $event) { $page = $event->arguments(2); $inputfield = $event->object; $field = $inputfield->hasField; if($field->name !== 'your_repeater') return; $label = strip_tags($event->wire()->sanitizer->truncate($page->getUnformatted('body'), ['maxLength' => 100, 'more' => ''])); $event->return = $label; });
-
I tested with the latest dev and latest version of the module but I can't reproduce that. The dropdown appears for CKEditor fields where it is added to the toolbar, inside a repeater or nested repeater. Let me know if you can give me any more tips for how to reproduce, thanks.
-
Recently answered here:
-
Besides @adrian's suggestion, here is another way: $width = $page->fields->getField('myfield', true)->columnWidth;
-
You'll need to use a hook for this rather than the access settings in the template. Give the role view and edit access in the template settings and add the following in /site/init.php $wire->addHookAfter('Page::viewable, Page::editable', function(HookEvent $event) { $page = $event->object; $user = $event->wire()->user; // Only for non-superusers, for a specific template if($user->isSuperuser() || $page->template != 'restrict_files') return; // Adjust to suit your template name // User may only view or edit page if they created it $event->return = $page->created_users_id === $user->id; });
-
Oh, right. Then the other thing to check is that the guest role does not have view access for the template. The notes for the "Prevent direct access to file assets" setting explain that this option means that files have the same access as the page that owns them. So if you want to deny file access to guests (or any other role besides superuser) then you must deny view access to the template for that role.
-
Are you testing this as a non-logged-in user, e.g. in an incognito window? The superuser is never restricted so if you are testing as a superuser then PW is going to serve you the file no matter what. Don't include the hyphen in the URL. The correct URL in this case would be http://localhost:8080/site/assets/files/1030/test.pdf. The point is that direct access to the file at its actual location is forbidden, and instead PHP will grant or block access to the file depending on if the user is allowed.
-
Markup Regions work by having markup appear before the opening <html> tag. Reference: https://processwire.com/docs/front-end/output/markup-regions/#technical-details-of-how-markup-regions-work So when hooking TemplateFile::render you would insert the HTML that will populate a Markup Region at the start of the rendered template file output, so it will appear before the contents of the auto-appended _main.php. Example: $wire->addHookAfter('TemplateFile::render', function(HookEvent $event) { $template_file = $event->object; $out = $event->return; // If the template file being rendered is basic_page.php... if($template_file->filename === $event->wire()->config->paths->templates . 'basic_page.php') { // ...then prepend the following Markup Region markup $my_region = <<<EOT <div id="body"> <p>Hello world</p> </div><!--#body--> EOT; $event->return = $my_region . $out; } });
-
Using Tracy Debugger to dump the name of the submit button can give you a clue... $wire->addHookAfter('InputfieldSubmit::processInput', function(HookEvent $event) { $inputfield = $event->object; bd($inputfield->name, "inputfield->name"); }); So there are two submit buttons in Page Edit that get processed: the Save button and the Trash button on the Delete tab. Rather than hooking InputfieldSubmit::processInput you can use the dedicated hookable method that performs the save actions: $wire->addHookAfter('ProcessPageEdit::processSubmitAction', function(HookEvent $event) { $value = $event->arguments(0); if($value === 'send_registration') { // Do your action here... } });
-
Thanks, I'm glad you like it. ? The "Admin theme settings (Uikit)" options don't exist for the standard Fieldset fieldtype (FieldsetOpen) so that wouldn't work, and in any case the location of the module settings fields doesn't determine whether or not they can appear in template context. But in the newly released v0.1.6 I have added support for defining the Minimal Fieldset settings in template context so this should cover what you're wanting to do.
-
Welcome to the PW forums @Rossie! This part... ...finds all the pages that contain at least one image in the gallery20 field that has furniture_list_type=3390 in the image's custom fields. But those pages can also contain images that don't have furniture_list_type=3390 in their custom fields. So if you only want to output certain images from the gallery20 field you need to use a WireArray find() selector to get those images. Your code would look something like this: // Find the pages that have at least one image in the gallery20 field with furniture_list_type=3390 $imagePages = $pages->find("template=makers-child, gallery20.furniture_list_type=3390") ; // For each of those pages... foreach($imagePages as $p) { // Find the images in the gallery20 field with furniture_list_type=3390 $chair_images = $p->gallery20->find("furniture_list_type=3390"); echo "<ul>"; // Loop over the chair images foreach($chair_images as $image) { echo "<li><img src='{$image->url}'>{$image->furniture_list_type}</li>"; } echo "</ul>"; }
- 2 replies
-
- 1
-
-
- images
- custom fields
-
(and 2 more)
Tagged with:
-
Here is a demo module: <?php namespace ProcessWire; class ProcessSaveSettings extends Process implements ConfigurableModule { /** * Module information */ public static function getModuleinfo() { return array( 'title' => 'Site Settings', 'summary' => 'A demo module showing how inputfield values can be saved in the module config.', 'version' => '0.1.0', 'author' => 'Robin Sallis', 'icon' => 'cogs', 'requires' => 'ProcessWire>=3.0.0, PHP>=5.4.0', 'page' => array( 'name' => 'site-settings', 'title' => 'Site settings', 'parent' => 'setup', ), ); } /** * Execute */ public function ___execute() { $modules = $this->wire()->modules; $input = $this->wire()->input; /** @var InputfieldForm $form */ $form = $modules->get('InputfieldForm'); // Add an inputfield /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f_name = 'site_name'; $f->name = $f_name; $f->label = 'Site name'; $f->value = $this->$f_name; $form->add($f); // Add another inputfield /** @var InputfieldSelect $f */ $f = $modules->get('InputfieldSelect'); $f_name = 'header_colour'; $f->name = $f_name; $f->label = 'Header colour'; $f->addOption('#F00', 'Red'); $f->addOption('#0F0', 'Green'); $f->addOption('#00F', 'Blue'); $f->value = $this->$f_name; $form->add($f); // Add more inputfields to the form here... /** @var InputfieldSubmit $s */ $s = $modules->get('InputfieldSubmit'); $s->name = 'save_settings'; $s->value = 'Save settings'; $form->add($s); // If the form was submitted... if($input->save_settings) { // Let the inputfield modules process their input $form->processInput($input->post); // Get all the inputfields in the form $inputfields = $form->getAll(); $data = []; // Add the inputfield values to $data foreach($inputfields as $inputfield) { // Skip the submit button if($inputfield->type === 'submit') continue; $data[$inputfield->name] = $inputfield->value; } // Save the config data $modules->saveConfig($this, $data); // Redirect: https://en.wikipedia.org/wiki/Post/Redirect/Get $this->wire()->session->redirect('./'); } return $form->render(); } /** * Config inputfields: required for ConfigurableModule * * @param InputfieldWrapper $inputfields */ public function getModuleConfigInputfields($inputfields) {} } And there are a couple of relevant modules that might suit your needs, or that you could study for learning purposes: https://modules.processwire.com/modules/process-general-settings/ https://modules.processwire.com/modules/settings-factory/
-
Yes, this is easiest to do if you apply the sorting as the page is saved. So you won't see the sorting immediately after the images are uploaded, but will see the sorting after the page is saved and Page Edit reloads. In the examples below you would add the hook code to /site/ready.php The sort settings for child pages prevents the editor from making any other sort order apart from the one specified. So if you want something like that for images, where the newest images are sorted first, it's very simple: $pages->addHookAfter('saveReady', function(HookEvent $event) { $page = $event->arguments(0); $pages = $event->object; if($page->template == 'your_template') { if($page->isChanged('your_images_field')) { // Sort the images from newest to oldest $page->your_images_field->sort('-created'); } } }); But if you want to sort newly uploaded images first once the page is saved, but still let your editors customise the sort order after that, then you can use this hook: $pages->addHookAfter('saveReady', function(HookEvent $event) { $page = $event->arguments(0); $pages = $event->object; if($page->template == 'your_template') { if($page->isChanged('your_images_field')) { // Get the old version of the page, without the current changes $old_page = $pages->getById($page->id, [ 'cache' => false, 'getFromCache' => false, 'getOne' => true, ]); // Get the names of the existing images on the old page $existing_image_names = $old_page->getFormatted('your_images_field')->implode('|', 'basename'); // Get the newly added images $new_images = $page->your_images_field->find("basename!=$existing_image_names"); // Prepend the new images to the start of the Pageimages WireArray foreach($new_images as $new_image) { $page->your_images_field->prepend($new_image); } } } });
-
You can use the API for this - covered in this post:
-
I don't think it's possible to use regex in config.allowedContent, but this seems to do the job: CKEDITOR.on('instanceReady', function(event) { var rules = { elements: { a: function(element) { // If a link href starts with 'javascript:'... if(element.attributes.href.substring(0, 11).toLowerCase() === 'javascript:') { // ...then the href is invalid so remove the link delete element.name; } } } }; event.editor.dataProcessor.htmlFilter.addRules(rules); event.editor.dataProcessor.dataFilter.addRules(rules); });
-
Additional help text for Page Status field
Robin S replied to Lance O.'s topic in Wishlist & Roadmap
Here's a hook (add to /site/ready.php) that allows you to set a description and your own help notes for each checkbox in the Status field: // Add some extra notes to the options in the Status field of Page Edit $wire->addHookAfter('ProcessPageEdit::buildFormSettings', function(HookEvent $event) { /** @var InputfieldWrapper $form */ $form = $event->return; $status = $form->getChildByName('status'); if(!$status) return; // Add a description to the field if you like $status->description = 'You can apply various statuses to this page to control its visibility and editability.'; $options = $status->options; // Define your notes here $notes = [ 2048 => 'Peter Piper picked a peck of pickled peppers.', // Unpublished 1024 => 'How much wood would a woodchuck chuck, if a woodchuck could chuck wood?', // Hidden 4 => 'She sells sea shells by the seashore.', // Locked ]; foreach($options as $key => $value) { if(!isset($notes[$key])) continue; $options[$key] .= "[br]{$notes[$key]}[br] "; } $status->options = $options; });- 1 reply
-
- 6
-
-
There's a module for that: https://modules.processwire.com/modules/template-tags-edit-list/
- 1 reply
-
- 1
-