Jump to content

nik

PW-Moderators
  • Posts

    294
  • Joined

  • Last visited

  • Days Won

    4

Everything posted by nik

  1. @bcartier: Sorry for the delay, I've been just catching up after being four weeks (almost) completely away from the computer. You're right, fields inside repeaters were not handled at all. But now they are, as I've just pushed a new version of the module to GitHub. Seems to work ok.
  2. nik

    Anybody here playing Go?

    I've played Go a little too, but it's been some years since I last played against a human player, even online. Computer has been enough of a challenge to me so far as I never quite reached single digit ratings being at 11-12k at my best. It would be great to visit IGS sometimes and play a game or two if you're willing to give a few handicap stones for me Soma. If only I had the time as it's the busiest time of year for me right now - week one out of four of my summer holiday.
  3. Check settings for the field "genres": in the details what's the options selected for "Dereference in API as"? To support multiple selections this should be "Multiple pages" but it sounds like you've got either of those "Single page" options selected at the moment. This is how it should *not* look like: (Edit: added "*not*" above the screen shot )
  4. You're very close actually . This is how it works: if($modules->isInstalled("MarkupBox")) { // do something }
  5. There are no selectors in your example, right? Just objects with properties and plain PHP. And the problem lies within the operators you're using (if you've tried literally those): "=0" and "=1" are assignments not comparisons and the results are what I'd expect them to be. Should be "==0" and "==1" naturally.
  6. @kongondo: Thanks for the request - and sorry for the delay. I've been a bit too busy lately and unfortunately will be in the near future as well. That feature has been on my todo-list since the first version of this module though. While it's straightforward to add, I'd like to come up with a decent solution for situations where there are a lot of siblings as well. I'll try and find some time to try this out as soon as possible.
  7. It seems to have something to do with the pipe character '|' in the beginning of the string. Based on a very quick test I'd say pipe isn't interpreted correctly as a first character of the value - except for native fields (id, name and so on). To solve the problem try and make sure there are pipes only in between of the values in the string.
  8. Here's an example that should get you there. No time to give a more detailed explanation right now, but go ahead and ask if there's something that seems odd =). Put this into site/modules/PageFirstProductPrice.module and install the module from the admin side (check for new modules first). <?php class PageFirstProductPrice extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'Copy first product price', 'version' => 100, 'summary' => 'Copies first product price from a repeater to another field', 'singular' => true, 'autoload' => true, ); } public function init() { $this->pages->addHookBefore('save', $this, 'copyFirstProductPrice'); } public function copyFirstProductPrice($event) { $page = $event->arguments[0]; // we're interested in product pages only if($page->template->name != 'product') return; // copy first product version price, if there is one with a price if(count($page->product_versions) > 0 && $page->product_versions->first()->price) { $page->first_version_price = $page->product_versions->first()->price; } else { // no items wih a price, clear the field // this is needed to keep the field in sync if all items get deleted from the repeater $page->first_version_price = ''; } } } *** Edit *** A bit too hurry as it seems I forgot to mention that my example needs a field called 'first_version_price' in your 'product' template to work. That field should be left hidden as it's populated automatically. And now that you've got a regular field right in your template it's straightforward to sort the product pages in the way you described. And horst seems to have given you the most essential pointer on hooks already, go for it! There's some pretty useful information in the wiki as well. After reading those two and looking at HelloWorld module you'll find yourself hooking away in the promised land of module development in no time.
  9. Soma, looks like it depends on the first field of the selector: if that one is native then other native fields work as well ("name|custom_x|template=..." works). But if the first field is custom, then only custom fields may follow ("custom_x|name|template=..." does not work). There's a todo comment in PageFinder.php regarding native fields not being multi-field aware (https://github.com/ryancramerdesign/ProcessWire/blob/master/wire/core/PageFinder.php#L215), so it's technically not a bug but a known missing feature. It's even halfway done, just needs fields in certain order.
  10. I don't think that's possible with a single find as you'd need an or-selector like this (this is a pseudo selector, not an actual one): "template=match OR (template=notification AND notification_type=something), ...". One way is to use two find() calls and merge the resulting PageArrays but that isn't necessarily an option as you obviously need to sort and limit in the database (or at least you're doing it now). There is a trick you could probably use to get over the limitation in this case. This is clearly a hack so you have been warned =). create a field 'fake' of type integer and add it to the template 'match' make sure every page with template 'match' has the same value for field 'fake' ('-1' for example). Choose a value that never exists in field 'notification_type' (you'd need an autoload module just for filling the field 'fake'...) use a selector like this: "template=match|notification, notification_type|fake=something|-1, summoner_id=$summoner_string, sort=-create_date, limit=15" Now that's one hell of a dirty saturday night trick isn't it? But it works. I truly hope someone comes up with a better alternative. Or that you could live without those sort and limit selectors and use two finds instead of one. *** Edit *** Actually I just found a bit cleaner way, one without a fake field. Assuming field 'notification_type' can't have value of 'match' you can use this selector: "template=match|notification, template|notification_type=match|something, summoner_id=$summoner_string, sort=-create_date, limit=15" It's a trick as well, but not a dirty one anymore. Do note that there seems to be a limitation with builtin fields (or something else weird): you have to use 'template|notification_type', as using them the other way around results in an error "Field does not exists: template". I'll experiment on this a bit more and file an issue if it seems to be a bug.
  11. Yes, that's right. I think you could benefit reading through the API documentation and browsing the cheatsheet. Probably you've done that to some extent before but now that you understand some basics a bit better there's so much more you're able to absorb.
  12. @Soma: Agreed. I guess that's the best alternative in most scenarios - a little redundancy can make a big difference in speed and memory consumption when used wisely. There are situations when this trick isn't that good but this isn't one of them as there's only a little amount of data that would be redundant. Ovi, drop us a line if you're interested in trying out yet another approach and need a helping hand.
  13. Great, we're clearly making progress. Looks like you've understood it as well - and that's the ultimate goal when helping out. Understanding selector formation is if not a necessity at least the key to unleashing the vast possibilities of ProcessWire. So to recap: $departmentSelector is initialized to a selector string that would match all the pages with template 'department'. Then, if current page has template 'location', the initial selector string is concatenated with another selector that would match all the pages having the current page as one of their parents. Comma separated selectors all have to match so that the whole selector matches (comma stands for 'and'). Thus with both of those selectors only pages with template 'department' that have the current page as one of their parents would match. Still that selector string that has to be passed to a find() method to actually get the pages (or get() when only a single page is wanted). Using find() method from $pages object you're aiming at all the pages in your site that match the given selector string. But there are also other places where there's a find() method available. To restrict finding to a specific subtree you can first get the wanted root page and call find() for that page object. Or if you want to filter further a previously retrieved or formed PageArray, they also have a find() function. But do note that this one's different to the previous examples as the page objects are already in memory and the filtering happens there instead of the database. But now I'm way off the original subject. I was supposed to describe things just a little bit deeper but got carried away...
  14. @Ovi, I have to take a closer look to your solution, it sure sounds interesting. PW uses usort for in-memory sorting because it's stable (=doesn't change order of equal items relative to each other) while quicksort isn't. But it seems I've got to dig a bit deeper on this sometimes (and make some speed comparisons) to see if PW could benefit from a stable variation of quicksort - thanks for sharing your findings on that. Then the actual point I was supposed to make: the solution in my previous post (last one on first page) doesn't use usort at all but leaves the sorting to MySQL. And that's the preferred way both for speed and memory consumption. But as it didn't fit your needs (the thread you linked to) the solution you came up with seems like a very good one too.
  15. Oops!... I Did It Again I somehow thought departments (and years) were direct children of locations, but there's this extra container there as well. So try changing parent to has_parent and it should work better.
  16. @Ovi, I think this could be of help to you: http://processwire.com/talk/topic/2884-sorting-based-on-repeater-field-values/
  17. Yes, explanation accepted . OK, see above how the selector is formed to find the search results; there you're searching for employees under the chosen location. And now you need to search for department/year under current location (and list those as options in the dropdown). Anything familiar there? The biggest difference - the only one you haven't solved already - is chosen vs. current location. You do know about $page variable holding the page object of the current page, right? So what you need is a way to use the $page variable in your selector somehow. Currently you're probably using something like $pages->find('template=department') to list options, correct? Now you need to add another part to that selector constraining the departments to your current location. As the same search form is used elsewhere as well (front page at least) you'd want that location constraint only when you actually are on a location page. Something like this should do the trick: $departmentSelector = 'template=department'; # variable holding a page object in a string enclosed in double quotes is interpolated to id of the page if($page->template == 'location') $departmentSelector .= ", parent=$page"; $departments = $pages->find($departmentSelector); And same for years. Got it?
  18. Thanks, glad I could help you RJay! I don't know why has_parent isn't in the cheatsheet (Soma/Ryan?) as it is mentioned in the API documentation (http://processwire.com/api/selectors/). There are one or two other selectors that are not mentioned in either of those I'm sure, but I think it's intentional as they're only for internal use for a reason or another. So everything you really need to know is documented . Happy studying with ProcessWire and don't give up if you ever hit a wall. Ask away and someone will help you for sure. But do try and describe the context and what you're trying to achieve detailed enough and there will be a solution in way less than four days next time.
  19. Doh, I got that structure of yours wrong, sorry! So you're right, using parent wouldn't give the right results. Yes, you could get rid of the container if there's no real need for one. But if that extra level is needed, you can change "parent" in the selector to "has_parent". Then the chosen location has to be one of the parents of the employee, but not the first one necessarily. If it still doesn't work, try echoing $selector right before it's being used for finding the results so that we can see if there's still something wrong with it. And you do have $config->debug = true; in your site/config.php and no errors in site/assets/logs/errors.txt, right? We'll get there, eventually.
  20. OK, now we're back on track I think. So, you've lined up those three things to use page id's? Then your search form would be like this: <select name="location"> <option value="">any</option> <?php foreach($pages->get("/")->children("id!=10") as $location) { $selected = $location->id == $input->whitelist->location ? " selected='selected' " : ''; echo "<option$selected value='{$location->id}'>{$location->title}</option>"; } ?> </select> And now you could use something like this in search.php: # has a location been selected? if($input->get->location) { # sanitize (page id is always an integer) # no need to fetch the actual page as the search selector restricts results to employees $location = (int)$input->get->location; # employees have template 'employee' and their parent page is the chosen location $selector .= "parent={$location}, template=employee"; # whitelist the sanitized value (and use from whitelist later on) $input->whitelist('location', $location); } Hope I didn't introduce any new errors there...
  21. I think I need version control to keep up with the changes in your post. It seems I'm even more lost now than I was before. Which template file are those snippets from exactly, which "child page" are you referring to? And what are the templates assigned to the pages in your structure? Which template has field 'location' you're using in $selector? What else goes into $selector? Can't see the whole picture here... At least you've got a nice mess there as you're using id, name and title like they were the same. What I mean is there's page id as the value for an option in the dropdown you're whitelisting page name as location check for previously chosen item uses page title Those three should be done using the same property, preferably id or name.
  22. I'm not sure I get the context right, but there are some things that don't look right to me. Here you've got a malformed selector: $location = $pages->get("template=location" . $sanitizer->pageName($input->get->location)); Should be: $location = $pages->get("template=location, name=" . $sanitizer->pageName($input->get->location)); This seems to have no function (but could of course be in use outside the provided clip): $selector .= "location={$location}, "; And the dropdown should use name as a value instead of title to match the search and whitelisting (and to be unique), like this: $selected = $location->name == $input->whitelist->location ? " selected='selected' " : ''; echo "<option$selected value='{$location->name}'>{$location->title}</option>"; Maybe these will help? I didn't take a look at the original by Ryan so I may just be missing something obvious here.
  23. Drop the "start=0" and you should be fine. (I'm on mobile, someone will give you a more detailed explanation soon I'm sure.)
  24. If I've understood right you only need to get rid of the <ul>...</ul> wrapping the initial function call and modify the if-statement inside the function just a little bit to let it proceed on the first round even if there are no records found. Like this: <?php function listProducts($productCat,$level=0) { $result = wire('db')->query("SELECT id, product, productcat FROM products WHERE productcat='$productCat' ORDER BY subcat"); if($level > 0 && $result->num_rows == 0) return; echo "<ul class='sortable'>\n"; while (list ($id, $product) = $result->fetch_row()) { echo "<li id='item_{$id}'>\n"; echo "<div class='dd-handle'>{$product}</div>\n"; listProducts($id,$level+1); echo "</li>\n"; } echo "</ul>\n"; } ?> <div> <h5>Products</h5> <?php echo listProducts(0);//call the function ?> </div> As a side note, I usually build a simple safety net when using recursive functions just to be on the safe side if (when) there's suddenly broken data in the database. Here that would mean adding one line at the beginning of the function: // ~25 levels of product categories could be considered an error, I think. // Use something big enough to allow any legitimate data but small enough to allow the server stay alive. if($limit > 25) throw new WireException("Recursion gone wild"); While it's not necessary, it's a small price to pay for peace of mind .
×
×
  • Create New...