Jump to content

ryan

Administrators
  • Posts

    16,714
  • Joined

  • Last visited

  • Days Won

    1,515

Everything posted by ryan

  1. Just a quick update this week. The dev branch version is now at 3.0.202 as of today. Relative to 3.0.201 this includes 22 commits of various fixes, issue resolutions, improvements and additions. While there's nothing major that's new to report in this version, there is nonetheless quite a bit there, and if you are already running on the dev branch it's a worthwhile upgrade. For full details be sure to see the dev branch commit log. Thanks for reading and have a great weekend!
  2. ProcessWire's core comes with a lot of helpful debugging tools and capabilities built-in. In this post we'll cover some of these useful tools and how to use them— https://processwire.com/blog/posts/debugging-tools-built-in/
  3. @joe_g That's right, it doesn't look like there's any reason to provide #maincontent for your situation. When populating markup regions, specify just the region you want to replace, append, prepend, or delete; not a structure of markup regions. Though you did have that case above where you were trying to a direct child to it: <div class="p-8"> outside of your _main.php, so in that case you would, or you could do a <div class="p-8" pw-append="maincontent">...</div> or <div id="maincontent"><div class="p-8">...</div></div>. I recommend adding <!--PW-REGION-DEBUG--> somewhere in your _main.php markup (like at the bottom), and that'll be automatically replaced with some markup that tells you everything your Markup Regions are doing and when it can't find where to place something, etc. Most of my sites have something like this below, and it's handy to look at when you aren't sure why something isn't working, etc. <?php if($config->debug && $user->name === 'ryan'): <div class"uk-container uk-margin"> <!--PW-REGION-DEBUG--> </div> <?php endif; ?> Another tip is that if you ever find Markup Regions are having trouble finding the closing tag for some specific element, you can tell it specially by marking it with a hint comment <!--#maincontent-->. Though I also just find it visually helpful, so I tend to do it whether for markup regions or not. <div id="maincontent"> ... </div><!--#maincontent-->
  4. This week core updates are focused on resolving issue reports. Nearly all of the 10 commits this week resolve one issue or another. Though all are minor, so I'm not bumping the version number just yet, as I'd like to get a little more in the core before bumping the version to 3.0.202. This week I've also continued development on this WP-to-PW site conversion. On this site hundreds of pages are used to represent certain types of vacations, each with a lot of details and fields. Several pages in the site let you list, search and filter these things. When rendering a list of these (which a lot of pages do), it might list 10, 20, 100 or more of them at once on a page (which is to say, there can be a few, or there can be a lot). Each of the items has a lot of markup, compiled from about a dozen fields in each list item. They are kind of expensive to render in terms of time, so caching comes to mind. These pages aren't good candidates for full-page caches (like ProCache, etc.) since they will typically be unique according to a user's query and filters. So using the $cache API var seems like an obvious choice (or MarkupCache). But I didn't really want to spawn a new DB query for each item (as there might be hundreds), plus I had a specific need for when the cache should be reset — I needed it to re-create the cache for each rendered item whenever the cache for it was older than the last modified date of the page it represents. There's a really simple way to do this and it makes a huge difference in performance (for this case at least). Here's a quick recipe for how to make this sort of rendering very fast. But first, let's take a look at the uncached version: // find items matching query $items = $pages->find('...'); // iterate and render each item foreach($items as $item) { echo " <!-- expensive to render markup here ---> <div class='item'> <a href='$item->url'>$item->title</a> ...and so on... </div> "; } That looks simple, but what you don't see is everything that goes in the <div class="item">...</div> which is a lot more than what you see here. (If we were to take the above code literally, just outputting url and title, then there would be little point in caching.) But within each .item element more than a dozen fields are being accessed and output, including images, repeatable items, etc. It takes some time to render. When there's 100 or more of them to render at once, it literally takes 5 seconds. But after adding caching to it, now the same thing takes under 100 milliseconds. Here's the same code as above, but hundreds of times faster, thanks to a little caching: // determine where we want to store cache files for each list item $cachePath = $config->paths->cache . 'my-list-items/'; if(!is_dir($cachePath)) wireMkdir($cachePath); // find items matching query $items = $pages->find('...'); // iterate and render each item foreach($items as $item) { $file = $cachePath . "$item->id.html"; // item's cache file if(file_exists($file) && filemtime($file) > $page->modified) { // cache is newer than page's last mod time, so use the cache echo file_get_contents($file); continue; } $out = " <!-- expensive to render markup here ---> <div class='item'> <a href='$item->url'>$item->title</a> ...and so on... </div> "; echo $out; // save item to cache file so we can use it next time file_put_contents($file, $out, LOCK_EX); } This is a kind of cache that rarely needs to be completely cleared because each item in the cache stays consistent with the modification time of the page it represents. But at least during development, we'll need to occasionally clear all of the items in the cache when we make changes to the markup used for each item. So it's good to have a simple option to clear the cache. In this case, I just have it display a "clear cache" link before or after the list, and it only appears to the superuser: if($user->isSuperuser()) { if($input->get('clear')) wireRmdir($cachePath, true); echo "<a href='./?clear=1'>Clear cache</a>"; } I found this simple cache solution to be very effective and efficient on this site. I'll probably add a file() method to the $cache API var that does the same thing. But as you can see, it's hardly necessary since this sort of cache can be implemented so easily on its own, just using plain PHP file functions. Give it a try sometime if you haven't already. Thanks for reading and have a great weekend!
  5. @joe_g No, you can specify this for each template if you want to. Edit a template and see the "files" tab. Or you could just use your _main.php as a controller that loads different layout files depending on some field value or condition that you determine. Sure you can. Use PHP include(), $files->include() or $files->render() with whatever files or order you want. Regions can be replaced, appended, prepended, removed, etc. as many times as they are output. You can do it individually for templates, see my response for #1. Though I usually structure my templates in a way that the _main.php is the "base" that's generic enough to not have ever needed to define alternate files. I think markup regions are the best way myself. Once you start using them a lot, I suspect you'll find you don't want to use anything else. That's been my experience at least. I don't know exactly what you mean by nested regions. You'd have to provide more details on what you are doing before we could say if you are using something in an intended way or not.
  6. This week I've been busy developing a site. It's the same one as the last few weeks, which is an established site moving out of WordPress and into ProcessWire. Next week the whole thing is getting uploaded to its final server for collaboration and for client preview. I've been pretty focused on getting that ready and don't have any core updates to report this week, though should next week. One thing about the prior version of this site (and perhaps many WordPress sites) is that there wasn't much structure to the pages used in the site, and hundreds of unrelated pages in the site confusingly live off the root, such as /some-product/ and /some-press-release/ and /some-other-thing/. There's no apparent structure or order to it. And those pages that do have some loose structure in the wp-admin have URLs that don't represent that structure on the front-end. There's very little relation between the structure one sees in the wp-admin and the structure that one sees in the URLs, or in the front-end navigation. They all seem to be completely unrelated. That's one thing that I've tried to fix, so that there is some logic and structure rather than having a bunch of unrelated pages all in the same bucket (is this common in WordPress?) But there's one big caveat. We didn't want to change anything about the actual URLs that are used on the site. This is a site with a long history, a lot of incoming links, and a lot of search traffic. The current URLs have been in place a long time and we didn't want to introduce more redirects into the site (there are already a ton of 301 redirects accumulated over time). So we wanted to make sure the existing URLs in the new ProcessWire-powered site are identical to what they were in the WordPress site. That might seem difficult to do, going from an unstructured WordPress site into a highly structured ProcessWire site... but actually it's very simple. Here's how: Making ProcessWire render pages from WordPress URLs We created a new URL field named "href" and added it to most of the site's templates. For established pages that came in from the old WP site, this "href" field contains the WordPress URL for the page. Depending on the page, it contains values like /some-product/ or /some-press-release/, /some-country/some-town/, etc. In most cases this is different from the actual ProcessWire URL, since the page structure is now much more orderly in the back-end. And for newly added pages, we'll be using the more logical ProcessWire URL. But for all the old WordPress pages, we'll make them render from their original URL. This is certainly preferable from an SEO standpoint but also helps to limit the redirects in the site. In order to make $page->url return the old/original WordPress URL (value in $page->href), a hook was added to the /site/init.php file: /** * Update page paths and URLs to use the 'href' field value on pages that have it * */ $wire->addHookBefore('Page::path', function(HookEvent $event) { $page = $event->object; /** @var Page $page */ $href = $page->get('href'); if(!$href) return; // skip if page has no 'href' value $event->return = $href; $event->replace = true; }); Now we've got $page->url calls returning the URLs we want, but how do we get ProcessWire to accept those URLs for rendering pages? The first thing we'll need to do is enable URL segments for the homepage template. We do this by going to: Setup > Templates > home > URLs > and check the box to enable URL segments. Save. Then we need to edit our /site/templates/home.php to identify when URL segments are present and render the appropriate page, rather than the homepage: $href = $input->urlSegmentStr; if($href) { $href = '/' . trim($href, '/') . '/'; $page = $pages->get("href=$href"); if(!$page->id || !$page->viewable()) wire404(); $wire->wire('page', $page); // set new $page API var include($page->template->filename); // include page's template file } else { // render homepage output } As you can see from the above, when URL segments are present, we find a page that has an "href" field value matching those URL segments ($input->urlSegmentStr). If we don't find one, we stop with a 404. But if we do find one, then we set the $page API variable to it and then include its template file, making that page render rather than the homepage. If there is no $input->urlSegmentStr present then of course we just render the homepage. That's it! By using these little bits of code snippets to replace ProcessWire's URL routing, now all the URLs of the old WordPress site are handled by ProcessWire. Like most things in ProcessWire, there's more than one way to accomplish this… We could have used URL/path hooks, or we could have hooked before Page::render to take over homepage requests with URL segments, before the homepage even got involved. Or perhaps we could have hooked in even earlier, to something in the ProcessPageView module or PagesRequest class. Or we could have used an existing module. Any of these might be equally good (or even better) solutions, but I just went with what seemed like the simplest route, one that I could easily see and adjust. Plus, it'll work in any version of ProcessWire. The actual solution I used is a little more than what's presented here, as it has a few fallbacks for finding pages and scanning redirect lists, plus passes along remaining pagination/URL segments to rendered pages. I'm guessing most don't need that stuff, and it adds a decent chunk of code, so I left that out. But there are a couple of optional additions that I would recommend adding in a lot of cases: Forcing pages to only render from their "href" URL and not their ProcessWire URL (optional) Our existing hooks ensure that any URLs output for pages having "href" values are always based on that "href" value. But what if someone accesses a given page at its ProcessWire path/url? The page would render normally. We might want to prevent that from happening, ensuring that it only ever renders at its defined "href" URL instead. If the page is requested at its ProcessWire URL, then we redirect to its "href" URL. We can do that by adding the following code to our /site/templates/_init.php file: if($page->id > 1) { // ensure that we are rendering from the 'href' URL // rather than native PW url, when href is populated $href = $page->get('href'); $requestUrl = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; if($href && $requestUrl && strpos($requestUrl, $href) === false) { // href value is not present in request URL, so redirect to it $session->redirect($config->urls->root . ltrim($href, '/')); } } Enforcing uniqueness and slashes in "href" values (optional) It's worthwhile to enforce our "href" values being consistent in having both a leading and trailing slash, as well as making sure they are always unique, so no two pages can have the same "href" value. To do that, I added this hook to my /site/ready.php file (/site/init.php would also work): /** * Ensure that any saved 'href' values are unique and have leading/trailing slashes * */ $wire->addHookAfter('Pages::savePageOrFieldReady', function(HookEvent $event) { $page = $event->arguments(0); /** @var Page $page */ $fieldName = $event->arguments(1); /** @var string $fieldName */ if($fieldName === 'href' || in_array('href', $page->getChanges())) { // the href field is being saved $href = $page->get('href'); if(!strlen($href)) return; // make sure value has leading and trailing slashes if(strpos($href, '/') === 0 && substr($href, -1) === '/') { // already has slashes } else { $href = '/' . trim($href, '/') . '/'; $page->set('href', $href); } // make sure that the 'href' value is unique $pages = $event->object; /** @var Pages $pages */ $p = $pages->get("id!=$page->id, href=$href"); if($p->id && !$p->isTrash()) { $page->set('href', ''); $page->error( "Path of '$href' is already in use by page $p->id “{$p->title}” - " . "Please enter a different “href” path and save again" ); } } }); That's all for this week. Thanks for reading, have a great weekend!
  7. When we released ProcessWire 3.0.200 one of the biggest differences from prior master/main versions was that PW now only includes 1 profile: the site-blank profile. This means there's probably going to be more people starting with it than before. Yet it is so minimal that I thought it deserved a bit of a walkthrough in how you take it from nearly-nothing to something you can start to build a site around. Everyone will have a little bit different approach here, which is one reason why the blank profile is a useful starting point. In this new post, here are some steps you might take when starting a new site with the blank profile— https://processwire.com/blog/posts/starting-with-the-blank-profile/
  8. The ProcessPageList module now has a configuration setting where you can select pages that should not be shown in the page list. For example, maybe once you've set up your 404 page, you don't really need it to display there anymore, except maybe in debug mode. Or maybe you don't ever need the "Admin" page to display in the page list. This new feature lets you do that, and for any page that you decide. Next, a "Usage" fields has been added to the "Basics" tab in the Field editor, just like the one in the Template editor (requested feature #445). This shows you what fields are using the template. It's essentially the same information that you'll find in the "Actions > Add or remove from templates" feature, but easier to find, especially for people newer to PW. That's all for this week, I hope you have a great weekend!
  9. @bernhard That's correct, a $page->extract() wouldn't be possible as the extract() function has a unique ability to create variables, as far as I understand it. The issue with extract() is that any variables it creates are unknown to your editor/IDE, and often times to the caller too. Whereas list() is defining variables in a visible manner that is readable and known to the IDE, clearly identified in the code as $variables. I rarely like extract() in code because it's too ambiguous, like tipping over a box of an unknown items and quantity. But there are times that's exactly what's intended, like in the TemplateFile class, where it has to pass an unknown set and quantity of variables to a php template file and make them directly accessible by $variables. This is fine because the php template file knows what variables to expect even if the class that provided them (TemplateFile) doesn't. So I think extract is good for cases like that, but otherwise I think it's preferable to have some kind of variable definition whether $name = 'value'; or list($name) = [ 'value' ]; etc.
  10. This week we have ProcessWire 3.0.201 on the dev branch which includes a couple minor fixes but also a couple of useful additions: There are new "Tab" field visibility options available for any field in the page editor. This makes the field display in its own page editor tab. It saves you from having to create a new/separate Tab field just to wrap around an existing field to make it display in a tab. So far I've found it particularly useful with ProFields (Combo, Table, Textareas, RepeaterMatrix) as well as the core Repeater, FieldsetPage and Images fields. For instance, I have a Combo field labeled "SEO" that lets me edit browser_title, meta_description, canonical_url, etc., and now I can add that field to any template and pages using that template have their own "SEO" tab. Sure you could do this before by creating a separate tab field with an "SEO" label, but now it's a lot simpler/faster, as any field can now display as a tab on its own. Like with the other visibility modes, also included are options to make the tab load dynamically on click with ajax or make the value non-editable. You can also optionally specify a label for the tab independently of the field label. This is because usually you want tab labels to be very short (1 word is best) whereas field labels have no such need. Please note that this new Tab option is exclusive to the page editor, and in order to work the field must not already be in a tab. Also added this week is a new $page->getMultiple() method. This method works the same as the $page->get() method except that it lets you retrieve multiple page property/field values at once and returns them in an array. For example: $a = $page->getMultiple([ 'foo', 'bar', 'baz' ]); list($foo, $bar, $baz) = $a; It also accepts a CSV string: $a = $page->getMultiple('foo,bar,baz'); By default it returns a regular PHP array, suitable for using in list() like the first example. But if you want it to return an associative array instead, then specify true as the 2nd argument: $a = $page->getMultiple('foo,bar,baz', true); echo $a['foo']; echo $a['bar']; echo $a['baz']; I find this method useful in reducing the amount of code/lines necessary in many cases, and most often I use it in combination with a PHP list() call, i.e. list($title,$subtitle,$body) = $page->getMultiple('title,subtitle,body'); That's all for this week. Thanks for reading and have a great weekend!
  11. I always start from scratch when it comes to creating the fields and templates, and basic site structure, but rarely when it comes to the pages/content. On previous conversions I've gone into WP’s database and exports to migrate content. This new case is a little bit unique in that WordPress couldn't do everything they needed, at least not in a manner that was affordable or reasonable to implement, from what I understand. While some of the content is in WP, other content is coming from authenticated web services. Lots of the pages have some content, custom fields and repeatable blocks in WP, but there are also custom fields with IDs for external services that it pulls other content from at runtime. They are paying a couple other companies quite a bit of money every month to host their content through these web services and make it searchable. They pull from those services at runtime and output it all from the WP templates. It strikes me as really inefficient, but it all works fine and you'd never know it from the front-end. But it's also expensive for them and fragile to have these kinds of external dependencies, not to mention a pain to have to manage content (even for the same page) across different services. This is all stuff that ProcessWire does well on its own, so none of those external services are needed on the new site. Since the front-end of the site is already compiling them all into single-page output, I built a scraper to pull it directly from the existing site and put it into the right places in ProcessWire. Scraping might seem like a last resort, but in this case it was the fastest, most direct way to pull everything out since the content is split among different databases and services. Basically using WP as an adaptor for the services it is pulling from. Luckily I can edit the WP templates to modify the markup (adding wrapping tags or custom html id attributes, etc.) where needed make the scraper relatively simple. @MarkE
  12. We had a smooth rollout of the new main/master version 3.0.200 last week (read all about it here). If you haven't upgraded yet, consider doing so, this new version is a great upgrade. I'm going to add the 3.0.200 tag shortly after I finish this post, which should trigger other services (like packagist) to upgrade. I've had a new client project in the pipeline that I've been waiting to start till the new main/master version was out, so this week I started that project. Pete and I are working together on it, like we've worked on others before. It involves taking a popular WordPress site and rebuilding it completely in ProcessWire. I've done this a couple times before, but this time it's bigger and broader in scope. I always find the large site conversions to be great learning experiences, as well as great opportunities to show how ProcessWire can achieve many things relative to WordPress, in this case. At this stage, I'm having to spend a lot of time in WordPress just to get familiar with the content, fields, etc., as well as in the theme files (php and twig). The more time I spend in these, the more excited I get about moving it into ProcessWire. For this particular site, moving from WordPress into ProcessWire is going to result in a big boost in efficiency, maintainability, and performance. Part of that is just the nature of PW relative to the nature of WP. But part of it is also that the WP version of the site is kind of a disorganized patchwork of plugins, code files, and 3rd party services, all kind of duct taped together in an undeniably confused, undisciplined and fragile manner. (Though you'd never know it by looking at the front-end of the site, which is quite nice). This has been a common theme among WordPress sites I've dug into. Though to be fair I don't think that's necessarily the fault of WordPress itself. I always enjoy taking a hodgepodge and turning it into an efficient, performant and secure ProcessWire site. I love seeing the difference it makes to clients and their future by taking something perceived as a "necessary liability to run the business", and then turning it into the most trusted asset. I think the same is true for a lot of us here. We love to develop sites because it's an opportunity to make a big difference to our clients… and it's fun. Ironically, if past history is any indicator, I seem to get the most done on the core (and modules) when I'm actively developing a site. Needs just pop up a lot more. I don't know if that'll be the case this time or not, but I do expect to have weeks with lots of core updates and some weeks with no core updates, just depending on where we are in the project. This particular project has to launch phase 1 by sometime in July, which is kind of a tight schedule, and that may slow core updates temporarily, but who knows. I'll share more on this project and what we learn in this WP-to-PW conversion in the coming weeks. Thanks for reading and have a great weekend!
  13. @creativeguy Usually this behavior indicates that the site is missing an .htaccess file. Check your /Applications/MAMP/htdocs/giftfunds/ directory to make sure there's an .htaccess file in there. I'm guessing there isn't. If you don't have a copy of it, you can get it from here and then rename it to ".htaccess" (with the period in front).
  14. @bernhard Just tried to setup that situation and duplicate it but not seeing it. My best guess is that something is later overriding your $config->noHTTPS. But I would suggest not using $config->httpHost at all and instead changing it to: $config->httpHosts = [ 'localhost:8080', 'localhost' ]; …just in case the the port isn't getting communicated in the host name. You can also set your $config->noHTTPS to be conditional for the host names: $config->noHTTPS = [ 'localhost:8080', 'localhost' ]; Another thing to look at is to use your browser view-source to view those page editor view links to see if they really are https links in the source, or if something is changing them after the fact (or browser interpreting them as https due to a current or cached former .htaccess rule). Try manually setting $config->https = false; in your /site/config.php to see if that makes a difference. Do a bd($_SERVER['HTTP_HOST']) to see how the http host is communicated to PHP, just in case it's different from what you expect.
  15. @olafgleba Edit your /site/config.php file and look for: $config->httpHost and/or $config->httpHosts. In most cases the $config->httpHost should not be present (since PW will set it automatically at runtime), but the $config->httpHosts (plural) should be present, and it should be an array of http hosts ProcessWire is allowed to auto-detect and use. It will pick one of the hosts in that array to use for the request, so long as it matches the $_SERVER[HTTP_HOST]. If it can't find one that matches the $_SERVER[HTTP_HOST] then it will simply use the first one in your httpHosts array: $config->httpHosts = [ 'www.company.com', 'dev.company.com', 'localhost:8888' ]; If it just contains one host then it'll always use that one, regardless of what's in $_SERVER[HTTP_HOSTS] … $config->httpHosts = [ 'www.company.com' ]; If you do have the non-plural $config->httpHost present (like below), then it forces use of that hostname, rather than letting PW auto-detect from your httpHosts array. Though if there's only one host in your httpHosts array (like above) then of course the effect would be the same. $config->httpHost = 'www.company.com'; My best guess is that you either have $config->httpHost or httpHosts set with '127.0.0.1', or that you have httpHost/httpHosts undefined in your /site/config.php file. To fix it you need to add your www.host.tld to a $config->httpHosts array and preferably as the first item in it. If you do see a $config->httpHost (non-plural) in your config.php them I would remove it.
  16. @ttttim In my experience a 504 gateway timeout comes prior to PHP max_execution_time and may not even be related to it (?). Which is to say, I think it's a server timeout setting that is probably specified somewhere in Apache or prior, rather than PHP. But my experience with 504s is mostly limited to this server we are typing on, and in the case of this server, I will get a 504 timeout on a long running process and the 504 comes from the load balancer rather than the actual node that is running the script. So when a 504 occurs here, it just breaks the connection with the browser but the script continues running till it finishes, interestingly. I have no idea if your case is similar, but one thing I can suggest in your script is that you call PHP's set_time_limit(600); within your long-running loop to reset PHP's timer on each iteration (600=10 minutes, or a different time if it suits you), otherwise you likely will be subject to PHP's max_execution_time as well.
  17. @JerryDi I don't think there's a right answer as to what would be the best structure for your case. It really comes down to your needs, which I don't have enough familiarity with this to give an ideal answer. You'll be able to build your search for championships by club, player, etc., either way, as PW will make that simple. You can have any kind of parent/child relationship for those championships such as… /years/year-num/championship-name/ /clubs/club-name/championship-name/ …and so on. But another route to take (and what I might recommend here) would be to have a /championships/ parent and have all the championships under there, perhaps auto-sorted by year. Each with fields for "year", "club", "players", etc. /championships/championship-name/ And perhaps fields like "club" and "players" on each championship page would be page references to other pages setup in a similar structure: /clubs/club-name/ /players/player-name/ …and so on. Taking this route (where all championships share a common parent) may not be perfect for any one need, but will likely be a good fit for a diverse range of needs, a solid choice overall. So without knowing the details of your needs that's the route I'd probably take.
  18. @Manaus This is a case where you should do a 302 redirect $session->location($article->url); rather than render different articles at the same URL. Otherwise folks won't be able to accurately bookmark it, and it'll confuse search engines, so it'd be an SEO problem. But I'll assume you know that and you want to do it anyway. What Zeka mentioned above is a good way to go, and probably the one I'd choose. But here's also another option below. It assumes you have a "latest-article" template and it is used by the page /latest-article/. /site/templates/latest-article.php $article = $pages->findOne("parent=/articles, sort=-created"); if(!$article->id) wire404(); echo $article->render(); If you are using prepend/append template files, then you'd also want to check the box to disable them in Setup > Templates > latest-article > Files (tab).
  19. @Robin S @bernhard @teppo I would say it's less important to limit how many fields you create than it was before, but it's still worthwhile to make efficient use of fields for other reasons (at least for the way I work). But the technical reasons for doing so appear to be much less than before. If you look here at the performance numbers on a system with 1000 fields you can see that prior to lazy loading, it took 0.5167 ms (half second) to load the fields. This might sound reasonable, but note the fields were created with an automated script and not as diverse as they would be in a real environment, so I'd expect the numbers to be higher/slower in real life. After lazy loading that part of the boot process was reduce to 0.0062 ms. Even without lazy loading enabled, the field loading was reduced to 0.0322 ms (in that 1000 field environment) just due to the other optimizations made in support of lazy loading. So there's some question as to whether lazy loading is even necessary anymore now that everything else more optimized. But using less time and energy is always good thing, even if not felt on individual requests, small differences add up to significant numbers over thousands of requests. The way lazy loading works is that everything in the database table (for fields, templates, fieldgroups) still gets selected and loaded, but into an array rather than into objects. That data doesn't get loaded into and converted to actual Field (or Template, Fieldgroup) objects until that specific object is requested. TheTuningSpoon found that overhead came from actually creating and loading the objects rather than selecting them from the DB, and I was able to confirm that. But it also means that the more fields you have, the more memory they will consume. But the memory consumed by the raw field data is very little and I think you'd have to have many thousands of them for it to even be a consideration. Lazy loading fields don't change the way I use fields, at least. I like to have as few fields as necessary just because it's easier for me to keep track of, fewer things to remember when writing code, fewer things to manage during changes, etc. But if your workflow is like the one Bernhard describes above then that seems like a case where more fields would appear to be a benefit.
  20. This new main/master version has more than 220 commits, resolves more than 80 issues, adds numerous new features, performance improvements and optimizations, and consumes HALF the disk space of our previous release— https://processwire.com/blog/posts/pw-3.0.200/ I've just merged the dev branch to the master branch so this new version is available now. I will add the 3.0.200 tag (which should trigger packagist and others) over this weekend or Monday.
  21. @chrismac That error seems to indicate that you might potentially be running a very old version of ProcessWire 2.x (last updated 7 years ago). While the module (ProcessHannaCode) is designed for ProcessWire 3.x (the current one). That's the only explanation I can think of for that error message, as there is no "ProcessWire\WireData" in ProcessWire 2.x versions. The only way to resolve this is to remove the files that were installed, removing the /site/modules/ProcessHannaCode/ directory that was added. This has to be done by someone with access to the server files, such as your web developer or someone with FTP access to the server.
  22. @Matzn Your TestModuleChild.module is overriding the getModuleConfigInputfields() of the TestModule.module and replacing it. In PHP, if you want the parent method to run, then you need to either omit the method completely in your child class, or call the method parent::method() so that it will run (like what you are doing with your __construct method). What you are doing currently is replacing the method with one that has no code in it. What I think you are wanting is this in your TestModuleChild.module: public function getModuleConfigInputfields(InputfieldWrapper $inputfields) { parent::getModuleConfigInputfields($inputfields); } After doing the above, now it will inherit the code of the parent class. And after calling that parent::method() maybe you want to add another configuration setting to it, i.e. public function getModuleConfigInputfields(InputfieldWrapper $inputfields) { parent::getModuleConfigInputfields($inputfields); $f = $this->wire()->modules->get('InputfieldText'); $f->attr('name', 'test_field'); $f->label = 'Test field'; $f->val($this->test_field); $inputfields->add($f); } But if you don't want to add anything new to the getModuleConfigInputfields() then just leave the method out of your TestModuleChild.module completely, and it will inherit automatically. Also, module configuration data should be defined with runtime calls, so I recommend you remove this: public $field_1 = "parent module property 1"; and replace it with this in your __construct(): $this->set('field_1', 'parent module property 1'); I see you are using static getModuleInfo() methods in your classes. In cases where you've got one module extending another, unless the child module literally does an include() at the top of the parent module's file, then you should define your child module's info in a ModuleName.info.php file like I described in my previous message (including the 'requires' statement), and omit the getModuleInfo() static method. Otherwise, if PHP/PW happens to include() the child module before the parent module, you'll get a fatal class error. By using a separate ModuleName.info.php, PW can learn about the module without having to load the class file, and it can see from your 'requires' statement that it needs to load the parent module before your child module, ensuring no fatal errors. If you can't do this, or don't want to, then make sure your child module does an include() or require() of the parent module's file, somewhere before your "class TestModuleChild ...".
  23. @DrQuincy Yes, sorry, it should be "return $this->halt();" rather than just $this->halt(), I have updated my example. If you don't do a return then it'll still do the same thing (see below), but instead it'll continue executing your code in that file after the halt() call. What $this->halt(); does is tell the current request not to render any more files. So if you call $this->halt(); from your template file, then it's not going to include any further files specified to render afterwards. For instance, it will skip rendering your _main.php file (if you are using one). But everything else about the request will continue normally, so it does a normal shutdown, etc.
  24. @Matzn ProcessWire classes are just PHP classes, so there would be no difference. Note that I don't think you can have a class named "Parent" as I think that might be a reserved word in PHP. I wouldn't bother trying to do an external configuration class. Start with an internal getModuleConfigInputfields() method, and when all works, then consider moving it to an external one if needed. Make sure your module implements the ConfigurableModule interface, indicated at the top of the class. I also think maybe you shouldn't try to extend your Parent module/class and instead should just write another module that pulls from the Parent module what it needs. Module inheritance is useful in many situations but it's not clear to met that this is one of those situations, though I could be wrong. This is fine the way you are doing it, but note that your class "Child" need not extend "Parent" given the approach you are using. Your "Child" module could just extend WireData instead, and the code in your myMethode() would do exactly the same thing.
  25. @DrQuincy Is this from a template file? You could do this: echo "<p>An error occurred!</p>"; return $this->halt(); That halts the rendering of output but lets PW finish everything else in the request. Another option is to throw a WireException. This will also halt the request but allow PW to still shutdown. The response is an http 500 error. The error message will be displayed if in debug mode or if the user is logged in and a superuser. throw new WireException("An error occurred!"); Often times on the front end a fatal error is about a resource not available, and a 404 is the appropriate response. So you can do this: throw new Wire404Exception(); or this does the same thing (I prefer this shorter version): wire404(); Lastly, while the above are preferable, it's also okay to do an exit() or a die(), is shouldn't break anything at least.
×
×
  • Create New...