Leaderboard
Popular Content
Showing content with the highest reputation on 11/10/2021 in all areas
-
https://right-to-know.org/ Website to check your local area's stressors e.g. air, noise and light pollution etc. Available for postcodes in the UK. I did quiet a bit of database stuff to host postcode lookup on the site and caches any API results for teh stressors on site for fast second query. We also choice against any tracking on the site (google analytics etc) and only track the number of total queries and number of requests to each specific postcode.5 points
-
New module: OneTimeOnlyCode https://github.com/benbyford/OneTimeOnlyCode Use this module to create codes with urls (or any of string data) and later check a code and its data e.g. to get one time access to content. I built this to send out specific "exclusive" users codes at the end of URLs to new articles where noramlly they would have to log in -> now they can see the content only once and then have to login if they navigate away. I made it only to show the content not any user profile infomation etc when using the code, be warned not to use it to show user information unless you know what you're doing! Codes can have an expiry and uses lazy-cron to cull codes out of day at a set interval (both in checking and elapsed interval for the codes). Check it out!5 points
-
Depending on what kind of page reference field you are using, you could achieve that with a hook, for example in site/ready.php. In this example I am using a page reference field named 'page_reference' and as the Input Field Type I am using a Select field. Now I hook into the Inputfield::render method with a before hook: // use before hook to alter options passed to the Inputfield $wire->addHookBefore('InputfieldSelect::render', function ($event) { // return; if($event->object->name != 'page_reference') return; // build our new options array $options = array(); // $event->object->options is an array of options originally passed to the InputField foreach($event->object->options as $id => $title) { $options[$this->pages->get($id)->name] = $title; // exchange name for email } // set our new options to the InputField $event->object->options = $options; }); This sets the value of the <option> tag to the page name. you can use $this->pages->get($id)->email to set the emails as value. Don't know where you render that form. If it is a custom form somewhere, this should do. But be careful if you plan to use this in the PW page editing form. You will need to take some extra steps when saving the page. Because PW needs the ID of the page to be saved. In that case you can have a look at InputfieldPage::processInput and hook into that to revert your email values back to IDs.2 points
-
As a hobby writer, I do have my doubts there. Natural language is the second most ambiguous thing in the world, right after Schrödinger's cat.2 points
-
I've been meaning to revise PageimageSrcset for a while now, to remove some features that I felt were unnecessary and to implement a better rendering strategy. The result is PageimageSource. What does it do? It provides a configurable srcset method/property for Pageimage It allows WebP to be enabled for images it generates. It allows Pageimage:render() to return a <picture> element It provides a Textformatter that replaces <img> elements with the output of Pageimage:render() Although it is based on a current module, this should still be considered beta and not used in production without a prior development stage. Here's the README: PageimageSource Extends Pageimage with a srcset property/method plus additional rendering options. Overview The main purpose of this module is to make srcset implementation as simple as possible in your template code. For an introduction to srcset, please read this Mozilla article about responsive images. Installation Download the zip file at Github or clone the repo into your site/modules directory. If you downloaded the zip file, extract it in your sites/modules directory. In your admin, go to Modules > Refresh, then Modules > New, then click on the Install button for this module. ProcessWire >= 3.0.165 and PHP >= 7.3 are required to use this module. Configuration To configure this module, go to Modules > Configure > PageimageSource. Default Set Rules These are the default set rules that will be used when none are specified, e.g. when calling the property: $image->srcset. Each set rule should be entered on a new line, in the format {width}x{height} {inherentwidth}w|{resolution}x. Not all arguments are required - you will probably find that specifying the width is sufficient for most cases. Here's a few examples of valid set rules and the sets they generate: Set Rule Set Generated Arguments Used 320 image.320x0-srcset.jpg 320w {width} 480x540 image.480x540-srcset.jpg 480w {width}x{height} 640x480 768w image.640x480-srcset.jpg 768w {width}x{height} {inherentwidth}w 2048 2x image.2048x0-srcset.jpg 2x {width} {resolution}x How you configure your rules is dependent on the needs of the site you are developing; there are no prescriptive rules that will meet the needs of most situations. This article gives a good overview of some of the things to consider. When you save your rules, a preview of the sets generated and an equivalent method call will be displayed to the right. Invalid rules will not be used, and you will be notified of this. WebP If enabled, WebP versions of the image and srcset variations will be generated and these will be returned by Pageimage::srcset(). As with the default implementation, the image with the smaller file size is returned. In most cases this is the WebP version, but sometimes can be the source. Make sure to experiment with the quality setting to find a value you find suitable. The default value of 90 is fine, but it is possible that lower values will give you excellent kB savings with little change in overall quality. For more information on WebP implementation please read the blog posts on the ProcessWire website. Rendering These settings control how the output of Pageimage::render() is modified. Use Lazy Loading? When enabled this adds loading="lazy" to the <img> attributes. It is useful to have this on by default, and you can always override it in the options for a specific image. Use the <picture> element? When enabled, the <img> element is wrapped in a <picture> element and <source> elements for original and WebP variations are provided. This requires WebP to be enabled. For more information on what this does, have a look at the examples in Pageimage::render() below. Remove Variations If checked, the image variations generated by this module are cleared on Submit. On large sites, this may take a while. It makes sense to run this after you have made changes to the set rules. Please note that although the module will generate WebP versions of all images if enabled, it will only remove the variations with the 'srcset' suffix. Usage Pageimage::srcset() // The property, which uses the set rules in the module configuration $srcset = $image->srcset; // A method call, using a set rules string // Delimiting with a newline (\n) would also work, but not as readable $srcset = $image->srcset('320, 480, 640x480 768w, 1240, 2048 2x'); // The same as above but using an indexed/sequential array $srcset = $image->srcset([ '320', '480', '640x480 768w', '1240', '2048 2x', ]); // The same as above but using an associative array // No rule checking is performed $srcset = $image->srcset([ '320w' => [320], '480w' => [480], '768w' => [640, 480], '1240w' => [1240], '2x' => [2048], ]); // The set rules above are a demonstration, not a recommendation! Image variations are only created for set rules which require a smaller image than the Pageimage itself. This may still result in a lot of images being generated. If you have limited storage, please use this module wisely. Pageimage::render() This module extends the options available to this method with: srcset: When the module is installed, this will always be added, unless set to false. Any values in the formats described above can be passed. sizes: If no sizes are specified, a default of 100vw is assumed. lazy: Pass true to add loading=lazy, otherwise false to disable if enabled in the module configuration. picture: Pass true to use the <picture> element, otherwise false to disable if enabled in the module configuration. Please refer to the API Reference for more information about this method. // Render an image using the default set rules // WebP and lazy loading are enabled, and example output is given for <picture> disabled and enabled echo $image->render(); // <img src='image.webp' alt='' srcset='image.jpg...' sizes='100vw' loading='lazy'> /* <picture> <source srcset="image.webp..." sizes="100vw" type="image/webp"> <source srcset="image.jpg..." sizes="100vw" type="image/jpeg"> <img src="image.jpg" alt="" loading="lazy"> </picture> */ // Render an image using custom set rules echo $image->render(['srcset' => '480, 1240x640']); // <img src='image.webp' alt='' srcset='image.480x0-srcset.webp 480w, image.1240x640-srcset.webp 1240w' sizes='100vw' loading='lazy'> /* <picture> <source srcset="image.480x0-srcset.webp 480w, image.1240x640-srcset.webp 1240w" sizes="100vw" type="image/webp"> <source srcset="image.480x0-srcset.jpg 480w, image.1240x640-srcset.jpg 1240w" sizes="100vw" type="image/jpeg"> <img src="image.jpg" alt="" loading="lazy"> </picture> */ // Render an image using custom set rules and sizes // Also use the `markup` argument // Also disable lazy loading // In this example the original jpg is smaller than the webp version echo $image->render('<img class="image" src="{url}" alt="Image">', [ 'srcset' => '480, 1240', 'sizes' => '(min-width: 1240px) 50vw', 'lazy' => false, ]); // <img class='image' src='image.jpg' alt='Image' srcset='image.480x0-srcset.webp 480w, image.1240x0-srcset.webp 1240w' sizes='(min-width: 1240px) 50vw'> /* <picture> <source srcset="image.480x0-srcset.webp 480w, image.1240x0-srcset.webp 1240w" sizes="(min-width: 1240px) 50vw" type="image/webp"> <source srcset="image.480x0-srcset.jpg 480w, image.1240x0-srcset.jpg 1240w" sizes="(min-width: 1240px) 50vw" type="image/jpeg"> <img class='image' src='image.jpg' alt='Image'> </picture> */ // Render an image using custom set rules and sizes // These rules will render 'portrait' versions of the image for tablet and mobile // Note the advanced use of the `srcset` option passing both `rules` and image `options` // WebP is disabled // Picture is disabled echo $image->render([ 'srcset' => [ 'rules' => '320x569, 640x1138, 768x1365, 1024, 1366, 1600, 1920', 'options' => [ 'upscaling' => true, 'hidpi' => true, ], ], 'sizes' => '(orientation: portrait) and (max-width: 640px) 50vw', 'picture' => false, ]); // <img src='image.jpg' alt='' srcset='image.320x569-srcset-hidpi.jpg 320w, image.640x1138-srcset-hidpi.jpg 640w, image.768x1365-srcset-hidpi.jpg 768w, image.1024x0-srcset-hidpi.jpg 1024w, image.1366x0-srcset-hidpi.jpg 1366w, image.1600x0-srcset-hidpi.jpg 1600w, image.jpg 1920w' sizes='(orientation: portrait) and (max-width: 768px) 50vw' loading="lazy"> TextformatterPageimageSource Bundled with this module is a Textformatter largely based on TextformatterWebpImages by Ryan Cramer. When applied to a field, it searches for <img> elements and replaces them with the default output of Pageimage::render() for each image/image variation. Assuming a default set of 480, 960 and lazy loading enabled, here are some examples of what would be returned: Example <figure class="align_right hidpi"> <a href="/site/assets/files/1/example.jpg"> <img alt="" src="/site/assets/files/1/example.300x0-is-hidpi.jpg" width="300" /> </a> </figure> WebP enabled <figure class="align_right hidpi"> <a href="/site/assets/files/1/example.jpg"> <img alt="" src="/site/assets/files/1/example.300x0-is-hidpi.webp" width="300" srcset="/site/assets/files/1/example.300x0-is-hidpi.webp 480w" sizes="100vw" loading="lazy" /> </a> </figure> <picture> enabled <figure class="align_right hidpi"> <a href="/site/assets/files/1/example.jpg"> <picture> <source srcset="/site/assets/files/1/example.300x0-is-hidpi.webp 480w" sizes="100vw" type="image/webp"> <source srcset="/site/assets/files/1/example.300x0-is-hidpi.jpg 480w" sizes="100vw" type="image/jpeg"> <img alt="" src="/site/assets/files/1/example.300x0-is-hidpi.jpg" width="300" loading="lazy" /> </picture> </a> </figure> Because the variation is small - 300px wide - the srcset only returns the source image variation at the lowest set width (480w). If the source image was > 1000px wide, there would be a variation at both 480w and 960w. PageimageSrcset This module is built upon work done for PageimageSrcset, which can be considered a first iteration of this module, and is now deprecated. Migration PageimageSource is a simplified version of PageimageSrcset with a different approach to rendering. Most of the features of the old module have been removed. If you were just using $image->srcset(), migration should be possible, as this functionality is essentially the same albeit with some improvements to image variation generation.1 point
-
Now that we're in the last couple months of this year, I've been trying to implement a lot of plans that we discussed early in the year. That meant a lot of updates to repeaters in the last couple of weeks (and likely more on the way). But this week, I've been working on another thing we discussed earlier, which is bringing automatic save and live preview capabilities to ProcessWire, independently of ProDrafts, and with full repeater support. In ProcessWire, it's your own code (in template files) that renders the site’s output. ProcessWire delivers a $page to your template file(s), and your template file(s) render it in whatever manner they see fit. In this environment, we need an automatic save capability before we can have a live preview capability. Working on that automatic save capability is what I've been doing this week. I figure that once that is finished, then we'll be able to start developing the live preview capability. I'm glad to report that we now have automatic save fully functional and have tested pretty thoroughly with every Fieldtype/Inputfield I can think of. Unlike in ProDrafts, it also fully supports repeater, repeater matrix, and even nested ones. Actually, it looks like we'll be able to support everything you would want it to. But it's early yet it'll need a lot of testing before its production ready. I've built it into a module called PageAutosave. It requires the latest version of ProcessWire on the dev branch (3.0.189). I'm not yet positive whether this is going to end up as a core module or not. I thought I would gauge interest and see. For now, I'm posting a limited release test version of it in the ProDrafts support board and ProDevTools support board, if anyone is interested in trying it out. The PageAutosave module lets you configure whether you want it enabled for all pages or just for unpublished pages. When needed, you can also optionally choose to limit it to certain templates, certain fields, or certain user roles. Autosave isn't always desirable as it literally means your changes get saved to the $page as you type, so I imagine it's something people might use more for unpublished pages. Autosave is one side of the coin and live preview is the other. The current goal for live preview is to not depend on any particular view or admin interface and instead to just simply have the option of having a window open to a page in the website that detects changes and updates them automatically. So if you had one window open to the page edit screen, and another window viewing the page being edited, you could observe your updates as you made them. Once that is working reliably, we can decide on how best to put an interface around it, and maybe some will also like the option of just having two browser windows open wherever they want them. This won't be the kind of live preview where you'll see every character as you type it, but more likely you'll see updates a second or so after you make them. That's because your edits have to be auto-saved in the page editor, ProcessWire has to call your template file(s) to render the output, and the live preview has to update whatever has changed since the last update. It's that last part of it that I'll need the most help on. Some of you have mentioned htmx as a potential way to accomplish that and I think it looks compelling. And if you know of any other [likely JS-based] tools or technologies that we should also look at, please reply and let us know. I've bumped the core version to 3.0.189 primarily because the PageAutosave module requires updates that are in this version. This version also continues some longer term build out of a couple Fieldtype interface methods across multiple modules, and adds a new 'sorted' JS event that is triggered during sort actions (also used by PageAutosave). But if you aren't going to be installing the PageAutosave module, there's no urgency to update to 3.0.189 if you are on the dev branch and already using 3.0.188. Thanks for reading and have a great weekend!1 point
-
In preparation for testing of the initial (alpha/early beta) release of Padloper 2, I would like to gather expressions of interest. In the past, some of you expressed a willingness to help with testing. It has been many days since and your position might have changed. In addition, I would like to do this in an organised manner so we cover as much ground as possible. The grounds I’d like to cover are usability and technical aspects with a bias towards the latter. Please also note that there are a number of planned features that will follow the initial release. Hence, we shouldn’t focus much on those. These and similar thoughts will be added to a planned features list (more on this below). The main focus of this testing is to make Padloper 2 production-ready. In order to properly organise this testing, I will need to gather some information from you. I will be doing this via Google Forms. The most important detail will be your email address. I will need this in order to inform you how to access Padloper 2 as well as for other necessary communication. I will not use your email address for any other purposes nor pass it to any third-party ?. Other information to be captured in the form would be what areas of testing you will you want to be involved in and your preference for planned features (since I will need to prioritise them). Forms are better than plain emails in this respect. Please note the following if you wish to be involved in the testing programme: Pricing and subscription will follow the model I have previously stated (similar to ProcessWire Pro Modules). However, for the testing programme, your subscription period will NOT start counting down until after the production-ready release. You will still also have VIP support (please note the nature and location of this may change). To be fair to other testers, anyone joining the programme needs to actually spend time testing the product. If you won’t have time to do this, please wait for the production release. This initial release is NOT a production release. Although it may work for some in that regard, it will not be tagged as production-ready (hence the alpha tag). Licences will be the usual three: (i) Basic/Single Site Licence, (ii) Developer Licence and (iii) Agency Licence. I can explain the different between these three if anyone needs clarity. The initial release will have the introductory prices of €150, €300, €900 for single, developer and agency licences respectively. Cooling period will be 14 days (within which a full refund can be requested, no questions asked). Please note that this time period may change for the production release. Here is the link to the Google Form to express your interest in the testing programme. The form will close in 10 days. Many thanks for your patience. Hope to see you soon in the testing programme. I trust you will enjoy Padloper 2 as much as I have had the pleasure (and honour) of developing it ?.1 point
-
1 point
-
I tend to have multiple items (pages) in my footers so there is more than one ‘footer’ page. The code is then included in _main.php. I guess they could be grouped into one page, but not sure of the merits of that.1 point
-
The following video demonstrates how to set up a development server that is 100% ProcessWire friendly and uses all the latest software (PHP 8, MySQL 8, Apache 2). While there are other approaches to it (such as using tasksel lamp), the video demonstrates an efficient and clean way in getting all the latest versions of the software, advanced configuration settings, in addition to setting up SSL. This could also be used for WSL2 since it's ultimately a barebone virtual machine, much like DigitalOcean and similar providers.1 point
-
As of ProcessWire 3.0.166 this may be an option: https://processwire.com/api/ref/page/secure-files/1 point
-
I've done a small test. Let's say you have a template "onlymembers" with a files-field "members_pdf". In this case your pdf file is safe as soon as you set pagefileSecure to true AND restrict the access of the template "onlymembers" (i.e. remove all guest access rights). ProcessWire gave me a 404 page. You don't need the pagefileSecurePathPrefix line. It is set by default. Hope that helps.1 point
-
1 point
-
Fantastic site, great job ? Ditto some random postcodes threw an error e.g. IV42 8YD, IV41 8WZ (selected off the web to compare against my home postcode).1 point
-
1 point
-
1 point
-
1 point
-
Thanks. ? I'm going to try and implement this when I get the time. I'm thinking use your code running only on Pages::delete with status!=trash added to the selector — and then issuing a warning on Pages::restore if there are any broken references (possibly also setting the page to unpublished). I'll post something once I've had a go.1 point
-
I guess you could exclude pages that are in the trash by changing... $referenced_on = wire('pages')->find("$pr_fields_str=$page->id, include=all"); ...to... $referenced_on = wire('pages')->find("$pr_fields_str=$page->id, include=all, status!=trash");1 point
-
Thanks for your thoughts @ryan. You raise some good points here. Setting the entry level as low as possible is desirable. Do you mean when coding in htmx or vanilla JavaScript/jQuery? Maybe have a look at htmx onLoad method? There is an example here for third-party integration, although I am not sure if it is applicable. Other than that, many of htmx attributes are inherited and can be placed on the parent element. htmx aside, with JavaScript event bubbling/delegation, even with vanilla JS, if you placed the events on the parent element, future events should be picked up. Another option is MutationObserver. It is a beast though! Or maybe I misunderstood the question?1 point
-
@kongondo Thanks, great ideas! Your SSE examples are eye opening. I think I understand a lot of this but not yet all of it, since I'm not deep in htmx yet, so I'll have to return to this once I do. But part of what you covered was the external interface to it that the web developer implements, and I think that's a good place to start, so I'll focus just on that. I understand the benefits of a separate config file, but am not sure how many would go to the effort of maintaining it for live preview. Maybe if PW auto-generates it somehow with functional defaults, it might help. Pros/cons aside, when we need something outside of the defaults, personally I'd rather declare this with markup classes or attributes in a manner similar to how we do for Markup Regions. Maybe I'm lazy, but it's already easy and familiar, and not much new to remember. Like with Markup Regions, ProcessWire can remove the attributes when they aren't needed, so no need for any output downsides. But if I had to declare it separately from the markup, I'd at least like to be able to do it in Setup > Fields > field rather than having to edit a .json file (and maybe this is a good fallback either way). I agree that it's good if the default behavior is to swap the entire <body> / refresh the window. But when we want to declare what gets updated with a live preview, here's an example of one way we could do it. If I wanted a particular section of markup to update automatically when the field "images" changed, I'd like if I could just do something simple like this, where div#gallery is an existing bit of markup a already there, like this: <div id='gallery'> // markup for an image gallery </div> …and I just add a class to that existing markup tag... <div id='gallery' class='pw-field-images'> // markup for an image gallery </div> ...or maybe a custom attribute instead: <div id='gallery' pw-field='images'> <!-- markup for images gallery --> </div> I'm not suggesting to add additional markup, but just an additional class or attribute to existing markup. If that same images field was also used elsewhere in the page, then I could just use that class (or attribute) again, and it would update too: <div id='sidebar-photos' class='pw-field-images'> <!-- markup for the sidebar photos --> </div> One thing I noticed in coding ProDrafts live preview is that field-level granularity often makes little difference in the end result. Replacing larger blocks of markup often is just as effective and visually identical. So I'd want to be able to say "if any of these fields change, update this…": <div id='content' pw-field='title,body,images,sidebar'> ... </div> For fields that already contain markup (like CKEditor), or fields that get rendered from their own /site/templates/fields/* template file, ProcessWire could automatically add the appropriate class by wrapping the value with it (this is similar to what ProDrafts and PageFrontEdit do): <div class='pw-field-body'> <!-- value of $page->body, div wrapper added automatically when live preview --> </div> This enables it to work automatically, without the developer doing anything at all. The only minor downside is that occasionally that can interfere with a CSS/JS selector, like if you are trying to target h1 + p:first-child, where the <p> is part of the CKEditor output but the <h1> isn't. Live preview still works, but the CSS/JS selector no longer matches when live preview is on. It's simple to work around though, and of course only affects output when someone is live previewing. Whether using a separate config file or not, if we use htmx, I think it should be a silent player and the developer wouldn't even need to know anything about how to use it. I'd like to avoid an external config file where I'm having to add 'htmx-attributes' arrays. I don't think we need the level of granularity or features in live preview that would demand the user know this kind of stuff. (Though fine for advanced users if/when needed). The more automatic it is, the more likely one is to use it. I think we'd also like the flexibility of not being dependent upon any particular library in case we ever decide to replace it with something custom. Side note, but one issue I also noticed in coding ProDrafts live preview is that when you update an element that has JS events on it that were added in document.ready, then they no longer work. For instance, an images gallery might have events that make thumbnails open in a lightbox or something. When the images gallery live updates, the lightbox no longer works unless the events were added to the whole document. Does htmx have some magic for this kind of situation?1 point
-
I don't know much about datetime libraries, just know that tabulator.info recently replaced momentjs by luxon. http://tabulator.info/docs/5.0/release#dependencies https://github.com/you-dont-need/You-Dont-Need-Momentjs https://www.htmlgoodies.com/javascript/luxon-vs-moment-javascript/ Good luck with your new challenge ??1 point
-
Announcing the current status, planned release, roadmap and preview of Padloper 2. Status Feature freeze. Full multilingual support. Only PHP 7.2+ supported. Support for ProcessWire 3.0 only. Backend support for modern browsers only (that support JavaScript ES6 modules). Current Work Finish work on admin/backend. Work on installer and uninstaller (including configurable availability of some features). Work on UI/UX improvements. Start work on documentation with special focus on technical documentation. Continue work on Padloper API and data/model component. Roadmap Please note that these ARE NOT hard and fast targets. The roadmap may have to be adjusted to accommodate technical and non-technical constraints. Q1 2021 Inbuilt support for (latest) PayPal (full rewrite, no external modules required). Additional work on Padloper API. Invite a limited number of early alpha testers (fully-priced product). Soft and closed release of Padloper 2. Q2 2021 Start work on relaunch of Padloper website. Inbuilt support for Stripe (no external modules required). Future Plans Support for more Payment Gateways. Support for order, customers, etc imports and exports. Support for AdminThemeReno and AdminThemeDefault. Separate fully-featured frontend shop module. Consider support for multiple currencies. FAQ 1. Have you abandoned this project? No. 2. When will Padloper 2 be released? First early alpha release is scheduled for Q1 2021. This target may change depending on circumstances! Access will be by invite only for this first release. 3. What is the pricing model of Padloper 2? Three licences: Single Site, Developer and Agency licences (12 months’ updates and VIP support). 4. How much will Padloper 2 Cost? No price has been set yet. It will cost more than Padloper 1. 5. Can we upgrade from Padloper 1? No. 6. Will existing users of Padloper 1 get a discount for Padloper 2? No, this will not be possible. Apologies for the earlier announcement. It was unrealistic and unworkable. 7. Can we pay for Padloper 2 in advance? No. 8. Does Padloper 2 render markup/templates in the frontend? No. Access to all data you need to build your shop’s frontend is via the Padloper API. 9. Can we keep sending you ‘Are we there yet’ messages? No, please. Preview Here is a video preview of the current state of the backend/admin of Padloper 2. Please note the following: This is early alpha. There are bugs! It even includes WIP/notes!! FOUC, misaligned things, etc. The video shows the near-raw implementation of Vuetify UI. The UI/UX improvements work is yet to start. What you see here is the development version. Some of the incomplete features may not be available in the early releases. Most of the features you see will be optional to install.1 point
-
I don't really do routing here. Still need to learn that. My use of Stencil is more based on the benefits in organization and workflow. It's super easy to bring a component from one project to the next, and it's easier to maintain when everything is neat and tidy. Using my boilerplate I basically start with a StencilJS + Storybook base, to develop individual components and demo them. If it's a super simple project, storybook already generates a static site nicely. See this one here: https://papoes.iniciativaliberal.pt/, where I just made the basic components and combined them in simple HTML pages. And from there, if we have an HTML page you know how easy it is to make it dynamic with PW ? My suggestion is just to try out the getting started on Stencil's page. It's really not that much of a stretch going from knowing HTML+CSS+JS to webcomponents. Once there, when you feel comfortable, look into the routing bit. You're right. Still plenty of room to improve that bit.1 point
-
I love ?the aesthetics of the site. Very great work and visually appealing ?️. There are some performance issues when zooming the map (because there are many retailers shown at once and maps get sluggish with many markers, even with MarkerClusterer), and the find function could be accomplished with a geolocate button (take actual position of you, to find dealers that are near you). Take a look at P. Jentschura – Natürliche Produkte für den Säure-Basen-Haushalt (p-jentschura.com) which as over 5000 dealers, where I tackled the performance problem. Also you could add a "Clear search" or "Reset" button, because If you clicked one dealer it is impossible to go back to the whole list. If you have interest in optimizing the whole map application you can contact me. I did several map applications in the last years. In addition I wrote an "ImportRetailers" module for one of my clients, that geocodes the addresses via geocoder-php/google-maps-provider which uses also caching if you query the same address again (and has almost no request restrictions).1 point
-
@Cybermano, I don't understand what you are doing with this line inside the foreach: $boat->barca_results->sort('id', $race); This doesn't seem to correspond to the correct use of either $wirearray->sort() or $pages->sort() so maybe you are getting mixed up with the methods? To go back to brass tacks (you may already know a lot of this but it might be useful for others)... The first meaning of "sort" as it relates to pages is the sort value. This is a column in the "pages" database table. Every page (including Repeater pages) has a sort value and this determines its sort position relative to its sibling pages (assuming no automatic sort has been set on the parent page or template). The sort value starts at zero, and the lower the number is the closer to the top of the sort order the page will be relative to its siblings. So in this page structure... The sort value of "Red" will be 0, the sort value of "Green" will be 1, and so on. In some circumstances you can end up with gaps in the sort values as pages are deleted or moved and that is where the $pages->sort() method can be used to "rebuild" those sort values under a parent. But in 99% of cases you don't need to worry about sort values because PW just takes care of it and you don't have to use $pages->sort() to sort your Repeater items so we can ignore that. You can set the sort value of a page the same as you would an integer field in the page's template: $page->of(false); $page->sort = 123; $page->save(); The second meaning of "sort" is the WireArray::sort() method. When it comes to pages, a PageArray is a kind of WireArray, and a RepeaterPageArray is a kind of PageArray, so this means we can use WireArray::sort() to sort a RepeaterPageArray. The method works by sorting the WireArray by one or more properties of its items. In the case of a RepeaterPageArray this could be something like the "modified" timestamp of the items or it could be a field such as "title". So you could do something like this to sort a field named "test_repeater" alphabetically by title (assuming that the Title field was used in the Repeater): $page->test_repeater->sort('title'); And you can get more advanced by adding a temporary custom property to the items in a WireArray/PageArray/RepeaterPageArray and then using WireArray::sort() on that temporary property. I'll show an example of that in a moment. If you have a page $p that contains a Repeater field "test_repeater" then you can sort the RepeaterPageArray as shown above in your template file and when you output the items in $p->test_repeater they'll be in the sort order you want. But if you wanted to save $p after you sorted test_repeater then it's not enough to just have the items in test_repeater in the right order and then save $p. And that's because PW uses the sort value of each Repeater page to determine the sorting of the Repeater field when it loads it from the database. So to make the sort order stick we need to save the sort value of each Repeater page in the RepeaterPageArray, and to do that we can use an incrementing counter that starts at zero. A couple of code examples... Sort test_repeater by title and save: // Get the page containing the Repeater items $p = $pages(1066); // Turn off output formatting for the page because we are going to save it later $p->of(false); // Sort the Repeater items alphabetically by title $p->test_repeater->sort('title'); // $i is a counter we will use to set the sort value of each Repeater item/page $i = 0; foreach($p->test_repeater as $repeater_item) { $repeater_item->of(false); $repeater_item->sort = $i; $repeater_item->save(); $i++; // Increment the counter } // Save the test_repeater field for $p $p->save('test_repeater'); More advanced sorting using a temporary property: // Get the page containing the Repeater items $p = $pages(1066); // Turn off output formatting for the page because we are going to save it later $p->of(false); // More advanced sorting: sorting by title length // We add a temporary "custom_sort" property to each Repeater item // And then sort the RepeaterPageArray by that custom_sort property foreach($p->test_repeater as $repeater_item) { $repeater_item->custom_sort = strlen($repeater_item->title); } $p->test_repeater->sort('custom_sort'); // $i is a counter we will use to set the sort value of each Repeater item/page $i = 0; foreach($p->test_repeater as $repeater_item) { $repeater_item->of(false); $repeater_item->sort = $i; $repeater_item->save(); $i++; // Increment the counter } // Save the test_repeater field for $p $p->save('test_repeater'); Hope this helps.1 point