Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 05/14/2021 in all areas

  1. ProcessWire 3.0.178 focuses largely in adding pull requests (PRs), which are code contributions by ProcessWire users. We had quite a few great pull requests pending, and in total we have added 26 of them in 3.0.178— https://processwire.com/blog/posts/pw-3.0.178/
    14 points
  2. Great to see pull requests merged. This will help community and pw greatly!
    8 points
  3. It's not really about being clever: the core ships with a metadata file (wire/core/.phpstorm.meta.php) that makes PHPStorm aware of the inner workings of the wire() method. PHPDoc comments only state that the wire() method may return a number of different objects, so there's little that the editor can figure out from that alone. VSCode doesn't (AFAIK) have anything similar to this, but depending on the plugins you use this may be possible — with some caveats. I use PHP Intelephense, and while it does actually read PHPStorm metadata, it doesn't seem to support reading it from subdirectories: https://github.com/bmewburn/vscode-intelephense/issues/1384. At the moment I don't have any idea how to get this to work, except of course for duplicating the metadata file to your project's root directory. (Or finding a plugin that supports this feature ?)
    2 points
  4. Like what Bernhard mentioned — my IDE knows all about what I'm accessing when I type in $this->wire()->apivar or wire()->apivar, so it can suggest methods, arguments, and tell me when I've typed something wrong. Whereas less of this happens with $this->wire('apiVarName') or wire('apiVarName') — the IDE isn't nearly as helpful. So it's more of catering to the way the IDE works than anything else, and in exchange it makes coding easier, faster and less error prone. It's the same reason you'll sometimes see this in modules: /** @var Pages $pages */ $pages = $this->wire('pages'); That comment in the first line tells the IDE that $pages is referring to the Pages class. But this produces the same result with no /** comment */ necessary: $pages = $this->wire()->pages; In most Wire derived classes, $this->wire->pages (like Bernhard was using above) or $this->pages will also work and the IDE will still know what API var you are accessing. The reason I prefer to call it as a function $this->wire()->pages rather than a property $this->wire->pages (or $this->pages) is because it will work consistently everywhere in PW, even if a class has "fuel" turned off (see useFuel). Having fuel off is necessary in classes that can potentially have properties or field names that could overlap with API var names; an example is the Page class or your own custom Page classes in /site/classes/. The other reason is that $this->wire()->apivar (wire method) is the most efficient access to an API var because it has the fewest hops. Accessing $this->wire->apivar or $this->apivar first goes to $this->__get('apivar') and then $this->wire()->apivar. So $this->wire()->apivar is more direct (one less hop). In reality it probably doesn't matter much though. @Zeka
    2 points
  5. This week I've been developing a client site, but also working through some of the feature requests. I'm going through them in order of "thumbs-up" on GitHub and trying to focus more on those that I can get through reasonably quickly. For a summary of what's been added, be sure to see the dev branch commit log. There's still a few more I'd like to add before bumping the version to 3.0.173, so will save that for next week. One of the requests was for the ability to add custom after-save actions in the Page editor. These are the "Save + Exit", "Save + Add New", etc., dropdown actions that you see on the Save button in the page editor. This is something that's already supported, but not formally documented. So I wanted to quickly go through a couple examples of how to do that here, as it is kind of useful and fun. Let's start with a "hello world" example to keep it simple, then we'll move on to a more practical example. Say we want a "Save + Say Hello" dropdown action in our page editor Save button. We need one hook to add the action, and another to process it. These hooks could go in your /site/ready.php file or your /site/templates/admin.php file, or in a module. First we'll want to hook ProcessPageEdit::getSubmitActions() to add our custom "hello" action: $wire->addHookAfter('ProcessPageEdit::getSubmitActions', function($event) { $actions = $event->return; // array of actions indexed by name $page = $event->object->getPage(); // page being edited // add a new action that says hello after saving page $actions['hello'] = [ 'value' => 'hello', // value for action that you will check 'icon' => 'hand-spock-o', // icon to show in action, excluding the 'fa-' part 'label' => '%s + Say Hello', // the '%' is replaced with 'Save' or 'Publish' 'class' => '', // optional class if you need different styling for button/link ]; $event->return = $actions; }); To process our action, we'll need to add a hook to ProcessPageEdit::processSubmitAction(): $wire->addHookAfter('ProcessPageEdit::processSubmitAction', function($event) { $action = $event->arguments(0); // action name, i.e. 'hello' $page = $process->getPage(); // Page that was edited/saved if($action === 'hello') { $notice = new NoticeWarning("Hello! You edited page $page->path"); $notice->icon = 'hand-spock-o'; $event->notices->add($notice); } }); That's all there is to it. That part where I created the $notice above could just as easily been $this->warning("Hello!..."); but I wanted to add a custom icon to it, which is why I created the Notice manually. Many of the built-in after-save actions perform a redirect to another location, such as adding another page, exiting back to the page list, viewing the page on the front-end, etc. If you have a need to perform a redirect after the save, use the $event->object->setRedirectUrl($url); method. This is preferable to calling $session->redirect(); yourself, as it is handled by the page editor after it has finished everything it needs to do. What if you just want to remove one of the existing actions? For instance, maybe you want to remove the "Save + Add New" action. That action has the name "add", so we can remove it like this: $wire->addHookAfter('ProcessPageEdit::getSubmitActions', function($event) { $actions = $event->return; // array of actions, indexed by name unset($actions['add']); $event->return = $actions; }); If there's another you'd like to remove, I'd recommend using TracyDebugger and bd($actions); so you can see and identify all the actions that are present from your hook. Now let's get to a more practical example. Let's say that you are using ProCache and you want to add a save action to automatically prime the cache after performing the save. By "prime the cache" I mean have it perform a page-view on the front-end that makes it save a new cache file for the page. Here's how you could do that: $wire->addHookAfter('ProcessPageEdit::getSubmitActions', function($event) { $actions = $event->return; // array $page = $event->object->getPage(); // page being edited $procache = $event->wire('procache'); if(!$procache) return; // if procache not installed, do not add action if(!$page->isPublic()) return; // page not public is also not cacheable if(!$page->viewable()) return; // page not viewable has no template file if(!$procache->isPageCacheable($page)) return; // page not setup for cacheing $actions['cache'] = [ 'value' => 'cache', 'icon' => 'fighter-jet', 'label' => '%s + Cache', // Save + Cache 'class' => '', ]; $event->return = $actions; }); …and our hook to process the action: $wire->addHookAfter('ProcessPageEdit::processSubmitAction', function($event) { $action = $event->arguments(0); // action name, i.e. 'cache' $page = $process->getPage(); // Page that was edited/saved if($action === 'cache') { $http = new WireHttp(); $response = $http->get($page->httpUrl); if($response) { $size = wireBytesStr(strlen($response)); $event->message("Cache primed for page $page->path ($size)", "nogroup"); } else { $this->warning("Error caching page: " . $http->getError()); } } }); Note that we don't have to clear the cache file here because that's something that ProCache has already done prior to our hook above being called. Thanks for reading and have a great weekend!
    1 point
  6. Check this: https://www.fastcomet.com/processwire-hosting I never try this Managed Processwire Hosting, but I used their regular hosting plans, and they comes with cpanel + softaculous, so you can install PW easily.. fast hosting
    1 point
  7. You could try any shared hosting with softaculous. Just checked the demo on their website, and it's up-to-date https://www.softaculous.com/apps/cms/ProcessWire
    1 point
  8. Related: https://github.com/processwire/processwire-issues/issues/550
    1 point
  9. You have an endless loop happening - you're hooking Pages::saved, and then saving the page inside the hook, which calls Pages::saved, which saves the page, etc. So you need some extra logic to exclude the page you are saving in the hook. In this case you can identify the page you want to exclude by checking if it is locked. if ($page->template == "invoice" && !$page->isLocked()) { //... Alternatively you can hook Pages::saveReady, then you don't need to worry about endless loops because you are hooking just before the page is about to be saved and therefore you don't need to save within the hook itself. $wire->addHookAfter("Pages::saveReady", function($event) { $page = $event->arguments(0); if ($page->template == "invoice") { // lock page if inv_status = paid (1034) or cancelled (1038) if ($page->inv_status == 1034 || $page->inv_status == 1038) { $page->addStatus("locked"); } } });
    1 point
  10. v0.0.63 Thx to the feedback of @wbmnfktr I've made it a lot easier to get started with RockMigrations! The readme has now a dedicated quickstart section: https://github.com/BernhardBaumrock/RockMigrations#quickstart The example that was shipped with RockMigrations was also improved. I removed some complexity and used real world example names (a simple blog setup) instead of "foo" and "bar". This should make it a lot easier to understand ? Also I improved the page name replacements feature introduced lately: Page name replacements now ship with the module. They are saved in a dedicated folder and named "de.txt" for german replacements. If you need any other replacement options just let me know! (maybe @apeisa ? ) $rm->setPagenameReplacements("de"); https://github.com/BernhardBaumrock/RockMigrations/tree/master/replacements
    1 point
  11. Not sure about performance, but I'm always using $this->wire->... because this supports intellisense while the other variants do not (in my setup): $this->wire->... correctly suggests the class properties and methods: $this->wire('files')->... does not: I guess $this->wire needs an extra call of the magic getter, but I have no idea if that really matters?! Whereas having intellisense matters a lot for me in my daily work...
    1 point
  12. @ryan Thanks for update! For some time I see a lot of such changes in the commits: //before $config = $this->wire('config'); $log = $this->wire('log'); //after $config = $this->wire()->config; $log = $this->wire()->log; Is there is some technical background for such changes or it's just a matter of preference? (I remember that you have explained it in some other thread or blog post, but I could not find it).
    1 point
  13. Hi, A bit of background. I am creating a website which lets you navigate through a protein database with 20 million proteins grouped into 50 thousand categories. The database is fixed in size, meaning no need to update/add information in the near future. Queries to the database are pretty standard. The problem I am currently having is the time it takes to create the pages for the proteins (right now around a week). Pages are created reading the data from a csv file. Based on previous posts I found on this forum (link1, link2) I decided to use $database transactions to load the data from a php script (InnoDB engine required). This really boosts performance from 25 pages per second to 200 pages per second. Problem is performance drops as a function of pages created (see attached image). Is this behavior expected? I tried using gc_collect_cycles() but haven't noticed any difference. Is there a way to avoid the degradation in performance? A stable 200 pages per second would be good enough for me. Pseudo code: $handle = fopen($file, "r"); $trans_size = 200 // commit to database every _ pages try { $database->beginTransaction(); for ($i = 0; $row = fgetcsv($handle, 0, " "); ++$i) { // fields from data $title = $row[0]; $size = $row[1]; $len_avg = $row[2]; $len_std = $row[3]; // create page $page = new Page(); $page->template = "protein"; $page->title = $title; $page->size = $size; $page->len_avg = $len_avg; $page->len_std = $len_std; $page->save(); if (($i+1)%$trans_size == 0) { $database->commit(); // $pages->uncacheAll(); // gc_collect_cycles(); $database->beginTransaction(); } } $database->commit(); } I am quiet new to process wire so feel free to criticize me ? Thanks in advance
    1 point
  14. Unless I'm forgetting something, the $pages->uncache($page); won't help here because $page is a newly created Page that wasn't loaded from the database. So it's not going to be cached either. Uncaching pages is potentially useful when iterating through large groups of existing pages. For instance, if you are rendering or exporting something large from the contents of existing pages, you might like to $pages->uncacheAll() after getting through a thousand of them to clear room for another paginated batch. Though nowadays we have $pages->findMany() and $pages->findRaw(), so there are fewer instances were you would even need to use uncache or uncacheAll, if ever. ProcessWire actually does an uncacheAll() internally after saving a page already. This is necessary because changes to a page or additions/deletions to the page tree may affect other pages, and we don't want any potential for old cached data to appear in future $pages->find() or other operations. Just one example is if we called $parent->children() before a save, and then after the save called it again, we'd want our new page to be in the children rather than having it return the previously cached value. There are a lot of similar cases, so the safest bet is for PW to uncache the results of future page get/find operations after a save as the default behavior. So that's the way it's always done it. As far as I can tell from fedeb's example (and often other with import operations), it may be better to tell PW to skip this "uncacheAll-after-save" behavior. That's because imports often involve Page reference fields, and you don't want PW to have to reload referenced pages after every save. So you could potentially reduce overhead by telling it not to uncache after save, i.e. $pages->save($page, [ 'uncacheAll' => false ]); I'm not sure if fedeb's import involves loading of any other pages, whether for page reference fields, or anything else. So it may not matter one way or the other here, but wanted to mention it just in case. I know about ProcessWire tuning, but not about MySQL server tuning. When dealing with 20 million rows that seems like getting into the territory where optimizations to the DB configuration deserve a lot of focus, so I would bet that BitPoet's suggestions are going to make the most difference.
    1 point
  15. @fedeb That's the largest quantity of pages I've heard of anyone creating in ProcessWire, by a pretty large margin. So you are in somewhat uncharted territory. But that's really cool you are doing that. I would be curious how different the graph would be if you split it up into batches so that you aren't creating more than a certain quantity per execution/runtime. For instance, maybe you create 10k in one execution and another 10k in the next, etc., or something like that. Would the same slowdown still occur? If so, I would start to think it might be the database index and increased overhead in maintaining that index as the quantity increases. On the flip side, if restarting the process to create each set in batches solves the slowdown, then I would think it might be memory or resource related. A couple things you can do to potentially (?) improve your page creation time: 1. At the top of your code (before the loop) put: $template = $templates->get('protein'); Then within the loop set: $page->template = $template; 2. I don't see a parent page assignment. How are you doing that? Double check that you aren't asking PW to load the parent page every time in the loop and instead handle it like with the template in #1 above. 3. What kind of fields are on your "protein" template? Depending on their type, there may be potential optimizations. Especially if any are Page references. Can you paste in a line or two from the CSV? 4. If you can assign a $page->name = "protein" . $i; rather than having PW auto-generate a name from the title, that will save some resources too.
    1 point
  16. This module is inspired by and similar to the Template Stubs module. The author of that module has not been active in the PW community for several years now and parts of the code for that module didn't make sense to me, so I decided to create my own module. Auto Template Stubs has only been tested with PhpStorm because that is the IDE that I use. Auto Template Stubs Automatically creates stub files for templates when fields or fieldgroups are saved. Stub files are useful if you are using an IDE (e.g. PhpStorm) that provides code assistance - the stub files let the IDE know what fields exist in each template and what data type each field returns. Depending on your IDE's features you get benefits such as code completion for field names as you type, type inference, inspection, documentation, etc. Installation Install the Auto Template Stubs module. Configuration You can change the class name prefix setting in the module config if you like. It's good to use a class name prefix because it reduces the chance that the class name will clash with an existing class name. The directory path used to store the stub files is configurable. There is a checkbox to manually trigger the regeneration of all stub files if needed. Usage Add a line near the top of each of your template files to tell your IDE what stub class name to associate with the $page variable within the template file. For example, with the default class name prefix you would add the following line at the top of the home.php template file: /** @var tpl_home $page */ Now enjoy code completion, etc, in your IDE. Adding data types for non-core Fieldtype modules The module includes the data types returned by all the core Fieldtype modules. If you want to add data types returned by one or more non-core Fieldtype modules then you can hook the AutoTemplateStubs::getReturnTypes() method. For example, in /site/ready.php: // Add data types for some non-core Fieldtype modules $wire->addHookAfter('AutoTemplateStubs::getReturnTypes', function(HookEvent $event) { $extra_types = [ 'FieldtypeDecimal' => 'string', 'FieldtypeLeafletMapMarker' => 'LeafletMapMarker', 'FieldtypeRepeaterMatrix' => 'RepeaterMatrixPageArray', 'FieldtypeTable' => 'TableRows', ]; $event->return = $event->return + $extra_types; }); Credits Inspired by and much credit to the Template Stubs module by mindplay.dk. https://github.com/Toutouwai/AutoTemplateStubs https://modules.processwire.com/modules/auto-template-stubs/
    1 point
×
×
  • Create New...