-
Posts
695 -
Joined
-
Last visited
-
Days Won
20
Everything posted by Jan Romero
-
Thanks for the quick response! Yeah, everything is set to utf8mb4, gotta have my emoji ??? I’m also using InnoDB, btw, but I feel like if it were a database issue I would either see corrupted data or an actual error in the logs. Anyway, I’m leaning towards this being some sort of exotic Tracy/PHP 8/mb4 bug. Guess I’ll try going back to PHP 7 to confirm that suspicion and see if I can narrow it down somehow. Unless in your case Tracy and PHP 8 weren’t involved? In the end it doesn’t trouble me too much, because non-superusers seem unaffected…
-
Hey @Zeka, did you ever solve this? I’m seeing the same problem now, after switching to PHP 8. The page is saved successfully, but PW logs me out in the next request (the redirect after POST). Only happens when emoji are present. Edit: Did you run Tracy Debugger by any chance? For me it seems to happen only when Tracy is enabled.
-
Hello @Ksenia! That’s a browser feature that’s supposed to prevent users from submitting the same form twice. I believe the quickest way to get rid of it would be to add a redirect to the same page after saving: $session->redirect('./', 303); That sends a 303 HTTP status code telling the browser to reload the page using a GET request, which MDN recommends for this purpose, as I understand it. Be aware that ProcessWire exits after a call to $session->redirect(), so no code below that line will get executed. Hope it works for you, I haven’t tested it though!
-
Another cool way to do this would be to let ProcessWire take care of the main selector string, because you don’t really want to write page status checks and all that stuff yourself. $query = $pages->getPageFinder()->find('template!=admin, has_parent!=2, include=all', [ 'returnQuery' => true ]); $statement = $query->leftjoin('field_title on field_title.pages_id = pages.id') ->where('char_length(field_title.data) > 10') ->prepare(); $database->execute($statement); $ids = $statement->fetchAll(\PDO::FETCH_COLUMN); $results = $pages->getByIDs($ids); For this purpose you could also do the join and the condition in one call using join().
-
Hi, welcome to the ProcessWire forums! The questions in your recent threads are kind of broad and it’s difficult to tell what exactly you’re struggling with and what you already know. I’m assuming you have ProcessWire installed and working, and you want to save some user inputs from the frontend into the fields you have created in PW’s admin area. Saving fields using the ProcessWire API First of all, you need a page to hold the data. Perhaps this page already exists, then you just get it using selectors, or maybe it’s the page you’re already on. Likely you want to save a new page for every time a user fills out the form, so let’s create a page: $p = new Page(); $p->template = 'form-submission'; //or whatever your template is called $p->parent = wire('pages')->get('/submissions/'); //or whatever the parent page is called Nice. Now, to get the information from the form you’re going to need ProcessWire’s input capabilities. You can find out all about it at the link and you’ll need to make some decisions about validation/sanitization depending on the data you’re dealing with, but the gist is to get stuff from the POST request sent by your user and put it into fields. Let’s say your user submits their e-mail address and you want to save it to a field called email: /* You see the name “email” three times: * 1. The first is the field you set up in the admin area. * 2. The second is the sanitizer that makes sure the thing the * user sent you actually looks like an email address. * 3. The third is the name of the input from from the form the * user filled out and submitted. */ $p->email = $input->post->email('email'); //Now you will probably want to fill out some more fields the same way: $p->comment = $input->post->textarea('comment'); $p->title = 'Form submission from ' . date('Y-m-d H:i'); Then you save the page and you’re done. You can go to the admin backend and check out the newly created page. $p->save(); However, we haven’t talked about the frontend bits yet. Creating a frontend form and sending submissions to ProcessWire Once again much depends on what you actually want to do, but for simplicity’s sake, let’s say this all happens on the same page. You have a ProcessWire template associated with a template file and all the above code is in it. Now we put the form into the same file. Basically the form is sent to the same page it’s coming from, but as you’ve seen above, you can still create the new page wherever you want. So here’s a simple HTML form that submits to the same page: <form method="POST" action="<?php echo $page->url; ?>"> <label for="email">Your e-mail address</label> <input name="email" type="email" /> <label for="comment">Your comment (no swearing!!!)</label> <textarea name="comment" rows="5"></textarea> <input type="submit" value="Send"/> </form> Note how the names of the input fields match the names we accessed earlier using $input->post(). Putting it together If you simply copy all my code blocks into your template file, you’ll probably notice that it tries to create a new page ever time the page is loaded. You’ll need to figure out if there is a form submission at all before you deal with it, and otherwise just skip that part and show the blank form. You may just check if there is anything in the comment variable. So here is your complete template file: <?php namespace ProcessWire; $thanks = ""; if ($input->post('comment')) { $p = new Page(); $p->template = 'form-submission'; //or whatever your template is called $p->parent = wire('pages')->get('/submissions/'); //or whatever the parent page is called $p->email = $input->post->email('email'); $p->comment = $input->post->textarea('comment'); $p->title = 'Form submission from ' . date('Y-m-d H:i'); $p->save(); $thanks = "Thanks a bunch, we value your feedback!"; } ?> <!doctype html> <html> <head> <title>Post a comment</title> </head> <body> <?php if ($thanks !== "") { echo "<h1>{$thanks}</h1>"; } ?> <form method="POST" action="<?php echo $page->url; ?>"> <label for="email">Your e-mail address</label> <input name="email" type="email" /> <label for="comment">Your comment (no swearing!!!)</label> <textarea name="comment" rows="5"></textarea> <input type="submit" value="Send"/> </form> </body> </html> Now I’m not saying you should put this exact code on your website, but it’s a demonstration of the most bare-bones things you’ll need to get input from users: A HTML form that generates a POST request and some PHP code to receive it. It doesn’t matter where these things are or what they’re called or how they’re generated. In this example we’ve written the form by hand because it’s easy, but you could just as well generate it from ProcessWire’s fields.
- 13 replies
-
- 10
-
-
Wherever you append ”id=“ to the selector string must be inside a loop. You only want to append it once after all the IDs have been collected. That is to say, I believe you probably have a foreach somewhere that either needs to be removed or closed earlier. It’s not in the lines you posted here, though.
-
Hi. Not sure how this relates to the original issue, but this selector string can never get any results, because it is asking for a page that has both no ID (”id=“) and ID 1705 at the same time!
-
Since the “I don’t get it” message is displayed, $final_output is the same whether the second-to-last line is commented out or not. So if nothing else happens to $selector_org that we’re not seeing, the results should be the same as well. Above, you called the results $matches. Can you put the following line immediately after the $pages->find() call and compare the output? var_dump($matches->getSelectors()); See the docs here: https://processwire.com/api/ref/page-array/get-selectors/ To help you debug you may also want to install the Tracy Debugger module. It can show you the selectors that were executed along with their SQL statements.
-
How get the name of a DOM element for use in hook
Jan Romero replied to abmcr's topic in General Support
Hi, I’m on my phone, but I think you might want to hook ProcessPageEdit::getSubmitActions and change the label in the returned array. It will look like this: $event->return['view']['label'] Apologies if this is not 100% correct – I’m looking through the code on a first gen iphone SE ? You should also be able to change the text using ProcessWire’s translation capabilities. -
I just ran into a PHP 8 issue with a line I contributed to this module. I opened a PR with @thetuningspoon’s original repo but I see the same error will arise in @MarkE’s fork, so @MarkE you may want add ”->name“ to the relevant line, too.
-
I would do the user agent thing. The age “verification” is pure CYA anyway, so the less it’s triggered, the less annoying it is for everyone involved. I doubt anyone will get in trouble over it being bypassable by spoofing the UA as opposed to disabling JS or just spoofing the cookie. edit: I just checked out Jack Daniels and Campari. Both use a JS modal. Jack Daniels’ can’t be completed with JS disabled, Campari’s doesn’t appear at all (however, without JS the site turns into an unusable mess anyway). Both sites load everything regardless of the modal so if you were 12 and too dumb to lie, you could still click view source and read all about the booze. I’ll pour one out for all the brain cells that died for nothing thinking about these things.
-
Hi, welcome to ProcessWire! A page reference field IS a many-to-many relationship. Say you want to model Students and Courses: each Student can enroll in many Courses, each Course can have many Students. You put a page reference field in your Student template and make multiple Courses selectable. Now you can get all Courses a Student is enrolled in: $studentPage->courses And all Students enrolled in a Course: $pages->find("template=student, courses=$coursePage") A feature that is often requested is the ability to edit or at least view this relationship from both sides. In my example, the Admin area will only show Courses while editing a Student, but when editing a Course you can’t see its Students . There are Modules that fix this, such as this one by @Robin S: https://processwire.com/modules/connect-page-fields/. It will synchronise two page reference fields so the relationship will actually be stored from both sides.
-
Usually when you use a page reference or URL field, you do so to model a specific relationship. That way it is often sufficient to have a fixed link text describing that relationship, or to generate it based on the target page. For example, links might always just say “more info” or “related: <?=$page_reference->title?>”, or the domain name extracted from a URL field. If you want arbitrary link text that is editable by users, your solution seems perfectly fine.
-
Try adding status>=hidden to your selector. I haven’t tested this with many pages, nor with an additional field selector, but it gives a much better index utilization than the query without. 17 examined rows vs. 2000 (this is on MariaDB 10.5.11). Clearly only values over 1024 (hidden) can contain the 1024-bit, so the result set should be the same.
-
So are you looking for hidden pages or unpublished pages? Because for pages that have never been published, this may be faster: $pages->find('published=, include=all'); The selector status=unpublished will turn into SQL as where pages.status & 2048. Now I don’t know what optimizations MySQL can do there, but it I suppose it will still have to look at a bunch of values and see if they match, whereas published=, include=all turns into pages.published IS NULL, so it should be a matter of returning a continuous range of rows from that index. Even better if you only want the ID, then it should never even touch the actual table.
-
A good feeling to have! Thank you for your tireless improvements to PW!
-
I haven’t used it yet myself, but there appears to be a module for this exact purpose by @Robin S :
-
Well, you’re going to have to fight ProcessWire at least a little bit to do something like this. PW makes it easy for you to make the pages accessible at example.com/building-1 by using UrlSegments or the new PathHooks, but the page will still have the path /buildings/building-1 internally, and every time you use $page->url or $page->httpUrl, you’ll get the “real” path (according to the page tree). So it depends on how far you want to go. If you just want buildings to be accessible as though they were somewhere else in the page tree, while also being accessible at their “real” path, you just use one of the two techniques I linked above and you’re done. You still have to watch out for pages whose actual path collides with the “shortcuts”, but it’s probably not going to be a problem unless you have buildings called “contact-us” or something ? If you want to completely hide the buildings’ real urls, it gets more complicated. You might throw Wire404Exceptions or simply have no template file associated with the building template (although that will lead to other problems, like I believe it will make $page->viewable always return false). Also may need to find a way to generate your “fake” paths and use them instead of the usual $page->url everywhere (e.g. for the canonical tag, sitemaps, every time you link to a building...). If your buildings use UrlSegments or have children themselves, more problems arise. It may be worthwhile to have all buildings be children of the home page and build a way to deal with the crowded page tree in the Admin instead.
-
More generally, there is a selector for this exact thing: has_parent https://processwire.com/docs/selectors/#finding2
-
ProcessWire is giving Error 404 on page number 1000
Jan Romero replied to 助けて's topic in General Support
There is a configurable limit on page numbers that you can increase from the default 999: -
API save back new arrangement of images field
Jan Romero replied to benbyf's topic in General Support
Huh, I thought you could just do $img->sort = 1 and save the field, but doing this does indeed require a small hack as described by Ryan here: So you can totally just send a bunch of numbers and figure the new order out on the server: $newOrder = [2,4,1,3,5]; $page->of(false); for ($i = 0; $i < count($page->images); $i++) { $page->images->eq($newOrder[$i]-1)->sort = $i; // the sort property doesn’t exist on PageImage, we just introduce it so we can call sort on it below } $page->images->sort('sort'); // this is the key to the whole thing $page->save('images'); Obviously IRL you would have to validate the input etc. -
API save back new arrangement of images field
Jan Romero replied to benbyf's topic in General Support
What’s the bit you’re asking about specifically? A general strategy could be to markup your frontend form the same way ProcessWire does it in the admin (i.e. the names of the inputs) and let PW do the server-side work somewhat like this: $yourImageField->processInput($input->post); /* upload errors must be handled separately, but you only want * to rearrange existing images, so you’ll probably want to * reject submissions with new images somehow. */ if (count($yourImageField->getWireUpload()->getErrors())) { $errors++; $yourImageField->error('Upload failed, tough luck.'); } if (count($yourImageField->getErrors())) { $errors++; } else { // successful form submission, so populate the page with the new values. $page->set($yourImageField->name, $yourImageField->value); } if ($errors === 0) $page->save(); You’ll notice that PW uses hashes to identify individual PageImages. It keeps track of the name of the image field and the image’s hash in the name of an input element that contains the image’s sort value: <input type='number' name='sort_<?=$yourImageField->name?>_<?=$image->hash?>' other-stuff-such-as-value /> For your use case it will likely be cleaner to just have a form with one number input per image, named after the hash, and hand rolling the sever-side processing. In fact, it may be easier to identify images by file name. Not sure how PW gets from the hash to the image. Since you’re likely using JavaScript to rearrange the images anyway, you might even get rid of the input element alltogether and just build the POST parameters from the actual order in the DOM before submitting. -
You're going to have to wrap the number in a tag, something like <span id='total-items'>{$matches->count}</span>, then keep a reference to that element around in your Javascript and update it as necessary. When deleting you might just take the innerText and decrement it, or actually count the list items (probably the most robust option). You might even calculate the new total on the server and put it into the responseText, but I would advise against it.
-
Not that I have anything to add to LMD's solution, but the shortest answer to your question is this: All you're missing is a condition on the else. } else if ($pages->get('1032')->settings_aside) {