Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 01/20/2022 in all areas

  1. The problem: Synchronizing fields and/or templates made on the dev server with the live server is cumbersome. At the same time, there is no version control of fields and templates, which some folks (including myself) see as a disadvantage of ProcessWire. A way to have version control to track changes and replicate automatically would be desirable. There is the template and fields export feature in ProcessWire which has said for ages that this is only a beta version, although I have used it many times without any problems. However, even with this method, it is very cumbersome to reconcile changes between dev and live. You have to remember which fields / templates you created and select them, then copy and paste them on the dev server. This is a manual, cumbersome and time consuming process. Existing solutions: For this reason, several solutions have been developed such as: Migrations by @LostKobrakai https://processwire.com/talk/topic/14603-rocksvn-brings-version-control-to-your-fields-templates/ ProcessWires Template's and field's export function https://processwire.com/modules/rock-migrations/ https://processwire.com/talk/topic/25307-oh-no-not-another-migration-module/ https://processwire.com/modules/auto-export-templates-and-fields/ Other systems like Laravel, Craft, Kirby and Statamic use configuration files (migrations, YAML) to manage fields / templates, which allow to create a state of fields / templates. Since the configuration is done in a file, you can of course manage it with git (or other vcs). By configuring in a file, it is also possible to automatically execute these migrations during a git push through different deploy pipelines like github actions, buddy, bitbucket pipelines and thus you have the desired state on the desired server. Where to go from here? In another post @bernhard showcased a prototype, that uses a YAML-file to create and manage fields / templates in ProcessWire. At the same time he showcased a YAML recorder which writes all changes that are made to templates and fields into a YAML file, which looks very promising. I think a combination of a recorder and a YAML config file would be a optimal solution, at least for me. What format to use for such a configuration file was and has also to be discussed: Update 30th September 2022: Until we might have a native method for migrations, I encourage you to checkout the great RockMigrations module. With the module you can have one or multiple migration files, that handle all the stuff mentioned above, like adding fields, adding templates, creating pages with content and setting roles. As the migrations are file-based they are also version-controllable. This makes it easy to work on a feature in a different branch which requires to have other fields/template than in the main branch. Now you can switch between branches and always have the required fields and templates. This is a huge time and workflow improvement. @bernhard steadily improves his module, and me and other contributors try to enhance it, or give feedback.
    7 points
  2. FYI: " Google Analytics Now Illegal in Austria; Other EU Member States Expected to Follow The Austrian Data Protection Authority ("Datenschutzbehörde" or "DSB" or "DPA") has ruled that Austrian website providers using Google Analytics are in violation of the GDPR. ... ...all Google Analytics data can be imported into Matomo so no historical data is lost. " you can read more: https://matomo.org/blog/2022/01/google-analytics-gdpr-violation/?mtm_campaign=newsletter_2022_01_21
    3 points
  3. @guy You could try this: if($this->wire()->process == 'ProcessPageEdit') { // save from page editor } If you want to capture other types of page editors, like ListerPro, User Profile, etc. you could do this: if(wireInstanceOf($this->wire()->process, 'WirePageEditor')) { // save from any page editing process }
    3 points
  4. Thank you for summing this topic up in a new thread. I had the same intention but couldn't spare the time. I am all for version control of fields and templates. @bernhard's RockMigration Module already does a great job here. And since he introduced the prototype recorder I am very excited that we will soon have something to work with and build upon. This should really be part of the PW core or available as optional core module. Would be great if @ryan put this on the roadmap for 2022.
    3 points
  5. There are also some other alternatives besides matomo with plausible analytics or fathom analytics. I personally like those because they generally also do less. Most people don't actually need all the fancy advanced features anyways.
    2 points
  6. Hi, I upgraded 100+ sites to the latest master on Friday, and we've gotten the following error email notification from a few of them over the weekend: Umm… Error: Exception: Unable to obtain lock for session (retry in 30s) (in processwire/wire3/modules/Session/SessionHandlerDB/SessionHandlerDB.module line 96) User: ?, Version: 3.0.184 This is a new error, added in the latest master release: https://github.com/processwire/processwire/commit/7a2ff6c15dde8f6768676181bfbeeaefe4761b0b#diff-4c158c18e5f331d4e9ff8b27eff8ae2c4cd34d16f6d0f2b427aa36791637c64f The session lock time is set to 50 seconds, I think this is the default, so I suspect the issue is on our end with our databases/server(s). I'm going to investigate further and try and figure out the issue and will update here if/when I do. If anyone else has come across this or has any more info, please let me know! Cheers, Chris
    1 point
  7. @Ivan Gretsky Have you seen this config options? https://wireframe-framework.com/docs/configuration-settings/ Probably you could change partials path to 'templates' folder, than you will be able to use components views as partials.
    1 point
  8. Hi @Ivan Gretsky Probably you can override render method of Type Component so it will render some partial. <?php namespace Wireframe\Blocks; use ProcessWire\Wireframe; class BlockTypeBlogTitle extends Block { protected function getDefaultViewData(): array { return [ 'title' => $this->item->get('title') ]; } public function ___render(): string { return Wireframe::partial('somepartial', $this->getDefaultViewData()); } } In this way you will be able to use same partial output both for components and partials.
    1 point
  9. Migration 21-11 (add foo field) <?php $rm->migrate([ 'fields' => [ 'foo' => [...], ], 'templates' => [ 'xyz' => [ 'fields' => ['foo'], ], ], ]); Migration 21-12 (add bar field) <?php $rm->migrate([ 'fields' => [ 'foo' => [...], 'bar' => [...], ], 'templates' => [ 'xyz' => [ 'fields' => ['foo', 'bar'], ], ], ]); Migration 22-01 (add baz field) <?php $rm->migrate([ 'fields' => [ 'foo' => [...], 'bar' => [...], 'baz' => [...], ], 'templates' => [ 'xyz' => [ 'fields' => ['foo', 'bar', 'baz'], ], ], ]); RockMigrations works in a way that no matter how often you run the migration the config will be applied and the system will result in the same config each time. I know this is a totally different concept than you are using in your migrations module but it has turned out to be extremely easy to use and it works well. In the example above it does not matter if you jump from 21-11 to 21-12 and then to 22-01 or if you go directly from 21-11 to 22-01. Or you could even start with 22-01 and nothing else before. That's easy as long as you add things to the system. Removing things is a little different, but it's also easy: 22-02 (remove baz field) <?php $rm->removeField('baz'); $rm->migrate([ 'fields' => [ 'foo' => [...], 'bar' => [...], ], 'templates' => [ 'xyz' => [ 'fields' => ['foo', 'bar'], ], ], ]); Reverting things it a totally different topic! 22-01 --> 21-11 would not really be possible using RockMigrations. Though you can think of 22-02 as a "revert migration" that does exactly what a reversion would do. But if one does not like that concept they could also use RockMigrations in a way your module works. In my experience this makes migrations just a lot more complex while adding things into a php array is cake. I've never had any problems over the last few years with my concept ?
    1 point
  10. I would love to see that todo list) It might be a good way to create a github issue for each item and group them with projects or project boards. Should I create an issue based on this topic?
    1 point
  11. 1 point
  12. I just re-read the previous post. It is what i did ask for not knowing we already have it) Could you please consider also allowing to put color code in that item headers string, so we can also define a per-type color? That would make different types really stand out)
    1 point
  13. Hi @sodesign, Haven't found a workaround, but can confirm @Clarity's message above is correct. For us it happens on sites which are querying external APIs every so often and updating the site data based on the results. Cheers, Chris
    1 point
  14. Note that legislation may differ from country to country. For an example here in Finland one apparently still has to document the cookies, even though "necessary" ones don't require opt-in (or opt-out). IANAL etc. but that seems to be the common consensus anyway ? Here's a rough translation of the descriptions we've been using: wires ProcessWire session identifier. First-party session cookie, expires when the browser is closed. wires_challenge ProcessWire session cookie used to verify the validity of a session. First-party persistent cookie, expires after 30 days.
    1 point
  15. Playing around with this, I have tested repeaters and there is some code to get titles in addition to the index from FieldtypeOptions (Not sure if you like this). Just sharing what I have. $this->addHook("Pages::findObject", function($event) { $event->return = $this->pages->findArray($event->arguments(0), $event->arguments(1), $event->arguments(2), true); }); $this->addHook("Pages::findArray", function($event) { $selector = $event->arguments(0); $fields = $event->arguments(1); $fields_pages = $event->arguments(2) ?: []; $type = $event->arguments(3) ? \PDO::FETCH_OBJ : \PDO::FETCH_ASSOC; // build sql string $sql = "SELECT\n p."; // add fields of pages table $fields_pages[] = 'id'; // make sure we return the page id $fields_pages = array_unique($fields_pages); $sql .= implode(",\n p.", $fields_pages); foreach ($fields as $f) { $field = $this->fields->get($f); if (!$field) continue; $fieldtype = $field->type; $f = strtolower($f); // fielddata is always stored in the "data" column of the field's table // multilang fields have several data columns identified by the language id // we use a variable to query the current user's language, eg data1234 $data = "data"; switch (true) { // if it is a multilang field we append the language id to query the correct column case $fieldtype instanceof FieldtypeTextLanguage: case $fieldtype instanceof FieldtypeTextareaLanguage: if ($this->user->language->name != 'default') $data .= $this->user->language->id; // no break here intended! // build sql query case $fieldtype instanceof FieldtypeText: case $fieldtype instanceof FieldtypeCheckbox: $sql .= ",\n (SELECT $data FROM field_$f WHERE pages_id = p.id) AS $f"; break; case $fieldtype instanceof FieldtypePage: case $fieldtype instanceof FieldtypeRepeater: $sql .= ",\n (SELECT GROUP_CONCAT($data SEPARATOR ',') FROM field_$f WHERE pages_id = p.id) AS $f"; break; case $fieldtype instanceof FieldtypeFile: $sql .= ",\n (SELECT $data FROM field_$f WHERE pages_id = p.id) AS $f"; //$sql .= ",\n (SELECT description FROM field_$f WHERE pages_id = p.id) AS ".$f."_desc"; break; case $fieldtype instanceof FieldtypeOptions: $sql .= ",\n (SELECT $data FROM field_$f WHERE pages_id = p.id) AS $f"; $sql .= ",\n (SELECT title FROM fieldtype_options WHERE fields_id=(SELECT id FROM fields WHERE name = '$f') AND option_id=$f) AS " . $f . "_title"; break; default: $sql .= ",\n '$fieldtype not supported' AS $f"; } } $pages = $this->pages->findIDs($selector); if (count($pages) == 0) { $event->return = []; } else { $sql .= "\nFROM\n pages AS p"; $sql .= "\nWHERE\n p.id IN (" . implode(",", $pages) . ")"; //echo '<pre>' . $sql . '</pre>'; $results = $this->database->query($sql); $event->return = $results->fetchAll($type); } }); Testing with: foreach ($pages->findArray("template=families, sort=title, limit=5000", array('title'), array()) as $p) { foreach ($pages->findArray("parent=" . $p['id'] . ",sort=title, limit=5000", array('title'), array()) as $m) { foreach ($pages->findArray("parent=" . $m['id'] . ",sort=title, limit=5000", array('title', 'sku12', 'Sound_Sample'), array()) as $s) { echo ($p['title'] . ' ' . $m['title'] . ' ' . $s['title'] . '<br>'); $repeater = $s['sound_sample']; if ($repeater) { foreach ($pages->findArray('id=' . str_replace(',', '|', $repeater) . ",limit=5000", array('name', 'Sound_Type_ss', 'Files_ss'), array()) as $r) { echo '<h5>' . $r['files_ss'] . '</h5>'; echo '<h5>' . $r['sound_type_ss_title'] . '</h5>'; } } } } }
    1 point
  16. Thanks marcus and Martijn. I found the saveModuleConfigData() method last night and ended up using: $this->modules->saveModuleConfigData($this, self::getDefaultData()); Works like a charm!
    1 point
  17. public static function getDefaultData() { return array( 'total' => 0, 'limit' => 10, 'anotherDefault' => 'blah blah', ); } public function ___install() { //do stuff here, etc., etc. //save default module configurations on install wire('modules')->saveModuleConfigData($this, self::getDefaultData()); }
    1 point
×
×
  • Create New...