Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by bernhard

  1. I've also had those problems, I know that it's not really straight forward and limiting sometimes... At the moment I have this in place and need to test it over the next weeks 🙂 $this->addHookBefore('ProcessPageList::execute', $this, 'redirectPageList'); /** * Redirect all PageList requests to Dashboard */ public function redirectPageList(HookEvent $event) { if($this->config->ajax) return; if($this->page->id > 3) return; $this->session->redirect($this->pages->get('name=ear')->url); } Edit: Just added the page id check, then all requests to "pages" will be redirected but one can show the pagelist by going to "pages > tree" 🙂 I try to answer that by asking you a question 🙂 I have several custom Process Modules. They are great, because I can control where they live (menu) and who can see them (access control). How would I display one of your - I say it again - really nice looking dashboard panels in one of my modules? I've just added a commit to my example module: https://github.com/BernhardBaumrock/InputfieldChartDemo/commit/3efa4bd8355bfe6e7499254cad58e70d3f283147 IMHO this is really close to what you built on your dashboard (at least as far as I understood it until now), but it uses PW core features and only a little extra markup: https://github.com/BernhardBaumrock/InputfieldChartDemo/blob/3efa4bd8355bfe6e7499254cad58e70d3f283147/ProcessInputfieldChartDemo.module.php#L139-L146 I agree that it is not the nicest thing to layout pages using InputfieldForm elements, but I think it would be the better way to push PW in that regard than creating custom solutions. We all know the benefits of using existing components: showIf would work out of the box collapsing works out of the box (ajax loading fields) development is the same for dashboard panels and regular inputfields panels can be used everywhere styling applies automatically (imagine a custom admin theme using your dashboard panel... To name just a few 🙂 What I mean is for example we could have something like InputfieldGrid that could work like this: $grid = $modules->get('InputfieldGrid'); $grid->addColumn([ 'class' => 'uk-width-1-4@m', 'children' => [ [ 'type' => 'markup', 'label' => 'one foo', 'value' => 'one bar', ],[ 'type' => 'markup', 'label' => 'one foo', 'value' => 'one bar', ], ], ]); $grid->addColumn([ 'class' => 'uk-width-3-4@m', 'children' => [ [ 'type' => 'markup', 'label' => 'two foo', 'value' => 'two bar', ],[ 'type' => 'markup', 'label' => 'two foo', 'value' => 'two bar', ], ], ]); $grid->render(); That would be really easy to build and could - same as everything else - also be used on page edit screens etc. Scenario from todays work: I'm building a custom CRM for myself where I manage invoices and documents. After import they get flagged as TODO. Then I see them on the Dashboard: When editing one of those pages I have basically the same Inputfield showing a list of all other todos:
  2. Hi @d'Hinnisdaël First of all congrats to this beautiful module. I have some suggestions and remarks: The panels do not have proper dependencies set. All panels are installable (and throw an exception, when installed): IMHO the Dashboard master module should be the only installable module. https://philippdaun.github.io/processwire-dashboard/#/configuration?id=dashboard-as-entry-point Any reason why you chose this version over a module setting (eg checkbox) that adds a hook? I was hoping that your way of doing it would solve the problem that when clicking "Save & Exit" one would be redirected to the dashboard. But still one gets to the page tree. This also happens when trashing a page. This is one thing annoying me for a long time, but I didn't try to find a solution for it yet. Maybe you can have a look, because imho when having a dashboard it's more likely that one wants to see the dashboard than the page tree 🙂 Edit: Just saw that changing the main admin page's process does at least help after trashing pages 🙂 I think I'll also redirect all user requests from the page tree to the dashboard... DashboardPanelChart uses jsdelivr CDN to load chart.js - this means that the panel will not work on offline applications (intranet). I think it would be better to ship chartjs with the module. This brings me to the next and more important point: Have you thought of making panels Inputfields? The last point needs some more words 🙂 I really wonder (not to say dislike) why you made the dasboard work on your own panel implementations rather than using regular PW Inputfields. Please don't take this as devaluation of your module, but after all it's just a ProcessModule like all the other admin pages (just really looking a lot better!). I've created a very simple Inputfield and posted a thread in the tutorials section: Take this screenshot of the Grid Dashboard demo: This is VERY similar to your Dashboard module - with the big difference that it is based on PW Inputfields that can be used everywhere in the PW ecosystem! Your panels can not. As I said your module does indeed look a lot better than a regular PW form. For example as far as I know grid spacing is not possible using InputfieldFieldset. Also the admin width settings are somewhat limited (see this old issue on github). But this is my point: Instead of creating a new module that handles things in its own ways it would be a lot better to improve or extend the PW internal tools. This means we could either create nicer CSS for PW Inputfields (here the InputfieldFieldset) or we could create an Inputfield that wraps other inputfields in a Uikit grid (as Uikit is already on board). This approach would also make it possible to use the "panels" that you create for your dashboard in other places like PW page edit screens or in other ProcessModules. I really like the look & feel of your panels, so it would be great to be able to use them all over the PW backend and not only in your module! Thx for creating and sharing this - I hope you get my point and I'm looking forward to hearing what you think about converting panels to Inputfields 🙂
  3. During testing of the https://processwire.com/talk/topic/22847-processwire-dashboard/ module I've created this simple demo inputfield to show how Inputfields can be used as presentation blocks in ProcessModules. The result is this little inputfield that shows the getting started chart of chartjs: https://www.chartjs.org/docs/latest/ https://github.com/BernhardBaumrock/InputfieldChartDemo It comes with 2 ProcessModules 1) One single chart inputfield 2) Grid Demo Creating an Inputfield is really nothing more than creating a module file having 3 methods: <?php namespace ProcessWire; class InputfieldChartDemo extends InputfieldMarkup { public static function getModuleInfo() { ... } public function ___render() { ... } public function ___processInput($input) { return false; } } Place this in /site/modules/YourModuleName, name the class exactly the same as your folder and you get an installable Inputfield that you can use everywhere in your admin and share across projects! Creating a ProcessModule is also very simple (see this old post): You do even need only 2 methods in this module! <?php namespace ProcessWire; class ProcessInputfieldChartDemo extends Process { public static function getModuleInfo() { ... } public function execute() { ... } } Using these internal tools it is really easy to create totally tailored user experiences for your clients in the PW backend!
  4. This sounds great, even though I don't use trello 🙂 A short screencast would be great to get a quick impression 🙂
  5. Don't know if anything changed since 2017 and just found this post by coincidence but wanted to show how this can be done easily now in 2020 😉 $wire->addHookAfter('ProcessPageEdit::getSubmitActions', function(HookEvent $event) { $actions = $event->return; $actions[] = [ 'value' => 'foo', 'icon' => 'check', 'label' => 'foo', ]; $event->return = $actions; });
  6. v1.0.10 is out: pwhookargument: Get hook argument pwhookobject: Get hook object
  7. Found the solution 🙂 /** * Modify submit button on doc-import pages */ $wire->addHookAfter('ProcessPageEdit::getSubmitActions', function(HookEvent $event) { $page = $this->pages->get($this->input->get('id')); if(!$page->id OR !$page->template == 'docimport') return; $event->return = []; }); $wire->addHookAfter("ProcessPageEdit::buildForm", function(HookEvent $event) { $form = $event->arguments(0); $page = $this->pages->get($this->input->get('id')); if(!$page->id OR !$page->template == 'docimport') return; $s = $form->getChildByName('submit_save'); $s->value = 'Import starten'; $s->icon = 'download'; }); 🙂 Does anybody know how I can remove the dropdown items from the page edit submit_save button? As I didn't find a solution quickly I wanted to replace the button entirely, but this results in the following markup: $wire->addHookAfter('ProcessPageEdit::buildForm', function(HookEvent $event) { $form = $event->arguments(0); /** @var InputfieldForm $form */ $s = $form->getChildByName('submit_save'); /** @var InputfieldSubmit $s */ $form->remove($s); }); This hook results in this output: I could hide this markup via CSS but I'd prefer a clean solution 🙂 Thx!
  8. I guess we have all been there... We need to store a price to a product. "Ok, easy, let's create a new field for that in the PW backend!" might be the first thought. But then the headache starts... What about TAX? What about NET and GROSS values? And what about rounding problems when not using the correct float or decimal values ( https://processwire.com/talk/topic/7542-development-fieldtypefloat-fieldtypedecimal/ )? Meet RockPrice - a brand new (and not well tested!) module to save you from those headaches and make the UI more compact and reactive (nobody wants to calc tax/net/gross manually!). If you discover any issues or have suggestions for improvement please let me know! 🙂 --- Download: https://github.com/BernhardBaumrock/RockPrice --- RockPrice Price Fieldtype + Inputfield for ProcessWire CMS Settings Usage Where tax stands for the tax rate in percent and vat for the actual tax value (eg Euros or Dollars). API $p1 = new RockPrice(1000, 20); $p2 = new RockPrice(1000, 0); $p1->equals($p2); // false
  9. Hi @Sevarf2 Maybe, but I don't use it any more on any installs. I'm using RockMigrations on all my sites and TracyDebugger makes it absolutely trivial to get the information necessary 🙂
  10. @Pixrael thanks for the insights! Do you have any links for live examples using PW + Shopify? 🙂
  11. Every Inputfield consists of this markup: <li class="Inputfield"> <label class="InputfieldHeader"></label> <div class="InputfieldContent ..."></div> </li> I want to inject some code either at the top or at the bottom: Hooking Inputfield::render does only let me modify the inner markup of InputfieldContent. Am I missing any hooks or other magic? 🙂
  12. Hm. My experience with foxy was quite bad. It looks ugly imho (both the backend and their frontend shop implementation), the checkout is complicated to impossible to customize and the implementation was not that straightforward. Luckily I don't have any e-commerce projects on the radar, but this module might be worth a try:
  13. If you hook the render() method, the $event->return contains the markup. Therefore you need to modify $event->return to modify the markup:
  14. Glad you solved it. Beside what I've already mentioned regarding isProductTemplate I have another suggestion: I think you could avoid neting IFs and make the code even more readable: public function checkSKUUnique(HookEvent $event) { $snipwire = $this->wire('snipwire'); if (!$snipwire) return; // only check snip products $page = $event->arguments(0); if(!$page->isSnipProduct) return; // exit if no changes if(!$page->isChanged('snipcart_item_id')) return; // don't check unsaved pages $field = $page->getField('snipcart_item_id'); $sku = $page->snipcart_item_id; // SKU field value if(!$sku) return; // exit if value is unique $exists = $this->wire('pages')->get([ ['snipcart_item_id', '=', $sku], ['id', '!=', $page], ['status', '<', Page::statusTrash], ]); if(!$exists->id) return; // value is not unique, show errors $error = $this->_('SKU must be unique'); $page->getInputfield($field)->error($error); $exception = sprintf($this->_('SKU [%s] is already in use'), $sku); throw new WireException($exception); // Prevent saving of non-unique value! }
  15. This works for me: // To test, add this to your sites/ready.php wire()->addHookAfter('Pages::saveReady', 'checkiconUnique'); function checkiconUnique(HookEvent $event) { $page = $event->arguments(0); $field = $page->getField('icon'); $icon = $page->icon; // preset icon // before the page is saved for the first time it does not have an id if(!$page->id) { $page->icon = "Preset icon " . uniqid(); } else { if(!$page->isChanged('icon')) return; $exists = wire('pages')->get("id!=$page,icon=$icon"); if($exists->id) { // value is not unique! $error = __('icon must be unique'); $exception = sprintf( __('icon [%s] is already in use'), $icon ); $inputfield = $page->getInputfield($field); $inputfield->error($error); throw new WireException($exception); // Prevent saving of non-unique value! } } } Not sure if that works in all circumstances - that's why we build modules for such things. And not sure if a module by Ryan is really a 3rd party module that one should not include in his module 😉 But maybe it helps nonetheless... I tested it with an "icon" field. You can simple find&replace that string to your fieldname. I made all occurrences lowercase to make that easier.
  16. Hi @Gadgetto the screencast was meant to show that I did search for the "unique" feature in the blog but didn't find relevant results 😉 It was not meant as something useful for your problem. To your problem... Such things are a little hard when one is not directly in the code! Could you please setup two example hooks for the BASIC-PAGE template and the TITLE field. Almost everybody has those available for testing so we could just copy&paste your hooks into site/ready.php and provide tested solutions. One thing that I saw in your code that could be slightly improved: // your version: if ($snipwire->isProductTemplate($page->template)) { ... // better: if($page->isSnipProduct) { ... $wire->addHookProperty("Page::isSnipProduct", function($event) { $snipwire = ... $event->return = $snipwire->isProductTemplate($event->object->template); } That's just a little detail but IMHO overall that makes code more readable... Another option would be to use the new Page Classes, but I guess that's no option for you because you because of the version requirement 🙂
  17. Ugh... that was really ugly 😐 Here's a better version: In your autoload module: $this->addHookProperty("User::isCustomer", function(HookEvent $event) { $event->return = $this->user->isSuperuser(); if($this->user->hasRole('manager')) $event->return = true; if($this->user->hasRole('customer')) $event->return = true; }); $this->addHookProperty("User::isManager", function(HookEvent $event) { $event->return = $this->user->isSuperuser(); if($this->user->hasRole('manager')) $event->return = true; }); In your processModule: public function checkAccess() { // if user is neither customer nor manager we redirect if(!$this->user->isCustomer AND !$this->user->isManager) { $this->session->redirect('/your/admin/url/to/no-access-page'); return; } } public function executeDNS { $this->checkAccess(); $user = $this->wire('user'); $out = "<div>Hello $user, here are your dns settings...</div>"; if($user->isManager) $out .= "<div>You are a Manager, so you can edit all settings!</div>"; ... return $out; } A lot better. Welcome to PW greatness 🙂
  18. Hey @adrian I've just started using live.js because I'm doing some work in the backend where I need JS/LESS a lot. After getting tired of reloading the browser I thought I'd try browsersync that I recently discovered but it did not work. Then I found live.js and added this to my module: if(!$this->user->isSuperuser()) return; if(!$this->config->debug) return; $this->config->scripts->add('http://livejs.com/live.js'); And this just works!! The great thing about it is that it even recognizes when my style.less file changed. The great thing here is that it does not reload the browser but only replaces the CSS file (which is crazy because the CSS is parsed via RockLESS on demand, so the server must somehow be involved. Anyway... the style gets updated without reloading the page as soon as I change my LESS file 😎 I thought this would be very easy to include in Tracy. For the frontend it would need to add the whole script tag instead of doing $config->styles->add(), but that would also be simple. What do you think? Edit: I understand now how the less-part works. On every poll of live.js the server is involved, so live.js results in lots of requests to your server! I don't think that's a very good option...
  19. I knew there was something added lately, but then I didn't find it and thought maybe I was dreaming 😄
  20. Hi, @AswinC and welcome to the forum! Sounds like a fun project 🙂 I'd suggest something like this Permissions: dns-view dns-edit licensing-view licensing-edit Roles: customer (dns-view, licensing-view) manager (dns-edit, licensing-edit) Then you build ProcessModules for those management interfaces and simply check for the role: public function checkAccess() { // $su is true for superuser $su = $this->user->isSuperuser(); // set user info object // for superusers all properties will be true $u = (object)[ 'isCustomer' => $su ?: $this->user->hasRole('customer'), 'isManager' => $su ?: $this->user->hasRole('manager'), ]; // if user is neither customer nor manager we redirect if(!$u->isCustomer AND !$u->isManager) { $this->session->redirect('/your/admin/url/to/no-access-page'); return; } // user has access, return info object return $u; } public function executeDNS { $u = $this->checkAccess(); $user = $this->wire('user'); $out = "<div>Hello $user, here are your dns settings...</div>"; if($u->isManager) $out .= "<div>You are a Manager, so you can edit all settings!</div>"; ... return $out; } That was really quickly typed here in the browser. Maybe even more elegant would be to add $user->isCustomer and $user->isManager to your user object in an autoload module, then you'd have it available in all your API 🙂 See You can then also prevent editing of pages via simple hooks that check if the user is a customer or manager. Then you can simply build your own logic like customers can only edit their own dns pages etc.; I'd really do that using ProcessModules and not via the page tree. The page tree has big problems hiding/showing stuff based on access related things (see AdminRestrictBranch and its limitations).
  21. Sounds like a job for https://modules.processwire.com/modules/fieldtype-text-unique/ ?
  22. It's impossible to know all features of Tracy 😉 Just getting used to the API Explorer. So useful!! Thx (over and over) again!
  23. I'd try to remove as much as possible and then add features step by step and see when things start breaking. After each action check Site Frontend (different pages, does the problem occur on one special page or on all?) Site Backend (sometimes I had problems with my own code, so the frontend was broken but the backend worked) This is what I'd do: Add a "return;" on top of ready.php, init.php and maybe other files that you load on every request; Remove all modules (eg by renaming the /site/modules folder to /site/modules_tmp The frontend will likely break if your modules are not available, but the backend should work. If your site works again, move over the modules 1-by-1 from modules_tmp to modules and see what happens.
  24. I haven't used frontend editing for ages (always had issues with images fields or css conflicts or the like), but it might be worth to try disabling AOS if you have that installed and you are using the language switcher? I had some problems lately with that feature of AOS...
  • Create New...