Jump to content


  • Posts

  • Joined

  • Last visited

Everything posted by SwimToWin

  1. Fixed! Documenting it helped clear my mind. update pages set templates_id = 50 where templates_id = 0
  2. Hello Community, I've encountered an issue while using the Custom Page Class to import pages into ProcessWire. Currently, the Custom Page Class does not support the new Page() method, as documented in Issue #1864 on GitHub. Consequently, I've ended up with a significant number of test pages that lack a template assignment (specifically, the pages table has a number of entries with templates_id = 0). When attempting to open these template-less pages via the URL /processwire/page/edit/?id=1234, I receive an Error 500. This error message is shown when opening ProcessWire's admin interface: PagesLoader: You must assign a template to the page before setting field values (title__data) [pageClass=ProcessWire\Page, template=] Here are the methods I've attempted to remove these pages: Deletion in ProcessWire editing interface: Cannot empty Trash due to missing template. Direct Deletion Using ProcessWire API: Attempting to delete pages directly through ProcessWire's API, like so: $pw = $pages->find("template.id=0"); foreach($pw as $p) { $p->delete(); } This approach was not successful. Database Query & Deletion: Running a direct query to identify and delete the pages results in a Server Error 500: $ids = $database->query("SELECT * FROM pages WHERE templates_id = 0"); foreach($ids as $id) { $p = $pages->get($id); if($p->id) { $p->delete(); echo "<br>Deleted: " . $p->id; } } Deletion by Specific ID Range: I also tried deleting pages by specifying an ID range, but this did not resolve the issue: $pagesToDelete = $pages->find("id>1188"); foreach($pagesToDelete as $p) { printf('<br>%s (%s)', $p->title(), $p->id); $p->delete(); } I am seeking advice on how to delete or update these pages effectively. Any insights or alternative methods you could provide would be greatly appreciated! Thank you in advance! PS: I suggested a fix that should prevent such scenarios: Gracefully handling errors in ProcessWire Custom Page Classes (Request #515).
  3. @zoeck, @wbmnfktr - Works. Thanks! How to protect / hide image files (info for others): Method 1: config.php: Add "$config->pagefileSecure = true;" # Go to the Page template Revoke "view pages" permissions for the "guest (everyone)" role to ensure guests have no permissions. Result: Page is now inaccessible unless you're logged in (as expected) When using a direct link to the image file, the Image file is also protected I had to save the page before linked image files became protected (so there seems to be an issue for image files on existing pages) Image files on new pages are protected right away Method 2: Edit the page directly Set Page status to Unpublished Result: Page is now inaccessible unless you're logged in (as expected) When using a direct link to the image file, the Image file is also protected
  4. @Jan Romero Steps to reproduce: Create page with image Edit page to get image url. It will look like so: https://www.example.com/site/assets/files/9999/foo.0x260.png Log out (or open a private browser session). Go to the link Result: Image is shown
  5. @BrendonKoz I'm aware of this possibility that doesn't satisfy the acceptance criteria because the image file is directly accessible (for instance, when a search engine or web spider somehow finds the direct image url). @wbmnfktr Most pages in this website are used for private note-taking and images (think Notion.os, Evernote, etc.). I don't share my private notes.. 😉
  6. How might I hide some/all images in a private Processwire installation used for note-taking? Acceptance criteria * Hidden image file url is never accessible * Hiding images per page is preferred (as opposed to hiding all pages for the site via .htaccess or similar) Suggested solutions (that I currently don't know how to implement): * ProcessWire module controls output of image files * PHP file to control image output ("/img.php?file=img_1234.png")? * .htaccess hinder external access to all image files (will work as a last resort) The Processwire installation in question is being used for personal purposes (think Notion.os, Evernote, etc.).
  7. Hi @Markus Thomas - Thank you very much for pointing out the opportunity to use url hooks. I can make it work on one page, but it keeps failing on the product page and I cannot tell why; I'm using PW v3.0.200. Anyways - using urlSegments() works: #workaround #uglyButWorks #inspiration Code // Match url - example: https://www.example.com/myproduct/r/foo1234 if( in_array($page->template, ['product','redirect']) && $input->urlSegment1()=='r' && $input->urlSegment2() ) { $p = $pages->findOne("template=redirect, title=" . $input->urlSegment2() ); if( $p->link ) { // Page exists according to "page that uses a redirect template" -> redirect to specified destination page. // Support absolute and relative links $p->link = str_replace(['https://www.example.com/','http://www.example.com/','//www.example.com/','www.example.com'], '', $p->link); $p->link = ltrim($p->link,'/'); $url = "//{$config->httpHost}/$p->link"; } else { // Fallback: Page doesn't exist, so redirect to product page $url = "//{$config->httpHost}/{$page->url}"; } printf("<p>Redirecting to <a href='%s'>%s</a></p>", $url, $url); $session->redirect($url); } Setup Redirect template with Title and Link text fields.
  8. Good idea, @Markus Thomas. Unfortunately these url hooks don't work in my use case because the redirect happens "below existing pages", as explained here: $wire->addHook('/existing-page/r', function($event) { return "Hello R"; // Not shown (contents from the "nearest parent page" is shown) }); $wire->addHook('/non-existing page/r', function($event) { return "Hello"; // Works });
  9. Hi, I want to redirect users that hit 1) pages using a specified template 2) when the url is using a specific syntax. Url syntax is: /PRODUCT/redir/PAGEID Example: /foo/redir/1234 My intention is to redirect the user to the specified PAGEID - but I don't know how to user $input in a hook. How might that be done with hooks in ready.php? $this->addHookBefore('Session::redirect', function(HookEvent $event) { $session = $event->object; // (Product template always lives a root level) if( TEMPLATE == 'product' && INPUT->urlSegment1()=='r' ) { $dest = $pages->get(PAGEID); $session->redirect( $dest->url ); } });
  10. When working with Checkboxes ("Type: Page Reference - Input field type: Checkboxes - with Page field value type: Multiple pages PageArray" fields, that is), this works: $rs = $pages->find('template=foo, parent=/bar/'); foreach ($rs as $p) { $p->of(false); $p->myCheckboxes = null; // Unset all values first $p->myCheckboxes = 'baz'; // Then set the active checkbox with name (or, use Page ID) $p->save(); }
  11. Small request: When working with files outside ProcessWire, it would be useful to know the the public / web folder. Having this folder or directory will allow me to work with the "non-Processwire file system". Example: /var/sites/www.example.com/public/ <- (or whatever your hosting provider calls the public directory for a website) I can get the directory with $_SERVER['DOCUMENT_ROOT'] - unfortunately, the $_SERVER variable is easily manipulated and therefore unsafe (needs to be escaped and such). sprintf('%s/%s/', $_SERVER['DOCUMENT_ROOT'], 'whatever'); Currently print_r($config->paths) outputs two array keys that hold (too deep) info about the public web directory: [sessions] => /var/sites/www.example.com/public/site/assets/sessions/ [classes] => /var/sites/www.example.com/public/site/classes/
  12. I'm importing data from an external system into ProcessWire. Each of the imported records have a unique ID. How might I use the unique ID to prevent duplicate records in ProcessWire? What I want: When importing data find the foreign record ID use it to check for duplicates if a duplicate record is detected, skip it import data into ProcessWire by creating a page in /import/ continue to next record ProcessWire: Later I'll move each page to another location ... meaning that '/import/' will be empty the next time, I run an import job Looking into possible solutions: Unfortunately, ProcessWire Unique Text Fieldtype doesn't do the trick. (ProcessWire Unique Text Fieldtype will allow the page to be created - only the field with a duplicated field value will be blank. In my case, the duplicate record needs to be blocked / *not* created.) Could it be solved by modifying the code for ProcessWire Unique Text Fieldtype?
  13. Solution: has('name') does the job, that's also self-explanatory .. compared to using IDs, as I did in my tests above. var_dump( $page->config->has('foo') ); // bool(true)
  14. Thanks Andreas @AndZyk - both for solution and find() explanation; never used find() much
  15. It's incredible what you can do with ProcessWire. I did hit a limitation on my side though... ? and would like to ask for some support: Problem: I'm using a Page Reference Checkboxes field that gets it's Options from a few Pages; Page field value type is set to "Multiple pages PageArray". Screenshot: What I want: to check if each checkbox is checked or not (without using a foreach loop). What I tried: var_dump( $page->config->has(1898)); var_dump( $page->config->getValues()); // (WireArray is output, I don't know how to use that.) var_dump( $page->config->getValues(1898)->id ); // Warning: Attempt to read property "id" on array var_dump( $page->config->get(1898) ); // NULL var_dump( $page->config->get(1898)->id ); // Warning: Attempt to read property "id" on null var_dump( $page->config->first()->id ); // int(1898) ... better, but how to get the next value? var_dump( $page->config[1898] ); // bool(false) var_dump( $page->config->find(1898) ); var_dump( $page->config->find(1898)->id ); var_dump( $page->config(1898) ); NULL (checkbox is set) var_dump( $page->config->1898 ); // unexpected integer "1898", expecting identifier or variable or "{" or "$" var_dump( $page->config->find(1898)->id ); // Fatal Error: Uncaught Error: Call to a member function find() on null var_dump( $page->config->has(1898)); // Fatal Error: Uncaught Error: Call to a member function has() on null $a = $page->config->getValues(); echo isset($a->1898->id) ? 1 : 0; $a = $page->config->getValues(); echo isset($a->1898->id) ? 1 : 0; // Parse Error: syntax error, unexpected integer "1898", expecting identifier or variable or "{" or "$" echo isset($a[1898]->id) ? 1 : 0; // 0 (but checkbox is set?) echo isset($a[1898]['id']) ? 1 : 0; // 0 (but checkbox is set?) var_dump( $page->config->eq('foo')->id ); // int(1898) var_dump( $page->config->eq('foo') ); // wirearray var_dump( $page->config->has('foo')); // bool(true) // Is this a bug? eq() returns same Page ID for two names. echo $page->config->eq('foo'); // 1898 (correct) echo $page->config->eq('bar'); // 1898 (incorrect, the ID is 1899. ... and thanks for always being a helpful, constructive, and knowledgeable community! Make a great day! ?
  16. When I use the suggested solution, then I loose the default markup from main.php. How might I keep the default markup from main.php
  17. `<?php var_dump($page->content3); ?>` outputs NULL. It seems $page->content3 isn't populated?
  18. I use these Markup Regions and Bulma CSS Framework in _main.php: <section class="section"> <div class="container"> <div id="content1" class="content"></div> </div> </section> <section class="section"> <div class="container is-fluid"> <div id="content2"></div> </div> </section> <section class="section"> <div class="container"> <div id="content3" class="content"></div> </div> </section> I want to specify HTML tags required by a CSS framework - and it shall be output only when the Markup Region produces an output. I want the full SECTION to be hidden in case the region doesn't output - because if the SECTION tags are output then it will affect the layout in unintended ways. So my question is, how can I hide SECTION tags when the region doesn't produce an output? To me, the challenge here is that Bulma requires a layout structure before Content 1-3 are output (specifically, the SECTION and DIV.container tags) - and it seems this pattern is always output by Markup Regions - which is causing the mentioned issues. Feel free to suggest alternative ways to work with Markup Regions and Bulma (or other CSS frameworks).
  19. Regarding multi-language fields such as TextLanguage, TextareaLanguage, and PageTitleLanguage: When multi-language fields are shown in Page Edit mode, I often use them next to non-multi-language fields. That makes the page appear a bit disorganized and cluttered because multi-language fields vs non-multi-language fields don't align horizontally. The reason is that multi-language field have "language switcher tabs" that forces the field to "jump down" whereas normal fields stay in the normal position. See screenshot 1. It makes me sea sick! ? Suggested solution is to move the "language switcher tabs" up so that it aligns with the field label. See screenshot 2.
  20. @dragan - That'll work. Thanks! I use the snippet below that copies the full Image object so that all Image properties remain intact for use in the subsequent foreach(): foreach ($page->children() as $p) { $imgs = $pages->get($p->foo->id)->images; if( isset($p->foo->id) && $imgs ) { $gmi = []; foreach ($imgs as $img) { $gmi[] = $img; } foreach ( array_reverse($gmi) as $v) { echo "<img src=\"{$v->width(140)->url}\" alt=\"{$p->foo->title}\">"; } } }
  21. How might I programmatically output images from an Image field from another template in descending order? I want to reverse the order of images on the front-end page (see code below). I want to keep the order in ProcessWire Admin. The Image field accepts multiple images. Code: foreach ($page->children() as $p) { if( isset($p->foo->id) && $pages->get($p->foo->id)->images->count>0 ) { foreach ($pages->get($p->foo->id)->images as $img) { echo "<img data-src=\"{$img->width(140)->url}\" width=\"\" height=\"\" alt=\"{$p->foo->title}\" class=\"uk-align-right uk-visible@m\" uk-img>"; } } } Things I tried (that didn't have an effect): $pages->get($p->foo->id)->images->sort("sort=-sort") $pages->get("id={$p->foo->id},sort=-sort")->images I also wanted to try a for() loop but didn't know how to.. # Failed attempts: $pages->get($p->foo->id)->images[0]; $pages->get($p->foo->id)->images->1; # This works - but only for first and last (not a third image) and I would need to check if each image existed. $pages->get($p->foo->id)->images->first; $pages->get($p->foo->id)->images->last; I am aware that ProcessWire isn't specifically designed for working with child pages this way - it's probably even a bad practice - it's just that it almost always works very, very well. ? PS: Would you normally set the width and height attributes, or leave them out?
  22. @adrian's script works like a charm when executed from a template page - I followed these steps: Step 1 - Create new template with same fields set as on the repeater field. * Field names must match (if they don't, you might map them manually). Step 2 - Add the script to a Template. * I set repeater field name and page template name. * The script will attempt to copy all "repeater pages" found by '$page->$rf'. So, I used a template file that could access the repeater fields with '$page->$rf'. Step 3 - Run the migration by visiting the page. * At this point, I removed the script and inspected the results. Results: * All fields were migrated (saved me a ton of detailed copy-paste work!). * Title field was set to a code ("1234-9234") because my Repeater didn't have a Title field - but it was easy to update manually. * Url name field was set to a code ("1234-9234") - and updated after I manually pressed Save on each page. * Even language fields were correctly migrated. Nice! <?php $rf = "my_source_repeater_fieldname"; //repeater field name $pt = "my-destination-page-template"; //page template name foreach($page->$rf as $r){ $np = new Page(); $np->of(false); $np->template = $pt; $np->parent = $page; foreach($r->fields as $f){ $np->$f = $r->$f; } $np->save(); }
  23. Where I am: Edit Page -> Settings -> Parent -> "+Change". Edit Field -> Page Reference field -> Input tab -> "Selectable pages (Select the parent of the pages that are selectable)" -> "+Change". ... and possibly other locations where the Page Tree is used. Quality of life improvement: When modifying Parent Pages (Edit Page) or Selectable pages (on a Page Reference field) and I press "+Change" to change the Parent Page, it would be nice if the current Parent Page came into focus without effort. Current solution: As an editor, I am required to find the Parent Page / "Page Reference parent page" manually which makes me think ("where did I put that page?"), takes a bit of time ("click, click, click"), and is hard on a larger site with a deep structure. The unmet goals are: I instantly see the context for the current Parent Page. I can effortlessly select another Parent Page. Constraints: Large website makes it hard to navigate and get a view of the Page Tree. I don't want to pick an incorrect Parent Page. It's sometimes difficult to see if I choose the right parent. The Parent Page must be in the current "Page Branch" ("/foo/bar/baz/" -> "/foo/quz/baz/"). I don't always need to see/browse the full Page Tree. Sometimes a lot of parent pages are unnessarily shown (larger websites with 4-5 levels of pages). Better: When I open the Edit Page / Edit Field page and click "+Change", I want the tree structure to expand (in a modal?) and bring the current Parent Page into focus. It's one of those small things that help create a smooth user experience. Additional thoughts: The displayed Page Tree only shows the current Page Branch; this might optionally be specified on the Template. Hide "unneeded" parent pages in a larger websites with 4-5 levels of pages (how?). Perhaps you have additional ideas that might improve working with Parent Pages when editing a page or a field?
  24. 1) It seems, the SEO reason that I gave is being taken very literaly. To me, it's more a matter of having built-in flexibility to structure pages without necessarily exposing the structure. I may not want to expose the parent page in the front-end. 2) "Virtual Pages" aligns with Ryan's "no assumptions" design principle. ProcessWire allows the admin to structure pages - but doesn't make (too many) assumptions about how these pages are output in the frontend. Or, to put it in the words of Ryan, "ProcessWire doesn't control the front-end, there are very few assumptions that can be made from an editing perspective." See also: No assumptions (cute interview!). 3) Short urls are cool - SEO or not - and "Virtual Pages" help me achieve that. Consider these versions of the same url: Long: www.example.com/book-reviews/wheres-wally-in-hollywood/ Short: www.example.com/wheres-wally-in-hollywood/ 4) WordPress has a bunch of change / shortify your urls tools - some quick examples: https://wordpress.org/support/article/pages/#changing-the-url-of-your-pages https://wordpress.org/plugins/url-shortify/ @bernhard URL hooks are nice. Thanks for that pointer. @wbmnfktr Thanks for the VirtualParents module link. I'm trying not to use plug-ins and would prefer to have this flexibility built-in (or use hooks). Thanks for constructive inputs and perspective. I'll rest my case.
  • Create New...