-
Posts
5,008 -
Joined
-
Days Won
333
Everything posted by Robin S
-
FieldtypeDatetimeAdvanced - subfield selectors for date/time
Robin S replied to BitPoet's topic in Module/Plugin Development
@BitPoet, what do you think about changing from SQL timezone support being a strict requirement for installation to it being a strong suggestion? My shared hosting server doesn't have timezone data but if I comment out the WireException in the install() method then things seem to work okay. The field values are saved with the correct date and time in the database and I can match pages as expected. Not sure if that means that the server's SQL and PHP are set to the same timezone (not sure how to test that). The only issue I noticed is that with the "Default to today's date?" option selected in the field config the field shows an invalid date before a date has been entered: Would that be due to the missing timezone support? -
[SOLVED] NEED HELP for checking if all elements have the same value
Robin S replied to PWaddict's topic in General Support
$all_match = true; foreach($items as $p) { $pp = $this->pages->get($p->product_id); if($pp instanceof RepeaterPage) $pp = $pp->getForPage(); if($pp->my_field != '3') { $all_match = false; break; } } // do something according to the value of $all_match- 1 reply
-
- 1
-
-
New post: Rebuilding processwire.com (part 2)
Robin S replied to ryan's topic in News & Announcements
Ryan, you're an absolute champ for grinding away on the documentation. We all know it's a developer's favourite task. But seriously, thank you. -
What @elabx said. And... ...is that intended to be a sub-selector? If so you need to use square brackets. $query .= 'guests=[party_guests>=1, party_guests<51], ';
-
How to assign custom pageArray to each instance of a repeater
Robin S replied to Sanyaissues's topic in API & Templates
In the getSelectablePages() hook $event->arguments('page') is the page being edited, but that is not so useful in your case because what you want is the Repeater page that contains the two Page Reference fields. Give this a try: $wire->addHookAfter('InputfieldPage::getSelectablePages', function(HookEvent $event) { if($event->object->hasField == 'people') { $inputfield = $event->object; $repeater_page = $inputfield->hasPage; if($repeater_page->team && $repeater_page->team->id) { $event->return = $event->pages->find("template=user, team=$repeater_page->team"); } } }); Note that if the user changes the selection for the team field they will need to save the page before the selectable options for the people field will update.- 2 replies
-
- 3
-
-
- getselectablepages
- pagearray
-
(and 2 more)
Tagged with:
-
[SOLVED] Pagination links render but do not work.
Robin S replied to FireWire's topic in API & Templates
How about getting the url-segments/page-num/get-vars suffix and then appending that to $page->localUrl? $url_suffix = str_replace($page->url, '', $input->url(true)); $redirect_url = $page->localUrl() . $url_suffix; -
Hi Adrian - is the gap between the dump heading and the dump output deliberate? I think it would look better without a gap.
-
Not easy using the core Datetime field type alone AFAIK. The DatetimeAdvanced module by @BitPoet supports querying by month, but see the notes about timezone support in the module readme. An alternative would be to add a hidden integer field to the template and save the month number to that in a saveReady hook, then use that field in your selector.
-
Really great tutorial, thanks! Might be worth noting that a minimum of PHP 7.1 is required for the code syntax used.
- 10 replies
-
- 3
-
-
- beginners
- helper function
-
(and 1 more)
Tagged with:
-
It's working for me here... <?php namespace ProcessWire; class TestModule extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => "Test Module", 'version' => 1, 'autoload' => true, ); } public function init() { $this->addHookAfter('Pagefile::url', function(HookEvent $event) { if(!$event->object instanceof Pagefile) { return; } $file = $event->object; $fileBasename = $file->basename; $event->return = $fileBasename . '?lorem=ipsum'; }); $this->pages->addHookAfter('save', function(HookEvent $event) { $page = $event->arguments(0); if($page->hasField('image')) { // Output formatting will probably be off, but get unformatted value to be sure $pageimages = $page->getUnformatted('image'); // Get first image URL $url = $pageimages->first()->url; // Dump URL with Tracy Debugger bd($url, 'url'); } }); } } You shouldn't use $this as the second argument to addHookAfter() if your hook function is a closure, but I'm guessing that is just an error in the demo code you posted and not in your actual module. Your issue might be due to output formatting being off in the Pages::save() hook which means an Images field will return a Pageimages object which doesn't have a URL property. So if the field holds only a single Pageimage you would get that with first().
-
FYI, you can set the age the temp directory lives for with the maxAge option: $files->tempDir('RockPdf', ['maxAge' => 600]); // or $files->tempDir('RockPdf', 600);
-
Yes, that's what the code in my previous post is for. There's no foreach loop involved. Did you try it? That code provides a way of working out the position of any page relative to a set of pages it is a part of. When you put the code in the template file of a restaurant location page then the page is represented by the API variable $page. If you want to use it in some other template file (e.g. your account template) then you would substitute $page with $p where $p is a restaurant location page.
- 6 replies
-
- 1
-
-
- position in array
- init file
-
(and 1 more)
Tagged with:
-
I understand now. There are a couple of ways you could do this - a simpler way and a more performant way. In the demo code below my selector is for sorting news items by title - you would adjust the selector as needed to find your restaurants. This code would go in the template file for your restaurant location template. 1. Simpler way: probably fine if there is not a huge number of matched pages // Function to get number plus ordinal suffix function ordinal($number) { $suffixes = ['th','st','nd','rd','th','th','th','th','th','th']; if(($number % 100) >= 11 && ($number % 100) <= 13) { return $number. 'th'; } else { return $number. $suffixes[$number % 10]; } } // Define the selector that finds your pages $selector = "template=news_item, sort=title"; // Get all the matched pages $items = $pages->find($selector); $position = $items->getItemKey($page) + 1; // add 1 to adjust for zero index $position_str = ordinal($position); // the position with ordinal suffix echo "This is the $position_str item."; 2. More performant way: if there are a large number of matched pages you can use an SQL query which avoids the overhead of loading all the pages First work out the SQL query for matching your pages: $query = $pages->getPageFinder()->find(new Selectors($selector), ['returnQuery' => true])->getQuery(); bdb($query); // Use Tracy barDumpBig() to dump the SQL query Now tweak the query a bit because you only need the IDs of the matched pages. The finished example for my sorted news items is below: $sql = "SELECT pages.id FROM `pages` LEFT JOIN field_title AS _sort_title ON _sort_title.pages_id=pages.id WHERE (pages.templates_id=45) AND (pages.status<1024) ORDER BY _sort_title.data"; $query = $database->query($sql); // Get the IDs in an array, flipped so the ID is the key and the position is the value $results = array_flip($query->fetchAll(\PDO::FETCH_COLUMN)); $position = $results[$page->id] + 1; // add 1 to adjust for zero index $position_str = ordinal($position); // the position with ordinal suffix echo "This is the $position_str item."; Credits: 1, 2, 3
- 6 replies
-
- 3
-
-
- position in array
- init file
-
(and 1 more)
Tagged with:
-
How to allow image upload in configurable module form?
Robin S replied to JayGee's topic in Module/Plugin Development
Everyone has their own strategies for this sort of thing. Some people like to use modules for site settings and just deal with the limitations around inputfield types. There are a couple of existing settings modules you could study: https://modules.processwire.com/modules/process-general-settings/ https://modules.processwire.com/modules/settings-factory/ Personally I have a custom site profile (generated via Site Profile Exporter) that I use as the starting point for every new project, that has all the fields/templates/pages/modules that I tend to use in every project. -
I don't understand the question - perhaps you can clarify more... How are you measuring and storing the popularity score? Some sort of "likes" system? If the popularity is per location rather that per restaurant brand then you'll need some kind of entry (page most likely, but technically it could be something like a Profields Table row also) for each restaurant location. Let's say it's a page, and it uses template "restaurant_location". Each restaurant location page is a child of the restaurant brand (or the restaurant locations could be under a separate parent and use a Page Reference field to link them with a restaurant brand - with PW there is always lots of flexibility to set things up in a way that suits you). Template restaurant_location has a Page Reference field for location that selects from the City pages, and a "popularity_score" integer field that gets incremented every time someone "likes" it. The listing page for each city gets all restaurant locations relating to that city sorted by popularity_score.
- 6 replies
-
- position in array
- init file
-
(and 1 more)
Tagged with:
-
How to allow image upload in configurable module form?
Robin S replied to JayGee's topic in Module/Plugin Development
Module config settings are stored as a JSON string in a single field in the database. Module config fields don't store data in separate tables as per the fieldtypes you might be used to from using fields in a template. So certain core inputfields that need special support from a fieldtype to store their data can't be used in module configs: Files, Images, Repeater, PageTable, maybe a few more. BTW, personally I would use a standard page/template to store site settings rather than a module config for just this reason. -
Those are some sweet updates Ryan! Seeing as you've been working on transferring the blog posts over to the new processwire.com site, do you think you could add a feature so that blog posts automatically get anchors on every <h3>? There could be an automatic table of contents from those anchors if you think that would be good, but having anchors is the main thing. Because there is so much useful documentation of features within the blog I often want to save references to specific sections within a blog post, or provide a link to a section in a forum reply. Having heading anchors would make it possible to do this.
- 13 replies
-
- 14
-
-
-
The page tree can actually be zero clicks or hovers away... there's an option in AdminThemeUikit to show the page tree in the sidebar. https://processwire.com/blog/posts/uikit-3-admin-theme-updates/
- 17 replies
-
- 8
-
-
-
- cms
- comparison
-
(and 1 more)
Tagged with:
-
New post: Rebuilding processwire.com (part 1)
Robin S replied to ryan's topic in News & Announcements
Excited about the new processwire.com! I agree that the search could be better - especially if processwire.com is to be advertised as powered by ProcessWire. I get why the forum search might be poor because that is not powered by PW, but it has long puzzled me why the Modules Directory search is so poor seeing as that is PW-powered. An example: right now in the "Latest Additions" section we can see a module from netcarver titled "Street Address". So how come when I enter the exact words "Street Address" in the search box that module doesn't appear as the first result, and even doesn't appear on the first page? https://modules.processwire.com/search/?q=Street+Address -
Correct.
-
Listing and filtering contents of repeater fields (similiar to SQL JOIN)
Robin S replied to j__'s topic in General Support
You could use a selector to match the repeater pages (according to their template) and then get their owner pages (the events) with getForPage(). // You need check_access=0 to match repeater pages for non-superusers $repeater_items = $pages->find("template=repeater_event_time, event_time_start>=06:00, event_time_start<=12:00, sort=event_time_start, check_access=0"); foreach($repeater_items as $repeater_item) { $owner_page = $repeater_item->getForPage(); // Use $repeater_item and $owner_page as needed to build the event/time string // ... } -
OR-groups are a feature of PageFinder selectors - selectors that query the database, e.g. $pages->find(), $page->find(), $page->children(). WireArray::find() is a completely different kettle of fish and doesn't support OR-groups. Related: @ryan, it would be good if the distinction between WireArray/PageFinder selectors were covered somewhere in the official documentation.
-
Note that if you have an SQL query that you are finding difficult to turn into an equivalent selector then you do have the option of getting the page IDs via SQL and then loading those page IDs. An example (not that this is difficult to do as a selector)... $sql = "SELECT pages.id FROM `pages` JOIN field_title AS field_title ON field_title.pages_id=pages.id AND (field_title.data LIKE '%a%') WHERE (pages.templates_id=59) AND (pages.status<1024)"; $query = $database->query($sql); $ids = $query->fetchAll(\PDO::FETCH_COLUMN); $items = $pages->getById($ids);
-
There isn't anything inefficient about this (or at least there isn't really a more efficient way of doing it). The value of a Repeater field is a PageArray. When you do anything with a Repeater field value then the whole PageArray is loaded to memory. It doesn't matter if you only want a single page from it - you can't avoid loading all the pages if you get the Repeater field value.
-
This might be relevant:
- 17 replies
-
- 2
-
-
- images foreach
- images
-
(and 1 more)
Tagged with: