Jump to content

Jan Romero

  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by Jan Romero

  1. @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)
  2. 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.
  3. Btw you may want to check $form['email'] instead of the raw input, because it’s sanitized. If your user enters an invalid email, your current code won’t catch it. The sanitizer will return an empty string if it doesn’t think the input is valid, so checking the sanitized value will also catch invalid input even if it’s not empty.
  4. This doesn’t happen after you set the error, by any chance? If that’s not it, try posting the whole code up until the point where the error should be displayed. Also, I would probably prefer to access the email field like this $input->post('email') because $input->post->email() is also the name of a sanitizer method.
  5. Huh, sorry, I thought ProcessWire would figure out the arguments automatically, since their types are distinct. It usually does that. Try passing null in the second argument: $sanitizer->date($input->post->termin1, null, ['returnFormat' => 'd.m.Y']); (Sorry, I’m on vacation, no code formatting on mobile) Anyway, as I understand it, the first parameter is the format you expect the incoming value to be. A sanitizer’s job is generally to make sure the input conforms to some expectation. In this case you don’t care what format the input is, so you don’t tell it your expectation and it will just try to make any valid date out of the input. Additionally you specify the returnFormat to get a pre-formatted string back (this is not always desired because often dates need to be used in calculations or be checked against additional logic). Be aware you might still get null if the input can’t be made into a valid date. Also, if the input is in an ambiguous format, it may get parsed in an unexpected way (in fact, sometimes it seems to default to the current date). But this shouldn’t be a problem because AFAIK browsers all send YYYY-MM-DD when a date input is used. It’s just to say that it’s usually good practice to specify the input format.
  6. Hi, as per the docs you can specify the return format in $sanitizer->date(), just not quite the way you have done it (https://processwire.com/api/ref/sanitizer/date/). This should do the trick: $sanitizer->date($input->post->termin1, ['returnFormat' => 'd.m.Y']);
  7. Ah, nice, definitely! I was hesistant to use the WireArray first() and last() functions, because I wanted to avoid loading all siblings. Not sure if that’s really a concern, though?
  8. This could be a job for the Elvis operator: //if $page->prev-path is empty, get the path of the parent's last child (sorted by sort descending), i.e. loop around to the end echo "<a href='" . ($page->prev->path ?: $page->parent->child('sort=-sort')->path) . "'><i class='fas fa-arrow-left'></i></a>"; //if $page->next-path is empty, get the path of the parent's first child, i.e. flip over to the beginning echo "<a href='" . ($page->next->path ?: $page->parent->child->path) . "'><i class='fas fa-arrow-right'></i></a>"; Btw in your if-condition you're checking for the next and previous sibling of a specific template, but you output the next/previous sibling without this restriction, so if you have mixed templates in this branch of your page tree, you may get unexpected results. I've left out the template conditions in my snippet above, you may want to add them in the appropriate places.
  9. By default, ProcessWire will prevent you from running subcruberList.php like that (you will get error 404 or 403). What you can do is create a ProcessWire template and set subcriberList.php as its template file. Then create a page with that template and do your POST request to that page. There are a couple of threads in the forums about handling forms that may be of help. Also consider using a form module such as FormBuilder.
  10. Hi, welcome to the forums! Are you using ProcessWire for this? It looks like you’re submitting your data to a file called “subcriberList.php”. Can you elaborate on where this file is and what it does?
  11. @ryan Have you considered putting some new screenshots here? It’s a very popular feature judging from showcase threads, developers here love to show off their images to great effect (it was also asked about in this recent thread, for instance), but it gets almost no love in the public docs/store page, and even in the introductory blog post it can only be seen for a split second in the video. The images in the video are also kind of grey in comparison to @olafgleba’s beautiful display 😄 I’m sure showing it off on the store page would boost sales some!
  12. These always trip me up, I get all excited by a big blog post and then it turns out I already know everything from following your lovely weekly threads 😄 Great stuff as always!
  13. Repeater fields give you a PageArray. Have you tried getPageByID($id) to retrieve the item? Check the return value before removing. It might be NullPage, or when using get() it might be null. As a matter of fact, since you already know the ID, it should be perfectly safe to just delete the page: $pages->get($id)->delete();
  14. @fruid Admin pages are just pages in the admin branch of the tree. The ones ProcessWire ships with as well as those of some modules (e.g. Adminer) use a special admin template, but you can just put any old page there. So I would just make a new template with the things you need and create a new page under Admin and set it to hidden and unpublished. When the form is submitted you can get the page by its ID, add the submitted data to it and save.
  15. Well, once you have the submitted data, you can do with it whatever you want. It really depends on what the data is and where you want it. In my comment above the example is one email address and one comment. So if you want to store those things in your admin page, its template would need a way to store multiple email-comment pairs. That could be a Repeater or a ProFieldsTable (👌) or a custom fieldtype. You could also store one new page per submission as a child of your admin page (that’s essentially what a repeater would do behind the scenes anyway, it just looks different in the page tree and page editor – pretty much a matter of preference). Having a page per submission takes care of some stuff you probably want anyway automatically, such as storing the creation date. It also gives you a url for each submission that you could put into an email notification for yourself, or something. My comment gives a pretty complete example of how to get the data from the user’s browser into ProcessWire’s database. Are you struggling with anything specific?
  16. Hi. You're using $input->get('doc') in a couple of places, but the files are sent in a POST request. Also, check out this thread, especially the bit about "new WireUpload()": Additionally please note how the code blocks are formatted in that thread. Please do the same when posting lengthy code excerpts. You can click the button labelled "<>" above the text editor to insert a code block and even choose the programming language there.
  17. In addition to the other very valid comments, this is what’s causing the problem as I understand it. ProcessWire will still prepend _init.php for Ajax requests unless you tell it not to. One way might be to wrap these two lines in an if-block in config.php. That will disable the prepend/append files for all Ajax requests, which seems reasonable: if ($config->ajax) { $config->prependTemplateFile = '_init.php'; $config->appendTemplateFile = '_main.php'; } A more flexible approach may be to forego auto-append and just call those files explicitly when you want them. To expand on @szabeszs comment, $config->ajax works by detecting the header “X-Requested-With”, which browsers don’t send by default. If you’re using XMLHttpRequest, you need to add it like this: var request = new XMLHttpRequest(); request.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); If you use the Fetch API, there is a Headers() object you can pass: https://developer.mozilla.org/en-US/docs/Web/API/Headers Jquery sends the header automatically, which is. I believe, why ProcessWire expects it.
  18. Perhaps you can just run your code after saving? $wire->addHookAfter("Pages::saved", /* … */); Also worth noting is the hook Pages::savedPageOrField.
  19. +1 for installing Decimal by default and perhaps even making Float uninstalled by default.
  20. Hi @xportde. That field is not part of a stock ProcessWire installation, afaik. It is installed by the SystemNotifications module that was introduced in this blog post: https://processwire.com/blog/posts/processwire-2.5.3-master-2.5.4-dev/ The module comes with PW but is not installed by default (maybe it is with some site profiles?). Uninstalling the module automatically removes the field as well.
  21. What happens when you run that code? The delete() method returns a boolean, try logging it to narrow down the problem. Btw, you don’t need to pass $pages to your function. This should work too: $hidden = $pages->find("template=cast, status=hidden"); deleteHidden($hidden); function deleteHidden($hidden) { foreach ($hidden as $item) { $item->delete(); } } Do these pages have children by any chance? In that case you should get an exception unless you move them away first, or specify that you want to delete them as well, using $item->delete(true).
  22. What do you expect $s->cast_language->title to be here? $s->of(false); $s->cast_language = $s->cast_language->title.'|'.$language; $s->save('cast_language'); As I understand it, cast_language allows multiple selection, so it’s nonsensical to access an option’s title without determining a singular option first. Multiple selection options fields have WireArray values, so I feel like this might work: $s->of(false); $s->cast_language = $s->cast_language->implode('|', 'title') . '|' .$language; $s->save('cast_language'); I agree that’s a bit ugly, but there is probably a better way. I’m guessing $s->cast_language->add($language) won’t work because it’s not a WireArray of strings. Probably only works if you pass a SelectableOption. Honestly, just always use $page->save() (in this case $s->save()), unless you have a specific reason not to.
  23. Yeah but still, count_years is always going to flip on New Year’s Day, so if you’ve been placing great value since December 31st, it’s going to say 1 year even though it’s barely been a day.
  24. Btw, just subtracting years from each other may yield unexpected results if you’re thinking in terms of “birthdays”, as most people likely will. That is, considering your example of 1980-07-01, right now you would get 42. If that’s a person’s birth date we would think of them as 41 years old, though. Also, I realize your site is probably not in English, but as I understand it, this is one of the classic “false friends” where “since” feels like the German “seit”, but unlike “seit” it’s not used with time spans: (I. e. you would only say “since 1980” or “since the relaunch”.)
  25. Since these tags are introduced by CKEditor you know they’ll always be there and always look the same (I guess). So you can pretty much just count how many characters you want to skip at the beginning (3) and end (4) and do it without ever mentioning anything about <p> and </p> to PHP: $bodyCopy = mb_substr($pages->get("/nastavitve/")->kontaktni_podatki, 3, -4); Or you can go the replace route: $bodyCopy = mb_ereg_replace('^<p>|</p>$', '', $pages->get("/nastavitve/")->kontaktni_podatki); Note how using mb_ereg_replace you don’t need those annoying slashes. The regex ^<p>|</p>$ just means, “find a <p> at the beginning OR a </p> at the end”, so this leaves all the inner p-tags alone. You can get more fancy if you need to take into account all the ways a HTML tag might appear, but eventually you’ll get into this territory. There is also the ol’ strip_tags function and ProcessWire ships with a Textformatter module called ParagraphStripper, I believe. As well as HTMLPurifier if you really want to get your hands dirty.
  • Create New...