-
Posts
4,928 -
Joined
-
Days Won
321
Everything posted by Robin S
-
Check out the brilliant Paginator by @LostKobrakai: https://github.com/LostKobrakai/Paginator/ I mentioned Paginator in a post yesterday but I hadn't used it at that point. I've just tried it out and it works a treat for when you want to paginate the results of two or more $pages->find() operations. There aren't any detailed instructions yet but the example in the readme should be enough to go on. So for your case you want to avoid the foreach and instead create two separate selectors for use in Paginator. Something like: include 'src/Paginator.php'; include 'src/PagesPaginator.php'; $paginator = new PagesPaginator(); $result = $paginator(array( "template=property$selector, address~=$locality, sort=$sort_order", "template=property$selector, !address~=$locality, sort=$sort_order" ), $input->pageNum, 25);
- 1 reply
-
- 2
-
Yes, but what is the problem with that? If it's a matter of not wanting the client name in the URL then these could be altered using Ryan's method from the CMS Critic case study.
-
Searching for numbers throws Exception: Operator '~=' is not implemented
Robin S replied to joe_ma's topic in General Support
One or more of these fields in your selector must be Page fields. If you are trying to match the title of the selected page(s) in your search then use a subfield selector for the page title. For example, instead of... $selector = "my_page_field~=$q"; ...do... $selector = "my_page_field.title~=$q"; I suspect that otherwise PW thinks that you might be trying to match the page ID to the number in your search query, which doesn't allow a ~= operator. -
Did you look into the module mr-fan suggested earlier? This sounds like it would be ideal for what you want to do. Any reason it's not suitable?
-
I can see two options: 1. Use Javascript to write something that identifies the article into a field in your form when a checkbox is checked. I can see this getting fiddly when it comes to dealing with multiple selected articles and removing articles from the field if their checkbox is later unchecked. 2. Place the articles inside the form, so checked articles are included with the form submission. Then when you process the form you look for checked articles. PS. I recommend you use something without spaces for your input name, e.g. $article->name
-
Just wondering why you would need to do this. A PageTable field does not necessarily include all the children of a given parent so the contents/order of the field could never match the children in all circumstances. I would have thought that if you create a PageTable field then you interact with its pages via the field (whether we're talking about the API or the admin interface) rather than the page tree. Personally, I always store my PageTable pages under the admin branch so they're not visible/confusing for clients.
-
Sounds like you have identified the likely source of the problem. Can you explain exactly what the setup is with these two instances of PW and the reason for it? Are you following one of the options described in the multiple-site documentation? If these are two entirely separate installations of PW that both relate to the same client then I would be inclined to place each instance in it's own dedicated hosting account. Then use a subdomain of the client's domain to point to the second hosting account.
-
http://php.net/manual/en/language.types.string.php#language.types.string.syntax.heredoc
- 5 replies
-
- 2
-
- contact form
- formmailer
-
(and 2 more)
Tagged with:
-
The bit that I can't work out at the moment is how to set the matrix item type using a friendly name. I'm sure @ryan will have built in a way to do this, but until he responds you can set the matrix type as an integer using "repeater_matrix_type". First you need to find out the integer for the type of row you want to add. You can do this by dumping a repeater item of the right type and checking the repeater_matrix_type value in Tracy. Or you can open the field settings and inspect the source for the type you want to add. For example, in the screenshot below you can see the id of the inputfield for the "body" type is "matrix3_item", therefore the repeater_matrix_type integer is 3. So find out the repeater_matrix_type value (integer) for "article_content_text" and then you would run some code like this... $articles = $pages->find("template=article"); foreach($articles as $article) { $text = $article->article_text; $article->of(false); $new_item = $article->my_matrix_field->getNew(); // replace with the name of your matrix field $new_item->repeater_matrix_type = 3; // replace with the integer of your matrix type $new_item->article_text = $text; // assuming you added the article_text field to this matrix type $new_item->save(); $article->my_matrix_field->add($new_item); $article->save(); } But first test this works for a single article page before you process all the articles.
-
Yet another sorting issue about featured and non featured articles
Robin S replied to Can's topic in API & Templates
Sadly I don't think it's possible to sort by whether some condition is true, e.g. sort=[props.name=featured] I think switching to separate checkboxes for each property you may want to sort on would be the easiest solution. If you want to stick with the Page field and the number of featured articles is likely to always be less than $limit then you could do something like... $featured = $page->children("props=featured, images.count>0, sort=$sort"); // no sub-selector for props is necessary $articles = $page->children("images.count>0, sort=$sort, limit=$limit")->filter("id!=$featured"); Then on page 1 of the results you loop over $featured, followed by $articles. Alternatively I think Paginator by @LostKobrakai is designed for this kind of scenario but I'm not sure how it works. Maybe he will reply with some tips. -
-
The Repeater Matrix documentation seems to be lacking in this regard - I have requested some in the Repeater Matrix subforum.
-
Users, events, registrations: how to structure data model?
Robin S replied to isellsoap's topic in General Support
Can a user theoretically sign up for a project but not sign up for any phases or events? If not then I suggest that the user only signs up for events, and this implicitly also attaches them to phases and projects by virtue of the page hierarchy above event pages. Users are pages, so each event has a Page field that stores all the users that have signed up for that event. -
The CSV format is so simple you can easily create a template to generate the right output. As an example: <?php header('Content-Type: text/csv'); header('Content-Disposition: attachment; filename="export.csv"'); $items = $pages->find("template=basic_page"); echo "title,url" . PHP_EOL; foreach($items as $item) { echo "\"$item->title\",\"$item->url\"" . PHP_EOL; }
-
Fieldtype image array: $key returns string, not number
Robin S replied to Stefanowitsch's topic in General Support
If you want to keep the original Pageimages WireArray but use an index you can create your own index counter: $index = 0; foreach($data->img_gallery as $image) { // do whatever with $index and $image here $index++; } -
You have to decode the error_reporting number to get a human-readable result. 32767 decodes to: E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE | E_STRICT | E_RECOVERABLE_ERROR | E_DEPRECATED | E_USER_DEPRECATED | E_ALL This is what I use for decoding: <?php // Usage: put the error reporting number in the query string like... // decode_error.php?number=22519 $error_number = $_GET["number"]; $error_description = array( ); $error_codes = array( E_ERROR => "E_ERROR", E_WARNING => "E_WARNING", E_PARSE => "E_PARSE", E_NOTICE => "E_NOTICE", E_CORE_ERROR => "E_CORE_ERROR", E_CORE_WARNING => "E_CORE_WARNING", E_COMPILE_ERROR => "E_COMPILE_ERROR", E_COMPILE_WARNING => "E_COMPILE_WARNING", E_USER_ERROR => "E_USER_ERROR", E_USER_WARNING => "E_USER_WARNING", E_USER_NOTICE => "E_USER_NOTICE", E_STRICT => "E_STRICT", E_RECOVERABLE_ERROR => "E_RECOVERABLE_ERROR", E_DEPRECATED => "E_DEPRECATED", E_USER_DEPRECATED => "E_USER_DEPRECATED", E_ALL => "E_ALL" ); foreach( $error_codes as $number => $description ) { if ( ( $number & $error_number ) == $number ) { $error_description[ ] = $description; } } echo sprintf( "error number %d corresponds to:\n%s", $error_number, implode( " | ", $error_description ) ); You want to set error_reporting so E_NOTICE is off (~ means not): E_ALL & ~E_NOTICE
-
If you're still seeing notices after doing this then the error reporting setting has not been changed successfully. You can use phpinfo() to confirm. Depending on how PHP is set up on your server you may need to use a php.ini file or .htaccess to change settings. Or if this is a cPanel hosting you can usually change error_reporting there. Your host can advise what you need to do to change PHP settings.
-
Thanks @horst. I have my dependent selects working acceptably well now. But there are a couple of things that could perhaps be improved if anyone has suggestions... 1. How can I add options to a select inputfield from outside getModuleConfigInputfields()? Any options used in the select must be added to field $f with $f->addOption() or else they don't pass validation and are not successfully saved on form submit. I need to add these options in my AJAX method according to what has been selected in the first select. I thought I would be able to do this... $fields = $this->modules->getModuleConfigInputfields($this->className); $f = $fields->get('my_select_field'); $f->addOption('my_value', 'my_label); But options added here do not persist, i.e. they are not included the the array of allowed options at the time the form is submitted and processed. Options added within the getModuleConfigInputfields() method in the module work normally. Currently my workaround is to set all possible options within getModuleConfigInputfields() and then filter out the 'wrong' ones with jQuery, but it would be nice to set just the 'right' options in my AJAX method. 2. The second one relates to what you say here... When accessing the module config page with an AJAX request we don't want all the normal form markup returned. I'm not sure what you mean about setting this manually with an if/else condition in init(). As I understand it, the form markup comes automatically from ProcessModule and doesn't depend on anything done manually in init(). The only modules that I know of that use AJAX in the config are the ones @adrian referred me to: http://modules.processwire.com/modules/process-email-to-page/ http://modules.processwire.com/modules/process-custom-upload-names/ These two avoid the normal form markup by doing exit() at the end of the AJAX method, but I think this is a bit ugly (and Ryan has said that it's best if PW can control its shutdown). So I am using a replace hook on ProcessModule::executeEdit. I'm interested if there are different or better ways to handle an AJAX request to the config page.
-
@POWERFULHORSE, if you have Imagick installed on your server you can try a slightly modified version (below) of the function I introduced in this post. // ImageMagick effects function imagickal($imagePath, $format, $method, array $arguments) { $path_parts = pathinfo($imagePath); $dirname = $path_parts['dirname'] . '/'; $filename = $path_parts['filename']; $mod = $method . '-' . implode($arguments, '-'); $mod = wire('sanitizer')->filename($mod, true); $savename = "{$dirname}{$filename}_{$mod}.{$format}"; if (!file_exists($_SERVER['DOCUMENT_ROOT'] . $savename)) { $image = new Imagick($_SERVER['DOCUMENT_ROOT'] . $imagePath); call_user_func_array([$image, $method], $arguments); $image->setImageFormat($format); $image->writeImage($_SERVER['DOCUMENT_ROOT'] . $savename); } return $savename; } I tested it as follows... $orig = "/site/templates/images/transparent.png"; $after = imagickal($orig, 'png', 'negateImage', [false]); echo "<img src='$orig'>"; echo "<img src='$after'>"; ...and the results...
-
Again I'm on the hunt for example modules to learn from. This time I'm wondering if anyone has released a module that uses dependent selects in the config - in other words, load select options for select inputfield A depending on the value of select inputfield B. Currently the module I'm working on requires a save after changing inputfield A, but it would be much cooler if I could update the select options for inputfield B via AJAX when the value of A changes.
-
Strategies for repeatable fields in module config
Robin S replied to Robin S's topic in Module/Plugin Development
Thanks, that's a good idea. Unfortunately it doesn't work for my situation because getModuleConfigInputfields() still reports the old set of configuration fields at the time that the saveConfig() hook runs. Not sure exactly when the inputfields are updated following a change - perhaps on the following page load of the module config screen? I have come up with something that works for now. I have an integer field in the module config that defines the number of repeated fieldsets, whose names contain an integer according to the iteration. In the saveConfig() hook I unset any fieldnames containing an integer higher than the fieldset count. -
I don't think you need nested repeaters, just a single repeater that has a title field (title of the gallery) and an images field. The images field can contain multiple images. Use the description field for each image for the overlay text.
-
Strategies for repeatable fields in module config
Robin S replied to Robin S's topic in Module/Plugin Development
Thanks @BitPoet. Module config fields don't exist in $fields so I can't use that to check which config values should be weeded out in a hook to saveConfig(). But it did give me another idea: save my own JSON string of current config fieldnames in a hidden config field, then check the keys in the config array against that and unset any that are not included. But now I'm banging my head against another issue which is that it's annoyingly hard to set the value of a config inputfield using the ModuleConfig class. -
Strategies for repeatable fields in module config
Robin S replied to Robin S's topic in Module/Plugin Development
I see that the approach of ProcessEmailToPage and ProcessCustomUploadNames is to save the repeatable fields as a combined JSON string to a single hidden inputfield. I'd like to try something different and use the core inputfields (as per a normal module config) inside a fieldset, with the number of fieldsets being variable. I've nearly got this working but have struck a problem with config fields being retained in the DB data after they have been removed from the config. This isn't just an issue for this repeatable config I'm trying to achieve but would also be an issue for a more typical module config if the number of config fields changed between versions. To illustrate, say my getInputfields() function consists of two text fields: text_1 and text_2. In the DB this is stored as: {"text_1":"foo","text_2":"bar"} Now I remove text_2 from getInputfields() and the inputfield is gone, all good. But the DB is unchanged and the value for text_2 is still stored. If the normal behaviour is not to remove config data when the config inputfield is removed, can I use a hook in my module to change this? I'm having trouble tracing where the ModuleConfig class actually saves to the DB. Does it do this via saveConfig() in Modules.php and would that be the right method to hook? Edit: found the source of this issue here in ProcessModule.module - the existing config array is loaded first and then data from the config inputfields is merged in. The net effect of this is that the inputfields specified in ModuleConfig can only ever add to the array of saved fields, never remove fields from it. The method isn't hookable so I don't see a way to override this behaviour. -
Strategies for repeatable fields in module config
Robin S replied to Robin S's topic in Module/Plugin Development
Thanks @adrian, glad to have those modules as a proof-of-concept.