-
Posts
5,034 -
Joined
-
Days Won
340
Everything posted by Robin S
-
Welcome to the PW forums @j-w! The thing you're asking about doesn't relate to PW as such - it's more an Apache question. As far as I know there isn't anything in the PW htaccess that would prevent you from using basic auth. I don't think you can use <Location> in htaccess - that has to go in your virtual hosts config file. If you want to use htaccess then this Stack Overflow answer might help (it worked for me when I tested it): https://stackoverflow.com/a/14605066/1036672 Or see the answer to the same question for a virtual hosts example: https://stackoverflow.com/a/26980313/1036672
-
[SOLVED] How to sort pages on top when the sort date field is empty?
Robin S replied to PWaddict's topic in API & Templates
For anyone interested in how you might do this by modifying the SQL query that's created from a PW selector, here is one way: In your template file or wherever: // A field name is supplied in a custom "empty_first" item in the $options array // The field name supplied here must also be used as a sort value in the selector string $items = $pages->find('template=news_item, sort=-date_1, limit=20', ['empty_first' => 'date_1']); In /site/ready.php: $wire->addHookAfter('PageFinder::getQuery', function(HookEvent $event) { $options = $event->arguments(1); // Return early if there is no "empty_first" item in the $options array if(!isset($options['empty_first'])) return; // Get the DatabaseQuerySelect object /** @var DatabaseQuerySelect $dqs */ $dqs = $event->return; // Prepend a custom ORDER BY $dqs->orderBy("ISNULL(_sort_{$options['empty_first']}.data) DESC", true); // Return the modified query $event->return = $dqs; }); -
When you do a $pages->find($selector) operation your selector is translated by PW into an SQL query. It's a bit of a simplification (because there some exceptions for things like "count"), but essentially this means that you can only sort by values that correspond to columns in the database. So for example you can sort by "title" because that corresponds to a column in the database. But you can't use some logic at runtime to conditionally build up a custom value based on various properties of each page and then sort by that because there is no corresponding column for that custom value. So your options are... 1. If the only way to work out the sort is to iterate over all the pages in a PageArray and you then want to paginate that sorted PageArray, you can do something like this: // $results is a PageArray that you have applied some custom sorting to at runtime $total = $results->count(); $limit = 10; // Convert page number to be zero-based $page_num = $input->pageNum - 1; $start = $page_num * $limit; // Get the slice of results for the current pagination $results = $results->slice($start, $limit); $results->setStart($start)->setLimit($limit)->setTotal($total); foreach($results as $result) { // Output result } echo $results->renderPager(); But because you have to load all the results into memory in order to sort them, this strategy is not going to scale well with large numbers of results. 2. If the sorting doesn't actually depend on dynamic input you can think about using an integer field in the template to store a weighting that you can sort by in a $pages->find() selector. You would use a saveReady hook to populate this sort_weighting field according to other field values in the page. You can use the API to loop over all your book pages to set a sort_weighting value initially. The sorting in your code didn't quite make sense to me so you'll probably need to adapt this to suit, but the general idea is this: // In /site/ready.php $pages->addHookAfter('saveReady', function(HookEvent $event) { $page = $event->arguments(0); if($page->template == 'book') { $sort_weighting = 0; if(!$page->subject) $sort_weighting = -1; if(!$page->subject && !$page->author) $sort_weighting = -2; $page->sort_weighting = $sort_weighting; } }); // In your template code $results = $pages->find("template=book, sort=sort_weighting, sort=subject, sort=cleanauthor, sort=cleantitle, limit=50");
-
Set the form action to the be the same URL that renders the form. Or just don't set the action for the form because the current URL is the default action. Look for the name of the submit button ("submit" is the default) in $input->post and process the form input when it is present. Example: public function ___execute() { $input = $this->wire('input'); $modules = $this->wire('modules'); /** @var InputfieldForm $form */ $form = $modules->get('InputfieldForm'); /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f->name = 'greeting'; $f->label = 'Greeting'; $form->add($f); /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f->name = 'name'; $f->label = 'Name'; $f->required = true; $form->add($f); /** @var InputfieldSubmit $f */ $s = $modules->get('InputfieldSubmit'); $form->add($s); // Process input if form was submitted if($input->post('submit')) { // Core form processing (required, etc) $form->processInput($input->post); // Custom processing $greeting = $form->getChildByName('greeting'); if($greeting->value !== 'Hello') { $greeting->error('Please say "Hello"'); } // Redirect (Post/Redirect/Get pattern) $this->wire('session')->redirect('./'); } return $form->render(); }
- 1 reply
-
- 2
-
-
Page Reference field - unpublished pages showing up in frontend
Robin S replied to jonatan's topic in General Support
Ryan's comment in the fixed GitHub issue: Therefore, to include unpublished pages you must get the unformatted value of the field: $items = $page->getUnformatted('your_page_reference_field_name');- 11 replies
-
- 5
-
-
-
- unpublished
- page reference field
-
(and 1 more)
Tagged with:
-
Could you please show the code you are using to access your custom image fields in your template file, and explain what error/problem happens when you try to do this? I might be misunderstanding but it seems like you are getting hung up on the inputfield names in Page Edit when really you don't have to worry about these. You just access the custom fields from the Pageimage object using the names of the fields that you added to the template. So if you added the "title" field to the template that defines your custom image fields you access that field as $image->title, where $image is the Pageimage object from your image field. The relevant part of the introductory blog post is:
-
-
Are you referring to the input names when you inspect them in your browser dev tools? It's normal for them to have that suffix - I expect it's to distinguish between inputs when there are multiple images in the same Page Edit form. But you should still be able to access the custom image fields without any suffix. It's working for me - see screenshot:
-
There is this module made by @bernhard:
-
It doesn't hurt to do this, but most of the time it's not necessary. When you change the output formatting state for a page, this only lasts for the current request. On the next request PW is going to automatically set the output formatting state depending on the context the code that's executing - to quote the docs, "By default, output formatting is turned on on the front-end of the site, and off on the back-end (admin) of the site." So probably the only case you would need to explicitly turn output formatting on after you have turned it off is if you had some code in a template file that was setting values to $page, and then later in that template file you are also outputting $page values to the front-end. But I think that would be quite rare, because most of the time when you are using the API to set page values you'll be doing that from a script separate from any template file that's outputting to the public front-end.
-
[SOLVED] Sorting pages by Select Options title, not ID
Robin S replied to rash's topic in Getting Started
There's an open issue in the old PW repo about the inability to sort by the "sort" subfield of a Select Options field: https://github.com/ryancramerdesign/ProcessWire/issues/2049 Looks like the "title" and "value" subfields don't work either. I've opened a new issue here: https://github.com/processwire/processwire-issues/issues/1231 @rash, in the meantime, if sorting by title is critical to your site perhaps the best thing would be to replace your Select Options field with a Page Reference field. When you've created the Page Reference field and added it to the relevant templates you could execute some API code in the Tracy Debugger console to transfer the Select Options field values to the Page Reference field (match option title to page title). -
Everything is possible in ProcessWire. ? For example, you could create a "max_children" integer field and add it to the template of any pages you want to limit the children of. Then use this hook in /site/ready.php: $wire->addHookAfter('Page::addable', function (HookEvent $event) { /** @var Page $page */ $page = $event->object; // If page has the "max_children" field, and the field isn't empty, and the number of children is at the maximum... if($page->hasField('max_children') && $page->max_children !== '' && $page->numChildren >= $page->max_children) { // ...then don't allow child pages to be added $event->return = false; } }); But this is not to say it's the best solution, just that it's possible. ?
- 7 replies
-
- 2
-
-
- blocks
- page builder
-
(and 1 more)
Tagged with:
-
I agree that the concept of output formatting could be better documented - questions about it come up regularly in the forums. @ryan, it would be helpful if there was a page explaining output formatting in the "Getting started" documentation. The key thing to take onboard is that if you are going to be setting and saving values to a page, you must set output formatting to false before you do anything relating to that setting and saving. In your case, you are getting the value of a field that you will later modify... /* get the images object array for the Page */ $myPageImg = $page->images; ...before you have turned off output formatting for $page. If you do... /* get the images object array for the Page */ $page->of(false); $myPageImg = $page->images; ...then when you save $page, the changes you make to $myPageImg will be saved to the field value. Another thing: assigning a field value to a variable like this ($myPageImg = $page->images) when you intend to later modify that field value is probably not a good idea. You can get away with it for an images field because the value of an images field is an object, and objects in PHP are assigned by reference. But the same would not be true for any field whose value is not an object, e.g. a text field. When you assign the value of a text field to a variable you are assigning by value, meaning that changes made to the variable are not simultaneously applied to the field value. To illustrate... $page->of(false); $images = $page->images; // $images is an object assigned by reference $images->add('https://www.site.com/image.jpg'); $page->save(); // Changes to $images will be saved to $page->images $page->of(false); $headline = $page->headline; // $headline is a string assigned by value $headline .= ' foo'; $page->save(); // Changes to $headline will NOT be saved to $page->headline So in your case, there's really no benefit to assigning $myPageImg = $page->images near the start of your code - it just increases the chance of confusion. You'd be better to make changes to $page->images directly: //... $page->of(false); while($file_headers[0] == 'HTTP/1.1 200 OK'){ $page->images->add($file); $affixnum++; $file = 'https://www.site.com/pictures/' . $page->title . "_" . $affixnum . $extension; $file_headers = @get_headers($file); $page->save(); echo $file . " added. <br />"; } //...
-
You can use a limit in a children() selector: https://processwire.com/docs/selectors/#limit For example, this... $sections = $your_page->children("limit=3"); ...will limit $sections to the first 3 children of $your_page.
- 7 replies
-
- 1
-
-
- blocks
- page builder
-
(and 1 more)
Tagged with:
-
For /site/ready.php, but you can adapt for use in a module if needed: $wire->addHookBefore('InputfieldPageTable::render', function (HookEvent $event) { /** @var InputfieldPageTable $table */ $table = $event->object; $field = $table->hasField; // Get array of table template data in the form 'label' => 'icon' $table_template_ids = $field->template_id; $table_templates = $event->wire('templates')->find(['id' => $table_template_ids]); $table_template_data = []; foreach($table_templates as $table_template) { $table_template_data[$table_template->get('label|name')] = $table_template->icon; } $event->wire()->addHookBefore('InputfieldButton::render', function (HookEvent $event) use ($table_template_data) { /** @var InputfieldButton $button */ $button = $event->object; // Return early if this is not a button we want to modify if(!isset($table_template_data[$button->value])) return; // Set button icon $button->icon = $table_template_data[$button->value]; }); });
-
I guess you could disable counting in your selector and get the count of matching pages separately via $pages->count() on the first page only. Then pass the count in the query string (or store it in $session) and use PaginatedArray::setTotal() to set the total count to the PageArray on each pagination. And if necessary you can fake the pagination entirely as shown by Ryan here:
-
Thanks for alerting me to this. In v0.1.0, if you didn't supply a limit as part of the selector string then all the matching pages are listed, which strictly speaking is the correct result. But it seems that Lister doesn't expect this scenario and renders pagination numbers as if a limit of 25 was supplied. Clicking these numbers doesn't do anything though because actually all the pages are already listed. But I think for most cases it's best to for Lister Selector to apply a default limit of 25 if none is supplied in the selector string - that way it's more in line with how Lister and Lister Pro behave. So I've changed to this in v0.1.1. And if you want a different limit you can supply it in the selector string (and you can use limit=0 if you want to see all results at once, but be aware that Lister will then render the incorrect pagination once again).
- 10 replies
-
- 2
-
-
- string
- lister pro
-
(and 2 more)
Tagged with:
-
Lister Selector A Process module that uses Lister/ListerPro, but with a selector string input instead of the normal InputfieldSelector filters. Features For power users, typing a selector string is often faster and more intuitive than fiddling with InputfieldSelector. It also lets you copy/paste selector strings that you might be using somewhere else in your code. Allows the Lister rows to be sorted by multiple fields (not possible in Lister/ListerPro) Allows the use of OR-groups (not possible in Lister/ListerPro) If ListerPro is installed you can run ListerPro actions on the listed pages - the available actions are defined in the module config. Bookmarks can be configured in the module config and accessed via the flyout menu for the module page. For your convenience you can copy/paste a bookmark string from the note at the bottom of the Lister Selector results. Usage Type your selector string on the Selector tab. The selector is applied when the "Selector string" field is blurred, so hit Tab when you have finished typing your selector. Unlike Lister/ListerPro, you can't sort results by clicking the column headings. Control the sort within the selector string instead. Superusers can jump to the module config (e.g. to create a bookmark) by clicking the cog icon at the top right of the module interface. The module is mostly intended for use by superusers, because in most cases site editors won't understand the ProcessWire selector string syntax. If you want another role to be able to access Lister Selector then give the role the "lister-selector" permission. Only superusers can define bookmarks because in ProcessWire module config screens are only accessible to superusers. Screenshots Process page Module config (when ListerPro is installed) Advanced If for any reason you want to create dynamic bookmark links to Lister Selector for a given selector you can do that like this: /** @var $pls ProcessListerSelector */ $pls = $modules->get('ProcessListerSelector'); // Define selector $selector = "template=foo, title%=bar"; // Define columns (optional) $columns = 'title,modified'; $pls_link = $pls->getProcessPage()->url . '?bm=' . $pls->urlSafeBase64Encode($selector . ':' . $columns); echo "<a href='$pls_link'>My link</a>"; https://github.com/Toutouwai/ProcessListerSelector https://modules.processwire.com/modules/process-lister-selector/
- 10 replies
-
- 13
-
-
-
- string
- lister pro
-
(and 2 more)
Tagged with:
-
I've released v0.2.3 to add some support for this. v0.2.3 1. Adds a setting to the module config: "Name stub classes for compatibility with custom Page classes". This option names the template stub classes using the same format as for custom Page class names. A side-effect of this is that your IDE may warn you that multiple definitions exist for your custom Page classes. This is because the stub class files generated by this module will always be distinct from any custom Page class files you create (overwriting the actual Page class files is not on the table for this module). If you enable this option then you'll indicate the class name for $page in your template files like this (using the home template as an example): /** @var HomePage $page */ 2. For new installs the default path for stub files is now "/site/templates/AutoTemplateStubs/". This path is still configurable though.
-
@teppo, a bit off-topic but I'm curious about the use of runHooks() because I haven't seen this used before. If you are adding a custom hook method "myEvent", what's the reason to do... $this->runHooks('myEvent', ['what' => 'listening']); ...instead of... $this->myEvent('listening');
-
I'm not quite sure if you mean thumbnails within the Files inputfield in the PW admin, or if you mean you want to resize the image file for the front-end. If it's the latter you could use a function or module method along these lines: function getResizedImageUrl(Pagefile $pagefile, $width, $height) { $variation_basename = $pagefile->basename(false) . ".{$width}x{$height}." . $pagefile->ext(); $variation_filename = $pagefile->pagefiles->path . $variation_basename; if(!is_file($variation_filename)) { copy($pagefile->filename, $variation_filename); $sizer = new ImageSizer($variation_filename); $sizer->resize($width, $height); } return $pagefile->pagefiles->url . $variation_basename; } $file = $page->files->first(); $resized_url = getResizedImageUrl($file, 400, 300);
-
How to tell selection to avoid empty fields
Robin S replied to lele_ballack's topic in General Support
No, because you are finding Field objects these are neither empty nor not empty. Instead you need to check the values of the field names for the current page to see which are empty. Something like this... $i = 1; foreach($page->fields as $field) { // Limit to 3 non-empty field values if($i > 3) break; // Check if value is empty $value = $page->getFormatted($field->name); if($value instanceof WireArray) { if(!$value->count) continue; } else { if(!$value) continue; } // Do whatever with $field here echo "{$field->name}<br>"; $i++; } -
@BillH, another way to change such labels is to install LanguageSupport (you don't need to install any of the related language modules if you're not using multi-language in your site). Then edit the Default language under Setup and "translate" any strings in the ProcessPageEdit.module that you want to change.
-
Personally I think it's best not to let editors choose font family or font size at all, lest your website ends up looking like a dog's breakfast. But to answer your question, you can use the Custom Config Options in the field settings: https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_config.html#cfg-font_names https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_config.html#cfg-fontSize_sizes
-
Another possibility: $clean = $sanitizer->purify($dirty, ['HTML.ForbiddenAttributes' => ['style']]);