Leaderboard
Popular Content
Showing content with the highest reputation on 10/08/2014 in all areas
-
Hello! There is a very simple answer for this: https://github.com/ryancramerdesign/ProcessWire/blob/dev/wire/core/WireInput.php#L60 This is ProcessWire's doing and it is meant to work like that. For now, I'd just suggest that you fetch them directly from the $_POST-variable ($_POST['players']). Obviously you need to validate/sanitize it yourself, but that's the way to go if you don't want to change your form. If you want to play by ProcessWire's "rules", then you will modify your checkboxes so that their name is "player_{{player.id}}[]" and parse them into a multi-dimensional array yourself. This could be done with a simple function like this: /** * Parses a multi-dimensional array * * This function will use $prefix to match the keys in the source $values. * For matching keys the suffix is then extracted and used as a key for the resulting array. * * @param array|Traversable $values The source values * @param string $prefix The prefix used for extraction * @return array The parsed multi-dimensional array */ function getMultiDimensional($values, $prefix) { // Validate the arguments if(!is_array($values) and !($values instanceof Traversable)) throw new Exception("Invalid values"); $len = strlen($prefix); if(!$len) throw new Exception("Invalid prefix"); $output = Array(); foreach($values as $key=>$value) { // The key needs to match our prefix if(strcmp(substr($key,0,$len), $prefix) != 0) continue; // We expect the other part of the key to hold numeric IDs $id = intval(substr($key,$len)); if(!$id) continue; $output[$id] = $value; } return $output; } // Demonstration $players = getMultiDimensional(wire('input')->post, "player_"); // print_r($players); // // [5157] => Array // ( // [0] => 1580 // [1] => 1578 // ) // ...and so on Edit: Added an example and some comments Needless to say, I suggest the latter solution8 points
-
Hi everybody, I'd like to share with you another new module. It helps you to manage user ratings for pages in a very simple way. You can add a user rating to a certain page with a line of code: $page->ratings->add(4) If the user is logged in, the module remembers which page the user has rated for. For non-logged-in visitors, the module stores the pages, the user has rated, in the session. You can get a page's rating and its total amount of votes in a similar way: $page->ratings->average; // => 3.2 $page->ratings->count; // => 5 For more information about this module, please check out its GitHub repository. You can check out a working version of the module here: http://curium-cte.lightningpw.com Edit: The module is now available in the ProcessWire modules directory. Update: Ratings has been updated to version 1.1, including a new, simpler API accessor. As always - please comment for bugs or feature wishes. Thanks in advance, Marvin7 points
-
I've just posted a Fieldtype and Inputfield module combination that support the use of MySQL time fields in ProcessWire. Ryan's Datetime module is great but I needed something that dealt specifically with times for a scheduling system and this is one of the results. For 24 hour clock format ('HH24MM') you now get a clock-picker pop-up by default... ...but you can inhibit it if you don't want it... Although the input time format is selectable, as this is stored as a MySQL time field, you currently need to specify values in selectors in full "H:MM:SS" format. So if you wanted to get all events starting on or after 9am you'd do something like this... $events = $pages->find("template=events, starts>=9:00:00")->sort("starts"); This is definitely a beta module as I've not tested every single input format yet. Currently does not support negative time-periods or fractions of a second. FieldtypeTime on Github FieldtypeTime in the Module Repository Releases Version 0.2.0: Adds support for the use of this input field in repeaters and repeater matrix types. Version 0.1.0: Adds clock picker.5 points
-
5 points
-
Great, then I can try to help you. I'm certainly interested in the steps 4-7, that you described in your OP. It would help even more if you could add the timers around the different phases of your process, like this: $timer = "newsletter_debug"; Debug::timer($timer."1"); // Phase 1 code Debug::saveTimer($timer."1", "Phase 1"); Debug::timer($timer."2"); // Phase 2 code Debug::saveTimer($timer."2", "Phase 2"); Debug::timer($timer."3"); // Phase 3 code Debug::saveTimer($timer."3", "Phase 3"); Debug::timer($timer."4"); // Phase 4 code Debug::saveTimer($timer."4", "Phase 4"); If you can enable debug-mode, then you could copy the timers directly from your admin site. If not, then you could just save them to disk. You can do this with file_put_contents(wire('config')->paths->logs."/timers.txt", var_export(Debug::getSavedTimers(),true), FILE_APPEND); Then just surf to your logs -folder (site/assets/logs) and post us the contents of the timers.txt -file.5 points
-
Yes, when you first create a page, it does not know what template you are using, unless you are only allowing it to use one template. So, any things you set on the template like the label of the title field will not show until you save the page.... er, obviously.5 points
-
Joss - My client currently updates their site via some kind of Microsoft Visual HTML Editor. They have (in their current site) pink and yellow text, blinking text and background music in their newsletters. One of us is going to end up crying in some corner of some room4 points
-
FormHelper The redesigned FormHelper extends the InputfieldForm object with additional features. Features The FormHelper module extends the PW form object and simplifies the form handling. create basic PW form object with submit button add form field value handling and sanitizing take care about form submit / error state and processing CKEditor pwImagePlugin field, jsConfig, load form admin styles FormHelperExtra is a submodule to handle additional features. create a form object with fields based on Template, Page, Form objects or field data array form file upload handling (temp page uploads, creation of a hidden storage page) Usage Documentation / examples Repository PW module repo GIT repo ToDo / Issues Issues3 points
-
Those you can't see from the debug-mode admin site's timers, which I was primarily aiming at3 points
-
Or just use $log ? $timer = Debug::timer(); ... $log->save("mylog", "phase 1: " . Debug::timer($timer)); $timer = Debug::timer(); ... $log->save("mylog", "phase 2: " . Debug::timer($timer)); Will create a log in site/assets/logs/ as mylog.txt3 points
-
I have read it. My point is that during ProcessWire bootstrapping, the class does not exist yet, and the existence (i.e. your conditional autoloading function) won't be checked after ProcessWire becomes ready() Edit: Just to make this clear - the only thing you have when your conditional autoloading function is called is a placeholder module, the actual class hasn't been included yet - so it doesn't exist (unless it's an autoloading module or your module cache is empty). It will be included and replaced when you request the module inside your template - but like I have said, this does not trigger any conditional autoloading for other modules. There is guarantee for the conditional autoloads - they are triggered when ProcessWire goes ready().3 points
-
Hello everyone, After playing a week with ProcessWire I'm really loving it. As a first project I wanted to create a Profile module based on the existing FrontendUserProfile trying to make it suit my needs, and I found the need for a filter system like the one WordPress has. I couldn't find anything similar or maybe I didn't completely grasp the Hooks concept, so I've created a simple ProcessWire module to handle that: Filter https://github.com/gyopiazza/pw.filter The module is autoloaded, and once installed you can use the 2 functions provided to filter data. This feature is very useful in certain situations where you want to be able to change some values in a simple way. function my_function1($value) { return 'filtered by my_function1'; } function my_function2($value) { return 'filtered by my_function2'; } // Parameters: filter name, function name or array(class, method), priority // Higher priority means later execution, default is 10 addFilter('some_filter_name', 'my_function1', 10); addFilter('some_filter_name', 'my_function2', 10); $result = 'default value'; $result = applyFilter('some_filter_name', $result); // $result = 'filtered by my_function2' Hope you like it, cheers! Giordano2 points
-
@sforsman: Thanks for your great answers in the forum recently! Looks like you have a lot of knowledge about PW even with only 50 posts in the forum Keep on doing the good stuff2 points
-
Ah nice! I think I kinda ignored or forgot the little appended note there in the timers tab. This is relatively new. I wasn't aware of the context when writing thinking about templates!2 points
-
2 points
-
Hello! Without one seeing actual code, it will be very difficult to say/guess unless you narrow down the bottleneck a bit. If you don't want to give us the code, could you clock the different stages and tell us the results?2 points
-
Hello and welcome! The Hooks are meant to extend (or even replace) the functionality of ProcessWire and it's modules. They are a general concept and not something that provide features on their own. Instead you attach to them, to implement the feature you are needing. In your case, one example for their usage could be hooking into Fieldtype::formatValue and automatically filtering some specific fields when they are output in a template. I don't know how you are using the filters, so this might not be very useful. Here's a quick example anyway // Filter.module public function init() { $this->addHookAfter("FieldType::formatValue", function(HookEvent $e) { $page = $e->arguments(0); $field = $e->arguments(1); $value = $e->arguments(2); // Execute for my_field only if($field->name != "my_field") return; $e->return = applyFilter("my_field", $value); }); } // Demonstration in CLI require 'index.php'; addFilter('my_field', function($value) { return strtoupper($value); }); addFilter('my_field', function($value) { return md5($value); }); // If you are inside a template this isn't needed $page = $pages->get('/some-example-page'); $page->setOutputFormatting(true); echo $page->my_field; // Would print a MD5-hash of the uppercase version of the original value It would be quite trivial to extend this so that you could do $field = $fields->get('my_field'); $field->addFilter(function($value) { ... }); $field->addFilter(function($value) { ... });2 points
-
Thank you for your feedback and your commitment. I already guessed that it won't work with every AD. So far, the few ADs I have for testing seem to work. Written before, I try to enhance the module over time and add more features and compatibilities to it. Therefore, I'd be pleased if you can share the code with me, so I can enhance this module and make it better. Of course, you will be given credits in the source code for this. What connects us is that we all love ProcessWire and want to see it grow in every environment. So if we pull together, we can achieve this.2 points
-
@Peter This might not be exactly what you want but I think you can get a long way towards making things easy using PWs existing per-template label feature for fields. Just edit your Staff Directory template and locate the "title" field in the list of fields and click on the word "title" to bring up the per-template field config sttings editor. You can now change the label for the title field from "Title" to "Full Name" and save that and the template you should now be able to use the title field and it will be displayed as "Full Name" on every page you edit or add. In effect you can re-purpose the title field and remove the need for a separate full_name field. I know that might not be 100% of what you are after but it goes a long way toward it.2 points
-
We have created an LDAP module for PW that supports mapping groups, setting the base dn and storing the e-mail address of the user (for an example). It also has an "Active Directory" -mode. I don't think Marvin's current code works with every AD-instance since it's missing a couple of ldap_set_option() calls that are needed for some. The only reason we haven't released it earlier is that we wouldn't have the time to maintain it. @Marvin: If you want to take a look at the code I can post it on Github and throw you a link. You could always implement all the stuff by yourself as well, I would understand2 points
-
Hi David, I'd be glad to take care of AIOM. I'm coming from the South of Germany. I work together with @phil at Conclurer, a web development company. If you want to, I can send you my personal mail address so that we can talk about AIOM. Thanks in advance, Marvin2 points
-
This is a simple module to prevent guest users and search engines from accessing to your site. Primarily it is designed for use during site development. Modules directory: http://modules.processwire.com/modules/protected-mode/ Github: https://github.com/adrianbj/ProtectedMode Install and check the "Protected Mode" checkbox Create a user with only the guest role and give the login details to your clients/testers. Of course existing admin users can use their personal logins still. There are some similarities with Pete's excellent Maintenance Mode module, but the reason I built this, rather than using Maintenance Mode is: I didn't want the "Maintenance Mode" badge showing up on the site since this is for development before a site has ever been live and I didn't want the client seeing that badge. I didn't want users redirected to the PW login page because I didn't want visitors to see the PW login page. I know the module has the option to redirect to a custom page, which you could use to make a front-end login form, but that seemed more complex than I needed (and I think other PW devs might also need). Because of the way this module replaces Page::render with the login form, visitors can be sent to any page on the site, and once they login that page will reload with its full content - no messing around finding the page again, and no need for sending page ids through the login process to redirect back. This module also lets you configure the message that is displayed along with the login form, and also apply some css to style the login form. Hope you guys find it useful.1 point
-
Hi everyone! With Batcher you can batch-edit and create Pages in the Pw Admin. If you install this module, you get a new Page "Batcher" under Setup. Modules page: http://modules.processwire.com/modules/process-batcher/ Github: https://github.com/wanze/ProcessBatcher Editing How does it work? Search your pages with a selector. You can check if you want to include also hidden/unpublished pages with the filters. Select the pages you want to execute an action (the action only gets executed on "checked" pages). Select the action and if necessary, additional data like the new parent or the new template. Execute. Supported actions: Publish/Unpublish Pages Hide/Unhide Pages Lock/Unlock Pages Trash Pages Delete Pages Change Parent Change Template Batcher does the following permission checkings for the current user: Don't display pages that are not editable Remove Actions if the user doesn't have the permissions (page-delete, page-move, page-template, page-lock) Important notes: When changing a template, data in fields of the old template which are not assigned to the new template gets deleted. When changing the parent, the template of the new parent must accept the pages template as children. This is a setting in the template under "family". Creating How does it work? Select a parent where your new pages will be added as children Add as many pages as you want by clicking "add Page" Click "Create Pages" You must enter a title and choose a template. The name is optional: If left empty, Pw will generate this for you. Includes permission checking and Family template restrictions. This means in detail: The selected parent must accept children and their template The pages template must accept the parents template User needs the permission to add children to the selected parents template User needs the permission to create Pages for the chosen Template Batch-creating tips The chosen template and the statuses are always cloned from the last row. So if you need to add 30 pages with the same template, define it first and the click "add Page" - it'll make your life easier ;-) You can drag & drop the table rows should you want to change the order. The dragging looks ugly but it works. For the lazy dogs and keybord hackers among us, you can add a new row by pressing "ctrl+n". This works (at least in firefox) only if no input has focus. After adding a new row, the title input gets the focus. By pressing 3 times tab you arrive at the published-checkbox, here the short-cut works. Restrict Batcher for a user to only allow editing or creating Create permissions "batcher-edit" and/or "batcher-add". As soon those exists, the module checks if the current user has the permissions. If you only need batch creating, check out the following module by Soma: http://processwire.com/talk/topic/2138-process-tools-create-pages-wip/ Cheers1 point
-
ok your question was some days ago but anyway: this post from ryan should give you an answere! as far as i understand, the main benefit is that you can define things wherever you want and then do the output at the right position. if you had a slider in a sidebar for example and needed a special stylesheet for that slider it would be too late to include that with a html-first approach. outputting everything afterwards lets you add $stylesheets[] = 'slider_style.css'; wherever you want and then put it out in your <head> right in place like this: <head> ... foreach $stylesheets echo <link ... stylesheet_name.css> </head> <body> <div id="main"></div> <div id="slider"></div> </body>1 point
-
I think I have it figured out. I ie9 does not like extra trailing commas in json. Also, it did not like my console.log. I removed those out and it appears to work now! What should I change? Thanks!1 point
-
The funny thing is, ProcessWire works like this for the exact same reason: to reduce loading of not needed modules If you really, really want to do this yourself, then you would have to create a container inside the main module (or create a new module), that holds the relationships (this can even be a module configuration field). Then each "sub" module registers themselves as a conditionally loadable module with the main module. This would be done inside their ___install() -method. Then in your main module's init(), you fetch all the registered "sub" modules and load them. This would work - I can even write you an example. But to be honest, I'd just autoload the damn the module Though just let me know if you still want an example of what I described.1 point
-
That's great news - glad I could help PS. I did a few edits a few minutes before your reply (comments and stuff)1 point
-
Super easy. One module, two clicks: http://modules.processwire.com/modules/process-export-profile/ And after you exported it just put it next to the other site-profiles in the folder of a new processwire installation. And while you're installing you can choose your profile More information: https://processwire.com/blog/posts/new-site-profiles-exporter-for-2.5/#new-site-profile-exporter-is-far-better-than-the-previous1 point
-
I'm not sure I really understand it enough, is it just to format values? But isn't that what TextFormatter modules are in PW. There can be multiple and sorted, attached to a per field basis. If there's any it will run the value through the Textformatters. Fieldtype::formatValue is used to sent through a value of a field after wakeup, but only when outputformatting is on ($page->of(true), you can also disable it or get the unformatted value). Some fields use that to format a value like Datetime or Page. It can also be hooked via modules or in templates. To get a unformatted value you can use $page->getUnformatted("fieldname"); A hook in a module example $this->addHookAfter("Fieldtype::formatValue", $this, function(HookEvent $event){ $value = $event->return; $value = $event->arguments("value"); $page = $event->arguments("page"); $field = $event->arguments("field"); $event->return = "new value"; }); About your module, I still don't understand the real world use case for this or and if it's really best way to go for it. Anyway I think it's a little problematic (?) to have the helper functions outside the module in the global namespace (no namespace yet in PW) and if it's good to name a module just "Filter" ? Edit: I'm maybe also confused by the word "filter" in context to PW, cause there's a $wirearray->filter(selector); but it's not about the same thing?1 point
-
Wow.... I've just tested what you said and .... THANKS a lot. This works fine and I guess I could have struggled many more days without finding it myself... I've used the second solution . And now I can go on with my little project, cool! Thanks again for your great explanations and answer.1 point
-
Yes it will be - it's a method provided by the class all Fieldtypes are extending from. This method will be called when you echo the field inside a template, or to be more precise, when output formatting has been turned on. There is also a hook for FieldType::wakeupValue, which is called when the value for the field is retrieved from the database and attached to the Page object. In other words, if you want the filters to run regardless of the state of output formatting, that's where you want to hook. Or you could even hook both. Since your module is an autoloading singular module, there's a very easy way to provide a flexible way to disable/enable the filters temporarily - globally or per field. Here's an example // Filter.module protected static $disabled = false; protected static $disabled_fields; // Turn the whole filtering system off public static function setFiltersOff($disable = true) { self::disabled = $disable; } // Turn filters off for a specific field public static function setFieldFiltersOff($field, $disable = true) { // If you pass a string instead of a Field-object, it has to be the name of the field if(is_string($field)) $field = wire('fields')->get($field); if(!($field instanceof Field)) throw new Exception("Invalid field"); // Initialize if(!isset(self::disabled_fields)) self::disabled_fields = new SplObjectStorage(); if($disable) self::disabled_fields->attach($field); else self::disabled_fields->detach($field); } // Modify the init() to support these features public function init() { $class = __CLASS__; $this->addHookAfter("FieldType::formatValue", function(HookEvent $e) use ($class) { if($class::disabled) return; $page = $e->arguments(0); $field = $e->arguments(1); $value = $e->arguments(2); if(isset($class::disabled_fields) and $class::disabled_fields->contains($field)) return; // The rest is business as usual... }); // Just a bonus hook for another shortcut $this->addHook("Field::setFiltersOff", function(HookEvent $e) use ($class) { $field = $e->object; $disable = ($e->arguments(0) !== null) ? $e->arguments(0) : true; $class::setFieldFiltersOff($field, $disable); }); } // Now you can use these like this // Disable all filters wire('modules')->get('Filter')->setFiltersOff(); // Turn them back on wire('modules')->get('Filter')->setFiltersOff(false); // Disable a specific field wire('fields')->get('my_field')->setFiltersOff(); // Turn it back on wire('fields')->get('my_field')->setFiltersOff(false); Edit: Added examples You could obviously implement this in other ways too.1 point
-
Thanks Adrian! I decided to just tack ProcessWire's page ID on the end if the story ID is a duplicate: public function changeName($event) { $page = $event->arguments[0]; if ($page->template=='story' && $page->story_id!="") { if (count($this->pages->find("story_id=" . $page->story_id))) { // uh-oh, we found another page with this story ID $page->name = $page->story_id . "-" . $page->id; } else { $page->name = $page->story_id; } } }1 point
-
I havent tested but you could try: 'autoload'=> function() { return wire('modules')->isInstalled('UserFrontendRegister'); }, Edit: changed wire('module') to wire('modules')... my bad1 point
-
1 point
-
1 point
-
There is a bit of SEO going on here too, or can be. So, for instance, the Full Name might be what you want to be displayed on the page, but its not what you want in the <title> tag or in the menu or in the URL. In that case, it actually may be beneficial to have separate fields. Of course, that might also send the client barmy and end up with them crying in the corner of the room in confusion, which might not be quite so desirable....1 point
-
I vote this site of the week +1! Only one remark, that has got nothing to do with your work of course: Did your client check the website legally? I wonder if the voting system featured for example here http://www.radiologische-allianz.de/praxen/radiologie-am-rathausmarkt-privatpraxis/ is an offend against German law, namely the Heilmittelwerbegesetz. I would recommend having it checked twice to make sure it complies with the law.1 point
-
1 point
-
1 point
-
do you know this thread? https://processwire.com/talk/topic/740-a-different-way-of-using-templates-delegate-approach/ a lot to read i really like the structure with _func.php, _init.php and _main.php - very clear, very flexible. i'm doing it like this most of the time: https://processwire.com/talk/topic/740-a-different-way-of-using-templates-delegate-approach/?p=758531 point
-
Any Info when support for 2.5 is coming? Just tried to update but no luck… i will not write any dumb post, i will not write any dumb post, i will not write any dumb post1 point
-
@Bernard, You can change this line: $category = $pages->get("/blog/categorieen/")->children->find("title=$page->title"); to this: $category = $pages->get("/blog/categorieen/")->child("title=$page->title"); Refer to $page->child($selector) in the cheatsheet1 point
-
Those are a couple of good questions - with the new core upgrade module I've started setting the dirs on my development boxes as 777 just to allow easy updates as the dev branch gets commits but I won't be doing that on production machines. I wrote the rule about making the site folder unwriteable by the webserver process in case someone managed to craft an attack against PW that tried to write to the file system; I'd prefer that such an injection/scripting attack - if found - would not be able to write to the disk. So that's definitely a me thing rather than an official PW rule. To try and anwser your question about how to set it - well, it depends on a few things... Going with 0550 means the owning user (the first 5) gets read and traversal rights, the next 5 means users in the owning group get read and traversal rights and the final 0 means other users get no rights. This is the most secure setting but requires that the user the webserver process runs as be either the owning user or a member of the owning group. Going with 0750 (owning user can write to the tree) would be better if the owning user were different from the webserver user and if the webserver user were a member of the owning group. Going with 0755 (owning user can write the tree and any user can read & traverse) would be the one to go for if the owning user were different from the webserver user and if the webserver user were not a member of the owning group. In this respect, this option is the most universally applicable but it allows anyone on the box the right to read and traverse into your file structure and, on a shared host this is a security risk as they can then possibly do things like read your config file - with your DB access credentials in it - if that has read permissions for other users too! If you are on a VPS with no shared accounts - then this setting is fine. To find out the user and group ownership you'd do an "ls -l" from a linux command line and it should show you the owning user and group names. The diagnostic module works by checking if the directory is writeable by the user the webserver process is running as; it doesn't try to analyse or recommend how to fix it (if I remember correctly.)1 point
-
@Marvin: Ah okay. Really cool stuff you guys are doing with/for Processwire Would love to join your company if it wouldn't be based in Heidenheim But if you need help with something or are in Berlin: Let me know1 point
-
Hello everyone, Thank you for your fast answers. Looks like there's definitely a need for an extended LDAP module. @teppo: Yes, I'll enhance the module's functionality over time. For ideas and feature wishes, you can just open up tickets on GitHub. Furthermore, if you can extend the module's functionality, you can open up a pull request on GitHub at any time. @horst: Thank you for finding the spelling mistake. I'll fix that one in the next update. @Pete: This is heading in the same direction as teppo's thoughts. Maybe in addition to mapping the groups into different ProcessWire roles, mapping some user-defined Active Directory attributes to ProcessWire user variables could be a nice extension. I'd be glad if we could talk about this in a separat GitHub thread so that this does not interrupt this one. The idea with the GUID is nice, although it needs an additional field in the user model and I'm not sure if that is a proper way to solve this issue. @Nico Knoll: Of course I'm German. How could you be unable to see that. ;-) I work together with @phil at Conclurer.1 point
-
Here you go guys: https://processwire.com/talk/topic/2387-the-structure-of-fields-and-templates/?p=22762 (found via a link halfway down this article: http://www.flamingruby.com/blog/anatomy-of-fields-in-processwire/ ) I know ryan has explained this several times over the years but I agree that as one of the real "what the heck?" points that come up when you're first exploring ProcessWire some page dedicated to it on the site and linked to wherever fields are mentioned might not be a bad idea1 point
-
I think it would be rather $products = $pages->find("template=product, (product_name=computer), (product_category=electronics)");1 point
-
Continuing from my previous post in this thread about some selector enhancements available on the dev branch, we've got a couple more advanced options for use in selectors in case anyone is interested: OR-groups These let you specify multiple expressions and only one of them has to match in order for the selector to match. It's a way of saying "either this has to match OR that has to match". This is useful because selectors always assumed AND – meaning everything has to match. While you have always been able to use the pipe "|" to specify ORs for fields or values or both, the scope of it was just that field=value statement only. Now we have something new called OR-groups. These let you create multiple selector groups and only one of them has to match. You can specify OR-groups by surrounding selectors in parenthesis. An example demonstrates it best. Lets say that we wanted to find all "product" pages that were in stock, and either in a featured date range, or had a highlighted checkbox checked. Previously we would do like this with two separate find operations: $items = $pages->find("template=product, stock>0, featured_from<=today, featured_to>=today"); $items->add($pages->find("template=product, stock>0, highlighted=1")); Now we can do it in one find operation: $items = $pages->find("template=product, stock>0, (featured_from<=today, featured_to>=today), (highlighted=1)"); Above are two selectors surrounded in parenthesis. Only one of them has to match. You can specify as many of them as you want. This type of OR expression is something you couldn't previously do with selectors. Think of the parenthesis as a way of saying "this is optional". But of course, at least one of your parenthesized selectors has to match in order for the full selector to match. I'm guessing the above usage probably covers 99% of the situations where you might need it. But lets say that you want to have different combinations of OR expressions. You can create named groups that OR with each-other by specifying: foo=(selector1), bar=(selector2), foo=(selector3), bar=(selector4) In the above you'd replace "foo" and "bar" with names of your choice. And you'd replace the "selector" with any selector strings. Those foo/bar names aren't referring to fields, instead they are just named groups that you can name however you want. In that selector, at least one of the "foo" named selectors would have to match, and at least one of the "bar" named selectors would have to match. If you didn't use the foo/bar named groups here (but still used the parenthesis), then only one of the 4 selectors would be required to match. Sub-selectors Some of you are already familiar with these because it was committed to the dev branch a couple weeks ago (and I think may have been outlined elsewhere in the forums). Sub-selectors let you put a selector within a selector, enabling you to perform more complex matches that used to require you to use separate API calls. These can be used on the 'id' property of any field that maps to a page. The 'id' property is assumed when referring to a page reference or a parent, so it's not necessary to specify it unless you want to, i.e. "field" and "field.id" mean the same thing in this case. Sub-selectors are specified between [square brackets]. For example, lets say we are matching products and our product template has a "company" page field. Each company also has it's own page field where all the company locations are identified. Lets say we want to find all products that are made by a company that has more than 5 locations and at least one of those locations has "Finland" in the title. Previously we would have had to do it like this: $companies = $pages->find("template=company, locations>5, locations.title%=Finland"); $items = $pages->find("template=product, company=$companies"); That's easy enough. But now it's even simpler, as you can do it in one operation: $items = $pages->find("template=product, company=[locations>5, locations.title%=Finland]"); When you've got a "field=[value]" selector, any properties you refer to in "[value]" assume the "field", so "locations" above is referring to a property of the "company" field.1 point
-
@Horst - according to Apple, the naming convention must be @2x, and that has to be the last part of the image name, unless you are adding device-specific images (-ipad, -iphone); I also actually just discovered thanks you you and @MadeMyDay, that the retina.js library also supports an override using data-at2x attributes. <img src="/images/my_image.png" data-at2x="http://example.com/my_image@2x.png" /> so that would be an easy way to do this in PW.... but still, having a module generate these instead of specifying manually would be cool!1 point
-
Actually, you can do this on the dev branch. Lets assume that cities are children of countries and that is reflected in your page structure (i.e. /countries/france/paris/). Create your 2 page fields (country and city), and configure 'country' as a single page field with "parent" set to "/countries/". Next, for the "city" field configuration, use the "Custom selector to find selectable pages", present on the "input" tab. In that field, enter "parent=page.country". Save and try it out. This works with select, selectMultiple and asmSelect fields (and possibly others), though not yet with checkboxes, radios or PageListSelect.1 point