Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by Gadgetto

  1. @NorbertH I'll contact you via PM!
  2. @bernhard & @wbmnfktr thanks guys for recommending me!
  3. I have the same problem. Tried to make strings translatable in module.info.php, but I get an error "__" is not a function. Do you mean "___" ...
  4. Hmm.. this feels a bit like a hack for me. And it doesn't work for sub-menu entries.
  5. @bernhard do you mean we can have different menu structure for admins and clients? This would be great!
  6. @kongondo initially suggested that I could also use URL segments and therefore the discussion. I'll stay with URL params which is OK in backend.
  7. Thanks for your infos guys! I'm probably still much too deadlocked from my MODX time. ProcessWire just makes things different and that's good!
  8. I didn't think I'd need to add executeRefresh(), executeReset(), executeThis(), executeThat(), ... methods. This would fragmentize the source of a module a lot. I thought it works like in frontend, where I can enable URL segments and then the parts of URL paths like /mymodule/this/that/ are simply assigned to urlSegement(1) = "this" ,urlSegement(2) = "that". And the request wouldn't be routed to /mymodule/this/that/ but /mymodule/. From this point of view, I don't see any advantage for using url segments in process modules. It could also be that I still don't understand how URL segments are working!? (which is probably the case)
  9. Hi @draganI don't have an ___executeRefresh() method. And as I read in the old thread you posted, it strengthens my view that url segments are not ideal for my purpose.
  10. Yep, the button URL leads to a 404 Process returned no content. But it should resolve the execute method.
  11. Here is the init() and ___execute() part of ProcessSnipWire: (please have a look at the "Refresh" button down below - at the end of source code) /** * Initialize the module. * (Called before any execute functions) * */ public function init() { parent::init(); // Get SnipWire module config. // (Holds merged data from DB and default config. // This works because of using the ModuleConfig class) $this->snipwireConfig = $this->wire('modules')->get('SnipWire'); // Get activated $currencies from SnipWire module config $this->currencies = $this->snipwireConfig->currencies; $this->snipWireRootUrl = rtrim($this->wire('pages')->get('snipwire')->url, '/') . '/'; $this->currentUrl = rtrim($this->wire('input')->url, '/') . '/'; } /** * The SnipWire Dashboard page. * * @return page markup * */ public function ___execute() { $modules = $this->wire('modules'); $user = $this->wire('user'); $config = $this->wire('config'); $input = $this->wire('input'); $sniprest = $this->wire('sniprest'); $this->browserTitle($this->_('SnipWire Dashboard')); $this->headline($this->_('SnipWire Dashboard')); if (!$user->hasPermission('snipwire-dashboard')) { $this->error($this->_('You dont have permisson to use the SnipWire Dashboard - please contact your admin!')); return ''; } $this->_includeAssets( self::assetsIncludeDaterangePicker | self::assetsIncludeCurrencyPicker | self::assetsIncludeApexCharts ); $startDate = $this->_getStartDate(); $endDate = $this->_getEndDate(); $currency = $this->_getCurrency(); $action = $this->_getInputAction(); $forceRefresh = false; if ($action == 'refresh') { $this->message(SnipREST::getMessagesText('cache_refreshed')); $forceRefresh = true; } elseif ($action == 'reset') { $this->message($this->_('Store performance date range set to default.')); $this->_resetDateRange(); } $packages = $sniprest->getDashboardData( "$startDate 00:00:00", "$endDate 23:59:59", $currency, SnipREST::cacheExpireDefault, $forceRefresh ); $dashboard = $this->_prepareDashboardData($packages); unset($packages); if (!$dashboard) { $out = '<div class="dashboard-empty">' . $this->_('Dashboard data could not be fetched') . '</div>'; return $this->_wrapDashboardOutput($out); } $out = $this->_buildDashboardFilter($startDate, $endDate, $currency); $out .= $this->_renderPerformanceBoxes( $dashboard[SnipRest::resourcePathDataPerformance], $currency ); $chart = $this->_renderChart( $dashboard[SnipRest::resourcePathDataOrdersSales], $dashboard[SnipRest::resourcePathDataOrdersCount], $currency ); /** @var InputfieldForm $wrapper */ $wrapper = $modules->get('InputfieldForm'); /** @var InputfieldMarkup $f */ $f = $modules->get('InputfieldMarkup'); $f->label = $this->_('Performance Chart'); $f->icon = 'bar-chart'; $f->value = $chart; $f->columnWidth = 100; $f->collapsed = Inputfield::collapsedNever; $wrapper->add($f); $out .= $wrapper->render(); /** @var InputfieldForm $wrapper */ $wrapper = $modules->get('InputfieldForm'); /** @var InputfieldMarkup $f */ $f = $modules->get('InputfieldMarkup'); $f->label = $this->_('Top Customers'); $f->icon = self::iconCustomer; $f->value = $this->_renderTableTopCustomers($dashboard[SnipRest::resourcePathCustomers]); $f->columnWidth = 50; $f->collapsed = Inputfield::collapsedNever; $wrapper->add($f); /** @var InputfieldMarkup $f */ $f = $modules->get('InputfieldMarkup'); $f->label = $this->_('Top Products'); $f->icon = self::iconProduct; $f->value = $this->_renderTableTopProducts($dashboard[SnipRest::resourcePathProducts], $currency); $f->columnWidth = 50; $f->collapsed = Inputfield::collapsedNever; $wrapper->add($f); $out .= $wrapper->render(); /** @var InputfieldForm $wrapper */ $wrapper = $modules->get('InputfieldForm'); /** @var InputfieldMarkup $f */ $f = $modules->get('InputfieldMarkup'); $f->label = $this->_('Recent Orders'); $f->icon = self::iconOrder; $f->value = $this->_renderTableRecentOrders($dashboard[SnipRest::resourcePathOrders]); $f->columnWidth = 100; $f->collapsed = Inputfield::collapsedNever; $wrapper->add($f); $out .= $wrapper->render(); /** @var InputfieldButton $btn */ $btn = $modules->get('InputfieldButton'); $btn->id = 'refresh-data'; //$btn->href = $this->currentUrl . '?action=refresh'; $btn->href = $this->currentUrl . 'refresh'; // <--- https://processwire.moduledev/pw/setup/snipwire/refresh // and leads to "The process returned no content." $btn->value = $this->_('Refresh'); $btn->icon = 'refresh'; /* $btn->addActionLink( $this->currentUrl . '?action=refresh_all', 'Refresh Complete Snipcart Cache', 'refresh' ); */ $btn->showInHeader(); $out .= $btn->render(); return $this->_wrapDashboardOutput($out); }
  12. Can anyone tell me what's the deeper reason for putting custom ProcessModule menus under "Setup"? It kind of feels wrong... especially for full featured Apps like my upcoming SnipWire. Wouldn't it be better to have a dedicated "Extras" menu or something else? I know I can place the menu entry for my module wherever I like, but I think we need a better standard. How do you think about this?
  13. I think I already tried to use url segments but in execute() method I'll get "404" errors. So URL segments doesn't seem to be fully supported in ProcessModules.
  14. You are right, it's a single process. Hooking into any method will still be in the same process and the visitor will need to consume the request time. I'll need to "launch" a new (background) process which will do the heavy lifting.
  15. Thank your for the kind words! 🙂 I don't know if this will make it into the first release version but it seems to be a necessary step. LazyCron, on the other hand, does not seem to be well suited. This would cause delays for website visitors. I was thinking more of a separate worker process, or multiple parallel processes, running asynchronously and externally triggered by a cron job or by Javascript runner. I have already implemented something like this for a newsletter module for MODX.
  16. UPDATE 2019-08-08 The module has made hug steps forward and we are nearing a first beta release version. So for those of you who are interested, I wanted to let you know what happened in the meantime 🙂 The dashboard interface was refined. Currency selector for switching dashboard currency (based on your currency fields) Added dashboard sections for managing Orders, Customers and Products Added a WireTabs interface to easily switch between the different dashboard sections. Orders, Customers and Product-details are opened and edited in ProcessWire Panels Added further properties to SnipCart product anchors like: categories, product dimensions, weight, and so on. Added field selector to SnipWire settings for choosing the desired field (FieldtypePage) to be used for categories handling. Refinded caching behavior. *) *) the proper caching of SnipCart data fetched through their REST API is giving me headaches. I'm still not sure what to cache and how long. For example, think of retrieving the list of purchase orders and creating a pagination. Every single page has to be cached. What if new orders are added when flipping backwards? Then the page numbers could get out of hand. (this only as an example). As SnipCart has relativ slow API response times (about 1.8-2.5 seconds for a request), I'm even thinking about developing a separate background job runner which continuously fetches data from SnipCart and caches it locally. Our SnipWire module could then only use locally stored data only. What needs to be done: As SnipCart has a totally broken presentation of multi currency values in it's dashboard (for example: they simply sum up order values in different currencies!) I need to calculate performance values manually. And this will be a huge job as the data comes from different REST API calls... Orders, Customers and Products detail editors (order status update, setting the order tracking number, add metadata information, creating notifications on the specified orders, ...) Order refunds handling through the SnipWire dashboard Integration of external shipping providers Integration of external taxes providers Subscription handling through the SnipWire dashboard Discount creation and handling through the SnipWire dashboard Documentation, documentation, documentation! and much more ... Here are some fresh screens:
  17. I also don’t know. ;) Didn’t even know there are Params set... Do you think I should use the modal=panel param instead of pw_panel=1?
  18. Ah ok - it was "pw_panel" not "panel". Thanks, it works now!
  19. Using an InputfieldButton + Dropdown addActionLink() in a custom admin page, leads to messy HTML code. Therefore the button dropdown renders wrong. I filed an issue here: https://github.com/processwire/processwire-issues/issues/948 Is it only me, or could somebody confirm this problem? Thanks, Martin
  20. In my Process module I'd like to load some processes (___executeSomething1, ___executeSomething2, ...) in PW Panels. If those pages are loaded in panel, I'd like to hide some interface parts (like WireTabs). The question is, is it possible to determine via API if a page is loaded inside a panel? Or do I need to use jQuery?
  21. Just stumbled across this thread and I have a question regarding thumbnail image size in ProcessPageLister grids. I have this grid in a Process Module: What I try to do is to resize the thumbnail images in "Product Image(s)" column to 60x60px. $adminThumbOptions = $this->wire('config')->adminThumbOptions; $adminThumbOptions['gridSize'] = 60; $this->wire('config')->adminThumbOptions = $adminThumbOptions; // Instantiate ProcessPageLister with default settings $this->productsLister = $this->wire('modules')->get('ProcessPageLister'); $this->productsLister->initSelector = ''; $this->productsLister->imageFirst = true; $this->productsLister->allowBookmarks = false; ... But this doesn't work although the $config->adminThumbOptions array has the correct value for "gridSize" the thumbnails are rendered 130x130px. Any hints?
  22. I'll first need to release SnipWire and in the phase of fine-tuning I would like to move some of the functionality into separate modules. A chart module could be such a candidate. I'm gonna check out your module and see how you were thinking of implementing that. Thanks for your hint! The first separate module will be a fully configurable array/json repeater Inputfield which stores its values in a single text field.
  23. Hi Bernhard, currently integrated directly. But having this as module is a nice idea. The problem is, this thing has over 150 config parameters so packing it into a module will be quite a bit of work...
  24. UPDATE 2019-06-15 The taxes repeater field in module config editor was updated: changed to a grid view for more flexibility added field validation prepared the taxes-repeater field code to become a standalone flexible Inputfield module for general use (Array/JSON repeater input field which stores its values in a single text field) The taxes handling is completed! SnipWire now acts as a full flexible taxes-provider for Snipcart (we use Webhooks for this). No configuration needed in Snipcart dashboard. SnipCart orders are now fully working (except shipping handling). The sample shop templates got an update: customer login/logout customer dashboard link/button to view orders history and subscriptions editing of customer profile Other updates and fixes: The SnipWire Dashboard was updated (Charts, Orders, Customers, ...) --> see screenshot below. The Dashboard fetches its data from Snipcart via CURL multi - the response time for a fresh load is now under 2 seconds The Webhooks handler now supports all Snipcart events via hookable methods. Snipwire now supports all major Admin themes (Uikit, Reno and Default) All module classes/files are more structured (e.g. separate helper and service classes) Under the hood many bugs are fixed and code is updated to prevent unexpected errors. Added a crispy SVG logo for all SnipCart back-end pages 🙂 Screen-recording of updated taxes-repeater: Screenshot of SnipWire Dashboard:
  • Create New...