Leaderboard
Popular Content
Showing content with the highest reputation on 03/29/2021 in all areas
-
4 points
-
v4.21.52 fixes an issue with uploading images to repeatermatrix fields. This fix might also take care of a few other randomly seen bugs, although only time will tell with those. Regardless, I think this is a pretty important update for everyone.3 points
-
Not all the API variables and classes are included in the API Reference menus. For example, the whole $fieldgroups API variable and methods exist in the documentation but do not appear in the menus. Ryan has said: Personally I'd rather have everything listed in the menus. In terms of modules there is also the Pro API Explorer.3 points
-
If anyone's looking for a shortcut to simplified/extended password reset features, there is a commercial extension module available.2 points
-
In the meantime you can go using this: https://www.uniformserver.com/ it has worked wonderfully for me2 points
-
I have never claimed anything different. That's why I think several of your statements sound like you did not get what I was trying to say even though you say you did. But it does also not sound like you want to hear another explanation so we can leave it with that ? Using custom page classes is great with or without using my technique ?2 points
-
2 points
-
A Fieldtype for dynamic options that are generated at runtime via a hook. Configuration Inputfield type You can choose from a range of inputfield types on the Details tab of a Dynamic Options field. Your field will return a string or an array depending on if the selected input field type is for "single item selection" or "multiple item selection". Maximum number of items You can define a maximum number of items the field is allowed to contain. The core inputfields supported by this module will become disabled once the limit is reached. This option is only applicable if you have selected an inputfield type that is for multiple item selection. Format as Pagefile/Pageimage object(s) If the field will store paths/URLs to Pagefiles/Pageimages then you can enable this option to have the formatted value be a Pagefile/Pageimage object for "single" fields or an array of Pagefile/Pageimage objects for "multiple" fields. There is a related Select Images inputfield module that allows you to visually select image thumbnails. Defining selectable options Selectable options for a Dynamic Options field should be set in a FieldtypeDynamicOptions::getSelectableOptions hook in /site/ready.php. The hook should return an array of options as 'value' => 'label'. An example hook is shown on the Details tab of a Dynamic Options field: $wire->addHookAfter('FieldtypeDynamicOptions::getSelectableOptions', function(HookEvent $event) { // The page being edited $page = $event->arguments(0); // The Dynamic Options field $field = $event->arguments(1); if($field->name === 'your_field_name') { $event->return = [ 'red' => 'Red', 'green' => 'Green', 'blue' => 'Blue', ]; } }); Formatted value If a Dynamic Options field uses a "single" input type then its formatted value is a string, and if it uses a "multiple" input type then its formatted value is an array. The unformatted value of a Dynamic Options field is always an array. Also see the Configuration section above for description of an option to have the formatted value be Pagefile/Pageimage object(s). Examples of possible uses $wire->addHookAfter('FieldtypeDynamicOptions::getSelectableOptions', function(HookEvent $event) { // The page being edited $page = $event->arguments(0); // The Dynamic Options field $field = $event->arguments(1); // Select from the "files" field on the page if($field->name === 'select_files') { $options = []; foreach($page->files as $file) { // Value is basename, label is description if one exists $options[$file->basename] = $file->get('description|basename'); } $event->return = $options; } // Select from files in a folder if($field->name === 'select_folder_files') { $options = []; $path = $event->wire()->config->paths->root . 'my-folder/'; $files = $event->wire()->files->find($path); foreach($files as $file) { // Value is full path, label is basename $options[$file] = str_replace($path, '', $file); } $event->return = $options; } // Select from non-system templates if($field->name === 'select_template') { $options = []; foreach($event->wire()->templates as $template) { if($template->flags & Template::flagSystem) continue; $options[$template->id] = $template->name; } $event->return = $options; } // Select from non-system fields if($field->name === 'select_field') { $options = []; foreach($event->wire()->fields as $field) { if($field->flags & Field::flagSystem) continue; $options[$field->id] = $field->name; } $event->return = $options; } // Select from FormBuilder forms if($field->name === 'select_formbuilder_form') { $form_names = $event->wire()->forms->getFormNames(); // Use form names as both keys and values $event->return = array_combine($form_names, $form_names); } }); https://github.com/Toutouwai/FieldtypeDynamicOptions https://processwire.com/modules/fieldtype-dynamic-options/1 point
-
The module has been lying around on GitHub for some time now, so I thought I'd give it its own forum topic so I can give it a module list entry. SymmetricEncryptedText Symmetric encryption for text based fields (supports multi language fields). Module page. Link to the GitHub repo. Description This module adds an encryption option to all text fields (and those derived from FieldtypeText). Field contents are encrypted using a symmetric key when a page is saved and decrypted when loaded from the database. The module by default uses sodium (if loaded) in PHP versions >= 7.2, otherwise it falls back to the bundled phpseclib. Multi-Language fields are supported too. WARNING! Setting a field to encrypted and saving values in those fields is a one-way road! Once encrypted, the contents cannot be unencrypted without writing a program to do so. Disabling the encryption option on a field after the fact gets you encrypted "garbage". Usage Download the zipped module through the green button at the top right of the GitHub repo or (once available there) from the official PW module repository Extract in its own directory under site/modules. In the backend, click "Modules" -> "Refresh", then install "Symmetric Encryption for Text Fields". Go to module settings. An appropriately sized, random key will be generated if this is your first use. Copy the supplied entry into site/config.php Add fields or configure already present fields. On the "Details" tab you can enable encryption for the field in question Edit a page with such a field, enter a value there, save and enjoy Existing, unencrypted values are left untouched until a new value is saved. That way, you can do a smooth upgrade to encryption, but you have to save all pre-populated pages to have their values encrypted in the database. Thus it is recommended to avoid adding encryption to already populated fields. Advanced Usage You can hook after SymmetricEncryptedText::loadKey to retrieve your key from somewhere else, e.g. a different server.1 point
-
This module was already introduced in another thread yesterday, but since each module should have a thread of its own, here we go. Login Scheduler adds a couple of new fields to user template(s) and provides support for disabling login for non-superuser accounts either instantly (with a checkbox, "Login disabled") or by specifying a time range ("Login allowed starting from", "Login allowed until"). If a user is already logged in when login access is disabled, logout should be triggered during next session validity check (usually next page load). Starting from version 1.1.0, superuser accounts are not affected by this module at all. This is a safety mechanism and prevents you from locking yourself out of the whole system. You can grab this module from GitHub: https://github.com/teppokoivula/LoginScheduler.1 point
-
PageEditSoftLock ProcessWire2+ Module There was a request for a page lock feature in PW2.1 for pages being edited by an other user already, it would lock or throw a message of along the line of: "This page is currently being edited by "username'." Thanks to Ryan for helping getting this done quickly! Download: https://github.com/s...ageEditSoftLock How it works Only the module "PageEditSoftLock" needs to be installed/uninstalled, the "ProcessPageEditSoftLock" Module will install/uninstall itself. The module creates a table and a hidden admin page under /page/edit/ for pinging in the background while editing a page. You can configure the ping interval and expiration timeout to what you think is good. Defaults - 20 seconds for pinging, - 60 seconds for expiration time (all entries in the table older than this will get deleted). ---- 27-02-2012 update https://github.com/s...1f204bc1b6c740a Fix for new repeater field throwing the lock message because of the way repeater work and this module. Thanks to Ryan for finding a quick fix.1 point
-
Thanks, @adrian! I was able to reproduce the issue and it should now be fixed in 0.29.4. Meanwhile 0.29.3 fixed those Debugger issues you mentioned earlier, and also a minor layout glitch related to grouping results list items ?1 point
-
<?php $searchEngine = $modules->get('SearchEngine'); echo $searchEngine->renderStyles(); echo $searchEngine->renderScripts(); $findOptions = [ 'group_by' => 'template' ]; $renderOptions = [ 'results_grouped' => 'template.label' ]; $query = $searchEngine->find($input->get->q, $findOptions); echo $searchEngine->renderResults($renderOptions, $query); {"SearchEngine":{"version":"0.29.2","settings":{"indexed_fields":["title","summary","body"],"indexed_templates":["basic-page","home","license","licenses"],"find_args__sort":"sort","find_args__operator":"~=","index_pages_now_selector":"has_parent=1","index_field":"search_index","override_compatible_fieldtypes":"","compatible_fieldtypes":["FieldtypeEmail","FieldtypeFieldsetPage","FieldtypeDatetime","FieldtypeText","FieldtypeTextLanguage","FieldtypeTextarea","FieldtypeTextareaLanguage","FieldtypePageTitle","FieldtypePageTitleLanguage","FieldtypeCheckbox","FieldtypeInteger","FieldtypeFloat","FieldtypeURL","FieldtypeModule","FieldtypeFile","FieldtypeImage","FieldtypeSelector","FieldtypeOptions","FieldtypeRepeater","FieldtypeRepeaterMatrix","FieldtypePageTable","FieldtypePage","FieldtypeTable","FieldtypeTextareas"],"indexer_actions":[],"render_args__themes_directory":"","debugger_page":0,"debugger_query":"","debugger_query_args":"{}","uninstall":"","submit_save_module":"Submit"}}}1 point
-
GraphQLFieldtypeSelectExtOption adds support of @kixe's FieldtypeSelectExtOption to @dadish's ProcessGraphQL. https://github.com/blue-tomato/GraphQLFieldtypeSelectExtOption Currently the module is experimental since I don't know how FieldtypeSelectExtOption is used in the wild ?1 point
-
This should be fixed now in 0.29.2. The module was relying on DatabaseQuerySelect::getQuery(), which no longer returns usable queries as of 3.0.158 (or something along those lines) ?1 point
-
I'm actually not sure why I used that and then $args['operator'] instead of simply: $findOptions['operator'] I can't see any reason at the moment not to change to the simpler version.1 point
-
Not at all, it is just that – as I have wrote somewhere above – I keep an eye on your posts so I have read them all because I am interested. Especially as we are indeed talking about the same topic, it is just that we prefer somewhat different approaches to achieve something pretty similar, and I have already taken notes of your "tips and tricks". Thanks once more!1 point
-
Thanks @adrian! First one was a PHP8 issue, while the second (and bigger) problem was related to fulltext index queries. Both should now be fixed in version 0.29.1, though please let me know if it doesn't work for you. Also: I had accidentally grouping by template enabled by default, this is now disabled by default.1 point
-
The TextformatterSoundmanager https://processwire.com/modules/textformatter-soundmanager/ works well for embedding audio files, but uses shortcodes. This module is a good choice for simple things where you wouldn't need a playlist or control the skin etc, like you can do with SM2 module. You could also skin the audio element using something like plyr.io, which is a nice replacement for the default player. MediaElement.js also works in a similar way. I can see using this module for quick and simple applications though.1 point
-
Hi @teppo - I am excited for these new features - thanks for you hard work. Unfortunately, when I install it I get this error: Deprecated: Required parameter $query follows optional parameter $args in /Users/ajones/Sites/ecoreportcard/site/modules/SearchEngine/lib/Renderer.php on line 615 Deprecated: Required parameter $type follows optional parameter $args in /Users/ajones/Sites/ecoreportcard/site/modules/SearchEngine/lib/Renderer.php on line 718 Deprecated: Required parameter $type follows optional parameter $args in /Users/ajones/Sites/ecoreportcard/site/modules/SearchEngine/lib/Renderer.php on line 755 and then when I try to do a search, I get: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ':pf19s0X IN BOOLEAN MODE) ) )) \n LEFT JOIN templates AS pwse_t ON pwse_t.id=pa...' at line 4 Reverting to the last version instantly fixes these. Note that for my testing I am using the simple: <?= $modules->get('SearchEngine')->render() ?> approach to handle everything. Let me know if you need me to dig a little deeper.1 point
-
This sort of thing is possible, but you might find life easier with https://processwire.com/modules/search-engine/ - it will also be much more performant for the end user.1 point
-
1 point
-
But I was ? And I tried to explain why... IMHO not That's what I was trying to explain. I'm using custom page classes in an object oriented way (similar to PW modules). And that's great because you have all your code pieces in one place - namely in one single php file of your custom page class. Let's say we build a webpage about cats. Step one: Create a custom page class and place it in /site/classes <?php namespace ProcessWire; class Cat extends Page { } Now all cats in our system are of type "Cat", and that's great! Now we want a custom headline for every cat on our frontend based on the title field, easy: <?php namespace ProcessWire; class Cat extends Page { public function headline() { if(!$this->title) return "This cat has no name"; return "Details for Cat '{$this->title}'"; } } In your template <h1><?= $page->headline() ?></h1> And that you'll do for any kind of business logic your application needs. Now what if we wanted to manage thousands of cats and we wanted every cat have a unique 4-letter page name instead of one based on the title (to prevent ugly suffix urls like catname-1, catname-2 etc)? We could do that easily with a hook. In the past one might have put the hook into ready.php and after time your ready.php grows and grows and grows and some day you totally lose control over your hooks and over your software. Not if you place them where they belong: Into the page class to the cat object: <?php namespace ProcessWire; class Cat extends Page { public function init() { $tpl = "template=cat"; $this->addHookAfter("Pages::saveReady($tpl,id=0)", $this, "onCreate"); } public function headline() { if(!$this->title) return "This cat has no name"; return "Details for Cat '{$this->title}'"; } public function onCreate($event) { $page = $event->arguments(0); $page->name = $event->pages->names()->uniqueRandomPageName(4); } } That's how you'd attach a hook in an autoload module, and that's what I suggest: Structure your custom page class just like an autoload pw module. Apply the same principles and your code will get better readable, better understandable and better maintainable. Now the only problem ist, that init() of the page class does not get called like it gets called in an autoload module. Neither does ready(). But it's simple to overcome this - just place this in init.php $cat = new Cat(); $cat->init(); This triggers the init method of your cat on INIT of PW and it attaches all hooks of your cat page class as if they where placed in init.php; The same technique can be used for ready() in ready.php; That does load one instance of cat into memory though. That's a little overhead. IMHO it's worth the overhead, but I can only guess that the overhead is very small... Maybe one could also use loaded() for that, I don't know and I'd have to investigate on this. Maybe someone can try and share their findings ?1 point
-
I'd say that these are more like two sides of the same coin: You've solved the file issue by directing static file requests to CDN and pointing file related requests to a single (?) master instance. This is of course a valid approach, but in this type of setup you've got at least two types of instances (read and read-write), which can make things more complicated than just replicating a single instance type based on the load, and may not work so well for sites that often require direct access to assets. This could also potentially impact fault tolerance: in case you indeed only have one write instance, that going down for any reason would be a big blow. Most cloud setups I've worked with have handled this the other way around: files offloaded to external buckets and database shared among instances. One benefit of this is that those instances are identical, there's no "master" to rely on. In most cases S3 hasn't had major impact on performance (plus there's always CDN) and I've never run into a case where database would've been an absolute bottleneck. Of course DB requests should be limited: most web requests can be served from static cache, and if advanced caching is needed, in comes Redis. The long story short is that I believe core level ability to store files somewhere other than local disk would be a splendid improvement for cloud use. It's true that you can get past this and it's not strictly necessary in order to run ProcessWire in the cloud, but it would simplify things quite a bit. That being said, I definitely get what you mean by this being the more complex part ? Also, just to be clear, I think that the database abstraction is a great addition!1 point
-
This is something where PW is a little... special. The problem is that it decides wheter a page is viewable or not from the existance of /site/templates/yourtemplate. That means you don't have those files under control of your module. Copying the file on install is not ideal as well, because you end up getting a static copy that will not update on updates. You could of course copy your files also on every update, but that approach has 2 other problems: Development gets complicated because you need to copy back and forth your files while testing them. And second you might modify the template file in /site/templates because you (or someone else) thinks that this is the correct file and on the next update you lose your changes. Or you have the file under control of git and you get conflicts there... To solve all that problems I have introduced the includeViews() method in RockMigrations: https://github.com/BernhardBaumrock/RockMigrations/blob/636cf1eca8f8f54683551ddea08ebc576c160124/RockMigrations.module.php#L305-L339 It will create a file in /site/templates/foo.php and you can happily code in /site/modules/YourModule/views/foo.php <?php namespace ProcessWire; // DONT CHANGE THIS FILE // it is created automatically via RockMigrations include($config->paths->root.'site/modules/YourModule/views/foo.php');1 point
-
Hi guys, that was a few days of fun for me. A good learning experience. I have done some experimental things (for me "experimental) ? The result: https://github.com/eversthomas/pw-maturana I have sass a small blog metainformation in header a responsive menu with hamburger my cookie consent a card component (repeater field) My experimental website: https://pwblog.end-linkage.de Greetz from germany Tom. PS: Everything is done with direct output strategy with includes. Actually i have to learn the delayed output strategy.1 point
-
Hi Jonathan, thank you for your answer. That solved the problem! The code looks now like this: echo $images_posts->renderPager(array( 'nextItemLabel' => "Vorwärts", 'previousItemLabel' => "Zurück", 'listMarkup' => "<nav aria-label='Page navigation'><ul class='MarkupPagerNav pagination'>{out}</ul></nav>", 'itemMarkup' => "<li class='{class} page-item'>{out}</li>", 'linkMarkup' => "<a class='page-link' href='{url}'>{out}</a>", 'currentLinkMarkup' => "<a class='page-link' href='{url}'>{out}</a>" ));1 point