Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation since 11/08/2022 in all areas

  1. This week the ProcessWire core version on the dev branch has been bumped to 3.0.207. Relative to the previous version, there are several minor issue resolutions and improvements (commit log). I also recommend this version if you are testing out the InputfieldTinyMCE module, which will likely be merged into the core near the end of the year. Speaking of that module, it also received updates this week with the biggest being the addition of improved lazy loading modules for the Normal (non-inline) editor. Rich text editors are one of the most heavyweight input types you can use, so not having to initialize them all during page load is a major performance benefit, especially when you've got multiple fields using them at the same time. With these new lazy-loading modes, the Normal editor has many of the benefits of the Inline editor in terms of page editor performance, but without any of the drawbacks. The new default setting is to "load editor when it becomes visible". This ensures that resources aren't spent loading editors that are hidden behind editor tabs, fieldsets or language tabs, until they are needed. The other lazy-loading option ("load editor when clicked") is the most aggressive lazy loading option. It shows a preview of the editor content but doesn't actually load TinyMCE until you click the preview to edit it. Lastly, I've also been working on a new module (WireSitemapXML) that generates sitemap.xml output, but in a way that I think is more configurable than the other modules available for it. It also supports multi-language sitemaps, URL segments, various hooks and more. While I've got it in use already, I'm going to spend more time on the documentation before releasing it. That's all for this week, have a great weekend!
    32 points
  2. This week we've got a new core version on the dev branch, version 3.0.208. This version includes 15 new commits with a combination of issue resolutions and new features. See the dev branch commit log for full details. In addition, we have new versions of the following ProFields modules: FieldtypeTable, FieldtypeTextareas, FieldtypeMultiplier and FieldtypeFunctional. (Last week a new version of FieldtypeCombo was released as well). These are all posted in the ProFields downloads thread. These versions all add support for the new InputfieldTinyMCE module, in addition to other regular improvements and updates. I think that completes the list of modules I've developed that needed an update to support InputfieldTinyMCE. Speaking of InputfieldTinyMCE, it also received updates this week, primarily focused on resolving reported issues. Thanks for reading and have a great weekend!
    25 points
  3. Just a quick update this week, as yesterday was a holiday here and it becomes kind of a holiday week with kids out of school. On the core dev branch, the built-in PageFrontEdit module has been updated to support the new InputfieldTinyMCE rich text editor module. In addition. The $sanitizer->email() method has been updated with several new options. These include support for emails with Internationalized Domain Names (IDNs), UTF-8 local parts and an option to validate the DNS of the email domain. Currently all of these options are off by default but can be enabled with a new $options argument. These options will likely be translated to configure options for email fields (FieldtypeEmail) in the next week or so. In addition, a new version of the ProFields Combo has been released and this version also adds support for the new InputfieldTinyMCE module. I'm also working on updates for ProFields Table and Textareas for support of InputfieldTinyMCE as well, but those updates aren't quite ready to post just yet. If you opt to use TinyMCE with PageFrontEdit or Combo, make sure you grab the latest version of InputfieldTinyMCE, as it also received related updates this week. Thanks for reading and have a great weekend!
    22 points
  4. 🚨 [[ UPDATE December 6, 2022 ]] 🚨 I prepared a small landing page to validate how many of you would be willing to take the course, so that we would have a rough estimate of how many people would be willing to take the course. 🔗 Show me your interest here 🔗 ------------------------------------------------------- Hello to the entire wonderful Processwire community! I am here to announce my willingness to create a video course for beginner/mid-level developers interested in learning more about the main aspects of our beloved CMS. I have been working with Processwire continuously for years now, so I feel confident that I can share what I have learned to other developers interested in becoming faster and more efficient in their day-to-day work. I have noticed that lately many people here in the forum have complained about a lack of material and tutorials for taking the first steps, and although so many resources are already present within the board, I understand how complicated it can be to be able to connect the dots and have a clear reference on how to get started or how to find clear answers in a short time. As you know Processwire is a very broad tool, very flexible and able to be adapted to any need, so it will not be possible to dissect every aspect in this course, especially the more advanced ones that can help in rarer cases (at least in my personal experience). 🎉 But don't worry, I plan to explain with many practical examples many tips and tricks that can help you in developing sites, even particularly structured ones! 🎉 So I am here to test your interest and ask you what aspects you would be most interested in me covering, even those related to design (css, scss, postcss, tailwind) or javascript libraries/frameworks integrations (vue, alpine.js, greensock for animations,etc.). My idea would be to create together a magazine with a restricted area for users, newsletter integration, catalog filtering according to different parameters (year, author, topics, etc.) and much more.💣 It will be a paid course, I have not yet decided what the price will be, but it will be affordable for everyone 👍. For a small period of time, I would be pleased if you would give me pointers and ideas, so I can see what your real interest is (if any!) and also motivate me 🙂 Let me know! Thanks! 🙏
    16 points
  5. The latest site of the week reminded me of https://senderkataster.rtr.at/ that I built with a friend some time ago and that I want to share. Tech: ProcessWire (obviously) https://getuikit.com/ (also quite obvious 😄 ) https://tabulator.info/ for all kinds of filters https://leafletjs.com/ for the map https://basemap.at/ using an Open Government Data License Some GDAL command line magic to transform the overlay source data into PNGs that are stored in ProcessWire pages and can then be queried and correctly placed on the map. ProcessWire has been a great platform for that project! If you need help with a ProcessWire project that needs some geo-magic or powerful web maps drop me line 🙂 I'm not responsible for the red background 😅 Show details of a tower Choose a program by name or type and show its radio coverage (not in the screenshot): Expert mode for nerds:
    15 points
  6. Hi everyone, I would like to showcase a small micro site of own studio - 7studio.eu Personally I don't like to design anything for myself (as most projects lands in the trash or on the shelf), but I needed something new and simple quite fast before building a fully fledged portfolio, so I thought to built a small "starting point". This is more like a work in progress, than a finished site, it contains only basic info, screenshots of some of the latest works and that's it - as for now 😉 Technically, on the front end we have a simple custom HTML5/CSS3/JS code, on the back end site uses only core PW features (there is more features already built in on both backend and frontend but not published yet). Any comments, suggestions are welcome, hope you will like it and have a great weekend everyone! P.s. Sorry - there is no english translation yet, PW multilingual features will land in the upcomming weeks 😉
    15 points
  7. I'm really happy with InputfieldTinyMCE so far. And as threatened to in reply to an earlier core updates post, I took a stab at migrating my autocomplete module over from InputfieldCKEditor. All in all, it was quite a pleasant experience and the JS side was really straight forward. The change also involved a lot of refactoring, and in the aftermath of that there's still a good bit of house cleaning to do, but for anybody willing to toy around with it, there's an alpha release of InlineCompleteTinyMCE on GitHub. A snapshot of InlineCompleteTinyMCEActionUsers in action: And the corresponding configuration in the field's "Input" tab (added to the TinyMCE config section): I haven't tested it with lazy loading or the inline editor yet.
    14 points
  8. This week I've been focused on a client project, building out this Reviews section (still a work in progress). There's a few hundred URLs within it, but it's just one page/template. The reviews are via ProcessWire's core comments (FieldtypeComments) field and primarily uses the FieldtypeComments find() method for filtering and sorting of comments/reviews. On this same site, this week Pete launched this very nice blog called Tailwinds, which he told me is using Tailwind CSS (and powered by ProcessWire). The name of the blog (Tailwinds) actually precedes the use of Tailwind CSS, but if you've got a blog named Tailwinds, Tailwind CSS certainly seems like the appropriate framework. 🙂 On the core dev branch we've had a few commits resolving issues and minor improvements, but not enough for another version bump this week. Have a great weekend!
    12 points
  9. https://50thbirthday.londonfriend.org.uk/ This is a site we created to celebrate the 50th anniversary of London Friend which is the UK's oldest LGBTQ+ charity. It has a timeline that covers significant events of the charity's history together with a showcase of 50 inspirational Londoners who have made a difference to life in the capital. The technical side of things is pretty much as you imagine. One choice we made was not to use ajax for loading the timeline events but instead loading all of the html and then leaning hard into caching and lazy loading of images. We did use @markus_blue_tomato 's imageBlurHash module to produce placeholders for our lazily loaded images - although honestly you rarely get to see them. For some of the pages the client wanted to be able to add footnotes so we created a text formatter than moves any text in a content block surrounded in square brackets into footnotes section and creates an anchor link. I'll tidy that up and pop it on GitHub when I get some time but feel free to nag me if you think it might be useful to you. Other modules of note were ProCache and (of course) TracyDebugger. We also have some galleries on the site that use PhotoSwipe which is still our g to script for phot galleries. We got great marks in Lighthouse, Observatory and Wave (even the timeline itself which is a complicated page still does very well). It was great to be part of the celebrations (just a shame that I'm on holiday when the launch party happens... dammit)
    12 points
  10. Since InputfieldTinyMCE appears to make huge steps towards becoming a stable replacement for CKEditor and TinyMCE comes with a native autocomplete API, I just had to try my hands at migrating the autocomplete module I had built for InputfieldCKEditor. Lo and behold, it went even easier than I had hoped. So here - mind you, still very alpha - is my autocomplete module for the new TinyMCE input field. Since I may still introduce breaking changes while things become stable, it will only be available at GitHub for now. Autocompleter for InputfieldTinyMCE What does it do? Autocompleters work like the mention plugin in this forum. You type a "trigger" character (or characters) followed by some letters, and a list of possible results pops up, from which you can choose. InlineCompleteTinyMCE comes with three different autocompleters (called "actions" in the context of this module): Pages: you can configure a selector, just like when you search for pages in the ProcessWire backend. You can search for title, name or any field you would like. Like every action, it allows you to specify templates for the label and the HTML/text to insert. Users: this is the equivalent to the form mention. Type an "@" sign followed by the start of a user name, and it inserts a link to that user. If you have added an image field to the user template, you can display that in the selection popup too. Hanna Code: just type the opening tag ("[[" by default) for your Hanna code and any letter, and the module will look for all codes starting with those letters. You can easily implement your own action modules too. Just inherit from InlineCompleteTinyMCEAction and add the code for a few methods. Enabling Actions For every installed action, you will find a checkbox on the "Input" tab when you configure a field. Configuration for Actions Once you have enabled the action, more configuration options become visible. The exact options depend on the action itself, but you usually have a label template and a value template. You can use placeholders in both. Actions in Action This is what it looks like when used: Compatiblity The module has been tested with InputfieldTinyMCE v6.0.6 both in standalone and inline mode. Lazy loading the standalone editor is also supported. Outlook There's still a bit work waiting for me, from cleaning up some code, over making the Pages action support multiple autocompleters with different triggers and selectors, to adding a lot of documentation. Nevertheless, I'd be happy to get some feedback.
    11 points
  11. A few months back I had the urge to try a lot of new things and one thing was a SSG (static site generator) called 11ty.dev and there was one channel and one website that made it super easy to start. https://www.youtube.com/@11tyRocks/videos https://11ty.rocks/ I liked it because it showed everything from start to "sure you can build an app with that". What I want to say is that even guides on how to install ProcessWire, make it more secure, or about hooks or how to "write your own module" would make perfect sense. There is more than enough courses could cover. As already mentioned... there are few bits and pieces out there, most of them are quite outdated or at least the ProcessWire backend already looks totally different which makes it awkward in some kind to watch those videos. A new fresh approach sounds really good. There are tons of topics your course or maybe even courses could offer and talk about. See @bernhard's videos. They are really great and in full detail while only talking about a specific module. Haven't thought it through but I personally would provide some basics at least (installation, file and folder structure, some best practices), then maybe something like building a blog or magazine (as mentioned already) and go from there. A blog could have a RestAPI, a custom RSS Feed, and, so, on... oh and there is always: SEO, Online Marketing and Affiliate Marketing. There could be courses about "Why ProcessWire is perfect for (or) How to do SEO, OM, AM with ProcessWire". Just outlined a few ideas out of my head. ProcessWire Basics Installation Security Migration Updates and Maintenance How to structure your project Dos and Dont's Import a HTML Template/Theme ProcessWire: Your First Real Project Blog/Journal/Magazine Member Area ProcessWire Advanced User, User roles, Access rights How to Hook How to Customize How to Whitelabel How to RestAPI/GraphQL ProcessWire as Headless CMS Use VUE, Angular, Svelte, AlpineJS with ProcessWire Your very first ProcessWire module How to structure your backend, fields and templates ProcessWire SEO PageSpeed Caching SEO-related Modules ProcessWire Setups Multi-User Setup Multi-Instance Setup Multi-Domain Setup ProcessWire Master Class ... ... ... My 2 cents for now.
    10 points
  12. ProcessWire Docker Image Dockerized Processwire installation and development enviroment Local enviroment with MariaDB container included Mount local filesystem Processwire versions VSCode Itelliphense configuration xDebug preconfigured Opcache + JIT ready (xDebug must be disabled) Installation & usage Development enviroment installation Build using local script $ git clone https://github.com/laikmosh/docker-processwire.git $ cd docker-processwire $ docker-compose up Install as usual, no extra configuration is needed. There is a config-dev.php file in the ./site/ folder, this file will load by default when running locally, but is in the .dockerignore, so it wont be included at image building time. Custom php.ini settings can be set at: /Processwire/scripts/php/php.ini *Image must be rebuilt for changes on php.ini to take effect Development enviroment usage By default the ProcessWire installer will load the `.env` configuration. Configure .env file for project and DB settings, default database credentials are: Database: {COMPOSE_PROJECT_NAME} User: admin Password: password Server: database Port: 3306 Editable files and templates will be installed to the ./site/ folder. Processwire documentation ProcessWire ProcessWire Repo ProcessWire Documentation
    8 points
  13. I've had a conversion with @3fingers over the last few days regarding that topic. I contacted him via PM because I am planning something similar and I did not want to give the impression that I was torpedoing his plan (or that he spends much time that in the end does not pay off because there is a similar free course by someone else). To be more specific, what I have had in my mind for quite some time now is to make a ProcessWire version of this video: ProcessWire from Scratch 2022 | Laravel Alternative? (on processwire.rocks) I thought that might be a good idea for several reasons: While watching that video to get an impression of laravel I thought so many times: "That would be so much easier in PW", so I wanted to show that to others I thought such a video could maybe catch brad's attention and he might be willing to share the video across his audience or even try PW and make a video about it himself I thought it's a good starter project with a good structure that shows a lot of the most important concepts and it would be nice to have a side-by-side comparison @3fingers asked me to post this publicly to get some feedback from the community so that we can then decide how we should proceed so that everybody benefits from it.
    7 points
  14. With all the hype about ChatGPT, I wanted to see how useful it could be for us ProcessWire lovers. In a word: wow! It's pretty darn impressive for such early public testing and for such targeted subject. I love how it proposes code with comments, then proceeds to explain it. (Note: I've been getting more impressive and consistent results on mobile for some reason.) Prompt: Filter blog post by category in ProcessWire To filter blog posts by category in ProcessWire, you can use the find method of the $pages object, along with the category field and the equals operator, like this: // Get the category slug from the URL $category_slug = $input->urlSegment1; // Find all blog posts in the given category $posts = $pages->find("template=blog-post, category.slug=$category_slug"); // Loop through the posts and output their titles foreach ($posts as $post) { echo "<h2>$post->title</h2>"; } This code will find all blog posts that are in the category with the given slug, and output their titles. You can modify this code to output other information about the posts, such as their content, images, or dates. To make it easier for users to filter posts by category, you can also create a navigation menu that lists all the available categories, like this: // Find all categories $categories = $pages->find("template=blog-category"); // Output a link for each category echo "<ul>"; foreach ($categories as $category) { echo "<li><a href='/blog/$category->slug'>$category->title</a></li>"; } echo "</ul>"; This code will find all blog categories and output a link for each one, using the category slug as the URL parameter. When a user clicks on a link, they will be taken to the blog page with the posts filtered by that category. Prompt: Login form in ProcessWire To create a login form in ProcessWire, you can use the following code: // Check if form has been submitted if ($input->post->submit) { // Sanitize user input $email = $sanitizer->email($input->post->email); $password = $sanitizer->text($input->post->password); // Check if user exists and password is correct $user = $users->get("email=$email"); if ($user && $user->matches($password)) { // Login user $session->login($user); // Redirect to home page $session->redirect("/"); } else { // Output error message $error = "Invalid email or password."; } } // Output login form echo "<form method='post'>"; echo "<label>Email:</label>"; echo "<input type='email' name='email' value='$email'>"; echo "<label>Password:</label>"; echo "<input type='password' name='password' value='$password'>"; echo "<input type='submit' name='submit' value='Login'>"; echo "</form>"; // Output any errors if ($error) { echo "<p class='error'>$error</p>"; } This code creates a login form that accepts an email and password. When the form is submitted, it checks if a user with the given email exists, and if the password is correct. If the email and password are valid, it logs in the user and redirects to the home page. If the email and password are invalid, it outputs an error message. Prompt: User registration class in ProcessWire with email, password of at least 10 characters and age over 18. Check if email is unique. To create a user registration class in ProcessWire with email, password of at least 10 characters, and age over 18, you can use the following code: class UserRegistration { public function register($email, $password, $age) { // Sanitize user input $email = $sanitizer->email($email); $password = $sanitizer->text($password); $age = (int) $age; // Validate user input if ($age < 18) { $errors[] = "You must be over 18 to register."; } if (strlen($password) < 10) { $errors[] = "Your password must be at least 10 characters long."; } if ($users->get("email=$email")) { $errors[] = "A user with this email already exists."; } // If no errors, create user account if (!$errors) { // Create new user $user = new User(); $user->email = $email; $user->password = $password; $user->age = $age; // Save user to database $user->save(); // Redirect to confirmation page $session->redirect("/confirmation"); } } } This code creates a UserRegistration class with a register method that takes an email, password, and age as arguments. The method sanitizes and validates the input, and creates a new user if the input is valid. It also checks if a user with the given email already exists in the database, and outputs an error if one does. To use this class, you would first instantiate it: $registration = new UserRegistration(); Then, you can call the register method to create a new user: $registration->register($email, $password, $age); Prompt (similar to previous one): User registration form in ProcessWire with first name, last name, email, password of at least 10 characters and age over 18. To create a user registration form in ProcessWire with first name, last name, email, password of at least 10 characters, and age over 18, you can use the following code: // Check if form has been submitted if ($input->post->submit) { // Sanitize user input $first_name = $sanitizer->text($input->post->first_name); $last_name = $sanitizer->text($input->post->last_name); $email = $sanitizer->email($input->post->email); $password = $sanitizer->text($input->post->password); $age = (int) $input->post->age; // Validate user input if ($age < 18) { $errors[] = "You must be over 18 to register."; } if (strlen($password) < 10) { $errors[] = "Your password must be at least 10 characters long."; } // If no errors, create user account if (!$errors) { // Create new user $user = new User(); $user->first_name = $first_name; $user->last_name = $last_name; $user->email = $email; $user->password = $password; $user->age = $age; // Save user to database $user->save(); // Redirect to confirmation page $session->redirect("/confirmation"); } } // Output registration form echo "<form method='post'>"; echo "<label>First Name:</label>"; echo "<input type='text' name='first_name' value='$first_name'>"; echo "<label>Last Name:</label>"; echo "<input type='text' name='last_name' value='$last_name'>"; echo "<label>Email:</label>"; echo "<input type='email' name='email' value='$email'>"; echo "<label>Password:</label>"; echo "<input type='password' name='password' value='$password'>"; echo "<label>Age:</label>"; echo "<input type='number' name='age' value='$age'>"; echo "<input type='submit' name='submit' value='Submit'>"; echo "</form>"; // Output any errors if ($errors) { foreach ($errors as $error) { echo "<p class='error'>$error</p>"; } } Watch out, this is addictive 😃
    7 points
  15. If you're just after making your image a wonky shape then you can probably just use some fancy css border radius values. Here's a handy looking site for generating the code that looks promising: https://9elements.github.io/fancy-border-radius/
    6 points
  16. @jacmaes To remove all in an existing parent (i.e. Align), you can add: #Align { display: none } To add custom styles at the root level, omit a #Parent. So to add "Red text" at the root level, add: span.red-text { color: red } /* Red Text */ To add your own custom parent at the root level, specify it as the #Parent for any items you want to add within it, i.e. here's how we add a parent named "Hello": #Hello span.blue-text { color: blue } /* Blue Text */ #Hello p.outline { padding: 20px; border: 1px dotted #ccc } /* Outline paragraph */ I prefer the single line rules, but it's also fine if you want to use multi-line rules: #Hello p.outline { /* Outline paragraph */ padding: 20px; border: 1px dotted #ccc; }
    6 points
  17. I usually do post rock: Sigur Ros Under Byen Album Leaf Godspeed You! Black Emperor, etc. Sometimes some shoegaze My Bloody Valentine (duh) Fleeting Joys Blonde Redhead, etc. Often game soundtrack bits: Amos Roddy (Two Kingdoms franchise) - this gets LOTS of play - just super calm and thoughtful ambient. Disasterpeace (Fez, Hyper Light Drifter) Bioshock scores and the Black Mesa score Love the Limbo soundtrack - its just too short. He's got some tracks in a few other games but they just aren't as interesting IMO. Lots of Fripp and GC stuff, some Eno also. Sometimes the prog side but usually that's too engaging to code. Dunno, all over the place in general. Lately I've been on an old Tame Impala and old Phantogram kick. My playlist is all over the place. Sometimes classical - Holst, Bartok, etc. I think the only rule is I have to be familiar with it. I can't just throw a new Tool album on or something and think I'm going to be able to concentrate.
    5 points
  18. This could possibly become a course all on its own, but there are often questions on how to manage navigational structures (header/footer/on-page) in ProcessWire. Covering how to (try to) plan around it, either based on the layout design, or based on the architectural design (or the client need?) are all potential topics. Sites with simple structures (and few templates) are usually fairly easy, but if you were to design a website for a university that holds many different departments all with unique needs and content, things can get quite complicated; often times there is the primary navigation, a sub-navigation (that may break into child-navigations per department), and custom footer navigation areas per section! If aimed at beginners, something that should likely be covered early on is templates/themes and ProcessWire's Site Profiles, and how unlike other solutions, downloadable site profiles contain not only the layout and design, but also the underlying architecture and fieldtypes, so switching templates is not (currently) a thing with ProcessWire. (We'd need something like WordPress' various theme builders [ex: Divi] where it's a theme framework, so the framework is the profile, and themes/templates/styles could be swapped within the framework...we just don't have that [yet?] for ProcessWire.) ...oh, and also that files and images are associated to the pages they were uploaded to (instead of a centralized media manager, unless one is setup [through a page] in your magazine website example). Also of note, and this took me awhile too: It's "ProcessWire", not "Processwire". 😅 I'd probably sign up just because I enjoy taking courses. You can always learn something new. Video courses are a lot of work (to keep updated) so I wish you the best of luck on this!
    5 points
  19. Frontend forms in general would be a good topic. There's so much to find scattered around the forum but still people seem to struggle with it, especially when it comes to frontend file uploads with WireUpload.
    5 points
  20. Sounds great. There are some PW video tutorials out there. But nothing structured or consistent like you are planning to do. Do you mean that others can contribute videos as well? You could use a platform like https://www.codecademy.com/ to publish your courses. Will propably reach a broader audience than a custom made solution. concept of "everything is a page" structuring content working with templates/fields in the admin different output strategies: delayed, MarkupRegions etc PW as headless CMS with https://processwire.com/modules/app-api/ or https://processwire.com/modules/process-graph-ql/ I wouldn't concentrate too much on that because there are tons of tutorials out there already and PW is flexible enough to let devs implement frontend stuff in so many ways. But the basics of where you can place your source files, and how to include assets in template files might be helpful. Go for it and good luck!
    5 points
  21. Eleven years later, but thanks for that, Ryan! It was exactly the explanation that I needed.
    5 points
  22. @bernhardI just haven't gotten to it yet, as it requires a PageFrontEdit module update rather than a TinyMCE one. I also have to update ProFields Table, Multiplier, Textareas and Combo to support TinyMCE. Once all of these are done we'll merge the TinyMCE module into the core.
    5 points
  23. It took some investigating and it would be great to have this made more obvious in any documentation for $config->pagefileSecure... Behind the scenes pagefileSecure is using $files->send(): And $config->fileContentTypes forces download for certain extensions based on whether the content type is preceded by a + sign. You can override the default for the pdf extension in your /site/config.php and then the files should display in the browser: $config->fileContentTypes('pdf', 'application/pdf'); // No plus sign before the content type
    5 points
  24. This is apparently a really old hat and common in many editors, but it’s the first I’ve heard of it and it just blew my mind. Did you know you can name heredoc strings “HTML” to get HTML syntax highlighting?! I kind of try to avoid heredoc, but this seems pretty neat.
    5 points
  25. You can use the User::changed hook to do what you want (see https://processwire.com/api/ref/wire/changed/). Put this in site/ready.php: $wire->addHookAfter('User::changed', function ($event) { if($event->arguments(0) === 'pass') { $user = $event->object; $this->wire->log->save('password-changes', "User $user->name has changed their password"); } }); Now everytime a user changes their password, it will be logged to Setup->logs->password-changes. You can do similar thing with roles if($event->arguments(0) === 'roles') { $user = $event->object; $oldRoles = $event->arguments(1); $newRoles = $event->arguments(2); // code to compare $oldRoles/$newRoles // write to log } If you want to have that information in the session log, just do $this->wire->log->save('session',...)
    5 points
  26. I finally found , the new master release 0.0.10 works here with the latest FormBuilder release. Let me know if you encounter any issues.
    4 points
  27. I agree. However, to make a tutorial series complete, one needs to introduce the basics as well. Perhaps a concise but not too long overview would do the trick (especially if it links to all the official docs and blog posts in order to point out where to learn more about the basics). @3fingers In order to teach as much as possible in the shortest possible time, you might want to provide your learners an installable site-profile which does all the basics already, and you "just" finish it off by implementing the rest (which is everything beyond the basics). I would also pay for such a course, so that I can think outside of my box (and to support your efforts, of course).
    4 points
  28. Short answer is "no", at least not for now 🙂 SE populates a search index for a piece of content (page) and compares provided query string against said index. It's a tool for handling "regular" site search, from indexing to front-end rendering. The index is a textarea field, so complex queries (advanced text search) and a few special cases ("link:https://www.processwire.com") are supported, but the module has little to do with facets/filters. On a loosely related note, in recent projects I've been leaning towards implementing filters/facets on the front-end based on static data generated by the backend and cached on disk. The main reasons are performance and scalability: real-time search using ProcessWire can be pretty quick, but won't achieve the speed of a front-end only implementation. This is especially tempting approach when the amount of data is relatively small (i.e. you don't have to deal with tens of thousands of pages (or more) with numerous searchable properties each.) Which approach makes most sense — and how vigorously the search should / needs to be optimized — depends on the case at hand 🙂
    4 points
  29. Hello @szabesz! I recently implemented this feature for a project done for a client, and I am very pleased with the result. Unlike how Ryan did it for the Skyscrapers profile I used ajax (through js's native fetch() functionality) to communicate with the filtering logic. It works very well and is very versatile. It will definitely be a topic of discussion. 💬 Why not? It is one of several alternatives and/or combinations for categorizing data along with Page Referece Fields (they can also be used together). I will take this into consideration! ✌️ @gebeer It is indeed and it's going to be treated with proper attention 🙂 ...and yes, I'm using some Emoji's to grab your attention too (I usually don't) 😺
    4 points
  30. Hello @3fingers, +1 to this approach. What I think nowhere demonstrated in a nice and concise tutorial is the broad topic of search. One can take a look at Ryan's Skyscrapers demo profile but other than that there are just scattered bits of info on the topic. There is also @teppo's SearchEngine but that is a 3rd party module and I am not sure it can be used for Faceted Search or not, for example. With all that ecommerce raging these days, showing how to implement Faceted Search would be invaluable (along with listing products, sortable by categories), I think. Also, frontend autocomplete is another valuable topic, and what I have not yet tried but looks useful to build upon is InputfieldTextTags: https://processwire.com/blog/posts/pw-3.0.177/ See this related quote from Ryan: "...InputfieldTextTags works on the front-end, such as in FormBuilder or LoginRegisterPro forms, or any other InputfieldForm on the front-end." I have done some of the above over the years (built on ProcessWire of course) and I had to dig up ideas from source code of modules and from this forum of course. However, a guided tour can always speed up the learning process. Good luck with your endeavor!
    4 points
  31. Preventing a page from being moved is not necessarily a straightforward matter of trapping the change in a save hook in the same way as a page edit. A problem occurs if the page is only to be 'blocked' conditionally - when the page path is in some given array, for example. In hooking before page save, the page path is the new page path after the move, rather than before it, so you need to do something like this: // .... In the before page:saveReady hook // $page is the page :) The code below operates when (isset($page->parentPrevious) && $object->parentPrevious != $object->parent) $name = $page->parentPrevious->path . $page->name . '/'; // need the path before it was moved if(in_array($name, $blockedNames)) { // $blockedNames are the ones where we don't want moves // Because this hook operates after the move, we need to reverse the move $page->parent = $page->parentPrevious; // Alternatively, to completely stop the save //$event->replace = true; //$event->return = false; } //... rest of hook This prevents the page being moved, both in the page hierarchy (by dragging) or in the page editor by changing the parent in the settings tab. It is also possible to hook before Page:moveable with something like this /** @var Page $page */ $page = $event->object; $moveable = $event->return; // ... code to set $moveable to false if conditions met $event->return = $moveable; Interestingly, the (not documented?) moveable method is created as a hook by PagePermissions and so is hookable. However, this method appears to catch only the situation where the move is effected by dragging the page in the tree, not when the parent is changed in the settings.
    4 points
  32. When toggling an Inputfield the whole row is toggled. I'm not sure if that is intended? Is that the same for you? What do you think? Should it be like this?
    4 points
  33. In v0.2.0 I've added a Pageimage::megapixelsDimensions() method that returns just the dimensions needed to resize an image to a target megapixel value. I used this recently to create a gallery of sponsor logos in normal and high dpi variations. Example from the updated readme: foreach($page->logos as $logo) { $dimensions = $logo->megapixelsDimensions(0.01); $width = $dimensions['width']; $height = $dimensions['height']; $width2x = $width * 2; $height2x = $height * 2; echo "<img src='{$logo->size($width, $height)->url}' srcset='{$logo->size($width, $height)->url} 1x, {$logo->size($width2x, $height2x)->url} 2x' alt='Logo' width='$width' height='$height'>"; } I've also added the module to the PW directory.
    4 points
  34. 4 points
  35. Hey Jonathan, I think this post should get you started: https://processwire.com/talk/topic/735-session-time-for-logged-in-user/?do=findComment&comment=6173
    3 points
  36. Thanks for all of your responses! 🙏 @wbmnfktr This is a very valuable feedback from your side. Kudos for all the insights you gave me! @pwired As I mentioned at the beginning of the post, my course will be for the benefit of those beginning and/or intermediate developers. So I think the sweetspot will be to not leave out the basic aspects of approaching processwire but at the same time focus on somewhat more advanced aspects, such as the ones you suggested, which seem to me to be excellent and absolutely doable. So, let's try to get serious here: I prepared a small landing page to validate how many of you would be willing to take the course, so that we would have a rough estimate of how many people would be willing to take the course. 🔗 Show me your interest here 🔗 It goes without saying that if, a month or so from now, I see a small number of consents perhaps I will understand that it will not be the case to proceed further. In any case, go visit the page and leave me your contact information (it is mentioned on the page but I would like to reiterate: none of your contact information will be retained by me, each e-mail is salted and hashed and handled securely by the newsletter service I have hooked up -- Mailjet in this case). Let me know what you think, let's keep comparing ideas. 💪
    3 points
  37. That sounds like a good way to approach it.
    3 points
  38. Really rough, but gets the job done. You could easily put this into a function. This builds up the name of variation (assuming you want 330x330), checks to see if it exists and if it doesn't then we need to go old school and get the page object and image and generate the variation. Then next time the page is loaded, the variation will exist and we can display it with $imageUrl as the image src directly from the data returned by findRaw. if(count($p->image) > 0) { $imageOrigUrl = $config->urls->files. $p->id . '/' . $p->image[0]['data']; $path_parts = pathinfo($imageOrigUrl); $imageVarFilename = $path_parts['filename'] . '.330x330.' . $path_parts['extension']; $imageUrl = $config->urls->files . $p->id . '/' . $imageVarFilename; if(!file_exists($config->paths->files. $p->id . '/' . $imageVarFilename)) { $image = $pages->get($p->id)->image->size(330, 330); $imageUrl = $image->url; } }
    3 points
  39. What does autojoin do? Using the 'autojoin' optimization can increase performance on fields that get used a lot. Not using it can reduce the page's memory footprint. What is more desirable in each instance depends on your situation. What sites should use autojoin? Autojoin is most applicable with larger sites. On smaller sites, there may be no benefit to using it or not using it. But it's good to know what it's for regardless. Where do you control autojoin? Autojoin is controlled per-field. You can turn it on by editing each field under Setup > Fields > [your field], and you'll see it under the 'Advanced' heading. When should you use autojoin? Autojoin causes the field's data to be loaded automatically with the page, whether you use it or not. This is an optimization for fields that you know will be used most of the time. Fields having their data loaded with the page can increase performance because ProcessWire grabs that data in the same query that it grabs the Page. Autojoin is a benefit for fields that are always used with the Page. This is best explained by an example. Lets say that you have a template for individual news stories called news_story. The news_story template has these fields: title date summary body sidebar We'll assume that when you view a page using the news_story template, all of the fields above are displayed. Fields that should have autojoin ON: Now consider a separate news_index template that displays ALL of the news stories together and links to them. But it only displays these fields from each news story: title* date summary In this case, the 3 fields above would be good to autojoin since they are used on both the news_index and news_story templates. If your title, date and summary fields didn't have autojoin turned on, then ProcessWire wouldn't go retrieve the value from the database until you asked for it it (via $page->summary, for example). Because the news_index template displays all the stories at once, and always uses the title, date and summary fields, it will perform better with title, date and summary having autojoin ON than with it OFF. In this case, it reduces the query load of the news_index template by 3 for each news story. To take that further, if it were displaying 20 news stories, that would mean 60 fewer queries, which could be significant. Fields that should have autojoin OFF: Now lets consider the body and sidebar fields, which are only used on the news_story template: body sidebar It would be desirable to leave autojoin OFF on those fields because there is no reason for the body and sidebar to be taking up space in memory when they are never used on the news_index template. While it might mean 2 fewer queries to view a news story, that is not significant and certainly not a worthwhile tradeoff for the increased memory footprint on the news_index template. Keeping autojoin OFF reduces a page's memory footprint. Conclusion Using the 'autojoin' optimization can increase performance on fields that get used a lot. Not using it can reduce the page's memory footprint. What is more desirable in each instance depends on your situation. But if your situation doesn't involve lots of pages or data, then you don't need to consider autojoin at all (and can generally just leave it off). Additional Notes Not all fields have autojoin capability. You won't see the option listed on fields that don't have the capability. *The title field has autojoin on by default, so you don't need to consider that one. It was included in the examples above because I thought it's omission might cause more confusion than it's inclusion. Be careful with multi-value fields that offer autojoin capability (page references and images, for example). Because MySQL limits the combined length of multiple values returned from a group in 1 query, autojoin will fail on multi-value fields that contain lots of values (combined length exceeding 1024 characters). If you experience strange behavior from a multi-value field that has autojoin ON, turn it OFF. If you want to play it safe, then don't use autojoin on multi-value fields like page references and images.
    3 points
  40. FieldTypeOptions gives you different UI and stores data in a different way. If you just need a checkbox, I'd go with InputfieldCheckbox. Less overhead.
    3 points
  41. You would use $county->setOptions($optionsArray) to populate the select options. Example: /** @var array $optionsArray */ $optionsArray = $pages->findRaw('template=basic-page', 'title'); // returns an array with page ids as keys and page titles as value $county->setOptions($optionsArray); // each option will have value="{pageID}" and label page title You need to adjust the selector to your needs.
    3 points
  42. I'm also not saying there's only one way of doing it. I just tried to invite you to think out of the box and leave paths that you have been using in the past. That does not mean you should forget them of course, because as already said you can also use PW in a traditional database table way. It's just not the most common way I guess (which is a shame imho because PW can be a great platform not only for building websites but also as a framework). Thx, that's a very good example. What you could do here is to create two templates: "protocols" and "protocol" The "protocol" template would hold all the fields necessary for storing data for each protocol. That would be similar to all the columns needed when storing that in a DB table. For example: title, datetime, message For the "protocols" template it would be enough to have a single "title" field. Then you create the parent-child relationship on those templates. You set the allowed children of "protocols" to "protocol" and the allowed parents of "protocol" to "protocols". Then you create a new page in the page tree and choose "protocols" as template. You can set the title to whatever you want, eg "My shift protocols". Then go back to the page tree and add a page UNDER the just created protocols page. As only "protocol" pages are allowed as children you should only be able to add such a page here. Then you can populate all fields (title, datetime, message - which could be your ckeditor field) and save that page. --> You have created your first protocol entry, which would be similar to inserting a new row in the DB table in a usual database world. So that's an easy example of how you can approach such things. There are many benefits of doing it that way rather than doing everything by hand: You have a GUI for adding, editing, deleting etc. those entries. You can use all kinds of fields for adding "content" to your entries, for example it's extremely easy to add an images/files field to upload images/files. That would be very much work with plain PHP/MySQL Every "protocol" entry is a PW page and you can do all kinds of great things with it. For example you could create a template file for that page (/site/templates/protocol.php) and you would have a publicly available digital version of your entry. As PW is built apon the page-tree paradigm you don't need to create "routes" or "endpoints" - they are already there. Out of the box, as soon as you add the mentioned template file. So in our example we could access that entry under yoursite.com/my-shift-protocols/demo-entry (where the parts of the url are the names of the created pages and you could of course make them random or auto-increment or things like that). You can change some kinds of that GUI easily via GUI or via code. For example you could change the label of the "title" field to something like "Enter your name here". You have a great system for access control on a field level. You can hook into every single aspect of your GUI. No limits. Multi-Language? Yep, easy to add! And many many more things. To be fair, there's also one thing that I've been missing when working with database-like data: Grid-Views. We have the page-tree which is great for websites, but it's limited when it comes to tabular data views. We also have Lister and ListerPro, but that's not great for such use cases imho. That's why I built RockGrid, which makes it possible to list ProcessWire pages as grid with other helpers like batch editing rows and adding custom actions, see https://processwire.com/talk/topic/26663-need-help-making-sse-work/?do=findComment&comment=220918 if you like and if you are bored 😉 Of course you could always just code some custom view just like you'd have to do when building such an app with PHP/MySQL or any other framework. You can do that in the PW backend (https://processwire.com/talk/topic/17709-how-to-create-custom-admin-pages-aka-processmodules-yes-its-that-simple/ ) or you just code your own custom frontend for it. Now that we have everything in place you can easily listen to events in the PW ecosystem: <?php // site/ready.php $wire->addHookAfter("Pages::added(template=protocol)", function($event) { $page = $event->arguments(0); // send email $mail = new WireMail(); $mail->to('your@mail.com'); $mail->from('robot@yoursite.com'); $mail->subject('new shift entry'); $mail->body("See here: ".$page->editUrl(true)); $mail->send(); }); Now whenever someone creates a new protocol page you get an email that shows the url where you can edit and review that new entry. Hope that makes sense! Have fun exploring PW 🙂 PS: Wondering what "INSERT INTO ..." would be in PW? <?php $p = new Page(); $p->template = 'protocol'; $p->parent = $pages->get(123); // page id of your parent page $p->title = "John Doe"; $p->datetime = strtotime("2022-11-11 11:11"); $p->message = "Your shift message"; $p->save();
    3 points
  43. just to make sure, did you copy/paste this from your code? There is a typo "Imput", note the "m". It should read "getModuleConfigInputfields" To retrieve module config data from anywhere you can also use https://processwire.com/api/ref/modules/get-config/
    3 points
  44. Here you are referring to ProcessModules. These provide custom pages in the admin. For an example see https://processwire.com/modules/process-hello/ and I also can strongly recommend the excellent blog post about ProcessModules linked by @BillH This is correct. You can read all about module configuration at https://processwire.com/blog/posts/new-module-configuration-options/ with examples both for the "old" and "new" way to implement your custom configuration fields. There is no settings button on the module's detail page. Once you have implemented input fields for module configuration, they will appear underneat the module information. All configurable modules are also listed in the admin menu under Modules->Configure When you are new to module development, the available classes can be quite confusing. But once you try and build a module yourself everything will get clearer. If you want to build custom pages in the admin, use a process module (https://processwire.com/modules/process-hello/). If you want to add general functionality, use a "normal" module (https://processwire.com/modules/helloworld/). This is because the API docs are auto-generated from the PW code. Since ConfigurableModule is an interface and not a class, the documentation for it is not being picked up by the script that generates the docs. But you have the path to the file in the core that defines the interface and there you have extensive documentation https://github.com/processwire/processwire/blob/master/wire/core/ConfigurableModule.php
    3 points
  45. Config variables should be available as properties of the module if I'm not missing anything. So if you add a config inputfield with the name 'foo' it should be available as $this->foo. Or from outside the module it should be available as $modules->get('YourModule')->foo;
    3 points
  46. @bernhard updated it! For anyone that might come across adding something else on the admin theme's markup, here's a recommendation from Ryan: $src = "https://unpkg.com/alpinejs@3.10.2/dist/cdn.min.js"; $this->wire()->adminTheme->addExtraMarkup('head', "<script src='$src' defer></script>");
    3 points
  47. Here is a minimal example that works for me: <?php namespace ProcessWire; if (input()->post('message')) { header('content-type: text/plain'); //this makes the browser show the "unformatted" response body, i.e. it won’t render HTML die(input()->post->textarea('message')); } ?> <form id="fruidform" method="POST" action="./"> <textarea name="message">&lt;h1&gt;two &gt; one&lt;/h1&gt;</textarea> <button id="urlencoded" type="submit">Tu es urlencoded</button> <button id="formdata" type="submit">Tu es als form-data</button> </form> <script> document.getElementById('urlencoded').addEventListener('click', async function(event) { event.preventDefault(); const response = await fetch('./', { method: 'POST', body: new URLSearchParams([['message', document.forms.fruidform.message.value]]) //you can also make a URLSearchParams from a form automatically, so you don’t have to reassemble all fields yourself: //new URLSearchParams(new FormData(document.forms.fruidform)) }); }); document.getElementById('formdata').addEventListener('click', async function(event) { event.preventDefault(); const response = await fetch('./', { method: 'POST', body: new FormData(document.forms.fruidform) }); }); </script> Observe how you get back “two > one” from the server in both cases. What are you doing differently? Also see how you don’t need to put the content-type header explicitly, because fetch() infers it from the body’s type automatically, but it is sent in both cases! If you look at the unformatted request body in the browser console, you’ll see that the first one is is: message=%3Ch1%3Etwo+%3E+one%3C%2Fh1%3E" message=%3Ch1%3Etwo+%3E+one%3C%2Fh1%3E" That mess of % symbols is “urlencoded” and the request has a header that announces this to the server, so the server will know how to decode it: “Content-Type: application/x-www-form-urlencoded;charset=UTF-8”. It’s called “urlencoded” because it specifically exists to encode GET parameters as part of URLs, but you can use it for POST as well, as you can see. The form-data request body looks like this: -----------------------------9162892302224017952318706005 Content-Disposition: form-data; name="message" <h1>two > one</h1> -----------------------------9162892302224017952318706005-- (Your boundary may vary. The browser generates automatically.) Again the request’s content-type header tells the server that it’s sending this format: “Content-Type: multipart/form-data; boundary=---------------------------9162892302224017952318706005”. If you use XMLHttpRequest, you may need to set the content-type explicitly according to the format you’re sending, I’m not sure, but it can't hurt. Another thing is that these are (I believe) the only two content-types that PHP will put into its $_POST and $_GET variables. That’s why @gebeer’s example had to use file_get_contents('php://input') to get the JSON. Of course you can also send JSON as urlencoded or form-data. Then you can use json_decode(input()->post('myjson')).
    3 points
  48. Hi @snck, Thanks for the feedback and the great example! Unfortunately the issue you've raised is more of an issue with how Pageimage::render() is implemented. Adding 'width' or 'height' options is interpreted as a request to resize the Pageimage, which is not what we want in PageimageSource::render(). The default markup does not include width and height attributes, so the only way to add them without resizing the image is to provide them in a specified markup string. I have a hook in an internal development module which sets a default markup string with these attributes: <?php // Pageimage:render $this->addHookBefore('Pageimage::render', function(HookEvent $event) { $markup = $event->arguments(0); $options = $event->arguments(1); if(!is_string($markup)) { $options = $markup; $markup = '<img src="{url}" alt="{alt}" width="{width}" height="{height}">'; } $event->arguments(0, $markup); $event->arguments(1, $options); }); This means I can generally call render() without any options. If your example is something you are doing repeatedly, you could utilise a similar strategy in site/ready.php: <?php // /site/ready.php $wire->addHookBefore('Pageimage::render', function(HookEvent $event) { $markup = $event->arguments(0); $options = $event->arguments(1); if(!is_string($markup)) $options = $markup; if($options['masonry'] ?? false) { // a custom option $img = $event->object; $thumb = $img->width(480); $markup = "<img src='$thumb->url' alt='{alt}' class='{class}' width='$thumb->width' height='$thumb->height'>"; $options = array_merge([ 'picture' => true, 'srcset' => [360, 480, 640, 800], 'sizes' => '(max-width: 579px) calc(100vw - (2 * 34px)), (min-width: 580px) and (max-width: 767px) calc(50vw - (1.5 * 34px)), (min-width: 768px) and (max-width: 1199px) calc(33.3333vw - (1.33 * 34px)), (min-width: 1200px) and (max-width: 1499px) calc(25vw - (1.25 * 34px)), (min-width: 1500px) calc(20vw - (1.2 * 34px))', 'class' => 'teaser-img proportional', 'alt' => $img->description, ], $options); } $event->arguments(0, $markup); $event->arguments(1, $options); }); // In your code $img->render([ 'masonry' => true, 'class' => 'overriding-the-default-class', 'alt' => __('Overriding the default alt text'), ]); // Not tested!!! Cheers, Chris
    3 points
  49. @jacmaes If you want to replace the entire styles menu on your own, you can do this with the custom JSON option (whether input or file). See the included defaults.json file "style_formats" item. But it sounds like you just want to remove a few things from the Styles dropdown. In that case, in your Module settings (or Field settings if enabled) edit the "Custom style formats CSS". The instructions there tell you how to add or remove items, but for the specific examples that you want to remove, enter this: #Align { display:none } #Blocks (Pre) { display: none } #Inline (Underline) { display: none } #Inline (Strikethrough) { display: none } #Inline (Code) { display: none } Note this option to remove items in this manner was added within the last week, so make sure you are running the latest version. Regarding the align options, I'm thinking we may just remove those since not many seem to want them, and our image plugin (pwimage) already includes the ability to assign alignment classes to images. For the Blocks tool, I think that is unrelated to the Styles tool in terms of configuration, and I don't think that it is a replacement for the Styles tool. I have built most of our configurable settings around the Styles tool since it offers a lot more flexibility in configuration. But if you want to investigate the Blocks tool further, it can be configured with the block_formats setting specified in custom JSON (input or file). What I would probably recommend instead of the Blocks tool is just to configure the Styles tool with exactly what you want. Keep in mind the parents (Blocks, Inline, etc.) are optional and you can add options to the root level if you prefer it, or create your own Parents within it.
    3 points
  50. This week I've worked through a few minor issue reports in both the core (ProcessWire) and InputfieldTinyMCE repositories. In addition, a new version of InputfieldTinyMCE was released that includes various improvements. We'll likely go through a few minor versions of this module before it is added to the core. I recommend downloading the latest posted version (6.0.3). Thanks to all that have been helping to test and report issues as they come up. I'm going to give the core another week or so of updates before we bump to the next version there. If you've recently launched any new sites, please add them to our sites directory at processwire.com/sites/submit/ when you have a moment. And if you aren't already subscribed to the ProcessWire Weekly updates email be sure to subscribe. Thanks and have a great weekend!
    3 points
×
×
  • Create New...