Leaderboard


Popular Content

Showing most liked content since 04/18/2018 in all areas

  1. 18 points
    Hello, friends! These days it is not that easy to join you here on the forums if you happen to be anywhere in Russia. You probably heard about our government's struggle to ban Telegram. And ProcessWire's ip is in the list. At these moments you start to understand just how important can a seemingly remote online community be in your everyday life and work. Thank you all for being here. As long as VPN's still function we can stay together .
  2. 14 points
    Hi, just wanted to share something I came across while working on an import module for XML data from a web service. The XML I got was not huge, but still, loading around 3.5 MB of XML with 250+ large child nodes into memory at once with simplexml_load_file() and then looping over it had significant impact on performance. I searched for a solution and found this great article about how to parse large XML files. It basically explains how to utilize the native XMLReader class together with SimpleXMLElement to handle such situations in a memory efficient way. After implementing it I got a significant improval on perceived performance. No comparison in numbers to share here as I'm a bit short on time.
  3. 11 points
    Hi Guys, Here's is our most recent website built in collaboration with the Design studio DITHO from Cologne, who designed and coordinated all the process. For now the website is only in German, but there will be a English version soon. https://bedrohte-ordnungen.de/ "Bedrohte Ordnungen" (Threatened Orders) is the display of an ongoing research by the University of Tübingen. Best described on their own words. Here on a hopefully accurate translation Here's a nice showcase video made by DITHO: This is a quite complex website. It's also quite heavy on images, videos and CSS animations, so old computers might struggle a bit to process it. All the website is dynamic and inside PW, including those animations. This is probably the most interesting part of how the website was built, since all the animations were created by DITHO themselves in ProcessWire thanks to a system that I created for them using a repeater field. You can have an idea through these screenshots: The content blocks of each case represent a question each and repeat throughout all the presented cases. Each question has a main content and most have also a hidden block that can be opened by clicking a button. They are created in PW using the very recent FieldGroups https://processwire.com/blog/posts/processwire-3.0.73-and-new-fieldset-types/: The only two third party modules used were AdminOnSteroids by @tpr and the very useful ColorPicker by @Soma. There would be more to talk about, but I don't want to extend myself too much. Hope you guys like it! Just a shout out to DITHO to say again how much fun this collaboration has been
  4. 11 points
    This week's version of ProcessWire on the dev branch includes some useful updates to the included AdminThemeUikit module. It also adds a new config setting for disabling HTTPS requirements in dev/staging environments, as well as some other updates: https://processwire.com/blog/posts/pw-3.0.99/
  5. 10 points
    Hi, based on the work of @microcipcip and @gebeer (see their posts here and here), I put together a Processwire + React boilerplate (profile). Here is the Github repository: https://github.com/lapico/process-react Cheers, K
  6. 7 points
    Nothing fancy, just solid basic sites for two different companies. Both happen to work mainly in construction sector. Both sites are only in finnish, but feel free to browse around. After a decade of Joomla I'm quite taken with Processwire, although having no background in any sort of programming the dive into PHP felt akin to jumping from 10 and landing on your stomach. ;-) Site 1: http://www.lahdenrakennusurakointi.fi/ site 2: http://www.peltityo.com/ If the sites look somewhat similar, it's on purpose. Some structural pieces are being recycled to make work more efficient. Aside from Processwire we started using UIKIT and it's been a pleasant experience. Although I'd love to have automated way of using UIKIT lightbox for images added with CK editor.
  7. 6 points
    Another update is online (branch DEV3): https://gitlab.com/baumrock/RockSqlFinder/tree/dev3 This is a major upgrade, a complete rewrite and finally a really good solution imho: I changed the syntax to object-notation in preference of nested associative arrays and it's a lot cleaner and easier to setup and read now. I rewrote the logic completely. It is NOT recursive any more but it takes away a LOT of complexity. You can add "fields" to your find-operation and those "fields" are fully customizable classes. The module ships with predefined classes for FieldtypeText (easy as it is just a column in the DB), FieldtypeFile (that shows concatenated filenames and descriptions) and FieldtypeRepeater (that shows concatenated data of the repeateritem's fields). The user can add custom FieldFinders in /site/assets/RockFinder (this will be the final name of the module). Possibility to add custom separators for concatenated fields Easy to create custom SQL by wrapping the created SQL in your own statement (SELECT ... FROM $finder->getSQL() GROUP BY ...) Examples: Query 10.000 invoices and return their date and value: Query all persons and show content of images (fieldtypeimage) and repeater (fieldtyperepeater): Same example but with image descriptions and all repeateritem's fields: Find 35.000 pages: This takes significantly longer than finds until 10.000 items. Maybe @adrian or @theo you have time to compare these results on your setups? Todos: Support for FieldtypePage (and other fieldtypes?) Support for Multilanguage (should not be hard, I've developed it with that in mind) Aggregation functions like sum(), avg(), min(), max() Support for closures? What do you guys think?
  8. 5 points
    Page Query Builder Build complex nested queries containing multipple fields and pages and return an array that can be parsed to JSON. This is usefull to fetch data for SPA and PWA. You can use it to tranfrom a ProcessWire Page or PageArray, even RepeaterMatrixPageArrays into an array or JSON. Queries can be nested and contain closures as callback functions. Installation Via ProcessWire Backend It is recommended to install via the ProcessWire admin Modules > Site > Add New > Add Module from Directory using the PageQueryBuilder class name. Manually Download the files from Github or the ProcessWire repository: https://modules.processwire.com/modules/page-query-builder/ Copy all of the files for this module into /site/modules/PageQueryBuilder/ Go to “Modules > Refresh” in your admin, and then click “install” for the this module. Methods There are two main methos: Return JSON $page->pageQueryJson($query); Return an Array $page->pageQueryArray($query); Building the query The query can be with key value pairs, or only keys. and can be nested. To ilustrate a short example: // simple query: $query = [ 'height', 'floors', ]; $pages->find('template=skyscraper')->pageQueryJson($query); Queries can be nested, call children etc: // simple query: $query = [ 'height', 'floors', 'images', // < some fileds contain default sub-queries to return data 'files' => [ // but you can also overrdide these defaults: 'filename' 'ext', 'url', ], // Assuming there are child pages with the architec template, or a // field name with a page relation to architects 'architect' => [ // sub-query 'name', 'email' ], // queries can contain closure functions 'querytime' => function($parent){ return "Query for $parent->title was built ".time(); } ]; $pages->find('template=skyscraper')->pageQueryJson($query); Keys: A single fieldname; height or floors or architects The Module can handle the following fields: Strings, Dates, Integer… Page references Pageimages Pagefiles PageArray MapMarker FieldtypeFunctional A template name; skyscraper or city The fieldname of a child (child.name); url or filename or title A ProcessWire selector; template=building, floors>=25 A new name for the returned index passed by a # delimiter: $query = [ 'skyscraper' => [ 'height', 'floors' ], 'architect' => [ 'title', 'email' ], ] Key value pars: Any of the keys above with an new query array: $query = [ 'skyscraper' => [ 'height', 'floors' ], 'architect' => [ 'title', 'email' ], ] A key and a closure functions to process and return a query. The closure gets the parent as argument: $query = [ 'architecs' => function($parent) { $architects = $parent->find('template=architect'); return $architects->arrayQuery(['name', 'email']); // or return $architects->explode('name, email'); } ] Real life example: $query = [ 'title', 'subtitle', // naming the key invitation 'template=Invitation, limit=1#invitation' => [ 'title', 'subtitle', 'body', ], // returns global speakers and local ones... 'speakers' => function($page){ $speakers = $page->speaker_relation; $speakers = $speakers->prepend(wire('pages')->find('template=Speaker, global=1, sort=-id')); // build a query of the speakers with return $speakers->arrayQuery([ 'title#name', // rename title field to name 'subtitle#ministry', // rename subtitle field to ministry 'links' => [ 'linklabel#label', // rename linklabel field to minlabelistry 'link' ], ]); }, // ProcessWire selector > name result "location" 'template=Location, limit=1#location' => [ 'title#city', // summary title field to city 'body', 'country', 'venue', 'summary#address', // rename summary field to address 'link', // ticket link 'map', // Mapmarker field, automatically transformed 'images', 'infos#categories' => [ // repeater matrix! > rename to categories 'title#name', // rename title field to name 'entries' => [ // nested repeater matrix! 'title', 'body' ] ], ], ]; if ($input->urlSegment1 === 'json') { header('Content-type: application/json'); echo $page->pageQueryJson($query); exit(); } Module default settings The modules settings are public. They can be adjusted, for example: $modules->get('PageQueryBuilder')->debug = true; $modules->get('PageQueryBuilder')->defaults = []; // reset all defaults Default queries for fields: Some field types come with default selectors, like Pageimages etc. These are the default queries for template names or object types: public $defaults = [ 'queries' => [ 'Pageimages' => [ 'basename', 'url', 'httpUrl', 'description', 'ext', 'focus', ], 'Pagefiles' => [ 'basename', 'url', 'httpUrl', 'description', 'ext', 'filesize', 'filesizeStr', 'hash', ], 'MapMarker' => [ 'lat', 'lng', 'zoom', 'address', ], 'User' => [ 'name', 'email', ], ], ]; These will only be used if there is no nested query for these types. So if you query a field with complex data and do not provide a sub-query, it will be transformed acordingly: $page->pageQueryArry(['images']); // returns something like this 'images' => [ 'basename', 'url', 'httpUrl', 'description', 'ext', 'focus'=> [ 'top', 'left', 'zoom', 'default', 'str', ] ]; You can always provide your own sub-query so the defaults will not be used: $page->pageQueryArry([ 'images' => [ 'filename', 'description' ], ]); You can also override these, for example: $modules->get('PageQueryBuilder')->defaults['queries']['Pageimages'] = [ 'basename', 'url', 'description', ]; Index of nested elements The index for nested elements can be adjusted. This is also done with defaults. There are 3 possibilities: Nested by name (default) Nested by ID Nested by nummerical indey Named index (default): This is the default. If you have a field that contains subpages, their key will be their name: // example $pagesByName = [ 'page-1-name' => [ 'title' => "Page one title", 'name' => 'page-1-name', ], 'page-2-name' => [ 'title' => "Page two title", 'name' => 'page-2-name', ] ] ID based index: If an object is listed in $defaults['index-id'] their index will be their id. Currently, no items are listed as defautls: $modules->get('PageQueryBuilder')->defaults['index-id']['Page']; // example $pagesById = [ 123 => [ 'title' => "Page one title", 'name' => 123, ], 124 => [ 'title' => "Page two title", 'name' => 124, ] ] Number based index By default, a couple of fields are transformed automatically to contain numbered indexes: // objects or template names that should use numerical indexes for children instead of names $defaults['index-n'] => [ 'Pageimage', 'Pagefile', 'RepeaterMatrixPage', ]; // example $images = [ 0 => [ 'filename' => "image1.jpg", ], 1 => [ 'filename' => "image2.jpg", ] ] When you remove the key 'Pageimage' from $defaults['index-n'], the index will again be name-based. Debug The module respects wire('config')->debug. It integrates with TracyDebug. You can override it like so: // turns on debug output no mather what: $modules->get('PageQueryBuilder')->debug = true; Todos Make defualts configurable via Backend. How could that be done in style with the default queries?
  9. 5 points
    I love TracyDebugger, but today I had a hard time debugging some stuff and tried XDebug to get support for breakpoints. It was a quite straightforward setup: create a file on your server and output phpinfo() Copy the content of this page to the wizard: https://xdebug.org/wizard.php Follow the instructions, they look like this: Instructions Download php_xdebug-2.6.0-7.1-vc14-x86_64.dll Move the downloaded file to C:\laragon\bin\php\php-7.1.14-Win32-VC14-x64\ext Edit C:\laragon\bin\php\php-7.1.14-Win32-VC14-x64\php.ini and add the line zend_extension = C:\laragon\bin\php\php-7.1.14-Win32-VC14-x64\ext\php_xdebug-2.6.0-7.1-vc14-x86_64.dll Restart the webserver check if everything worked by visiting the phpinfo() page again - it should show a section about xdebug now enable validaton in vscode by adjusting the user settings: "php.validate.enable": true, "php.validate.executablePath": "C:/laragon/bin/php/php-7.1.14-Win32-VC14-x64/php.exe", "php.executablePath": "C:/laragon/bin/php/php-7.1.14-Win32-VC14-x64/php.exe", "php.validate.run": "onType", install "PHP Debug" extension by Felix Becker and read the instructions enable remote debugging by xdebug by adding this to your php.ini [XDebug] xdebug.remote_enable = 1 xdebug.remote_autostart = 1 create a testfile, eg home.php and set the debug config to "PHP" add breakpoints and start debugging by pressing the green play icon reload your page in the browser and the debugger will stop on lines 2 and 3 where we set the breakpoints. open vscode (if you don't have two screens) and follow code execution step by step. There are also some videos on youtube: https://www.youtube.com/watch?v=poty5nKk2m4 Edit: Just realized that xDebug slows down ProcessWire extremely. See here: If anybody knows how to tackle this, please post the solution in the linked thread and I'll update this tutorial. Thanks See quickfix in my next post
  10. 5 points
    I've deleted the RockSqlFinder repo on gitlab and created a RockFinder repo. This will be the final name once I'm done with testing + writing docs. I've also added a simple tester process module to quickly inspect and test find operations: Note that this processmodule requires RockGrid which is not available for public yet, so this screenshot is just a sneak peak what will come.
  11. 5 points
    One way to do something like that is with the repeater field. You have a repeater field and the repeater has two page ref fields (people, roles). And you repeat the fields for every person. The way i described in my first comment the roles field would go to the people template, so on the video page you would only have the people field. You add a person and then click on it, a modal opens to edit the persons page where you can set the role.
  12. 5 points
    That property is added by the ProcessWire installer, and reflects the date that PW was installed. Here's the purpose of it: when there are additions/modifications to the core that are potentially not backwards compatible, it will check the installed date to make sure it doesn't need to retain some backwards compatible behavior. There aren't many instances of this, but here are a couple: 1. If your PW was installed after 2017-12-15, then it uses an "ms" suffix on image variations that use the "maxSize" method on Pageimage. 2. Another example has to do with Markup Regions. These were originally introduced supporting class attributes for certain actions, and that was later removed, as Markup Regions now use their own attributes. But if you installed your site before 2017-06-21, then the legacy class attribute actions will still work, if you happen use them.
  13. 5 points
    Hi @Karl_T sorry for that and thanks for reporting this issue, I think I have an idea why is happening - checking this afternoon.
  14. 5 points
    "Government guys" all over the world just do not understand that there is no such thing as "only officials can exploit security measures on behalf of the law". If they force backdoors to be implemented into software/hardware then anyone with enough technical skills can also walk through that door. They do not understand the basics of IT security, they live in their dream worlds trying to make the internet less secure therefore introducing more chaos instead of order they say they are striving for. They are doing quite the opposite what they are saying. Why am I not surprised?
  15. 5 points
    You can use a hook in ready.php to delete cache on save of pages // delete caches when pages are created, saved or moved around wire()->addHookAfter('Pages::save', function(Hookevent $event) { $page = $event->arguments(0); // do nothing on admin pages if($page->template == 'admin') return; // delete cache for templates if($page->template == 'where-to-go-detail' || $page->template == 'our-guides-detail') { $this->cache->delete('wtg'); // here you could add logic to rebuild the cache } });
  16. 5 points
    The skipLabel option is about whether or not to render the header of the inputfield. An example with InputfieldText: $f = $modules->get('InputfieldText'); $f->name = 'text1'; $f->label = 'label'; $inputfields->add($f); $f = $modules->get('InputfieldText'); $f->name = 'text2'; $f->label = 'label'; $f->skipLabel = Inputfield::skipLabelHeader; $inputfields->add($f); For InputfieldCheckbox, the header is already not rendered by default unless a description is defined for the inputfield. Instead, the label is rendered next to the checkbox itself. So setting skipLabelHeader or skipLabelBlank won't do anything because the header is already skipped. If you do want a separate header label for InputfieldCheckbox you can use the "checkboxLabel" or "label2" properties (they both do effectively the same thing). When these properties are set the "label" is rendered in the header and the "checkboxLabel" or "label2" is rendered next to the checkbox: $f = $modules->get('InputfieldCheckbox'); $f->name = 'checkbox1'; $f->label = 'label'; $inputfields->add($f); $f = $modules->get('InputfieldCheckbox'); $f->name = 'checkbox2'; $f->label = 'label'; $f->checkboxLabel = 'checkboxLabel'; $inputfields->add($f); If your question is actually "is it possible to have a checkbox without any text next to it" I think the answer is no, not using the API options. You could try a str_replace() in a hook after InputfieldCheckbox::render, or use Javascript to remove the text. Edit: another alternative for a checkbox without text next to it is to use a space character as the label: $f = $modules->get('InputfieldCheckbox'); $f->name = 'checkbox1'; $f->label = ' '; $inputfields->add($f);
  17. 4 points
    xdebug has always been slow (all over Google). Some things you can do Disable xdebug Profiler Disable xdebug Profiler enable trigger Disable xdebug auto trace Disable xdebug auto start (if you can) Helpful hints http://www.devinzuczek.com/anything-at-all/i-have-xdebug-and-php-is-slow/
  18. 4 points
    I am right now working on a quite similar project. In my case I import from an XML that I get through an API and populate product pages, check for there status etc. I can encourage you to go on the way you started. It is all pretty straight forward and nice to handle with the PW API. Your import code looks basically fine. So you shouldn't have major problems there. I set up a process module that creates a page in the backend where admins can manually trigger imports. If you would like to go that route, there is a skeleton Hello Process module that you can use and @bernhard wrote a great article on building admin pages with process modules. I find this approach much cleaner than doing all the logic in a template file. Regarding your concerns Use lazy cron module for automation. Each time you get a new JSON, loop through it and compare it to the single-movie pages you have and act on them (modify/delete) or create new ones. You can use custom fields on the single-movie template to store that Have a look at https://github.com/webcreate/infinite-ajax-scroll You can use kongondos Blog module or at least get a lot of inspiration from it ;-)
  19. 4 points
    According to the image above. // loop over repeater items // repeater is the name of my repeater field foreach ($page->repeater as $r) { // person is the name of my page ref field for selecting persons // can hold a single page (can be set in field's settings, details tab) echo $r->person->title, " "; // skills is the name of my page ref field for selecting skills // can hold multiple pages so we have to loop (can be set in field's settings, details tab) foreach ($r->skills as $s) { echo $s->title, " "; } // or use eq echo $r->skills->eq(0)->title, " "; echo $r->skills->eq(1)->title, " "; } // outputs // Jim Programmer Designer Programmer Designer
  20. 4 points
    Up until now not one of the many softwares on github that I have been using even had branding attached. With pro modules the user knows exactly what to expect: buy and then use. With free modules that ask for money to remove brandings, the user could feel tricked. I'd rather prefer that for the same reason mentioned above. I happily pay for pro modules and use them a lot. I totally respect the way you see things in this matter and it is your freedom as a module developer to handle things like you do. Just wanted to share my thouights and feelings about it and explain some negative views people might have on your approach, especially since it is the first time I come across this in the PW module world. Enough said. Thank you for everything you're giving to the community and keep up the great work!
  21. 4 points
    I think you need quotes to get accurate results. How about this one: https://nerdydata.com/search?query="%2Fsite%2Fassets%2Ffiles%2F" Although I don't think the total count is relevant, but definitely show some sites I haven't seen, especially of interest is: https://www.payrexx.com/
  22. 4 points
    Another year has passed... I was looking for a way to include database backup in my deployment process. I did not want to use some external secrets storage yet, so looked for a way to use db credentials already present in PW config. So I wrote a simple script, which I put in the project repo and call from cli during the deployment process like this: php -f backup.php For the sake of simplicity backup.php is in the web root. Here are its contents: <?php // backup.php include("index.php"); $backup = $database->backups(); $file = $backup->backup(); if($file) { echo "Backed up to: $file"; } else { echo "Backup failed: " . implode("<br>", $backup->errors()); } The full docs on how to customize it as you need should be here, but are now missing for some reason. One can still get them from the source code anyway) P.S. I am looking for a way to do it with a simple one-liner in cli to get rid of the backup.php, but not sure it is possible with php an easy way. Any advice appreciated! P.P.S. I knew I could do it, because @adrian done it in his wonderful Admin Actions module. Go read its code for inspiration and for education, if you are not a PW guru yet.
  23. 4 points
    Sorry guys for all those posts... Found the performance-killer: It is the ORDER BY field(`pages`.`id`, 52066,52067,52068,52069,52070 ... ) part. Without retaining the sort order of the pages->findIDs it is a LOT faster (4s without sort compared to 60s with sort and 75 using findMany): 91300 items: rockfinder = 4385.5ms | findmany = 74213.9ms | 5.91% I'll add this as an additional option and switch sort order OFF by default since sorting will be done by RockGrid anyhow No problem at all. I need this stuff for my own work, so any help is welcome but of course not expected PS: again the tests without sort order 11 items: rockfinder = 4ms | findmany = 6.9ms | 57.97% 1000 items: rockfinder = 35.7ms | findmany = 744.2ms | 4.8% 5000 items: rockfinder = 165ms | findmany = 1675.4ms | 9.85% 10002 items: rockfinder = 327ms | findmany = 3359.5ms | 9.73% 35000 items: rockfinder = 1745.2ms | findmany = 28547.7ms | 6.11% 91300 items: rockfinder = 4385.5ms | findmany = 74213.9ms | 5.91% Now that looks a lot better, doesn't it?
  24. 3 points
    Try: $datetofind=strtotime($date); foreach($page->special_days->find("date_value={$datetofind}, time_from!='', time_to!=''") as $special_day) { $slot_txt.=$special_day->time_from." to ".$special_day->time_to."<br/>"; }
  25. 3 points
    https://processwire.com/blog/posts/processwire-3.0.62-and-more-on-markup-regions/ try in main <div id="page-content"> <!-- Fill content --> </div> and like the blogpost in overview <div pw-replace="page-content"> <h1><?=$page->title?></h1> Overview page </div> it should work this way...you have a lot of other options like append, prepend and so on... best regards mr-fan
  26. 3 points
    You can also add class names on the ProcessPageEditImageSelect module options, but unfortunately UiKit lightbox plugin (https://getuikit.com/docs/lightbox) needs a wrapper div , so the code should be something like: <div uk-lightbox> <a href="image.jpg" data-caption="Caption"></a> </div> @Hurme, maybe you can try creating a new module based on@Martijn Geerts's Image Interceptor for this.
  27. 3 points
    This module evolved from the RockDataTables discussion thread: https://processwire.com/talk/topic/15524-previewdiscussion-rockdatatables; Special thanks to @adrian for the idea and @theo for his contributions. Several performance tests showed that it is absolutely necessary for grids with several thousand of rows to use SQL queries instead of $pages->find() operations. ALPHA, I'm currently working on it and the syntax will likely change a little bit Download: https://gitlab.com/baumrock/RockFinder Usage: Please see instructions in this post: I open a separate thread for this module because the initial discussion thread is quite bloated already and here I can share informations only related to this module. Also maybe some of you might not even know about it yet. Requires PW >= 3.0.46 because it utilizes the $pages->findIDs() method: https://processwire.com/api/ref/pages/find-i-ds/ Changelog: https://gitlab.com/baumrock/RockSqlFinder/commits/master
  28. 3 points
    You can use page.fieldname on the right hand side in your selector, so you need something like this: parent=/hotels/, template=hotel, hotel_country=page.destination_country, sort=title There's a discussion with a similar setup here:
  29. 3 points
    Hi @adrian, I'm experiencing an issue with Tracy in AdminThemeUikit (I don't remember it happening in AdminThemeDefault) where the debug bar forgets its position between page loads. I normally keep the debug bar at bottom right, but it forgets this and jumps up to the top left (sometimes other random locations too). It seems to be related to opening a modal window, with Tracy enabled for modals. See in the screencast below how after opening and closing the modal then reloading the page Tracy is now at the top left of the screen. Hopefully not too tricky to fix. If in fact it is tricky, I wouldn't mind an option that keeps the debug bar locked in the bottom right because personally I never move it from there. Edit: it does happen in AdminThemeDefault also. Funny, because I always have Tracy enabled for modals and I don't remember this occurring before. Maybe a side-effect of a recent update to the module?
  30. 3 points
    Sure, is now pending approval approved for the directory.
  31. 3 points
    Well, the first time you have to handle such situations is always a bit rough. Lots of trial and error, and trying to stay in sync, but also trying to get the best possible speed performance etc. From what little I could see, the JSON you get is well-structured. There are unique IDs that you could use in your import/update process. There are time-stamps for performances. So, overall you should be fine (not every SaaS who claims it has its own API is actually usable). With projects like this, it's even more important to have a solid test/dev platform. If you have a live site, and add or change features, you don't wanna do it directly first on the production site. I'm sure we'll have suggestions and tips if you run into any problems. That's the most important thing.
  32. 3 points
    Thanks @SamC, I understand. I kind-of did it in a test environment, let me explain the full case scenario: A local (and really small) movie theater in my area was looking for a web designer to help them out with their website and primarily their ticket management integration. They absolutely need to sell their tickets on-line. I quickly jumped in to start the negotiations around budget, best solution, how to manage the whole thing, ecc. During our chats I found that there was a widely used ticket management service in Italy called Wintic/Webtic, it is used in around 70% of cinemas in Italy and I knew that very probably I would have to integrate that sooner or later. So I started calling the software house regarding their ways to integrate the whole "thing" in an existing portal. They told me that they made available a webservice with the cinema schedule and send me a link to the JSON I was frightened! Being this the first time I've found myself in a situation (that I was actively avoiding) where I just needed to step out of my relatively comfy zone of CMSs and tackle the issue as best as I could and in a budget friendly way. (The integration with Wordpress is just a headache to think about compared with Processwire) Then I started to read (many times) all the threads regarding JSON import and this one really helped me out understanding the whole process. From that thread and a couple of others I modified the script and now it looks like this: https://gist.github.com/protorob/e6050c78b4bee2dbce59c38234afa0de In the end I came out with a functional mockup that you can find here: http://webtic.artomultiplo.net/ and accepted the job. Full of courage. Now I have a whole lot of new questions regarding the best way to wrap it out, so expect to see me around a little more this time. I'm planing to document the whole process in a very long blog post Now my main "concerns" are regarding: - Automate the create/modify/delete of the schedule comparing differences between the current JSON and a New one - Adding extra information to the events and not losing them when the schedule re-synchronize - Working with AJAX Load more for some parts of the website - Handling the blog I know I'll need a little bit of help specially with the importing script. I'll let you know how it goes
  33. 3 points
    I made it work with PHP 5.x just by changing one line. SubscribeToMailchimp.module - Line 23 - before: public function subscribe(string $email, array $data = [], string $list = "") { SubscribeToMailchimp.module - Line 23 - after: public function subscribe( $email, $data = [], $list = "") { This works without any problems so far.
  34. 3 points
    server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name example.com; root /home/forge/example.com/public; index index.html index.htm index.php; charset utf-8; # ----------------------------------------------------------------------------------------------- # Access Restrictions: Protect ProcessWire system files # ----------------------------------------------------------------------------------------------- # Block access to ProcessWire system files location ~ \.(inc|info|module|sh|sql)$ { deny all; } # Block access to any file or directory that begins with a period location ~ /\. { deny all; } # Block access to protected assets directories location ~ ^/(site|site-[^/]+)/assets/(cache|logs|backups|sessions|config|install|tmp)($|/.*$) { deny all; } # Block acceess to the /site/install/ directory location ~ ^/(site|site-[^/]+)/install($|/.*$) { deny all; } # Block dirs in /site/assets/ dirs that start with a hyphen location ~ ^/(site|site-[^/]+)/assets.*/-.+/.* { deny all; } # Block access to /wire/config.php, /site/config.php, /site/config-dev.php, and /wire/index.config.php location ~ ^/(wire|site|site-[^/]+)/(config|index\.config|config-dev)\.php$ { deny all; } # Block access to any PHP-based files in /templates-admin/ location ~ ^/(wire|site|site-[^/]+)/templates-admin($|/|/.*\.(php|html?|tpl|inc))$ { deny all; } # Block access to any PHP or markup files in /site/templates/ location ~ ^/(site|site-[^/]+)/templates($|/|/.*\.(php|html?|tpl|inc))$ { deny all; } # Block access to any PHP files in /site/assets/ location ~ ^/(site|site-[^/]+)/assets($|/|/.*\.php)$ { deny all; } # Block access to any PHP files in core or core module directories location ~ ^/wire/(core|modules)/.*\.(php|inc|tpl|module)$ { deny all; } # Block access to any PHP files in /site/modules/ location ~ ^/(site|site-[^/]+)/modules/.*\.(php|inc|tpl|module)$ { deny all; } # Block access to any software identifying txt files location ~ ^/(COPYRIGHT|INSTALL|README|htaccess)\.(txt|md)$ { deny all; } # Block all http access to the default/uninstalled site-default directory location ~ ^/site-default/ { deny all; } #Amplify dashboard location /nginx_status { stub_status on; allow 127.0.0.1; deny all; } # ----------------------------------------------------------------------------------------------- # If the request is for a static file, then set expires header and disable logging. # Give control to ProcessWire if the requested file or directory is non-existing. # ----------------------------------------------------------------------------------------------- location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|eot|woff|ttf)$ { expires 15d; log_not_found off; access_log off; try_files $uri $uri/ /index.php?it=$uri&$query_string; } # ----------------------------------------------------------------------------------------------- # ProCache Rules # ----------------------------------------------------------------------------------------------- set $cache_uri $request_uri; if ($request_method = POST) { set $cache_uri 'nocache'; } if ($http_cookie ~* "wires_challenge") { set $cache_uri 'nocache'; } if ($http_cookie ~* "persist") { set $cache_uri 'nocache'; } # ----------------------------------------------------------------------------------------------- # This location processes all other requests. If the request is for a file or directory that # physically exists on the server, then load the file. Else give control to ProcessWire. # ----------------------------------------------------------------------------------------------- location / { expires -1; try_files /site/assets/ProCache-b3d534d...d/$cache_uri/index.html $uri $uri/ /index.php?it=$uri&$args; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } access_log off; error_log /var/log/nginx/example.com-error.log error; error_page 404 /index.php; location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; fastcgi_index index.php; include fastcgi_params; } location ~ /\.ht { deny all; } }
  35. 3 points
    I'm with @Macrura as i'm using wireRenderFile() extensively with a dedicated /views/ folder where I can organise my output in components / atoms / whatever you want to call it, using templates (and sometimes /fields/field.php) more or less as controllers. @bernhard brings up some good points I haven't thought of though, especially the JS part - I awkwardly tucked that into wire('config')->scripts, which isn't as elegant / nice. Anway, it's great having the flexibility and options to use PW as you see fit Quite liberating.
  36. 3 points
    I know this may sound strange, but when it comes to https and redirects browsers become very "cachehappy"! When running into problems with this I use the browsers incognito/private mode, have to empty cache, restart browser, use different browser, use a VPN, and so on. Tiresome sometimes...
  37. 3 points
    Not a big problem, but the only other thing I would say is: imagine if every PW module developer did this. Would it be cool if there was an extra branding link in every MarkupSimpleNavigition menu? Maybe nobody would use that module then...
  38. 3 points
    I have used the script below to do that, but must emphasise that this is destructive. The script does copy the original image to a "for_deletion" folder in the site root, but in case of disaster it would be a big PITA to go through and put the original images back to their relevant pages. So use at your own risk! // You could run this script manually, or put it on LazyCron if you have a lot of images // Maximum image dimensions $max_width = 1600; $max_height = 1600; // Images to process per operation $limit = 5; // Create array of large images $large_images = []; $i = 1; foreach($fields->find("type=FieldtypeImage") as $field) { if(!count($field->getFieldgroups())) continue; foreach($pages->find("{$field->name}.count>0") as $p) { foreach($p->getUnformatted($field->name) as $image) { if($i > $limit) break; if($image->width > $max_width || $image->height > $max_height) { $large_images[] = [ 'basename' => $image->basename, 'filename' => $image->filename, 'page' => $p->url, ]; $i++; } } } } // Iterate over images foreach($large_images as $large_image) { // Make backup copy of image (create the "for_deletion" folder first) $destination = $config->paths->root . 'for_deletion/' . $large_image['basename']; if(!file_exists($destination)) { $success = copy($large_image['filename'], $destination); // Don't carry on to the resizing stage if the copy wasn't successful if(!$success) continue; // Log file copy $log->save('resized_images', "Copied original image {$large_image['basename']} from {$large_image['page']} to /for_deletion/"); } /* @var ImageSizer $sizer */ $sizer = new ImageSizer($large_image['filename'], ['cropping' => false]); $sizer->resize($max_width, $max_height); // Log file resize $log->save('resized_images', "Resized image {$large_image['basename']} on page {$large_image['page']} to max width $max_width, max height $max_height"); } If you are using image field types besides the core FieldtypeImage you could modify the identification of image fields to something like this.
  39. 3 points
    I have posted this link in some other thread, but as this thread also relevant leave it here Search by "X-Powered-By" header - 8599 https://publicwww.com/websites/"X-Powered-By%3A+ProcessWire"/ Seach by "site/assets/files" - 17384 https://publicwww.com/websites/"%2Fsite%2Fassets%2Ffiles%2F"/
  40. 3 points
    ~488 websites listed here using ProCache: https://nerdydata.com/search?query=%2Fsite%2Fassets%2Fpwpc%2Fpwpc
  41. 3 points
    $exhibitions->append($exhibition->getForpage());
  42. 3 points
    Can you be more precise please? What kind of calculations are you talking about? I'll try an answer with a guess This is a quick test i did with 10.000 fake invoices. The result is great (but see later). Here the setup for the Tracy Console: $selector = 'parent=/invoices, limit=2'; // the limit is for demo of the sql $finder = new RockFinder($selector, ['value', 'date']); $finder->sort = false; $sql = $finder->getSQL(); d($sql, [6,999]); This finds all invoices and returns their "date" (a datetime field) and their "value" (random number between 1 and 100). The resulting SQL is this: SELECT `pages`.`id` AS `id`, `value`.`value` AS `value`, `date`.`date` AS `date` FROM `pages` /* --- join value --- */ LEFT JOIN (SELECT `pages_id` AS `pageid`, `value`.`data` AS `value` FROM `field_value` AS `value`) AS `value` ON `value`.`pageid` = `pages`.`id` /* --- end value --- */ /* --- join date --- */ LEFT JOIN (SELECT `pages_id` AS `pageid`, `date`.`data` AS `date` FROM `field_date` AS `date`) AS `date` ON `date`.`pageid` = `pages`.`id` /* --- end date --- */ WHERE `pages`.`id` IN (42063,42064) Now the funny part: You can do all kinds of custom SQL with that returned SQL statement, for example grouping the invoices by month and building a sum of their values: $results = $this->database->query("SELECT sum(value) as monthsum, DATE_FORMAT(date, '%Y-%m') as date FROM ($sql) AS rockfinder group by date"); And here the absolutely awesome result: So you get aggregated data for 12 months in no-time (166ms!!) with some VERY basic SQL. I'll think about how this can be made even easier in the future. Maybe by providing a method that does the query and returns the result. I'm open to suggestions. The maybe greatest thing about that is that you do not need to take care about processwire page statuses. That has always been a real pain when working with SQL because it makes things so complex. You always need to think about adding WHERE pages.status < ... and so on. That sucks. Now you just build your custom "view" with RockFinder and do some simple SQL on that result. You get the idea? Edit: I put $finder->getSQL() inside the timer, now it took 280ms - still great IMHO. And see how easy it is to add an invoice-count for that month for example
  43. 3 points
    My config.php file says:
  44. 3 points
    I have encountered an issue for Duplicator ver 1.2.9. I am moving a site from localhost(windows 10) to Amazon Linux. I use RDS, which is a standalone server for database, so the dbHost is not localhost. The issue happened in the installation process after entering the database data and proceed. There's an error telling config file cannot be found. Then I go to config.php, there are at least 4 places are using old information. They are dbHost, dbName, dbUser, dbPass and httpHosts. I think for some reasons the config.php did not update at all after the installation complete. After I manually update the fields, the site works fine now. This means database import is working fine. I wonder if it is the dbHost matters. It is a long URL ended with xxx.rds.amazonaws.com.
  45. 3 points
    Sort order in database can affect the results returned. So, unless you are 'finding' everything, it is good to have the option to sort server-side.
  46. 3 points
  47. 3 points
    Building a website is not the problem. Running a business with it can become the problem. Collecting e-mail addresses, tracking visitors and monitoring visitor-behaviour, combining it with 3rd parties like Facebook and ad networks will be a much bigger thing now. Cookie permissions here, double-opt-in there, and so on... it will be much more challenging than before. Don't know anything special about sources in Spain, UK, US but here in Germany there are some lawyers offering (free and paid) help for all kinds of businesses. Just to name two I prefer: https://www.e-recht24.de/ and https://drschwenke.de/ And as always with legal stuff: lawyers are my one and only trusted source. Not other companies (like the one above) that offer checklists, guides and tutorials.
  48. 3 points
    i haven't worked on this ajax module for several months so it really is not ready, but i do have a working version if you want to try it. It needs testing, and work; The screenshots show some elements of the setup in case of any confusion. ---the field--- ---the files--- InputfieldSelectizeAjax.js InputfieldSelectizeAjax.module
  49. 2 points
    Hey @adrian, glad you gave it a try 1) No, I guess this was just for development. PR welcome (really need to work on other projects atm, see rockgrid and rockfinder for example and some client work). 2) Everybody who wants to (or needs to) remove the branding can contact me via PM 3) I agree. I've used Nette Live Validation in an older project and this looked a lot better, but I've just not had the time to implement it. This might be more complex when thinking about supporting different css frameworks. Or it might be as easy as loading this script: https://github.com/contributte/live-form-validation. I don't know and I wanted to go with the default tools as I'm short on resources for this module. And the most important part was that it works and is quick to setup and save, of course If you come up with a better solution I'm happy to merge it, but at the moment, I'm sorry, I have other priorities.
  50. 2 points
    Guys, I guess Sandra Morgan's post is spam. It includes a link not to a checklist but a service, most probably their own...