Jump to content

Jonathan Lahijani

  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by Jonathan Lahijani

  1. Very cool Ryan. I built something very similar for my own purposes in ProcessWire as well (invoices, clients, projects, proposals, expenses). It's similar to FreshBooks but with my own needs. It uses the Table field (profields) and ListerPro to make things more convenient.
  2. I have a page field that I am hooking into and providing the custom dropdown values like this: $this->addHookAfter('InputfieldPage::getSelectablePages', function(HookEvent $event) { if($event->object->hasField == 'my_page_field') { $ids = []; foreach(wire('pages')->find("...") as $p) { $ids[] = $p; } $event->return = $ids; } }); Due to the nature of my site, the amount of items that will populate in that dropdown field will be quite high (over 2000 pages). Due to this high amount of pages in that dropdown, the PW admin slows down quite a bit (extra 2 seconds) on edit pages that utilize that field. To counteract this, I have made that field have the Visibility Presentation of Closed + Load when opened (AJAX), however because I am using the hook described above, it will still load the pages even if the field has not yet been opened. So my question is, how do I improve the the hook above to execute only after the field has been opened?
  3. If anyone is thinking of using MediaTemple and their latest Grid (shared) plan, please reconsider. You will hit this issue and they will not disable mod_security. MediaTemple is owned by GoDaddy, so you should just avoid them all together because GoDaddy is garbage in my opinion anyway.
  4. Works great as an alternative to repeaters. Way fewer pages. For example I use it on my ecommerce site to hold what items are in a person's cart.
  5. Example: $finds = []; $finds[0] = $pages->find("title*=foo", ['findIDs' => 1]); $finds[1] = $pages->find("title*=bar,id!=".implode("|", $finds[0]), ['findIDs' => 1]); $finds[2] = $pages->find("title*=baz,id!=".implode("|", array_merge($finds[0],$finds[1])), ['findIDs' => 1]); // etc... // final query that gets ids from 0, then 1, then 2 $final = $pages->find("id.sort=".implode("|", array_merge($finds[0],$finds[1],$finds[2])));
  6. @formulate Refer to my post here, specifically under the search section which contains a link to a commit that should be here. In short, that minor change opens up the possibility to do multiple $pages->find and stack them one after another, while maintaining pagination. This means you can use multiple finds and effectively build search results that are ranked. I used this technique very successfully for the site I showcased and if I'm understanding your post, I think that's what you're ultimately looking to do.
  7. Slightly off-topic, but what is the correct way to manage frontend packages without a Node-based method (grunt/bower/webpack)? Does a formal way to do this even exist? Composer is not meant for frontend packages (right?), but I see that you can get Bootstrap and UIkit from there (but not HTMX or Alpine.js for example) wget into your themes folder? Make a ProcessWire module for each frontend package (that you as a module maintainer manage the versions of yourself)? This is more WordPress / non-developer like for those that consume the package as opposed to the module maintainer. I'm really trying to become Node free... not because it's causing me problems, but just because I feel I barely need it except for package management.
  8. Reviving this old thread... I've been deeply thinking about a simplified build process in addition to a more standard, non-NPM/Webpack/etc. way of loading CSS and JS. I agree with @Nuwanda in that the way WordPress does it is well thought out. It's pretty straight-forward, but I wonder if ProcessWire could standardize something like wp_enqueue_scripts/styles in the core. Right now there's no standardization, but that's probably by design (ie, ProcessWire doesn't dictate markup / not a theming CMS).
  9. Yes, but the module is still in deep development. It's kind of never ending, but I have put a lot of consistent time into it over the last month. I'm at mostly the refactoring stage now as I have gotten in most of the features I want. I am stripping out experimental ideas that just didn't feel right, such as the 3rd approach in my video (too overcomplicated). Page builders are... not difficult to develop but easy to overcomplicate. To be clear, my module is not going to be just a page builder (although that is a large part of it). It's essentially my vision of a highly opinionated, modularized starting point that works well with a CSS framework of your choosing (UIkit3, Bootstrap5, Tailwind, CodyFrame or no CSS framework). Whichever CSS framework one uses, a page builder (ie, the 'Blocks' field), would be provided that's built around the chosen CSS framework. UIkit3 would be the most flexible in page building capability (since UIkit is designed for page building scenarios and it's easy to replicate the logic and thought process of how YOOtheme did their builder), but the page builders for others would work well too as they would be inspired by YOOtheme's approach but just adapted for the respective CSS framework. I'm taking great care to make it as easy to use as possible. A goal of this is to make ProcessWire easy to use for those who are just starting to use it and not sure how to structure things. This is where the heavily opinionated decisions I made come in.
  10. ProcessWire does not use a favicon in the admin backend. I usually insert a PNG-based one of the ProcessWire P logo to differentiate the frontend and backend of a site, however I upgraded my technique to use an SVG-based one, which has the added benefit of being able to quickly set the fill color. This is a nice trick, especially if you're working in multiple admin backends of different sites and want to be able to quickly identify which tab belongs to which site by the ProcessWire favicon color alone. Insert this in /site/templates/admin.php: wire('adminTheme')->addExtraMarkup('head', "<link type=\"image/svg+xml\" rel=\"shortcut icon\" href=\"data:image/svg+xml,%3Csvg width='256' height='256' viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='#EB1D61' fill-rule='nonzero' d='M234.02346,56.2065308 C226.258185,44.611679 213.340949,31.3634673 200.370381,22.7873303 C173.426584,4.33370224 142.216153,-2.21573572 114.611028,0.642976614 C85.8219124,3.7470262 61.1714319,14.5951995 40.9049183,32.6861551 C22.1317268,49.454423 9.73715371,69.9560838 4.27586162,89.5083961 C-1.24942998,109.060708 -0.513435538,127.162331 1.45988289,140.794549 C3.53986718,154.629436 10.4304818,172.037714 10.4304818,172.037714 C11.8384712,175.376434 13.7904564,176.731123 14.8037821,177.296465 C19.8384108,180.048509 28.105015,177.627137 34.4516337,170.50169 C34.7716313,170.06435 34.9422967,169.45634 34.7716313,168.944332 C33.000978,162.128223 32.3609828,156.997474 31.7316543,153.029411 C30.2916651,145.178619 29.65167,132.026409 30.6116627,119.866214 C31.0916591,113.284776 32.3716494,106.244663 34.6116325,98.8632122 C38.9422665,84.281646 48.0728642,69.0600695 62.3447564,56.4092007 C77.715307,42.7876498 97.4271581,34.3715154 116.16835,32.1954806 C122.738967,31.4061347 135.240206,30.6487893 150.290759,34.3608485 C153.501401,35.1608613 167.282631,38.7555854 182.023853,48.7397449 C192.754438,56.0358614 201.394373,65.0386719 207.346328,73.9454809 C213.404949,82.44695 219.986232,96.783179 221.916885,107.279347 C224.647531,119.226204 224.647531,131.88774 222.706212,144.218603 C220.30623,156.570801 215.975596,168.581659 209.24498,179.152495 C204.605015,187.344626 194.983755,198.171465 183.613174,206.299595 C173.362585,213.510377 161.66134,218.715793 149.650764,221.595839 C143.57081,223.035862 137.469522,223.95321 131.218903,224.15588 C125.661612,224.32655 118.291001,224.15588 113.117706,223.2812 C105.427098,222.054513 103.82711,220.091815 102.067123,217.425106 C102.067123,217.425106 100.840466,215.505075 100.499135,210.36366 C100.616467,163.376243 100.595134,175.920443 100.595134,151.525387 C100.595134,144.63461 100.371136,138.383844 100.435135,132.709086 C100.755133,123.396937 101.54446,116.996835 108.20041,110.063391 C113.01104,104.953976 119.741656,101.87126 127.154934,101.87126 C129.405583,101.87126 137.160191,101.977929 143.97614,107.642019 C151.282751,113.74345 152.509409,122.084916 152.797407,124.314285 C154.461394,137.359827 145.842792,147.077316 142.536151,149.541355 C138.440182,152.613404 134.760209,154.106761 132.274895,154.981442 C126.984268,156.752137 121.170979,157.264145 115.944352,156.922806 C115.144358,156.869472 114.41903,157.392147 114.259031,158.19216 L112.499044,167.322972 C110.781724,174.256417 114.632361,176.795124 116.872345,177.691138 C124.029624,179.899173 130.376243,180.816521 137.896186,180.251179 C149.426765,179.440499 160.797346,174.896427 170.450607,165.893616 C178.663878,158.085492 183.346509,148.453338 184.946497,137.679832 C186.546485,125.722308 184.466501,112.847436 179.015875,101.945928 C173.021254,89.9244028 162.674665,79.8869091 149.042768,74.393488 C135.272206,68.9747348 124.317622,68.7827317 110.195062,72.3881226 L110.035063,72.4414568 C100.861799,75.5988406 93.0111915,79.4922361 84.8405865,87.9297042 C79.2406288,93.7537973 74.6539968,100.804577 71.8593512,108.762037 C69.0860388,116.783498 68.3393778,122.767594 68.2113788,132.069076 C68.0407134,138.959853 68.3713775,145.359955 68.3713775,151.354717 L68.3713775,190.832681 C68.3713775,203.462216 67.9447141,205.648918 68.3713775,212.145022 C68.6060424,216.454424 69.2033713,221.329168 71.091357,226.566585 C73.0326757,232.337344 77.1073116,238.257439 79.9019571,240.988149 C83.8165942,245.158882 88.7978899,248.508269 93.693853,250.588302 C104.904435,255.569715 120.125653,256.359061 132.466893,255.879054 C140.637498,255.569715 148.85077,254.439031 156.904042,252.529667 C173.010587,248.700272 188.477137,241.734828 202.077034,232.070673 C216.658258,221.798509 229.330162,207.782285 236.327442,195.878095 C245.298041,181.733869 251.100664,165.861616 254.119308,149.552022 C256.839287,133.210428 256.711288,116.452827 253.063316,100.356569 C250.183338,85.4229975 242.492729,69.0387358 233.61813,55.8118579 L234.02346,56.2065308 Z'%3E%3C/path%3E%3C/svg%3E%0A\">"); Replace the fill color (#EB1D61 -- the PW pink color) with your own brand color if needed. Note: this is not tested on Safari (doesn't support svg favicons) so make sure to implement a proper fallback if that's important to you.
  11. The author of Alpine.js and Alpine Components (Caleb Porzio) mentioned the following in an email announcement today: So, that will in fact be a fourth option. 🙂 Works for me.
  12. This is something I've been thinking about over the years and I want to hear other people's thoughts on whether custom forms should be built using ProcessWire's form API. For a simple contact form, I'll usually use Form Builder. For something like a complicated signup application (like a university admissions application for example), I've used the ProcessWire admin itself (heavily locked down depending on the user's role) as the "form". However let's take an example of an ecommerce checkout form. Pros It's the "ProcessWire" way to do it. Built-in server-side form validation, CSRF and session related persistence. Cons Requires jQuery (for example when showing/hiding) and jQuery UI if using advanced fields (date picker, ASM Select, etc). Must load the appropriate JS correctly. You can also argue it loosely depends on Font Awesome 4 for icons. Due to some limitations, it doesn't work well with something like Alpine.js; for example this issue. Work-arounds are required to get the correct markup in place. It just feels more difficult even though it's the ProcessWire way to do it. Thoughts?
  13. If you're looking for a JS library that pairs well with Tailwind, might I recommend Preline, which I just found on Hacker News: https://preline.co/ Another option includes Flowbite, but at the time of this writing, Preline's JS goes a bit further and has more components and more options (such as offcanvas, mega menu): https://flowbite.com/ There's also Alpine Components if you're into Alpine, however it's commercial: https://alpinejs.dev/components I like Alpine.js, but the "locality of behavior" approach it takes for these common components is not my style. I do use it elsewhere however. - Lastly, there's Headless UI, but that probably won't fit with a typical ProcessWire frontend unless you are using React or Vue: https://headlessui.com/ I wish Headless UI had a Alpine.js version, but the author of Tailwind ultimately scrapped the idea (it was mentioned in a Tweet thread somewhere). This would have been my go-to approach, assuming it was comprehensive enough. But there's many options as stated above.
  14. For at least a few years, I would add the following bit of code to my config.php and I would stay logged in for 7 days, whether or not the browser has been closed: ini_set('session.cookie_lifetime', 60 * 60 * 24 * 7); ini_set('session.gc_maxlifetime', 60 * 60 * 24 * 7); However, that no longer is effective, and I think it has to do with PHP 8.0 or PHP 8.1 changing something. I'm also on Ubuntu 22.04. Does anyone know what's going on here?
  15. Thanks for the reply. The purpose of my question is ultimately related to priming my ProCache cache. Right now, I have a whole bunch of optimizations in place, but when I deploy my site, I purposely clear all cached pages as they need to be rebuilt. If I have a script to primes 50 pages that each take 20 seconds to prime, one after another right after deploy, I'm wondering to what extent this makes the site inaccessible during the priming process. My question is what is it that exactly causes a site to lag for one person while another person (or my priming script) is loading intensive pages?
  16. Let's say I have a page A that takes 20 seconds to load due to the number of database calls being generated. And then I have another page B that takes 2 seconds to load because it's less database intense. If person 1 goes to page A, the server will start the page rendering process and 20 seconds later the page will be served. If person 2 goes to page B right after after person 1 went to page A, will person 2 see the page B in 2 seconds or 22 seconds? Meaning, what factors go into play in terms of how Apache/PHP/MySQL responds multiple large requests, server resources (cores, memory), etc.? This is something I never really understood but I'm doing some big performance optimizations and it would be helpful to have an understanding what's going on deep down. Any resources would be appreciated.
  17. The TCC site actually uses aMember Pro which is what I integrated with (the handshake). I didn't set up aMember Pro originally, but I believe TCC likes the system, although there has been some concern with the recent Russia/Ukraine situation as there are developers from both countries that are involved in the project (and could lead to potential support issues should they arise given the displacement of many people). Creating the handshake was straight-forward and didn't involve too much code. I could give you some tips as to how I did it should you go that route, but in short, when a member logs in via ProcessWire's admin form, a hook it hits a script on the main site (via a get request) that bootstraps aMember's system and runs a check on the credentials entered.
  18. Over the course of 2021, I re-developed the Transferware Collectors Club Database of Patterns and Sources. It is a private, members only database that contains nearly 20,000 patterns of various types of transferware, which in layman's terms is basically art on plates, bowls, cups, etc. (Wikipedia) Many archaeologists and transferware enthusiasts use this database to learn more about the historical nature of their collections or archaeological finds. The system had a long history and there were two versions prior. I believe the first iteration was made with a PHP framework of some sort, then it was re-developed around 2015 in ProcessWire. One special aspect of the previous version was that it utilized Elastic Search. Advanced search capability of the system, both in terms of free-form text entry as well as filters were the crux of the system. In 2020, I was introduced to this project as the previous developer decided to retire. While doing some various maintenance type work, I realized that there was much that could be done to improve the system, from re-imagining the user interface to utilizing all the latest features in the newer versions of ProcessWire, as it had been locked to version 3.0.135 or something at least 3-4 years old. Also, Elastic Search had become deeply outdated and unreliable since the entire site had been moved to a new server. Finally, I saw various aspects of the data model that could be improved as well as reduce several dependencies, while also using new techniques like HTMX. I redeveloped the system over the course of 2021 and the end result has greatly impacted the capabilities of the system as well as its ability to be maintained with little complication years into the future. Search: First, it became apparent that the way in which Elastic Search was being used had little benefit, became unstable and was outdated in the time since it was implemented. I don't like relying on 3rd party solutions, especially for something so critical and I thought about how I could develop a great search experience with ProcessWire alone. To do this, I utilized the WireWordTools module to handle lemmatization and such. Then, I advocated for this feature to be developed into the core, which could allow the results from multiple search queries to be easily stacked one after another and not affect order or pagination. This was a key change allowed for "ranked" search results. Finally, I integrated the BigHugeThesaurus API so that entered search terms can have their synonyms automatically generated. Filters: The previous version of the system had filtering capability, but it was too cumbersome and in my opinion, just didn't feel right. A significant amount of thought went into how to improve it while untangling some issues with the data model (and just understanding what Transferware is in the first place). The end result has has been an extensive set of filters with a special user interface so that users can easily select what they need. Frontend: I take the "classic", server-rendered approach when it comes to web-apps, and during this time, HTMX started becoming a favorite among such developers. By using HTMX, searches can be conducted without having to hit the submit button every time. It gives it that polished ajax-y feel without having to write any JavaScript whatsoever and allowing the use of ProcessWire in the expected way as opposed to it acting as some API end-point. To be able to do this is somewhat of a game-changer and I feel like I'm not "missing out" on these features which in the past were a pain to have to invent as there really wasn't a clean, straight-forward way to do it. HTMX is a gem and it couples very nicely with ProcessWire. I'm also using Alpine.js lightly for toggling things here and there. My goal was to make this project jQuery-free. UIkit 3 is being used as the frontend CSS framework. User Authentication: As mentioned, the database must be accessed after a membership has been purchased. TCC already has a 3rd party membership system, so I developed a handshake that allows a user to log in with the ProcessWire admin form using their credentials from that 3rd party system. If it's the member's first time logging in, it will then automatically create a ProcessWire account for the member so they can bookmark patterns, save searches, etc. The previous version had a different type of handshake that ultimately only logged the users into one master "member" account, so users wouldn't be able to save any information since everyone technically shared the same account. New Server: I put the site on its own dedicated droplet to squeeze out even more performance and be independent of their main marketing site (based on Drupal). We had a couple instances of configuration changes causing some clashes, so this move isolated it from any potential breaking changes that may occur on the main site. A 2-core droplet is all that is needed for now, which is cost effective. Demo Video and Article: While the site can't be visited given it requires an account, I did create an in-depth search tutorial video which shows off quite a bit which I can post here since it's publicly accessible: https://player.vimeo.com/video/666912411?h=30a94132db Feel free to read more about the TCC DB in this interview with Dr. Loren Zeller, who I worked closely with the entire time and who provided invaluable feedback and guidance along the way: https://www.transferwarecollectorsclub.org/sites/default/files/pdf/special-interest-pdf/0225_d_001_analink.pdf
  19. Thanks for your response. In my case it was definitely the check_access option. To figure this out, I had to diff the MySQL queries as superuser vs. non-superuser and see where the bottleneck was and it had to do with calls to the pages_access table on a particular query.
  20. Ack, well it had to do with 'check_access' not being set to zero in my selector. I don't think I've ever had to deal with that before. https://processwire.com/docs/selectors/#access_control
  21. I'm having an extremely weird issue that I can't pinpoint in my code. When a particular $pages->find is done as a superuser, the search is quick. However if the user doesn't have the superuser role, it's very slow (over 15 seconds). There's no code in my codebase that would cause this. Any ideas would be appreciated.
  22. @OllieMackJames I've experimented with most of the popular page builders in WordPress, including Oxygen. The direction I'm taking is vastly different from all of them. Simply put, the page builder being based on RepeaterMatrix is what I'm trying to accomplish and for it to be usable with the developers CSS framework of choice (Uikit, Tailwind, Bootstrap, Codyframe, no framework, etc.). Anything beyond that is outside my skillset and the scope of what I'm truing to do. I have no interest in using React, Vue, etc. and going to the extreme like the WP page builders do. The page builder will simply be "good enough" to make marketing pages based on the capabilities of whatever CSS framework is installed.
  23. I just picked up my Model Y today. I've been driving my previous car for ~15 years. Here's a photo of the first webpage I loaded in the browser 🙂
  24. Just wanted to add my 2 cents and say that a database migration system (like Ruby on Rails... they've had it perfected since 2005 or so) takes ProcessWire from being a CMS/CMF to something more web application framework-like, at least from my point of view. That's a defining feature the way I see it and what I believe Bernard is shooting for (I haven't experimented with RM yet). Personally, I do everything by hand the way Ryan described (because I'm impatient and it's fast enough), combined with little 1-off scripts that modify big chunks of data as needed, but that approach will fall apart when there's multiple developers involved, syncing changes, or even re-implementing your own changes on a production site that were originally done on a development site. I do wonder if I would use a migrations feature if it were native to ProcessWire. Right now, I rarely even use Field/Template/Page Exports when making field/template/page changes from dev to production, but I definitely understand the use case (having worked with web applications frameworks extensively). While having a database migration system is the more 'proper' and 12-factor-y way to do complex development, I don't personally view ProcessWire as a web application framework like Laravel and Rails. There's something to be said about being able to throw ProcessWire around and experiment with things quickly. It has had a real impact on my productivity and solutions. Hand-writing every field or template added or changed would be tiring (although it would optional). Having it auto-recorded like CraftCMS would be interesting and there have been attempts to do that. Not sure where I'm going with this, but just some thoughts I felt like sharing.
  • Create New...