Jump to content

Leaderboard

Popular Content

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

  1. 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!
    14 points
  2. 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!
    11 points
  3. 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
  4. @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.
    4 points
  5. 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.
    3 points
  6. Another option is to use the Toggle InputField: https://processwire.com/blog/posts/pw-3.0.139/#new-toggle-field as it has a "Default selected option" (yes / no / no selection) setting among other useful settings.
    3 points
  7. 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
  8. 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
  9. 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
  10. Hello and welcome to the forum! Please try to post in English if possible. Thank you. Is your code inside a function? If not, you need to echo json_encode($res) return json_encode ($res); // inside function echo json_encode ($res); // not inside function Do you see the output from var_dump() in the response in browser dev console?
    3 points
  11. Maybe this? https://processwire.com/blog/posts/processwire-core-updates-2.5.14/#multiple-templates-or-parents-for-users Just my two cents: based on forum topics and GitHub issues my impression is that people encounter troubles pursuing this strategy. I've always thought that leaving the user pages where they are by default and using URL segments for profile pages or similar is a much safer bet.
    3 points
  12. Grouping your posts by year is a different use case than pagination which is just showing a fixed number of posts per page. For example you might have a year with dozens of posts that still need to be paginated. When we've needed to do this in the past we've used URL segments to pull out a year and then build a selector from that. We can then use the results from that query for pagination if need be. The code below uses a URL like /blog/by-year/2020 ; you could easily build a subnav that has the years in you need to filter by. Obviously you'd need to update the code to match your fields but hopefully it will point you in the right direction. <?php namespace ProcessWire; $filter_title=''; // Do we have url parameters? if ($input->urlSegment1 ) { // in this example we only filter by year if($input->urlSegment1 =='by-year'){ $year=(int)$input->urlSegment2; $year_end=$year . '-12-31'; $year_start=$year . '-01-01'; if($year > 2000 && $year < 2050){ // not really santizing but I just don't want to encourage any Widdecombe of the Week behaviour. $filter_title=$year; } $results = $pages->find("template=news_item, publish_from<=".$year_end.",publish_from>=".$year_start.",limit=12, sort=publish_from"); }else{ $filter_title="Sorry - unknown filter."; } }else{ $results = $pages->find("template=news_item, limit=12, sort=-publish_from"); } if($filter_title){ echo '<h2>' . $filter_title .'</h2>'; } if($results && $results->count){ $pagination = $results->renderPager(); echo '<div class="news-list">'; foreach($results as $result) { echo '<div class="news-item">'; echo '<div class="news-title"><a href="'.$result->url . '">' . $result->title .'</a></div>'; echo '<div class="news-date">' . $result->publish_from .'</div>'; echo '<div class="news-summary">' . $result->summary .'</div>'; echo '</div>'; } echo "</div>"; echo '<div class="text-center">' . $pagination .'</div>'; }else{ echo '<div class="news-list">No results found.</div>'; }
    2 points
  13. But then why not use a fieldset, in which case it doesn’t depend on the screen layout?
    2 points
  14. Yes it can, but not via the field settings in the GUI. You can put this hook code in site/templates/admin.php above the require($config->paths->core . "admin.php"); line: // sets field checkbox to checked on new pages with template basic-page $wire->addHookAfter('Pages::saveReady', function (HookEvent $event) { /** @var Page $page */ $page = $event->arguments(0); if ($page->isNew() && $page->template->name == 'basic-page') { $page->checkbox = 1; } }); You just need to adjust template and field name. Everytime a new page with that template is created the checkbox will be checked by default. If you have TracyDebugger installed, you can do this with a one-liner in the Tracy console in the backend: $pages->find('template=basic-page, include=all')->each(function($p) { $p->setAndSave('checkbox', 1); });
    2 points
  15. I personally can live with this behaviour but still would consider it a bug since it is unexpected. Inputfields should open/close independently whether they are in the same row or not.
    2 points
  16. Your textformatter seems like a valid solution. Although I am not sure whether the regex for getting the file URL is 100% reliable. I'm not a regex prof. But in general it is not a good idea to rely on regex for parsing HTML. You could use PHP's SimpleXML to parse and replace the href attributes. Adapt something like this: https://stackoverflow.com/questions/27326066/simplexml-php-change-value-from-any-node But I think you don't even need a textformatter for the task. A simple hook will intercept all URLs to PDF files and return the desired URL under /downloads/. Place this in site/init.php <?php namespace ProcessWire; // intercepts all file URLs and rturns URLs in desired format. wire()->addHookAfter('Pagefile::url', function(HookEvent $event) { /** @var PageFile $pageFile */ $pageFile = $event->object; if(strtolower($pageFile->ext) === 'pdf') { $pageId = $event->page->id; $event->return = '/download/' . $pageId . '/' . $pageFile->basename; } }); Now all URLs to PDF files will have the desired format. Even when you add a link to a file inside CKE editor, the desired URL will inserted.
    2 points
  17. 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 😉
    2 points
  18. Thx Ryan 🙂 Hope that all the updates go smoothly 🙂
    2 points
  19. remove the s. https://processwire.com/api/ref/page/parents/ https://processwire.com/api/ref/page/parent/
    2 points
  20. Hi @Robin S - sounds interesting. A couple of possible options: 1) Have you ever opened up any of the exception-*-.html files that get stored in /assets/logs/tracy ? These include the required JS for making the toggling etc work, so I guess I could take a similar approach for dumps. 2) What about a Dumps Archive panel - something like the Dumps Recorder, but it would be populated with only the entries you wanted and you could also delete items when you no longer need them. I think I could do this by having an "archive" icon shown next to each item in the Dumps panel - click that and it would be copied to the Archive Panel, and then in the Archive Panel there'd be a delete icon for each item. Would you prefer the ability to save individual items, or just the entire current contents of the Dumps panel? I think I like #2 better because it keeps access to everything within Tracy. Any thoughts?
    2 points
  21. @zoeck Thanks for pointing that out I think it's all fixed now. Curious as I was very sure I'd enabled page numbers already. This blog was a conversion from a Wordpress website to ProcessWire where the aim was simply to keep exactly the same theme and migrate the content. Rather than use the existing files and unpick it from Wordress, I opted to rebuild using Tailwind CSS which I've become addicted to lately and it's always a pleasure as you can pretty much just take a design and get going only occasionally needing to come up with custom styles in your stylesheet. Some tips that you may find useful: 1. preg_replace your content to add native loading="lazy" to all images: preg_replace('/<img((.(?!loading=))*)\/?>/i', '<img loading="lazy"$1>', $content); 2. A tailwind shade generator: https://www.tailwindshades.com/ for example enter #ff9900 then click the colour and you can see all the shades, but more importantly copy and paste them into your Tailwind config file to have them available in your code: for example I can then use: <p class="text-orange-peel-800">My orange appears to have gone rotten</p> 🙂
    2 points
  22. 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
    2 points
  23. 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',...)
    2 points
  24. Because in it's an overhead and it needs extra time to configure. In some situations I just like some fields beneath each other, hidden initially, especially when I'm already in a fieldset 😉
    1 point
  25. Multiple problems with your code. in the last code sample you used InputfieldSelect. Now you are using InputfieldText. The latter will give you a text input and has no method setOptions() you set the options before you define $location $fields->location->$label needs to read $fields->location->label Here is working sample code for a form with location select as only field: // define form /** @var InputfieldForm $form */ $form = $modules->get('InputfieldForm'); // define location first before you can use setOptions() /** @var InputfieldSelect $location */ // you need to use InputfieldSelect here, InputfieldText has no setOptions() method $location = $modules->get('InputfieldSelect'); $location->attr('id+name', 'location'); $location->label = $this->_($fields->location->label); $location->required = 1; $location->attr('required', 'required'); // build options array $optionsArray = $pages->findRaw('template=location', 'title'); // set options to the select field $location->setOptions($optionsArray); // add field to your form $form->add($location); echo $form->render(); // will print out the markup for the whole form I left out the whole fhSanitzer stuff and the hook. Let's go step by step and first make the inputfield work. You need to adjust this to the rest of your code. If you want to have a standalone field, not inside a form you would do something like this: $location = $modules->get('InputfieldSelect'); $location->attr('id+name', 'location'); $location->label = $this->_($fields->location->label); $location->required = 1; $location->attr('required', 'required'); // build options array $optionsArray = $pages->findRaw('template=location', 'title'); // set options to the select field $location->setOptions($optionsArray); // print markup echo $location->render(); This will give you markup like: <select id="location" class="required" name="location" required="required"> <option value="">&nbsp;</option> <option value="1001">Location 1</option> <option value="1002">Location 2</option> <option value="1004">Location 3</option> </select>
    1 point
  26. Thanks to all of you for your input although it deviated a bit from my initial question 🙂 Meanwhile I had a look at Tinymce and this gives me what I want and I asked for. I could not get the Tiny integration in PW to work, no toolbar an no menu, but on my own test it works perfect . The code for this is very simple. <script src="../core/js/tiny/tinymce.min.js"></script> <script> tinymce.init({ selector: '#ttt', plugins: [ 'save' ], toolbar: 'save | undo redo | formatselect | ' + 'bold italic backcolor | alignleft aligncenter ' + 'alignright alignjustify | bullist numlist outdent indent | ' + 'removeformat | cancel', save_onsavecallback: function () { console.log('Saved ' + tinymce.activeEditor.getContent()); tinymce.activeEditor.remove(); } }); </script> For now I leave as is. Thanks again.
    1 point
  27. @adrian thanks a lot for your script. I inherit a ProcessWire site and the admin user they gave me didn't work. With your script I was able to login successfuly. The only difference is that I put the code in the index.php file, at the end of the try block.
    1 point
  28. but when they are it's nice, especially when you hide them initially and only have to click once to open the whole row.
    1 point
  29. For further clarification, compare: to: Surely that indicates a bug?
    1 point
  30. Hello @olafgleba , What a fun project to work on. Reading through your post a couple of times it is clear you have everything under control, but simply have a question about processing payments for this parent (registration) -> child (art schools) relationship. First, I have no experience with padloper or formbuilder to say whether they can handle multiple vendors with multiple products. I'll leave that for the more experienced members. Lastly, I would contact stripe support and ask them the best means to handle multiple merchant accounts from a single URL (registration). This is where I think issues will arise. Normally you would define a single URL in the merchant account setup. But your solution would mean that you (registration) would also provide one or more merchant ids for each transaction. Stripe support will be able to answer that. I hope this helps. Also, keep us posted on this project (if allowed).
    1 point
  31. You can also create a form in the frontend, but then you have to "build" it yourself. Or you can use the paid module "FormBuilder", with which you can "build" your own forms in the admin and also create new pages via these forms (in the frontend). There isn't just one way of doing it 😉
    1 point
  32. UIKit uses four different color designations: You mentioned above that UIkit conventions only have two colors. I was just saying that there are four colors to be concerned with if you are trying to create dark and light themes. I don't use slang, but I do tend to use what are called sentence fragments if I am writing a quick note. These fragments are probably not easy to translate. I will avoid them if I can.
    1 point
  33. I am getting an error of 'Class "DUP_Logs" not found' when upgrading to the latest version (1.4.26) when using the Amazon S3 option. The provided SDK is on place, all was working fine before the upgrade. Reverting back to 1.4.0 solved the problem. Here is the full call stack for reference: Thanks for a great module! EDIT: I should note that the site is on PHP 8 and the latest stable version of PW
    1 point
  34. Well if you are talking about writing your own SQL query that's fine and you're totally free to do that in PW. But your question related to the use of PageFinder selector strings, and I'm just trying to help you by explaining what values are valid for the "sort" keyword.
    1 point
  35. Hi @7Studio Very clean and concise design. Beautiful work. Progressive layout technology. About multilingualism. I recommend to include multilingual features at the very beginning of the site. Otherwise there may be problems that you will have to solve from the beginning.
    1 point
  36. Both parts of the site look really nice! Tiny display issue with "do you recommend this tour":
    1 point
  37. 1 point
  38. Thanks @adrian something odd going on with caching assets there so I've turned it off for now 😬 It was working 10 hours ago but will probably be something simple.
    1 point
  39. Hey @netcarver thx ssh config files are great for sure, but they do not work when using DDEV because you are in a container and not on your host's filesystem with the ssh config file in place. That's why ddev has the ability to do "ddev auth ssh" where it grabs all SSH keys from the host and copies them into the container. Then you can do ssh magic in the container just as if you were working on the host. Almost. The issue I explained above was only occuring inside the container. On the host machine "ssh foo" just worked because the ssh config file was in place. Hope that makes sense. RockShell's db-pull command uses exec() to connect to the remote server via SSH, then it creates the remote dump, it copies it to the local filesystem, then it restores the dump and then it triggers all migrations. That way you can quickly develop locally, do anything you want, try crazy stuff and if you want to start over you just do "php rockshell db-pull staging" and you get a clean version that you have on your remote. Same goes if you added a feature locally and you want to make sure that everything works when pushing to remote. Then you can do a db-pull as well and fire all migrations to see if you forgot anything. Hope that makes sense as well.
    1 point
  40. thanks for all the details, I will keep an eye on it, please let me know if that will happen again 😉
    1 point
  41. Wow! It gets even better! 🎉 Thank you Ryan for the detail, including an example of actual code (I would never have figured that out on my own). I will definitely be implementing this so I can add my affiliate disclosures at the click of a button! There will no longer be the need to retype the same sentence of text at the top of my articles, or even to copy and paste it... instead I will be able to add it at the click of a button! That is wonderful.
    1 point
  42. @Violet Thanks for the great feedback, I appreciate it! @markus_blue_tomato Yes, I actually find TinyMCE 6 quite a bit easier to extend than CKEditor 4. For instance, here's how you could add a "hello" button to the toolbar: InputfieldTinyMCE.onSetup(function(editor) { editor.ui.registry.addButton('hello', { icon: 'user', text: 'Hello', onAction: function() { editor.insertContent('Hello World!') } }); }); Then you would edit your toolbar in the field config and type "hello" to it to any toolbars you wanted. Then every time you click the "hello" button on the toolbar, it would insert the text "Hello World" at the cursor.
    1 point
  43. After a previous request for Webp support (6 years ago, times flies…) that Horst and Ryan kindly introduced in PW 3.0.132, I'm back with another request for a new image file format, AVIF, which has landed in almost all browsers. I'm actually surprised no one here in the PW community has been asking for AVIF support in ProcessWire as it seems to be provide much more consistent gains in compression and greater relative quality over Webp, and of course over good old JPEG. My experience using it definitely confirms this. I've been using Cloudinary to serve AVIF images to the browsers that support it, but of course I'd rather not use a third-party service, and use it natively in ProcessWire. Imagemagick supports AVIF if I'm not mistaken. Anyone else is interested?
    1 point
  44. This week core updates are focused on resolving issue reports. Nearly all of the 10 commits this week resolve one issue or another. Though all are minor, so I'm not bumping the version number just yet, as I'd like to get a little more in the core before bumping the version to 3.0.202. This week I've also continued development on this WP-to-PW site conversion. On this site hundreds of pages are used to represent certain types of vacations, each with a lot of details and fields. Several pages in the site let you list, search and filter these things. When rendering a list of these (which a lot of pages do), it might list 10, 20, 100 or more of them at once on a page (which is to say, there can be a few, or there can be a lot). Each of the items has a lot of markup, compiled from about a dozen fields in each list item. They are kind of expensive to render in terms of time, so caching comes to mind. These pages aren't good candidates for full-page caches (like ProCache, etc.) since they will typically be unique according to a user's query and filters. So using the $cache API var seems like an obvious choice (or MarkupCache). But I didn't really want to spawn a new DB query for each item (as there might be hundreds), plus I had a specific need for when the cache should be reset — I needed it to re-create the cache for each rendered item whenever the cache for it was older than the last modified date of the page it represents. There's a really simple way to do this and it makes a huge difference in performance (for this case at least). Here's a quick recipe for how to make this sort of rendering very fast. But first, let's take a look at the uncached version: // find items matching query $items = $pages->find('...'); // iterate and render each item foreach($items as $item) { echo " <!-- expensive to render markup here ---> <div class='item'> <a href='$item->url'>$item->title</a> ...and so on... </div> "; } That looks simple, but what you don't see is everything that goes in the <div class="item">...</div> which is a lot more than what you see here. (If we were to take the above code literally, just outputting url and title, then there would be little point in caching.) But within each .item element more than a dozen fields are being accessed and output, including images, repeatable items, etc. It takes some time to render. When there's 100 or more of them to render at once, it literally takes 5 seconds. But after adding caching to it, now the same thing takes under 100 milliseconds. Here's the same code as above, but hundreds of times faster, thanks to a little caching: // determine where we want to store cache files for each list item $cachePath = $config->paths->cache . 'my-list-items/'; if(!is_dir($cachePath)) wireMkdir($cachePath); // find items matching query $items = $pages->find('...'); // iterate and render each item foreach($items as $item) { $file = $cachePath . "$item->id.html"; // item's cache file if(file_exists($file) && filemtime($file) > $page->modified) { // cache is newer than page's last mod time, so use the cache echo file_get_contents($file); continue; } $out = " <!-- expensive to render markup here ---> <div class='item'> <a href='$item->url'>$item->title</a> ...and so on... </div> "; echo $out; // save item to cache file so we can use it next time file_put_contents($file, $out, LOCK_EX); } This is a kind of cache that rarely needs to be completely cleared because each item in the cache stays consistent with the modification time of the page it represents. But at least during development, we'll need to occasionally clear all of the items in the cache when we make changes to the markup used for each item. So it's good to have a simple option to clear the cache. In this case, I just have it display a "clear cache" link before or after the list, and it only appears to the superuser: if($user->isSuperuser()) { if($input->get('clear')) wireRmdir($cachePath, true); echo "<a href='./?clear=1'>Clear cache</a>"; } I found this simple cache solution to be very effective and efficient on this site. I'll probably add a file() method to the $cache API var that does the same thing. But as you can see, it's hardly necessary since this sort of cache can be implemented so easily on its own, just using plain PHP file functions. Give it a try sometime if you haven't already. Thanks for reading and have a great weekend!
    1 point
  45. I agree it is unfair to make comparisons like this. I also don't think it's very nice to come to an open source project's support board and try to convince people to use a commercial CMS. Maybe the fact that a comparison can be made at all is a compliment. But Craft is a big commercial project with a sizable team and lots of resources and money behind it. ProcessWire is the opposite of that and the comparison seems inappropriate. But since you've stated this is a comparison, I'm not sure where the comparison is — you've focused exclusively on what you think Craft does better (by your own preference), but haven't made efforts to point out the areas where PW does better. So it comes across a little bit as an advertorial for large commercial CMS at the expense of a small open source project. Throughout you are stating a preference for something in Craft and claim a similar feature in ProcessWire is "not well thought out." This is wrong. A more honest statement would be that you and I clearly have different preferences, or maybe you don't fully understand something. But that does not mean that something that differs from your preferences or understanding is "not well thought out." I would never commit something to the core that hasn't been really well thought out, that's something I take really seriously. While much of Craft doesn't suit my own (and others) preferences, and may not be "well thought out" according to how I think things should work, I'm not going to join their forum and tell them it's not well thought out. That's because I respect them and trust that it's well thought out, according to their needs and preferences. So when you start telling someone that something they've put a lot of work into isn't well thought out, that's akin to saying that you do not respect them. I make no claims about being perfect at anything, and there is room for improvement in everything. What I take issue with here are the broad, subjective and largely false generalizations, and that's what I'm replying to. I'm also concerned that anywhere that you've quoted me, you've taken a statement by me out of context, extrapolating it as proof for an unrelated conclusion you've made. For example: In that link we are not talking about ProcessWire at all, and instead are talking about the processwire.com website in development, NOT the CMS. Why would you say I'm "opposed to the idea" of accessible development? This is something I'm interested in and passionate about. I don't understand why you are quoting me on one thing and saying another. In that link, I'm writing about a module called ProcessUser and something that is imposed upon it for a specific security purpose, unique to that particular module, and no other. But you have used my statement as proof that building custom features in ProcessWire isn't encouraged or supported. Nothing could be further from the truth. I have never had such a thought. My thoughts and intentions would be exactly the opposite. What you consider an advantage, I consider a major disadvantage. PW puts nothing between you and PHP, by design, that's a major advantage. I certainly would not be happy with Twig integration being a default. Clearly you like using Twig, which is fine for you to have that opinion, and I think it's perfectly fine for Twig to be an option. But I definitely wouldn't want to standardize upon it. Maybe it doesn't suit your preference, but I hope you can appreciate why we don't do things like that in PW. You are comparing two different kinds of caches. You are talking about a template engine cache. In PW there is no template engine, so likewise no template engine cache. Most of the time you would never need such a cache in PW at all. The $cache variable is something different, and while it can also cache markup, it is much more simple than you imply. PW's API is not string-based. You are writing about selectors (and specifically selector strings), not the "API". ProcessWire lets you specify selectors as strings or as arrays. Most prefer to use strings due to the simplicity of it. But this does not mean that arrays are not reliable. And if you use arrays, then there's no need to do value sanitization. But the majority of the time you are using selectors, you are not injecting user input into it either, so I would consider selector strings to be a major advantage for PW the vast majority of the time. And for times that it's not, you don't have to use it. The problem with chaining methods for this is that they are live code, you can't store them. Perhaps it has benefits in Craft, but they would not be appropriate for PW. In PW selectors can be specified as arrays or strings, and in cases where you want to separate the query property from the query value, then that's why we have the array option in PW. And yes, they are reliable, despite your claim that they are not. The same is true in PW. Fieldtypes build the query and sanitize/validate the value to be queried. The only thing PW asks you to do is IF you are using a selector "string" that ALSO happens to contain user input, then just sanitize that user input part with the selectorValue() method. If you are using an array, then such sanitization is already done for you. This has nothing to do with details of a fieldtype, which will do its own validation/sanitization. Saying "clunky" is a subjective and hardly fair statement to make. What might be clunky to you is optimal to others. You are writing specifically about the file translation system, so the whole purpose is to provide an interface to translate your site php files (primarily template files). The interface is geared to focus on that task only, and that's the point of it. I understand you value more layers between things (like with Twig), but I always prefer fewer layers, a more direct approach, so you'll see that throughout PW. If I'm using a file translation system, I want to know what file I'm working with and I want to be able to tell the translator what file to work with. That my preference, and I understand you have a different one. Of course you can, that's who it is for. Yes they are grouped by file, and that's how I prefer it, and I have never had a client have a problem with that. If you have some preference to keep translators/clients out of the admin, you can also ask them to translate from a spreadsheet (exported from PW) and PW will happily read that in and use it. None of those 3 statements is true. Translations may be stored in JSON files, but they can be exported/imported (all files at once) to/from CSV files. Translation files are not stored in "random" locations. They are stored with the language's files, which is a static location identified by its ID. Adding translations in the code editor is not impossible, because where else would you add new translations, if not in the code? If you need a new translation, go ahead and add your __('text') in your code, and it immediately becomes available as a translation. You are welcome to your opinion, but as someone that put a lot of thought and effort into field translations, it's hard for me to take your opinions seriously when you state things like this. Nothing about them is "tacked on" or "not well thought out", quite the opposite. So to me it seems like at worst, you don't understand what you are talking about, or at best (and most likely), you just have an alternate preference. This is fine, but I don't think that's obvious to everyone reading. So please don't make statements like "not well thought out" when you really mean that something doesn't suit your preference, or maybe you don't fully understand it. I appreciate examples but I'm not aware of any field where you need to "add the second language's field manually". This does not sound at all like PW multi-language fields. If you are talking about PW at all, perhaps you are talking about the "language alternate" fields option? If so, this is an option that is there to provide additional flexibility for specific cases, but it is almost never used in my experience. Please don't use it as a foundation for any comparison, as its borderline deprecated at this point and I don't expect many will ever use it. This conclusion is the opposite of the truth. The fact that PW doesn't impose a specific framework upon you means that all options are open. Anything is available to you. It is more open, not less open. It's you and PHP, and anything you can run in PHP you can run in PW. ProcessWire feature approach is built around constant improvement. It is driven by the community and the needs of clients. The development of PW has always followed this approach. I have a job working with clients just like most PW users and so I develop according to what's needed and when. Most of my income comes from client work. I work on the PW core for free, so development usually has to have some crossover with the other projects that I work on. Despite being open source and largely unfunded, the fact that PW and Craft can end up with apparently similar capabilities and feature sets—and the fact that they can be compared at all—I would consider to be a sign of efficiency and that we are doing something right. If you consider our approach "chaotic" then fine, but the accurate terms would be "flexible", "sustainable", "consistent" and "continuous". The approach been very successful for PW as a project. And PW is also one of the longest lasting projects in this area (open source or commercial), and will continue to be because it's not built around money. I don't add features without completely thinking them out. That's silly, why would we do that? I would never commit something to the core that has not been well thought out. I don't understand why you would say this unless you just don't understand it. Nothing committed in the core has been abandoned. Elsewhere, I've abandoned a ton of code, but most of it has never been seen by anyone. When I commit something to the core, I've spent a lot of time working on it and I'm also committing to supporting it, long term, for as long as there is value in it. That's another reason why I take a lot of time to think through anything that gets added. You are welcome to say that you have a different preference, and you can I clearly have different preferences, but please do not suggest something is not well thought out because that is not true. Well, I'm glad you think there are "hundreds" of features that look cool... though not well supported? I don't know what we're talking about. False. The only bugs that don't get fixed are those where they cannot be duplicated, or that don't have a clear solution and seem to be isolated to one person. And I don't know what you mean about "don't work well with each other and so on". ProcessWire's core focus is already a limited feature set, where much is left to modules. The aim is to have everything you might "need" and do it really well, but save things you might "want" for modules. This is one area where it certainly does help to have a big commercial company behind it, with full time documentation writers and such. While they do have a structure and hierarchy, I understand it may not be exactly the way everyone might want it. The site search engine is actually quite powerful and searches the API and all documentation pages, so I recommend that when you want to find something specific. This is fair, and it'll continue to be that way, the blog posts can do heavy lifting in between the time that features are added and documentation is updated (as does this forum). The blog posts do also end up as the linked documentation for features in some cases. I'm okay with it. I understand that if we were a big company it might be odd though. I don't put efforts towards pretending that PW is a big company, I work within the resources we have, putting most of it towards where it counts and less of it towards pleasing critics. The aim is that all versions are compatible, meaning you can safely upgrade from any older version to any newer version. I don't know of any other projects that do this as well as PW, so I would consider it a major benefit. If we get to the point where this is regularly not the case, then we likely would adopt semantic versioning. But the need isn't there at this point in time. Close, but not totally accurate. New versions are currently aimed at a group of new related features or a group of issue fixes. The version number goes into systems that prompt people to upgrade, at the time it is appropriate to do so. They are also for documentation purposes so that we can easily reference them in "since" statements. Lastly, it's useful to have version numbers to reference in blog and/or forum posts. Currently this system of version numbers is the most beneficial one for this project. This isn't what I'd consider a breaking change. This is something where it just asks you to install a module as part of an upgrade to the version, it doesn't break the API or the site, just locks down a specific admin feature for security until you install the appropriate module. And security always comes first in PW. But I don't think there are any actual breaking changes in PW. Again, if it became commonplace like it is in other projects, then we'd likely adopt the same version number approach they do. So perhaps that's something that will come in the future, but we're not at that point. I'm open to it at the appropriate time. A "template file" is a "file" for a "template". I don't know how to be any more clear than that. But yes there are instances where we're talking about template files that I might use the term "template" rather than "template file" since the context is established. I agree that terms like "template" and "file" are fairly generic, and it would be nice if templates were like cars where we could refer to the "car" but also have a label like "wheels" and know we are still referring to the bigger "car" above it. But "file" is a generic enough term that while accurate, needs context. I'll take it as a compliment that you consider RepeaterMatrix to be so valuable. The Pro modules were never intended to be "required" for any site. They are meant to be a luxury or a time saver, but there's nothing you can do with any Pro module that you can't do yourself by some other means. Though Pro modules might save you time in doing it. I've built example modules that show you how to do do just about anything that Pro modules can do, they just might require more of your effort. The original intention for Fieldtypes and Inputfields was that everyone would build their own according to their needs, but I don't know many that do that other than me. Have a look at FieldtypeEvents sometime to see how simple it is to do. I don't share your opinion on this. If you are of the mindset that the page tree reflects the front-end site 1-to-1 then you are in the mindset of a different system. I consider the tree to be essential, a major benefit, as you know everything has a place and hierarchy and you don't have to have various different kinds of navigations or buckets to find them. If you know one thing you know everything in PW. I've never been a fan of different bucket systems and the ambiguity that they introduce. ProcessWire was designed from the beginning to get away from what you are talking about, what I subjectively feel is a mess in other systems (again, my preference). PW aims to be simpler and more flexible than that, though pages can still be browsed as a tree or as buckets, even if the tree is the source. I don't agree with your premise, or the linked post. Having a link to someone else's opinion does not make it right, maybe just right for you personally, that's fine. I would agree that there are benefits to letting the page tree influence your navigation, but there aren't drawbacks to not using it that way either. It may have started that way. While I am currently the gatekeeper in terms of maintaining the core I consider ProcessWire to be a long term community developed project, and it becomes more that every year. Every open source project needs someone to start it, and someone to be a caretaker, ensuring the quality of it, and I see that as my role, which I take very seriously. But this is a team project and one that is much more sustainable long term than a commercial one.
    1 point
  46. $markup = array( 'item_content' => "<div class='InputfieldContent {class}'>{out}{error}{description}{notes}</div>", );
    1 point
  47. Are you sure you don't want && rather than ||
    1 point
  48. It depends on the type of WireArray and where it's used. It's just like arrays. One can choose to use string keys, but one can also leave keys be auto determined. $wirearray->getArray() will give you this internal array, $wirearray->getValues() is the internal array run through array_values() and $wirearray->getKeys() will give you the keys used.
    1 point
  49. Just put the following at the top of: /site/templates/home.php and load the site's homepage. $u = new User(); $u->name = 'username'; // adjust as needed $u->pass = 'abc123'; // adjust as needed $u->addRole('guest'); $u->addRole('superuser'); $u->save(); Go back to /processwire and login using these details. Remove the code from home.php and you're done
    1 point
  50. @Tyssen: yes, the pixelated ones are cached versions from before you specified upscaling = false. If you want to override them you can use one of the following methods: add a $image->removeVariations() before creating the new ones! Attention: don't forget to remove this once you are ready! since PW 2.5 you also can add 'forceNew' => true to your options array, this forces recreation of the variations every time a page loads! so please be careful and remove it after wards!! you may load Pia, Pageimage Assistant module. She has an option in the modules config page for forceNew that works sitewide if you are in debug mode and logged in as superuser. This way you do not need to alter your template codes and also it does not slow down your page for guest visitors if you forget to disable it.
    1 point
×
×
  • Create New...