Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 09/14/2024 in all areas

  1. FontAwesome Upgrade ProcessWire's backend with the latest Font Awesome free icons (solid + brands). Install Link: https://github.com/PWaddict/FontAwesome Copy all files included in this module into new directory /site/modules/FontAwesome/. In the ProcessWire admin, go to Modules > Refresh. Click install for the Font Awesome module. IMPORTANT: The module has a duplicated folder of the core's InputfieldIcon module where only 2 files (icons.inc, InputfieldIcon.js) have been modified so you must select the InputfieldIcon version from Font Awesome module to load. To do that go to InputfieldIcon module screen by using search or refreshing modules (you will get the duplicated notification) and on the section "Module file to use" select the proper version and click on Submit button.
    3 points
  2. PageListCustomSort Github: https://github.com/eprcstudio/PageListCustomSort Modules directory: https://processwire.com/modules/page-list-custom-sort/ This module enables the use of a custom sort setting for children, using multiple properties. About This module is similar to ProcessPageListMultipleSorting by David Karich but is closer to what could (should?) be in the core as it adds the custom sort setting in both the template’s “Family” tab and in the page’s “Children” tab (when applicable). Usage Once a custom sort is set, it is applied in the page list but also when calling $page->children() or $page->siblings(). You can also apply the custom sort when calling $page->find("sort=_custom") or $pages->find("parent_id|has_parent=$id,sort=_custom"). Unfortunately this won’t work the same way sort=sort does if you only specify the template in your selector.
    2 points
  3. <?php // site/init.php namespace ProcessWire; if (!defined("PROCESSWIRE")) die(); $classLoader = $wire->classLoader; $classLoader->addSuffix("Service", __DIR__ . '/services'); $classLoader->addSuffix("Form", __DIR__ . '/forms'); $classLoader->addNamespace("ProcessWire", __DIR__ . '/utils');
    2 points
  4. Today while working on RockCalendar I had the need to change the database schema of my daterange fieldtime to add support for recurring events. I didn't know how to do it, so I had to do some research and that took quite some time. Here's the solution that I found in FieldtypeComments.module. When developing the fieldtype you can add a database schema like this and PW will take care of creating the table and columns for you: public function getDatabaseSchema(Field $field) { $schema = parent::getDatabaseSchema($field); $schema['data'] = 'timestamp NOT NULL'; // the from timestamp $schema['foo'] = 'timestamp NOT NULL'; return $schema; } This is quite easy, but I wanted to add another column and tried this: public function getDatabaseSchema(Field $field) { $schema = parent::getDatabaseSchema($field); $schema['data'] = 'timestamp NOT NULL'; // the from timestamp $schema['foo'] = 'timestamp NOT NULL'; $schema['bar'] = 'timestamp NOT NULL'; return $schema; } No luck. You will get an error that column "bar" does not exist. Ok, so we have to modify the table somehow... But we also have to make sure that this is only done once. How to we do that? The solution is to save the schema version to the field and use that to compare versions and conditionally update the schema: public function getDatabaseSchema(Field $field) { $schema = parent::getDatabaseSchema($field); $schema['data'] = 'timestamp NOT NULL'; // the from timestamp $schema['foo'] = 'timestamp NOT NULL'; $schema['bar'] = 'timestamp NOT NULL'; $schemaVersion = (int) $field->get('schemaVersion'); $updateSchema = true; $table = $field->getTable(); $database = wire()->database; if ($schemaVersion < 1 && $updateSchema) { try { if (!$database->columnExists($table, 'bar')) { $database->query("ALTER TABLE `$table` ADD bar " . $schema['bar']); } $field->set('schemaVersion', 1); $field->save(); } catch (\Throwable $th) { $this->error($th->getMessage()); $updateSchema = false; } } return $schema; } And maybe at a later point you want to add another column "baz": public function getDatabaseSchema(Field $field) { $schema = parent::getDatabaseSchema($field); $schema['data'] = 'timestamp NOT NULL'; // the from timestamp $schema['foo'] = 'timestamp NOT NULL'; $schema['bar'] = 'timestamp NOT NULL'; $schema['baz'] = 'timestamp NOT NULL'; $schemaVersion = (int) $field->get('schemaVersion'); $updateSchema = true; $table = $field->getTable(); $database = wire()->database; if ($schemaVersion < 1 && $updateSchema) { try { if (!$database->columnExists($table, 'bar')) { $database->query("ALTER TABLE `$table` ADD bar " . $schema['bar']); } $field->set('schemaVersion', 1); $field->save(); } catch (\Throwable $th) { $this->error($th->getMessage()); $updateSchema = false; } } if ($schemaVersion < 2 && $updateSchema) { try { if (!$database->columnExists($table, 'baz')) { $database->query("ALTER TABLE `$table` ADD baz " . $schema['baz']); } $field->set('schemaVersion', 2); $field->save(); } catch (\Throwable $th) { $this->error($th->getMessage()); $updateSchema = false; } } return $schema; } 😎
    1 point
  5. Hi, I tried the same a while ago and it appears PW is forcing custom classes to be in site/classes directory. The code seems to be in ProcessWire.php: $cfg['paths']->data('classes', $cfg['paths']->site . "classes/"); Maybe you can overwrite this in your own config.php? Not sure if this is a good idea. ^^ But these classes dependencies can be in any package in site/templates/YourPackage (parent/abstract classes, Traits...). On my side the code I put in page classes is only related to the model part (getting/setting data), I don't use them to do rendering or controller stuff. The main part of the code is in my packages in site/templates. So I'm not really annoyed by the fact they have to be in the same directory, but I admit it would be better to put them in their related package.
    1 point
  6. @FireWire Apologies, I still don't completely follow what you are trying to do in the code above, but wanted to comment about a couple of things. This is because at this point in your code, you've only dealt with the Field object (or in this case a CustomField object), and no $page has been involved. Since values are stored with pages, all you've got here is a set of blank Inputfields, which probably isn't useful for anything. In this case you are iterating that Field object, which I don't think has any value. What you want to iterate is the value from the page. So if your CustomField is named "custom_field": foreach($page->custom_field as $property => $value) { echo "<li>$property: $value</li>"; } Are you setting an 'addClass' property to your Inputfield definitions in your /site/templates/custom-fields/field_name.php file? And you want to use the value of that property somehow on the front-end of your site? That property is for adding a class to the Inputfield in the admin, but if you want to have access to it on the front-end of your site, I suppose you could do this: $defs = $fields->get('custom_field')->defs(); /** @var CustomFieldDefs $defs */ foreach($page->custom_field as $property => $value) { $f = $defs->getPropertyInputfield($property); echo "<li>addClass for $property is: $f->addClass</li>"; } But you might also just consider going straight to the source, by including your field definitions php file directly: $defs = include('./custom-fields/field_name.php'); /** @var array $defs */ foreach($page->custom_field as $property => $value) { $def = $defs[$property]; if(isset($def['addClass'])) { echo "<li>addClass for $property is: $def[addClass]</li>"; } } Note this will only work if you don't have your properties nested within fieldsets. If they are nested in fieldsets, you can still do it, but you'd just need to account for that in the code. You wouldn't need to account for it in the example above this one.
    1 point
  7. It definitely is useful. 😊 Thanks @virtualgadjo
    1 point
  8. Hi @TomPich i've often to do this kind of thing, typical example is a password reset link, in this case i usually create a personal db table with, worse than the case you describe, this page is limited to be viewed only one time... - auto increment id of course - user email - uid - creation date - used default 0 - used date (not necessary but i like to keep track of what happens) the page contains obviously a field to get the user email as soon as it is displayed - i check if the uid is in the db,, if not > die() and if the used field still contains 0 - the used field is set to one and it will not usable again (you may not need this limitation) the uid if of course a long (64char min) string easy to handle with pw url segments and a regex to define what you accept i've done this a lot, be it in pw but also in the old modx evo i used a long time ago as in all my framework based tools, pw just, as usual, makes it even easier to set up 🙂 of course, this is fully adaptable for any other need than password reset adding a user id field if you want to check the user email and password as well as what follows if the user is successfully logged in case it could be useful have a nice day
    1 point
  9. Thank you so much @Robin S. Your answer is more than I expected... That’s what I love about you guys, in this forum. I don’t get only the answer I was asking for... I get detailed help that anticipates my need!😊
    1 point
  10. Yes, you could do that. The fieldtype just needs an array of options returned from a hook to FieldtypeDynamicOptions::getSelectableOptions() and there are no constraints on how that array is generated. The fieldtype only stores the value, but if you needed to look up the label that goes with a value you could just run the same code that generates the options array and then get the label for any value. One way you might do this is via a method for a custom Page class that returns the selectable options - that way you don't need to repeat any code. So you would add a method like getDynamicOptions() to the Page class that the Dynamic Options field is used with. Your hook would then be: $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') { /* * Get an array of options as $value => $label from the custom Page class method * * If you have more than one Dynamic Options field on the page that you need * to distinguish between then you could pass the field name as an argument to the method * e.g. $page->getDynamicOptions('your_field_name') * */ $options = $page->getDynamicOptions(); // Set that options array as the event return $event->return = $options; } }); And to look up the label for the selected option in the template file: // Get the label for the selected option $options = $page->getDynamicOptions(); $label = $options[$page->your_field_name]; This assumes your field is for single options. If it's for multiple options then you would loop over the field value and look up each label from the $options array.
    1 point
  11. You are completely right. Since strftime() is no longer a thing in PHP> 8.1, ProcessWire no longer uses it to format it's dates. Quickly skipping through the code, you can find that Ryan introduced a replacement for strftime() which uses date() and then translates the language-dependent parts using the PW translation system. Here's the section in question: https://github.com/processwire/processwire/blob/3cc76cc886a49313b4bfb9a1a904bd88d11b7cb7/wire/core/WireDateTime.php#L476 Remember, to get gettext-style translations working, you don't need any other modules activated than the LanguageSupport module itself. No need for PageNames and all the others. You can then just add a translation file for the WireDateTime class and translate the months, short months and days to German and you're done.
    1 point
  12. 1 point
  13. Found this recently. Thought I would share. It provides a GUI in VSCode for DDEV. https://marketplace.visualstudio.com/items?itemName=biati.ddev-manager
    1 point
  14. Just wanted to share what I've just found: https://get-deck.com/ It looks like a nice Docker environment with a simple GUI and lots of options. I'll try it for the next projects.
    1 point
  15. Not a question, but just something I discovered that I wanted to share on the forum since I haven't seen it discussed anywhere. If you are familiar with the "autojoin" option on individual ProcessWire fields, enabling this feature means that every time a page with that field on it is loaded into memory, the field will be included with it immediately. (Normally just the page's name and meta data is included, and getting a specific field from the page requires a separate trip to the database. This is to conserve memory) Normally this is fine and it keeps things simple, but occasionally you may be loading a lot of data in a consistent fashion (for, example, to populate a table) and know exactly which fields you need. With the autojoin option on fields, you would have to enable autojoin for all pages at all times, which you probably don't want. With the following code, you can do a $pages->find() and specify exactly which fields you want to autojoin with it: $pages->find("template=whatever", ['loadOptions' => ['joinFields' => ['filed1','field2','field3']]] ); I tested out in debug mode on one of my projects, and it seemed to significantly reduce the number of SQL queries required for an html data table I was building. Hope that helps someone!
    1 point
×
×
  • Create New...