Leaderboard
Popular Content
Showing content with the highest reputation on 09/10/2024 in all areas
-
I removed the header in simple mode to be even more compact: In advanced mode the header will be shown:2 points
-
Thx. I changed the default pagination size to 5 instead of 10 which makes the grid almost half the vertical size: If anybody needs to see more events the pagination size can be changed via dropdown. I think completely hiding it is not a good idea, because the live preview is important to double check the result of the rrule that is setup above. For example it's easy to forget to change from "every day" to "every week" and with the live preview one can instantly see that, because days will be mo, tu, we, th, fr... instead of mo, mo, mo, mo...2 points
-
Another idea close to the @bernhard one: lock the quantity field so it's not editable add a field "quantity to add" in saveReady hook, load page without cache to get real quantity and update it with "quantity to add" field.2 points
-
The site uses the Codyhouse CodyFrame CSS framework. They also have a version of Tailwind CSS. The megamenu component can be found here https://codyhouse.co/ds/components/app/mega-site-navigation2 points
-
I've been having a bit of a struggle converting a page reference field from Select to Autocomplete, as with Select, it's possible to hook getSelectablePages, and the actual page the inputfield is on is available to the hook, but with autocomplete, you have to hook findReady, and the page the field is on is not passed to the hook, only the name of the field, which then looks up the selector string from the field definition. None of the hook arguments include the calling page, however $event->argument(0) gives the selector string, and in the field definition it is possible to include some page fields in the selector string in the field definition. eg: The problem is, typically these will affect the pages returned, but I realised that if I added at the START of the selector string in the field definition id!=page.id that will have no influence on the pages returned, as I'm not likely to want a circular reference with a page referring to itself in a page reference field, but this will provide the actual calling page id that requested the page autocomplete. Since the selector string is just a comma delimited list, it's easy enough to convert this to an array, and if I have id!=page.id as the FIRST selector parameter it's easy to get it like so: $selector = $event->arguments(0); $selectors = explode(',', $selector); $pageSelector = explode('=', $selectors[0]); $page = wire('pages')->get($pageSelector[1]); Now that I have the actual page that the autocomplete is on, I can do things beyond what is possible with the selector string in the field definition. In my case I wanted to do this: $owner = $page->parent('template=client'); //Get ancestor page with given template and retrieve a field value from it to use in selector I can then rewrite the selector string as desired. I suppose in theory it would be possible to not use the selector string in the field definition as a selector string at all, but rather as a way of passing parameters to the hook, and then just build your own selector string in the hook. I hope this helps others who've struggled with figuring out where ProcessPageSearch::findReady is being called from. It won't necessarily work for all situations but should work when called from page autocomplete. Edit: I discovered that ProcessWire adds other selectors after the last selector in the selector string in the field definition, so it's really important that id!=page.id is the FIRST parameter in the selector string in the field defintion, unless you like searching arrays. If you make it first, you just need to explode the search string, get the first array element, explode that again, and you've got the page id.1 point
-
I have more than a dozen PW sites running on CloudPanel, which uses NGINX. I’m using the basic PHP site configuration CloudPanel offers, and it works out of the box. I’ve added a few rules mentioned above in this thread for extra security (they’re not actually needed for running PW), plus ProCache rules. Not sure if these settings can be copied as such in a standard NGINX setup that does not use CloudPanel, but I could post them here if you want.1 point
-
Hello, When reading this, I think it's related with .htaccess not processed, I might be wrong but that's the first thing I would look at. How do you configure the VirtualHosts of each site? Is there a directive AllowOverride? https://stackoverflow.com/questions/35251032/how-to-create-virtual-hosts-in-mamp1 point
-
@MarcC Got by any chance the module EMO EmailObfuscation installed? I once had the same problem and it was EMO.1 point
-
That's excellent. 🥰 Ah, I did not intend to suggest complete removal - only a collapsed interface to lessen the vertical scroll when a user might not need to interact with individual dates in a recurrence. The difficulty might be in separating out the progress bar, depending on how you're handling the HTML (since I think having that shown at all times is absolutely important). szabesz mentioned BusyCal; I use Rainlendar for my calendaring; it uses a tabbed interface to section out different aspects of events/reminders, that way (theoretically) similarly used functions are grouped together, but not everything is viewed at once. That said, there are benefits to certain users having everything viewed at once that can get lost in tabs/collapsed areas too, so I humbly refer to your best judgment and preference! 🙂1 point
-
Hi @Pete, Defo! And carefully! 😀. Yes. But we need to come up with a way to have your custom tweaks applied without touching Padloper itself. Are you able to capture these in one document? Even a git diff would do, but an annotated document is better, i.e. did this here, because...etc. Thanks!1 point
-
Introduction Automated PDF production is a quite common task for ProcessWire developers. PW does not offer core tools for that. There are some external modules that we can utilize. In this showcase I would like to share my considerations for the tool of choice and my experiences working with it. The task at hand PDF production for product pages on an existing ProcessWire installation acniti.com is a Japan based company that specializes in nanotechnology solutions for gases in water. They have developed technologies to create nanobubbles in water, which can change the properties of water and improve dissolved gas levels through super saturation. Their founder and CEO has chosen ProcessWire for his website and has developed the site himself. He tasked me to add functionality for creation of downloadable PDFs from available product data. The client was forwarded to me from Bernhard because of time constraints on his side. I really appreciate that. The core requirements in detail: Produce separate PDF files for multiple languages, including LTR languages Design a template: cover page, images page, content pages, specs pages Cache PDFs Minimal impact on existing template code Tool choice: RockPdf module I had done some PDF generation before, using mPDF library directly. While there are other options available for ProcessWire (Pages2PDF, MakePDF) I decided to use Bernhard's RockPdf module since it seems the most feature rich and well maintained one. It is also based on the quite popular mPDF library. Reasons for choosing RockPdf Auto-reloading of PDFs in concert with RockFrontend This can save a lot of time (and strain on the F5 key), since the PDF is automatically reloaded every time a code change is made. All it requires to achieve that is one line of code: $pdf->save(__DIR__ . "/tmp/{$filename}.pdf", preview: true); Easy font loading I needed to load different fonts depending on the content language. Here is, how I did that RockPdf CSS utility classes They really came in handy, since they are specifically targeted at mPDF, using pt units. I could easily set some base colors with $pdf->setLessVars([ 'col-muted' => '#dddddd', 'col-primary' => '#0b54a2', ]); The utility classes that I mostly used are those for widths, margins and paddings. They are quite handy for setting up the layout of the PDF. Easy file saving to PW field For caching the created PDFs I utilized a RockPdf convenience method to save the files to a field on the product page $pagefile = $pdf->saveToField( page: $page, field: self::PDF_FIELD, filename: $filename, append: true, ); Implementation Modular approach for minimal impact on existing code I created two modules: Main module ProductPdf: non-autoload, holds all logic/templates for generating PDFs and required markup (download button) Module ProductPdfHooks: autoload, hooks: Page(template=product)::render displays PDF for download Pages::saved(template=product|product-type) creates PDFs in all languages and saves them to field for caching Re-usage of existing template logic There was quite a lot of logic (some of it rather complex) already available in the project that I wanted to utilize. Mainly for specs table creation. I had to do some minimal refactoring of original code. Then I was able to include that logic into my module without having to duplicate it. Benefits of this approach: Minimal impact on existing code Easier to maintain Challenges Limitations of mPDF library mPDF is not good at modern CSS features. It is quite limited in terms of CSS support. I had to do some workarounds to make it work with the layout I needed. Different approach to styling Although RockPdf's utility classes helped a lot, I still had to do some inline styling. Display of complex tables Display of tables in particular was a pain point since mPDF does a lot of automatic adjustments to column widths and distribution that I needed to disable in order to get the desired results: // Ensures that tables retain their original proportions $mpdf->keep_table_proportions = true; // And adding autosize="1" attribute to tables. Page headers, footers, margins and page breaks The RockPdf module docs have some great examples for setting up headers and footers, margins and page breaks. I used those to set up the layout of the PDF without having to read too much into the mPDF docs. Minimal impact on exisiting code base This was overcome by the modular approach I described earlier and it worked out really nice. The only addition to the original product template file for rendering the download button, was calling a static method from my module: <?= ProductPdf::renderDownloadbutton($page) ?> That button requests the page URL with a query parameter. The display of the PDF for download is handled through a Page::render hook PHP DOM manipulation of existing markup necessary Since I reused existing logic for constructing specs tables, I needed to add some inline styles and change some URLs on the fly. I used native PHP DOMDocument for that. There is a feature in the RockFrontend module that offers DOM manipulation tools with a nice API. I would have loved to use those but at the the time of working on this project, I just was not aware of their existence. The result Product pages on acniti.com now have a download button that allows the user to download the PDF of the product page in their language. See it live here The PDF is loaded from the cache field on the page, which is updated every time a product is edited and saved. If no cache file exists, the PDF is created on-the-fly and cached for future use. It is presented to the user in a new browser tab for viewing and downloading. The PDFs feature a clean layout / design which corresponds to the acniti branding. Cover page: Content pages: Specs table: Feedback from the client The client has a lot of experience with ProcessWire which one can see from looking at their website at acniti.com. He gave me great feedback on the project: Erik van Berkum, acniti LLC Lessons Learned and conclusion PDF creation in PHP is still not an easy task. The most popular library, mPDF, has some restrictions related to CSS that can make it tedious to work with. Especially when it comes to more complex layouts and tables. Using the RockPdf module for the task was a great choice. Its API is very well designed, offers a lot of conveniences and is well documented. Bernhard responded quickly to my questions and provided great support. In conclusion, the ProcessWire ecosystem offers great tooling for PDF creation that makes life for developers more enjoyable :-) Future considerations Would I use this approach again? Well, that depends mainly on the requirements. For this task the chosen tooling worked very well and I am happy with my choice. But for more complex layouts/designs that require modern CSS features, I would prefer rendering PDFs through Chromium browser using puppeteer or a self-hosted gotenberg service.1 point
-
PDFs are created in multiple languages, so that is why :-) I looked at the implementation of the saveToField() method to figure out the exact behaviour.1 point
-
Cool, thx 🙂 Thx a lot. Always appreciated! Actually it's the other way round. I think I can just remove the warning 😄1 point
-
Great write up gebeer! Very nice looking pdfs. I would also be interested to see how the mega menu was created on that site.1 point
-
Yes we can @SIERRA. Introducing: Fluency. The complete translation enhancement suite for ProcessWire.1 point
-
It will be a standalone module, but for the recurring events part you will need the "RockGrid" module. Other than that there will be no dependencies, no RockMigrations, no RockFrontend.1 point
-
@kongondo I am still on 008 (well as you know somewhere between 8 and 9 😅) - should I go through 009 to get to 010? I'm thinking probably yes - if it enables me to better understand all the changes with the amount of custom tweaks I have on my site and make sure they all get re-applied.1 point
-
Nice @poljpocket! I've starred it and will keep this in mind. Where's the image referenced here: https://github.com/poljpocket/processwire-docker/blob/19e801318605bfabb81e262baa9ddb3d10ef2afd/docker-compose.yml#L5 (I'm guessing wherever that code is is where the Apache stuff is configured?) Thanks! Edit: I saw it's in your 2nd link: https://github.com/poljpocket/processwire-docker-image/blob/main/scripts/install.sh I'll take a look 👀1 point
-
I would advise you to use Docker or DDEV for that. You could use my composition here as a starting point. It uses MariaDB 10.6 and apache+php8.2 (custom image which auto-installs PW). You can then replace the web container with a Litespeed+php container and configure it. You can refer to the Dockerfile of my custom image to get started with that. As for Litespeed, from my very limited experience, any serious hoster should be using the enterprise variant because, as far as I know, only that really offers full drop-in replacement for apache. This makes it hard to run locally without a license.1 point
-
Just clicked FOLLOW. I'm on there for over 15 years, and while it needs more work done itself, it just got way better. At least for me. I would do that. I'll take care of this. It absolutely is. Best community ever. AND it's a forum/board and not Discord or whatever.1 point
-
1 point
-
One idea to solve this in a quite easy way: Add a hidden field to your template called "quantity_before_edit" Add a saveReady hook that calculates the difference between "quantity_before_edit" and "quantity" Use that delta to calculate the new "quantity" Example: Quantity is 10 User A visits the public website (quantity = 10) User B visits the backend (quantity = 10, quantity_before_edit = 10) User A orders 2 pieces and the page gets saved (quantity = 8 ) User B saves the page without editing the quantity (quantity = 10, quantity_before_edit = 10) saveReady hook kicks in: quantity = 10, quantity_before_edit = 10 ---> diff = 0 get current quantity from uncached page from the database, quantity = 8 add diff and write result to $page->quantity = 8 ideally show a warning to the user that a quantity has been saved that is different from his/her input page is saved, final result is quantity = 81 point
-
The ProDevTools module of User Activity is another possible option. I haven't used it, so I'm not 100% sure if it prevents this from happening, or just alerts users when the possibility of a collision exists. https://processwire.com/store/pro-dev-tools/user-activity/1 point
-
@Carsten The echo '<pre>' part comes too early. Change the first few lines to: <?php namespace Processwire; ini_set('max_execution_time', 60 * 5); // 5 minutes, increase as needed include("./index.php"); echo '<pre>'; // rest below unchanged: // Add a leading back slash to the class so it can access the global namespace $dir = new \DirectoryIterator(wire('config')->paths->files); Tried the script like this and it works just fine (PW 3.0.205)1 point
-
Thanks @BrendonKoz, I did already see the LiteSpeed WordPress setup you linked, which appeared to be for the enterprise version. Assuming a paid license would've been required, I tried OpenLiteSpeed one instead. I'm not sure if you looked at the template at all but there's a lot going on there. I did give it a try, it generated lots of conf files in a new lsws directory, and I ran into some errors trying to modify the Docker compose file—it would be far too time-consuming to do it this way, and if I'm going to go to that level, I may as well configure a VPS since changing a Docker configuration is doing that plus containerizing it. DDEV sounds appealing but upon closer inspection, this supports MariaDB but does not have documentation for LiteSpeed so unless it's an undocumented feature, this isn't a suitable suggestion. Did you see support for LiteSpeed somewhere? Feel free to link it, because I did not. My question was specifically about dev environments for spinning up LiteSpeed with MariaDB to ensure compatibility with the client's infrastructure.0 points