Jump to content

Leaderboard

Popular Content

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

  1. @ryanThis is a bit off topic, but I would also support version control for fields/templates as something to maybe concentrate on for this year. There is a lively discussion going on: And Bernhard has already shown an awesome proof of concept in his video:
    3 points
  2. 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.
    2 points
  3. I am more excited about the recorder than about YAML. And I see your point. When using a PHP array for the migrate() method, you can do things that you can't do in YAML. But on the other hand, for recording changes locally and than migrating them to staging/live, YAML would be sufficient. Your use case, where you setup fields and templates for a RockMails module with RockMigrations is different. When installing that module, it needs to check whether it is being installed on a multilang site or not. But when recording and migrating changes, we already know the context for the migration since it has been recorded through YAML. My conclusion would be to store the recorded data in YAML or JSON. For other use cases, like you described, we can still use a PHP array.
    2 points
  4. Thanks, should be fixed in v0.1.2.
    1 point
  5. YAML is easier to read and write as PHP and less error prone (Yeah I know, we are devs, but there might be unexperienced devs / users that try to accomplish something fast). Indeed I agree, that PHP would offer more possibilities, but I think most times YAML or another configuration markup are enough. Every developer ist different here. Some might prefer writing directly to the file to change things or add new fields/templates, others prefer to do it via the admin. Update: I would like to shift this conversation to a newly created thread, because we are getting off-topic of sharing out setup/tools.
    1 point
  6. Hi Robin, It's only a minor thing, but I just noticed this when clicking the show when using InputfieldSelector. Note the position of the calendar icon on top of the page numbers. matches 1716 pages (show)
    1 point
  7. Thanks for the explanation, Jan. And, yes, that makes sense as to the difference between roles and permissions. I have created the permission tasks-list-access and assigned it to the role content-manager. I have then added 'permission' => 'tasks-list-access' to my Process class but it hasn't made a difference. Am I missing something? I refreshed the module and it worked. Hoorah! Thanks very much for your help. ?
    1 point
  8. The Role comes into it because it’s what connects the Permission to a User ? A User has one or more Roles, a Role has one or more Permissions which it grants to those Users. So if you create a Permission for your Process and give it to only one Role, “content-manager”, only Users with that Role will be able to access the Process (apart from superusers who can access anything, I guess). I don’t know, it’s difficult to come up with a succinct example, but basically you can use roles to group users by their jobs and permissions to define what activities those jobs entail. Then if you need someone to do two jobs, you just give them two roles. If a role needs to do more things, you give the role more permissions (instead of going through the users separately).
    1 point
  9. Well, yeah, but you can’t give the Process to a Role. You can give it to a Permission and add that Permission to the Role content-manager.
    1 point
  10. Is this a Permission or a Role? You have to put a Permission.
    1 point
  11. Hi @Robin Wow, what a seriously awesome reply thanks so much. I'm going to be implementing this today. Thank you!!
    1 point
  12. The trick is to put all the affected images into a new Pageimages object before you start setting the field values, so you can later get each image from there even after it has been removed from a field value. A proof of concept... Image fields in Page Edit: Tempate file markup: <script src="/site/templates/js/jquery-ui.min.js"></script> <script> $(document).ready(function() { var $sortable_images = $('.sortable-images'); $sortable_images.sortable({ // When any image has been moved... update: function(event, ui) { // Add the image basenames to an array in the new order var value = []; $sortable_images.find('img').each(function() { value.push($(this).data('filename')); }); // Join to a comma separate string and set as the form field value $('#images').val(value.join(',')); } }); }); </script> <div class="sortable-images"> <img src="<?= $page->image_1->size(150,150)->url ?>" data-filename="<?= $page->image_1->basename ?>" alt=""> <img src="<?= $page->image_2->size(150,150)->url ?>" data-filename="<?= $page->image_2->basename ?>" alt=""> <img src="<?= $page->image_3->size(150,150)->url ?>" data-filename="<?= $page->image_3->basename ?>" alt=""> </div> <form id="image-order" action="./" method="post"> <textarea name="images" id="images"></textarea> <button>Submit</button> </form> Template file PHP: // Look for the comma separated value in POST $images_value = $input->post('images'); // If the value exists then the form was submitted if($images_value) { // Explode the comma separated value to an array of image basenames $image_names = explode(',', $images_value); // Create a Pageimages object using the individual image basenames $all_images = new Pageimages($page); foreach($image_names as $image_name) { $all_images->add($image_name); } // Turn off output formatting because we are about to set field values $page->of(false); // Loop over the image basenames foreach($image_names as $index => $image_name) { // Get the Pageimage from $all_images $pageimage = $all_images->get($image_name); // Create a new empty Pageimages object $pageimages = new Pageimages($page); // Add the Pageimage $pageimages->add($pageimage); // Determine the field name that will be updated $image_field_name = 'image_' . ($index + 1); // Set the field value $page->$image_field_name = $pageimages; } // Save the page $page->save(); // Redirect back to the page (Post/Redirect/Get pattern) $session->redirect($page->url); }
    1 point
  13. Well, editing YAML is easier, that's what YAML is about, after all. However, most PHP developers are probably more familiar with the PHP syntax than the YAML syntax and since the recorder would generate the text file, a developer would just read the file and not edit it anyway (at least that would be the point, wouldn't it?) So yeah, PHP looks a lot more feasible than YAML.
    1 point
  14. A bit of background: rendering partials (using the partial name as method) is a relatively new addition, while including partials with chained syntax (<?php include $partials->common->summary ?>) has been an option since the very beginning. I don't have a strong opinion about what should be the default behaviour, but the main reason why I likely won't change this is that it would potentially break a lot of sites ? At this point I would recommend against partial names with dots or dashes. Personally I tend to use snake_case for naming, as I find that the most sensible option: dashes or dots won't work, and camelCase and PascalCase are prone to errors (although it's customary to use them in class names). It is actually possible to access properties with dashes as well, but it's not exactly pretty: <?= $partials->common->{'summary-block'}(['heading' => 'Hi!']) ?>. Extending $partials->get() with support for paths does seem like a good idea, though, so I'll add this to my todo list ?
    1 point
  15. Side note @ryan it would be nice if you could add relevant keywords to the title of new news or blog posts. This makes it easier to find information when you are searching for it weeks or months later ("weekly update 14.1." is not nearly as helpful as "weekly update find raw parents, sanitizer float" in a search result) +1 for better version control support. I've not built RockMigrations just for fun ?
    1 point
  16. Sorry I missed your second post... Actually something similar would already be possible using RockMigrations. At least for basic setups. I'm not sure how that can work for more complex setups though. I'll try to explain that by an example: Let's say we created a new blog module. We need a blog page (parent) and several blog-items (children): - home '- blog |- blog entry 1 |- blog entry 2 ... This setup could easily be built into a module using rockmigrations: <?php namespace ProcessWire; class MyBlog extends WireData implements Module { public static function getModuleInfo() { return [ 'title' => 'MyBlog', 'version' => '0.0.1', 'summary' => 'blog module using rockmgirations', 'autoload' => true, 'singular' => true, 'icon' => 'smile-o', 'requires' => [], 'installs' => [], ]; } public function init() { $this->rm()->fireOnRefresh($this, "migrate"); } public function migrate() { $this->rm()->migrate([ 'fiels' => [...], 'templates' => [ 'blog_parent' => [...], 'blog_item' => [...], ], ]); $this->rm()->setParentChild('blog_parent', 'blog_item'); // --> this sets the family settings for both the parent and the child template - how long does that take by hand? ;) It means that all pages having the "blog_parent" template will create a "blog_item" page automatically when you click on "add new page". Basically the stuff that you set on the family tab of the template. } /** * @return RockMigrations */ public function rm() { return $this->wire->modules->get('RockMigrations'); } } That means I'm literally defining my config in the module code. We could also have the config read from a config.yaml - that would really be the same (just less powerful IMHO)! The problem arises when you want to make that config customizable. For example you want a page reference field to select the author for every blog post. Building that into the blog module would probably not be a good idea because not every site might need such a field. What I do in such situations is this: I make the migrate() method hookable and create one module that handles all the project-specific stuff: <?php namespace ProcessWire; class MyProject extends WireData implements Module { public static function getModuleInfo() { return [ 'title' => 'MyProject', 'version' => '0.0.1', 'summary' => 'module that handles site specific stuff', 'autoload' => true, 'singular' => true, 'icon' => 'smile-o', 'requires' => [], 'installs' => [], ]; } public function init() { $this->addHookAfter("MyBlog::migrate", $this, "migrate"); } public function migrate(HookEvent $event) { $this->rm()->createField("author", "page", [ 'label' => 'Select the author', ... ]); $this->rm()->addFieldToTemplate("author", "blog_item", "title"); } /** * @return RockMigrations */ public function rm() { return $this->wire->modules->get('RockMigrations'); } } That means you can have your blog module that you can reuse from project to project (and improve it and just pull changes if you need to) and you can still customize it the ProcessWire way (which we all love I guess). BUT Now we got a new field on the "blog_item", the "author" field. So the config.yaml of the blog module would change, wouldn't it? I'm not sure how CraftCMS handles such situations? And that's one of the reasons why I think that efforts like this are going in a wrong direction. It sounds intriguing for sure to have something like a "migrations recorder". I'm working or at least thinking about that since 2016. But I simply can't imagine a way that could reliably work in all situations. RockMigrations does. And it does it really well. And it does it for almost 3 years now and has evolved a lot. It's still not perfect for sure. But I don't think that This feels wrong. I'dont know how to explain. I think you have a good understanding of composer and such things. Likely a much better understanding than I have. So if it is true what you are saying, I must be doing a lot wrong in my daily work or at least I must be understanding a lot wrong... Because a lot of my workflows do feel very version control friendly. And I've lately started working in a company in vienna where we work on ProcessWire projects with fully automated workflows. We work in a team. We work on different local machines. We deploy to staging and if everything works (which has been the case 100% so far), we deploy to production with a single click. But maybe I'll change my opinion some day and look back and laugh. Maybe I should just try CraftCMS. Maybe many other fancy new tools. At my company they also work (or worked) with another CMS. They said they liked to be able to define fields and templates in code. They said that was one of the (few) things they didn't like about ProcessWire, because they love professional workflows and automated deployments... But they also admitted, that it was somewhat painful to define fields and templates in the other CMS. They said you have to add pieces of config in that file, then change another piece in another file. And end up changing many files for simple changes. Now they like RockMigrations ? And such comments make me think I am on a right track and we as ProcessWire enthusiasts are not that far away from what you seem to be missing. @MoritzLost have you ever heard someone saying "ProcessWire is great for small websites, but not for larger, more complex ones"? We all know how wrong that is, don't we? That's the way I feel when people here on the forum are talking about missing migration / version control features... PS: I tried to keep this post short and not so emotional. I think I failed, sorry ?
    1 point
  17. Well in this scenario I was talking about a particular project that is more "app like". But the rest of sites I manage, which might have specific features regarding template/fields, different templates that are for one specific website/design, I handle them the same way, repo and deployment through pipelines. I'd love to hear about what other things you've tried if you'd be keen on sharing. I've seen some folks move to Statamic/Kirby for this purpose. Thinking about this I've thought a "migration recorder" built on field save hooks, would be neat. Like, you're doing your work on PW thinking about the awesome features you wanna build, building repeaters/matrix, changing file widths, show conditions, all those things we love. Then you go into Setup > Migrations and you find all the work you just did on your repeater field recorded. Just a thought for one part of the whole problem. EDIT: I just read about the YAML thing Craft does, thanks for sharing! ?
    1 point
  18. Hi. I also needed a solution for Images Pagination and came up with this solution. It only works on PW 3 with the new PaginatedArray class. My Situation: I have a image field with about 150 images. I want to output these Images with a PagerNav. The same i use on $pages->find(). This is the function wich I wrote to get this working for PageImages. /** * Renders a pagination based on files using the PaginatedArray Class. Overrides the input parameter $files with the sliced result * and returns the rendered pagination. * @param $files ... the full Pageimages WireArray * @param int $perPage ... items per Page * @param $pagerOptions ... standard Pager Options as used in MarkupPagerNav.module * @return string ... rendered pagination */ public function renderFilePagination(&$files,$perPage=10,$pagerOptions) { $total = count($files); if($total <= $perPage) return ''; $pagerArray = new PaginatedArray(); $pagerArray->setLimit($perPage); $pagerArray->setTotal($total); $pagerArray->setStart(($this->input->pageNum - 1) * $perPage); $pagerArray->import($files->slice($pagerArray->getStart(), $pagerArray->getLimit())); $files = $pagerArray; // overwrite $files $ret = '<div class="paginationInfo uk-text-center uk-text-small uk-margin-top">'.$pagerArray->getPaginationString().'</div>'; $ret .= $this->modules->MarkupPagerNav->render($pagerArray,$pagerOptions); return $ret; } This function has to be available in your template files. Perhaps you need to remove the public. I am using it in in a custom module. Now in your template file you have your images field for ex.: $page->images (multiple Images). You can call the function like this: $pagination = $modules->KaTemplateHelper->renderFilePagination($page->images,$perPage=40,array( 'listMarkup' => '<ul class="uk-pagination">{out}</ul>', 'itemMarkup' => "\n\t<li class=\"{class}\">{out}</li>", 'linkMarkup' => '<a href="{url}"><span>{out}</span></a>', 'currentLinkMarkup' => '<span>{out}</span>', 'currentItemClass' => 'uk-active', 'nextItemLabel' => '»', 'previousItemLabel' => '«' )); The third array parameter is completely optional. I only use it for changing the standard page nav markup. If you use the standard markup then call: $pagination = $modules->KaTemplateHelper->renderFilePagination($page->images,40); ----------------------- After the call: $page->images only contains the subset wich will be display on this page. $pagination contains the rendered HTML Markup for $pagination. Perhaps this helps someone. I know this is not fully flexible implemented, but this is only a snipped for me that I change as i need it.
    1 point
×
×
  • Create New...