Jump to content

Jan Romero

Members
  • Posts

    672
  • Joined

  • Last visited

  • Days Won

    18

Everything posted by Jan Romero

  1. A page’s status is a bit field technically you need to check whether it contains the hidden status. You can do this with ProcessWire selectors using the bitwise AND operator and negating the result: $page->parents('id!=1, !status&1024') Instead of the number 1024 you can also use the named constant: $page->parents('id!=1, !status&' . Page::statusHidden)
  2. Does your Earth page use the template "planet" that you set up in Step 2? I imagine this is the problem. Check the page’s settings tab, it’s probably "basic-page". If that’s not the issue, did you use all the same names from the tutorial? ProcessWire auto-detects the template file from Step 1 and uses it for the template in Step 2 if they have the same names (without the .php extension). So your template should be named "planet" and the file in /site/templates/ should be named "planet.php". Although if ProcessWire couldn’t auto-detect the template file, you shouldn’t be able to view the page at all.
  3. Hi, welcome to the forums! ProcessWire is very mobile friendly. I can only speak about the Default theme, which works flawlessly on a phone. I’m sure the other stock themes work similarly well or even better. However, it’s your responsibility to make the actual public site you build with ProcessWire mobile friendly yourself. ProcessWire won’t get in the way of doing that, because it doesn’t come with any assumptions about your frontend. I’m not sure I fully understand your question here. There is nothing wrong with setting up links to a separate shop system and ProcessWire will definitely work well for you there, but if you’re planning on building your own web shop, check out Padloper 2:
  4. Sorry, I was a bit terse. To be clear, I meant storing your custom path in the $config->paths object, somewhat like this: // config.php (or init.php) $config->paths->set('home_sidebar_timeline', $includes_path . 'home_sidebar_timeline.php'); Then you should be able to get it from anywhere anywhere like this: include $config->paths->home_sidebar_timeline; //or include $config->paths->get('home_sidebar_timeline');
  5. I imagine global variables might work, but I would probably but it into $config->paths: https://processwire.com/api/ref/paths/
  6. Hi everyone, I’ve come across this phenomenon where WireCache never builds cache entries if they were previously attempted to preload. Just wondering if anyone has any experience with preloading WireCache items? Am I doing something wrong? I’ve described the issue here: https://github.com/processwire/processwire-issues/issues/1604 Here is the code I’m using: cache()->preload([ 'imaginary', 'names' ]); //these don’t exist. //now cache()->preloads is [ 'imaginary' => '', 'names' => '' ] $freshlyGeneratedValue = cache()->get('imaginary', WireCache::expireDaily, function() { return 'so fresh'; //this never happens }); var_dump($freshlyGeneratedValue); // string(0) "" Thanks!
  7. Apparently ready.php is too late for direct page views, so I would recommend init.php.
  8. I dunno, it works for me. I did add names to the inputs, because they wouldn't get serialised without them, but the javascript is the same as yours: Note that action="/ajax-handler/" with the "/" at the beginning will submit the request to "example.com/ajax-handler/" regardless of the original url. If you want to request a relative path, remove the first "/".
  9. I think you don’t need to manually set the Content-Type header if you send a URLSearchParams object: secondAJAXXHR.send(new URLSearchParams(request)); (no support in the old IE though)
  10. Yeah, you’re right, the piggybacking I mentioned only works with full page saves… Guess you’ll have to call save() after all. You can do so by specifying the noHooks option, so that you don’t call your hook infinite times: $user->setAndSave('title', 'that user who keeps changing their bookmarks', ['noHooks' => true]); You can also hook savedPageOrField(), in which case the names of the changed fields will be in $event->arguments(1).
  11. Do you specifically need to use that nested hooks technique? If you want to update related user fields when a specific field is about to be saved, you can just hook savePageOrFieldReady() and evaluate the changes: wire()->addHookAfter("Pages::savePageOrFieldReady(template=user)", function(HookEvent $event) { $user = $event->arguments(0); if (!$user->isChanged('user_bookmarks')) return; //bookmarks weren’t changed, nothing to do $user->of(false); $user->set('title', 'that user who keeps changing their bookmarks'); }); Note you don’t need to call save() or anything, you’re piggybacking off of the hooked save operation. <-- doesn’t work if the hook was triggered by a field save. Otherwise, did you remove the nested hook according to the example in the docs?
  12. Hi, this works for me: wire()->addHookAfter("User::changed(user_bookmarks)", function(HookEvent $event) { $user = $event->object; // User $old = $event->arguments(1); // old value $new = $event->arguments(2); // new value wire()->addHookAfter("Pages::savedPageOrField($user)", function(HookEvent $event) use($user, $old, $new) { var_dump($user); var_dump($old); var_dump($new); var_dump($event); }); }); Btw there is also savePageOrFieldReady(). Might be of interest if you want to modify the user.
  13. I think you fell victim to one of the classic blunders. SetAndSave() specifically only saves a particular field, and field-saves don’t trigger the saved() hook. Check out savedPageOrField() to catch both types of save operation: https://processwire.com/api/ref/pages/saved-page-or-field
  14. Must be a mistake in the blog post, I’m pretty sure Ryan meant the “Details” tab: (the screenshot is from 3.0.191, though)
  15. Yeah, you can probably replace that line with this if($page->id && $page->if('ImportPagesCSVData')) { to make it work on your end. For a permanent solution the module will have to be updated.
  16. Feels like one of those Errors that used to be Warnings before PHP 8. Do you have a detailed error message with the line number? Count appears 4 times in the Module, but it should be an easy fix either way to add some null-checks or is_countable(). @ryan
  17. There is a lot going on here. You mentioned that visitors (guests or logged-in users?) will be able to subscribe to multiple events at once, but you will likely only want to verify the email once. AFAIK the only way to verify emails is to actually send a secret to the address and have the recipient send it back. So I would do a poor man’s solution somewhat like this: Create one page per recipient that stores the address and a secret token (ProcessWire can generate one for you like this: (new Password())->randomBase64String()) When the user has entered their address and you have created the page, send them a link like https://example.com/verify?mail=myemail@example.com&mytoken=xyIu6yehxXfTelYpqcOdv8 When that link requested, find the recipient and consider them verified if the token matches (i.e. set a checkbox or just delete the token and consider everyone without one verified) Store event subscriptions as multiple page references either on the recipient or on the event, whatever As long as these transactional mails don’t go overboard you should be fine. If you don’t need any personalisation, you might actually send the event reminders as a single email per event, just dumping everyone into BCC. If you’re thinking of growing the business, you will want to go with a dedicated solution such as https://de.sendinblue.com/preise/ (a German company formerly known as Newsletter2Go, should be fine GDPR-wise). Mass mailing is serious business. You don’t want to get blocked by Gmail or something, so above some threshold it’ll be worth shelling out for a service whose business is making sure emails go through. You mentioned you’re on shared hosting. Do you have cron jobs at all? Some shared hosting providers offer something like “cron jobs lite”, where you get a configuration form and the only action you can perform is an HTTP request. In that case you just expose some URL from your site that will send emails upon request.
  18. Since you have the codes separated by spaces, word matching selectors may work well for you. Check out “~|= Contains any words”, “**= Contains match” and “~= Contains all words” in particular. You could also hook after Pages::savedPageOrField and transform the textual list into page references whenever it changes.
  19. Are you on the latest version? That looks very similar to the error I mentioned above.
  20. Mh, this might be a ProcessWire bug? This configuration causes multiple database queries to be executed. The query you end up with contains a list of all pages that reference the "Global" report_type. To get this list, a different query is run beforehand and that one doesn’t seem to get the right results for guest users. I assume this is because guests don’t have access to the repeater pages (a hidden page called "Repeaters" under the "Admin" branch), but I haven’t been able to figure it our completely. As a workaround, you can use "include=all" instead of "check_access=0", but be aware that this may have unintended effects because it will find pages that are hidden or unpublished. You can also get the IDs yourself and use them like so: $ids = pages()->findIDs('template=report_type, title=Global'); //adjust selector according to your setup $reports = pages()->find('parent.name=reports, report_meta_details.report_type=' . implode('|', $ids)); //note: don’t use “report_type.id=” Can you confirm that your "report_type" pages have no access restrictions and are not hidden or unpublished?
  21. This surprises me. To debug this, it may be useful to look at the generated SQL. You can do this easily with Tracy Debugger (I guess you would have to enable it for guests temporarily?), but you can also do it in code:
  22. BTW, you don’t need write “name=” here, $pages->get('reports') should be sufficient, unless you like the added clarity.
  23. Almost exactly 6 years ago Ryan released pagination support for ProFields Table and was thinking about implementing this for more Fieldtypes such as Images: https://processwire.com/blog/posts/fieldtype-pagination/ Unfortunately this hasn’t happened yet, so maybe commission a website from Ryan that involves 600 images per page and he'll prioritise the feature ? The first thing I would do to remedy the immediate problem would be to move the images to a separate tab in the page editor. That should keep the loading times down when you just want to change some other stuff. Otherwise, I guess you’ll have to build a custom Inputfield (perhaps without thumbnails) or structure your site differently. Here is a longish thread about turning off the Image field's auto-thumbnails, maybe it has some pointers relevant to your endeavour: https://processwire.com/talk/topic/21112-do-not-create-default-image-variation-on-image-upload/ You could also try using a Files field instead. I imagine the page editor performance will be better and it won’t auto-generate thumbnails. Of course, you’ll have a harder time scaling and using the images in the front-end. Check this thread for more info https://processwire.com/talk/topic/26113-resize-image-manually/
  24. @bernhard Admittedly, I had never really paid attention to php://input, so this thread prompted me to google it. As I understand it, that stream always contains the raw request body, so anything could be in there, however only two content-types end up in $_POST and thus also in PW’s $input->post: application/x-www-form-urlencoded and multipart/form-data. For these, in addition to sorting everything into an associative array, PHP also takes care of unescaping the URL encoding. When OP wants to send Json, I’m assuming he quite sensibly declares application/json. PHP doesn’t know this content-type (plus, the whole thing is a nameless Json object, so what would be the key for $_POST’s associative array?), so nothing happens automagically. This answer on SO gives a lengthy overview on how to handle php://input. If you’re asking about the client-side fetch() API, I have to confess I didn’t test the code I posted, but the idea is to create a request with the content-types application/x-www-form-urlencoded or multipart/form-data mentioned above. Indeed, for some reason I thought it would be necessary to specify the former content-type, but it’s actually set automatically when URLSearchParams are used for the request body (at least in Firefox). Likewise, when the body is of type FormData, the default content-type will be multipart/form-data. As for when to send a body, it’s just the HTTP request’s content, so I guess whenever you want to transmit data to the server, i.e. usually with POST (or PUT or something). When dealing with third party APIs you gotta do the weird things they want you to, of course. If it’s your own PHP/ProcessWire site you send requests to, I’d say it doesn’t really matter whether it’s application/x-www-form-urlencoded or multipart/form-data (or URLSearchParams or FormData for that matter), since both deliver keys and values that end up in $_POST/$input->post. In this case I would just use whatever is more convenient to assemble in JS, i. e. if the data actually comes from a HTML form, you can pass the form element to FormData’s constructor and you’re done. Sorry if I’m not telling you anything new here ? Trial and error makes up a large chunk of my modus operandi as well m)
  25. Well, you can just send your POST request in such a way that the Json will be available as $input->post['myData'], that is, as FormData or UrlEncoded: fetch('https://example.com', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest' }, body: new URLSearchParams({ 'myData': JSON.stringify(someObject) }) }); or const formData = new FormData(); formData.append('myData', JSON.stringify(someObject)); fetch('https://example.com', { method: 'POST', headers: { 'X-Requested-With': 'XMLHttpRequest' }, body: formData }); If your object is just a simple key-value affair, you may actually want to send it that way and not as Json at all, because you’ll be able to use the sanitizer methods for each value. With the Json you have to parse it and then sanitize the properties, watch out for properties you didn’t want etc.
×
×
  • Create New...