Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 08/29/2020 in all areas

  1. I've probably thought up a dozen different approaches to creating an ideal page builder in ProcessWire but each of them have their pros and cons. It's very difficult to strike a perfect balance for something that suits both developers and editors. There are so many (!) other variables to consider. This isn't just a ProcessWire dilemma, but just the nature of page building itself. There are trade-offs and complexity must live somewhere. In an ideal world, you'd use RepeaterMatrix in a classic way, but if you run that thought experiment, here's what happens: I'll make matrix-types for all the sections in a particular page. I'll write the templates for those matrix-types, so all an editor has to do is fill in the fields and everything just falls into place. I'll drive off into the sunset and be happy. Well, turns out there are some changes that need to be done. MatrixType X needs another field. I'll add that field and update the template. Well now we need another matrix-type, but it's basically identical to MatrixType X except the columns are flipped. Does this warrant a new matrix-type or a toggle option of some sort? ... You start another new project and it needs a page builder like the first site. You realize there's going to be some heavy re-use of matrix-types from the first site, so you now think... hmm maybe I should somehow modularize this approach where there is a shared matrix-type library. (I've done this) ... Many of the matrix-types between site 1 and site 2 are similar, but with slight differences... some have different css class names, some have different field names. Now this shared matrix-type library has a bunch of matrix-types but you feel unsatisfied because you think there is a better way to refactor this. The ideas in your head about how to refactor end up going against the grain of the classic page builder way / repeater matrix approach and now you're frustrated. I've gone through this thought process a bunch of times. I've researched basically every single page builder out there. It's like trying to solve a puzzle without a definitive end result. One thing that happened is reactive frameworks gave rise to the current generation of page builders (think WP Block Editor / Gutenberg, SquareSpace, and few dozen others). This left the classic page builder approach behind (RepeaterMatrix, ACF Flexible Content). But I like the classic approach because it gives more programmatic control and it's the way ProcessWire works... and editors can't really mess things up since it's a more controlled experience. I feel like there hasn't been experimentation and development for the classic approach since the world has "moved on" to the newer generation approach. I think RepeaterMatrix is good, but maybe it can benefit from some experimentation of some sort.
    11 points
  2. This week I’ve been working on a combination of the core, and a PW audio-streaming project for a friend, working as a volunteer. There’s some overlap in these two things, as a lot of the core updates this week are somewhat related. It provided the needed motivation to finish a new feature I started working on in 3.0.149, which will be finally finished in 3.0.166. Actually, it’s finished now, but I haven’t bumped the version number on the dev branch yet—I’ll do that next week. The feature finished this week adds support for a new secure files option similar to the $config->pagefileSecure option (you may or may not have heard of), except that it allows you to configure secure files at the template level, rather than just site-wide level. In ProcessWire, when you unpublish or trash a page, or when you access control a page so that it’s not visible to guest users, the page’s files in /site/assets/files/page-ID/ can still be accessed directly by URL (like if someone bookmarked a PDF or something). So we have the $config->pagefileSecure option that lets you specify that the files should also be access controlled. This ensures (for example) that if a page is unpublished, its files can’t be loaded by anyone except a user that can view unpublished pages. But I rarely use this option because it is site-wide, and access controlled files take some overhead (being delivered by ProcessWire rather than Apache) and thus are something I’ve always wanted finer control over. That’s because most of the time, I don’t care too much about direct access to files because they are mostly images and endless variations of them. But there are also those specific cases where I really do need it. So being able to make it part of the template-level access control really makes it a lot more flexible, and hopefully makes the option a lot more obvious: There’s also that “Yes always” option (in the screenshot above), which is something we’ve not had before. This is useful when you want to have full control over a file download (or stream). Because the files would always pass through ProcessWire, you can hook any part of the process, keep a download counter, log downloads, etc. ProcessWire supports partial file delivery and delivery of specific byte ranges and seeking, which comes in especially handy with <audio> tags. In the case of the project I was working on this week, the audio streams are available only to logged in users (via LoginRegisterPro) and we had to find a way to make the audio files protected from direct access, so that they would only work as a stream through an <audio> tag to an authenticated user, not be accessible outside of that, and not be downloadable. That was all a bit of a challenge, but a fun one. If anybody ever runs into a similar need, be sure to send me a message. I have a few more things I want to work into version 3.0.166 before bumping the version number, so that’ll likely come by this time next week. I also hope to fully wrap up the new version of either FormBuilder or ProCache next week, followed by the remaining one the following week. Thanks for reading. Have a great weekend!
    5 points
  3. Hey @ryan! This is very loosely related to the weekly update, but I noticed that this week (as well as in some earlier updates) you've started converting $this->wire('api_var_name') to $this->wire()->api_var_name. Just wanted to ask if there's some benefit to this, or if it's mostly just a matter of taste? ? Not a big deal by any means of course, but I've been writing stuff like wire('session') all over my modules, so wondering if there's a reason why I should rather prefer wire()->session etc.
    4 points
  4. @ryan there is still one of my very first PW projects, the MP3-DB site profile, which doesn't work with any PW 3 version (or newer PHP versions ?). I've been wanting to put the essence of it into a module for quite some time, so that one can add MP3-DB support to any existing site with ease. It seems that I'm getting a bit closer to the goal thanks to your new features, because it will be much less work if partial file delivery and delivery of specific byte ranges and seeking is now natively supported by PW! ? When starting with it (maybe around christmas this year), I will contact you before.
    4 points
  5. @teppo The only reason I've started using wire()->pages->find() rather than wire('pages')->find() is just because the IDE (PhpStorm in my case) recognizes what wire()->files is, but doesn't recognize what wire('files') is... well it does, but it only knows that it could be any one of a bunch of API vars, rather than knowing it's the $pages API var. Substitute any API var for "pages" here, I'm just using pages as an example. Phpdoc data is able to traverse through variable and method names like wire()->pages or pages(), but not through strings like wire('pages'). It makes zero difference technically which you use, but at least as far as IDEs like PhpStorm goes, it's the difference between the IDE knowing what you are doing and not really knowing what you are doing. I like it knowing what I'm doing because it helps to find potential issues more easily, and it knows arguments, types and return values on methods I'm going to call, etc. You can also do the same by using phpdoc to tell it what type a particular variable is. For instance, the two bits of code below would have the same effect in terms of the IDE knowing what $pages is: // this: /** @var Pages $pages */ $pages = $this->wire('pages'); // or this: $pages = $this->wire()->pages;
    3 points
  6. It's definitely possible. I built a complicated online scholarship application with ProcessWire, while not the same thing as an exam, it did have some similarities. An application would be initiated by a nominator on behalf of the person being nominated, and then there were 3 reference people per application (it got pretty complicated). Notification emails, application statuses, a bunch of other things. In my case, the public interface was mostly the in admin, so it had no "frontend" (other than some templates that would be used for redirecting to the edit url). That meant using roles, permissions and hooks accordingly to lock things down. In your use case, I would say to build a custom front-end for it and not do it the way I did it. It will be easier and I think it makes more sense for your use case (ie, multiple choice questions as opposed to all kinds of various fields from files, rich text, etc.). One crucial thing to test heavily is making sure the test takers don't get logged out for some reason. In my situation, that happened and I could not exactly pinpoint why, but it caused a lot of trouble especially since the application involved people filling out long-form answers, which would then be wiped when they hit the save button and their session had expired. I'll have to figure that out in the next iteration, but that was bad. You may want to have one question per page. This is how online / computer-based tests usually do it anyway. As for structure, maybe this could work: Home Exams Exam 1 Question 1 ('question' template) Answer Option 1 ('answer' template) Answer Option 2 Answer Option 3 Question 2 Answer Option 1 Answer Option 2 Answer Option 3 Submissions Submission 1 ('submission' template) Submission 2 question template title - the question being asked answer template title - the answer text correct - checkbox indicating this is the correct answer submission template (title -- make the field not required and hide it, rather than removing it as a global field... a trick I use) user - page field for parent /admin/access/users/; the person who took the test; maybe use the autocomplete inputfield here since loading 25,000 things into a select list will be problematic exam - page field for parent /exams/; the exam that was taken answers - multi-select page field (asm-select) that has all the answers they chose for the particular exam (any other relevant data you need to store) With some code you can check the correct answers of an exam vs. the submission answers and go from there.
    3 points
  7. Relative to version 3.0.164, this latest version on the master and dev branch (3.0.165) contains 16 commits with various minor fixes, improvements and optimizations, and it resolves 6 reported issues. Version 3.0.164 has been very stable, and this version should be even more so. Both the dev branch and master branch are identical at this moment. As mentioned last week, new versions of both FormBuilder and ProCache are in development, and I’ve been working on both of them quite a bit this week. I mentioned some of the updates being made in FormBuilder last week. Another new feature to mention is the addition of reCAPTCHA to the spam prevention tools. While our built in honeypot is just as effective (when setup properly), it does its work silently, behind the scenes, never visible to anyone. Whereas reCAPTCHA is hard to miss, which is a benefit for clients that want to to be able to literally see spam prevention measures in place. No doubt, it brings a certain level of comfort, and adds another level of authority to your forms. So I’m really glad to add it to our set of form tools. Rather than building it into the form “actions” I’ve instead built it as an Inputfield module (InputfieldFormBuilderRecaptcha), as this gives you a little more flexibility with regard to placement and customization. It is ready for download now in the FormBuilder board Download thread (login required). It can be used with any version of FormBuilder 0.3.9 or newer; meaning it’s ready to use now. If you download it, be sure to read the pinned reCAPTCHA thread in there for detailed instructions (it's very easy to setup). I’ve been talking about it for a long time, but it seems like it may finally be a good time to re-do the modules.processwire.com site. It all works just fine, but just needs an update, consistent with the rest of processwire.com. So we’ll likely slow the pace of core updates for 2-3 weeks to work on that, sometime between now and the end of the year. Thanks for reading and have a great weekend!
    1 point
  8. A project I worked on the beginning of this year. Simple website with great content. Used the Repeater Matrix Field to define custom content blocks so the client has a few options to build nice content pages. https://volstok.com/
    1 point
  9. @horst The partial file delivery was added last year. I'm not sure of the exact right terms for it, but it's basically giving proper responses to the $_SERVER['HTTP_RANGE'] "bytes" requests which specify starting and ending ranges of bytes from a file to respond with. More details on the implementation in the WireHttp::sendFileRange method. Browsers basically send a test request to the server to see if it supports it, and if they give the proper response, then it starts requesting byte ranges and we just just give it the expected ranges. They aren't always sequential either, sometimes it wants a piece of the beginning and a piece of the end, sometimes different things, and it seems to vary between browsers. You don't have to do anything special to use it, as any file delivered by ProcessWire already supports it when the browser requests it.
    1 point
  10. Thanks for setting this up! ? Of course this won't be a problem for everyone, but personally I avoid direct downloads. Here are a few reasons: With direct downloads I can't easily validate the package to make sure it is indeed the original one in case the server has been compromised or something along those lines — which of course is something that shouldn't happen, but in this regard I have more trust in GitHub than individual hosting providers / server maintainers. GitHub (/ Git) allows me to see and track the full change history in case something doesn't work. This way it's easier to track what change caused the problem, why it was made (commit message), and (assuming that the module author is somewhat active on GitHub) file an issue or even submit a fixed version for approval. Finally, I prefer to handle updates via either Git or Composer. It would be too much work to keep track of different blogs for individual modules, let alone download the module package every now and then to see if it has changed . GitHub makes this trivial (periodic git fetch or git pull is quite enough). No pressure, but big thumbs up from here for always uploading modules to GitHub ??
    1 point
  11. thanks for the quick answer and solution. I knew it had to be simple, works now.
    1 point
  12. Has your root .htaccess file made it through the FTP program into the online host? Please double check if it is in place there. Some FTP programs have filters that hide and exclude dot files from transfers per default.
    1 point
  13. I wrote this a while back for my company's internal documentation and just realized it might be a benefit to others on the forum, so here it is! Checking whether a field was changed To check whether a specific field was changed you can do $page->isChanged(‘field’). This can only be done before Pages::save, since the save clears change tracking by default. Getting the values of a page before they were changed, from within a hook before Pages::save Method 1: The hacky way $clone = clone($page); $e->wire('pages')->uncache($clone); $oldP = $e->wire('pages')->get($clone->id); $oldP then represents the page and all its values as they were before any changes were made. Again, this will only work for hooks that run prior to Pages::save. Method 2: Using change tracking to get the old values If change tracking is set to track values, then the above is not necessary. In this case, calling $page->getChanges(true) will return an associative array of fields that changed and each field's prior value. Note that the value itself is also an array, since it is designed to be able to track multiple changes over the course of a single request/response cycle. Tracking of values is turned off by default (for efficiency sake), and there is no global switch to turn it on and off. To enable tracking of values, you must call $page->setTrackChanges(Wire::trackChangesOn | Wire::trackChangesValues) before any changes are made to the page that you want to track. Here is an example of how you can enable value tracking in ProcessWire's page editor: $this->addHookBefore("ProcessPageEdit::execute", null, function($e) { $p = $e->pages->get((int)$e->input->get('id')); if($p->template == 'event-registration') { $p->setTrackChanges(Wire::trackChangesOn | Wire::trackChangesValues); } }); Running hooks on both page saves and field saves Please note that using the following hooks is preferable if you want the hook to run both when individual fields are saved as well as the whole page: Pages::savePageOrFieldReady https://processwire.com/api/ref/pages/save-page-or-field-ready/ (for before a save) Pages::savedPageOrField https://processwire.com/api/ref/pages/saved-page-or-field/ (for after a save) Getting changes in a hook after Pages::save Note the $changes parameter passed to Pages::saved and Pages::savedPageOrField allows you to check which fields were changed during the save, even though the save is already completed. Using this is sometimes preferable to using a Pages::saveReady or Pages::savePageOrFieldReady hook since you don’t have to worry about the page cache or something else in your code preventing the original save from completing. A $values array is also provided, which is populated only if change tracking is set to track values (see above) Page cache issues when hooking before Pages::save Page cache issues may occur when you try to save another page inside of a before save hook (Pages::saveReady or Pages::save). A page save normally clears the entire page cache, which means any page fields on the page you were originally trying to save will have their values reset. So if you have to save another page inside of a before save hook, just use $page->save([‘uncacheAll’ => false]) to prevent the cache from being cleared. Preventing hooks from running on a particular save To prevent any hooks from running on a particular page save, you can use $pages->save($page, [‘noHooks’ => true])
    1 point
  14. Hey @fruid, SearchEngine finds content via the API and the operator used for text searches is configurable (see module config screen), so there's that. Depending on the operator you use you'll get a different set of results (obviously). You can read more about available selectors from the docs. As for Google-style search queries, there's nothing exactly like that built-in, but if you've got a newish version of ProcessWire (3.0.160+) and a recent version of SearchEngine installed, the module supports the advanced text search operator. The downside is that it's currently a little unclear how such queries should be sanitized so this feature is not fully functional. If you don't mind writing a bit of code yourself, there's also an example in the README about how you could provide your own search query and frontend (which, in turn, would allow you to sanitize the query string and then perform a find operation using the "#=" operator). ... and, as for the last point, it's actually also possible to use markup generated by SearchEngine yet still provide a custom results object. It involves a couple of extra steps, but something like this should work (requires SearchEngine 0.26.0 and ProcessWire 3.0.160+): // load and init SearchEngine $searchEngine = $modules->get('SearchEngine'); $searchEngine->initOnce(); // (for autoloader) // construct a Query object ($q stands for the _sanitized_ query string) $query = new \SearchEngine\Query($q); $query->results = $pages->find('search_index#=' . $q . ', limit=25'); // render results echo $searchEngine->renderResults([], $query); That doesn't remove the need to sanitize the query, though. That's something you'd (currently) have to do yourself if you want to use the advanced text search operator to the full extent.
    1 point
  15. With 5 million pages do people actually click through who knows how many pages you get? Generally offset/limit pagination scales quite badly because it always needs to count the offset part as well. So the higher the page number (offset) the slower the query will get. For big datasets cursor based pagination is usually adviced, but on processwire you‘d need custom sql for that. Also it will no longer give you pagination in terms of „you‘re on page 6043 of 20383“. You can only do next/prev. But from an UX pov page numbers that big aren‘t useful in the first place. Having means of filtering down to a more manageable result set is what I would rather strive for.
    1 point
  16. There's now a free and open source version similar to sizzy available: https://responsively.app/
    1 point
×
×
  • Create New...