-
Posts
366 -
Joined
-
Last visited
-
Days Won
18
Everything posted by MoritzLost
-
[SOLVED] Sorting pages by Select Options title, not ID
MoritzLost replied to rash's topic in Getting Started
Have your tried sorting by the value instead? See Separate Option Values. If you have defined only titles so far, you can just add the values without having to change existing pages (since the values are stored by ID). Not entirely sure, but sorting by value might work (sort=direction.value). In any case, I have also found that the Select Options fieldtype is kind of lacking in selector support, and searching / sorting by values and titles does not always work. I now prefer custom page templates with page reference fields in most situations for this reason, they are way easier to use in selectors. -
After csv import site becomes almost unresponsive!
MoritzLost replied to Roych's topic in General Support
Maybe your site was infected by Drupal ? In that case you shall require an excorcist and some thoughts and prayers ... In all seriousness though, I can imaging an export from Drupal containing some huge chunk of random junk that somehow got dumped into one of your fields. Maybe a huge text block that ProcessWire is trying to parse (some of the textformatters use Regex with some backtracking, so very large texts could be a problem). Is the page still in the trash? In that case, some template or process might still try to load it, resulting in whitescreens. Maybe check the database, see if the pages table still contains the new page. And check the tables corresponding to the page's fields as well, see if anything unwieldy comes up relating to the imported page ... -
@JeevanisM @LostKobrakai That doesn't mean you can't have search, but it would probably be in the form of an external service or a serverless function. Algolia is the go-to solution for client-side search. Basically, you send all your content to their API during the build step, allowing them to index it. Then you use their API or their InstantSearch component to perform searches against their index. The search results then take you to the canonical URL of that content.
-
[SOLVED] Sort search results by most matching page field options
MoritzLost replied to alexm's topic in General Support
You can use the count selector to get to the number of selected options, and use a descending sort order to show pages with the most selected items first: $results = $pages->find('sort=-categories.count'); Add the rest of your selectors and replace categories with the name of your page reference field ? See Using selectors in ProcessWire -> Count selectors. -
Static site generators will probably be 'the next big thing'. You get way better performance and security by default than you could have with any CMS by definition. Which doesn't mean that you can't have dynamic content like comments, e-commerce etc. But instead of bundling that functionality, you're using external services, APIs, serverless functions and build automation to persist data and trigger builds whenever something changes. I'd recommend reading the Jamstack book (created by the Netlify people), you can get the ebook for free and it explains all the concepts related to SSG. By the way, you don't need NodeJS / NPM to have a static site generator. Though many SSG are built with JavaScript, they use NodeJS only as a runtime for the build step, not as an actual server. But there are SSG written in all kinds of languages - check out this site if you want to find one you like. One could argue, by the way, that the ProCache module for ProcessWire is also kind of a SSG generator, even though it works a bit differently than most tools on that list. My current recommendation is eleventy, I'm currently rebuilding a couple of my own sites as well as a ProcessWire-related project that I might release soon with it ?
-
Pager Render works but the query of pages isn't
MoritzLost replied to Pip's topic in General Support
Alright, I see. Though this makes sense, even if you include a different PHP template, you're still viewing a template of type "home", and ProcessWire uses the settings of this template to determine stuff like pagination, url segments, caching etc. For the record, this is what I meant by Have you made sure that the pagination option is active in both templates you need it in? ? -
Pager Render works but the query of pages isn't
MoritzLost replied to Pip's topic in General Support
@Pip Glad you found the cause of the issue, but could you clarify what you mean by your home is not allowed to do pagination? Is the option not active in the template? -
Not sure if this is documented anywhere, but you can use the RepeaterMatrixPage::matrix() to get the label: // get the label in the current language $page->my_repeater_matrix_field->first()->matrix('label'); In recent versions of RepeaterMatrix, you can also call RepeaterMatrixPage::getMatrixInfo() to get an array of information, including the label: $page->my_repeater_matrix_field->first()->getMatrixInfo();
-
Pager Render works but the query of pages isn't
MoritzLost replied to Pip's topic in General Support
@Pip Hm, the code looks good to me. Have you made sure that the pagination option is active in both templates you need it in? Other than that ... maybe calling renderPager() twice is tripping something up? Maybe save the result in a variable and output that instead. Also, you sort by ID? That's curious, are you relying on newer pages having higher IDs? In this case, maybe just sort by created date (sort=-created). And again, have you made sure there's no caching active on any layers? -
Not sure, but I don't think so. It's primary function is to list and edit existing pages. Might be there's an action for bulk import / creation, but I haven't seen it yet. But again, if your client absolutely needs something like that, why not build a simple interface that will allows them to batch create pages? See the example code above by @Kiwi Chris, it's literally that simple. I've even done some imports directly from the Tracy Debugger Console before, and it took like 15 minutes ... all you need is a couple of lines to create a new page, and then assign values using the field names in your template. Add an file_get_contents to read from a CSV file or something, a foreach loop and you've got your reliable and simple pages import.
-
textformatter Automatically link page titles
MoritzLost replied to MoritzLost's topic in Modules/Plugins
I just published version 4.0.0 of this module, a large update that makes it possible to completely customize the markup created for detected page titles. For example, let's say you have a glossary and want glossary terms that appear anywhere on your site to display a popover with the term's definition. This update allows you to do that! Previously, the module always created an <a> tag with an href attribute, and always checked if the page was viewable before doing anything. This update comes with configuration options to change the HTML tag, disable the automatic href attribute and disable the visibility check. This allows you to use the module for a wider range of use-cases. If you need even more control, the methods the module uses to create markup are now hookable, so you can customize the output format even further! Here are some additional links to help you get started: There's a new step-by-step guide for a setup with glossary terms with inline definitions. Both new hooks are documented with usage examples in the hooks documentation, learn how to customize the markup generated for titles and how to add attributes to the generated link / HTML tag dynamically. All the new options are available for manual usage, find the list of options here. Check out the CHANGELOG for version 4.0.0 -
Pager Render works but the query of pages isn't
MoritzLost replied to Pip's topic in General Support
You need to remove the start=0 from your selector. Automatic pagination works by automatically injecting the start parameter into all pages queries with a limit, based on the defined limit and the current page number. By including a start selector you overwrite this behaviour, forcing ProcessWire to not return paginated results for that query. See Pagination in ProcessWire, section "Are there any side effects?" If it isn't working without the start selector either, and it's just not working sometimes, it might just be a caching issue. -
@fruid I don't really understand your use-case. You say your client is going to use SQL to update the database, does that mean they are going to write raw SQL queries in front of a terminal? That seems like a really inefficient way to go about content creation, especially since you have to make sure your data fits within the constraints defined in the template and field settings. Despite that, you can still do that, you just have to add a couple of JOINs and be careful with your WHERE clauses. Each field table comes with a foreign key corresponding to the page ID. If your client is really some kind of SQL wizard who prefers the power of raw SQL for data migration over the limited interfaces puny mortals have to use, what's stopping them? Or do you mean "the client is going to log into phpMyAdmin / Adminer / MySQL Workbench / ... and insert data through that interface"? In that case, you're not really using SQL anyway, you're just using an interface that's closer to the database, that *may* be slightly more efficient to use for batch creation / updates if you really know what you're doing. If that's what your client wants – well, that's an interface you can build for them! Something like a batch update module that lists pages and allows you to edit them inline. In fact, such a module exists already: Lister Pro comes with inline editing for multiple fields at once. This gives you a convenient interface to update many pages at once and still stay within one backend and have all the input / constraint validation apply to your edits. Best of both worlds ? By the way, if you've ever tried to manually find something in a Drupal 8 database, you will like ProcessWire's database structure MUCH more ...
- 40 replies
-
- 11
-
It happens to all of us ? This is actually why I dislike the use of the magic methods like __call, because they make tiny mistakes like this harder to spot ... without the magic, this would just result in a clear, easy to fix error message, but with it it's way harder to figure out what's going on.
-
Not quite sure what's causing the recursion error, but your method is marked private, which means it can't be called from outsite. Because your page class extends Page which extends Wire which comes with a magic __call method that will be invoked in this case. That method tries to figure out what you're trying to do, since it's supposed to provide easy access to properties and methods of all Wire extending objects. The error call stack indicates there's something going wrong there. Making your getSummary method public should fix the issue!
-
@ryan Thanks for the reply! Sorry, I failed to mention that I'm talking about pasting text through they context menu (right-click -> paste). In this case, they keyup event is not triggered, because no key was pressed. Pasting with CTRL / CMD + V works fine. Great, thanks ? We use Twig for most of our ProcessWire sites, which comes with autoescaping. In this case, having the formatter on leads to double escaping, and it's easier and more consistent to have Twig handle escaping everything by default.
-
No, that's a common misconception. There's no security benefit at all (it can be bypassed super easily), but comes with multiple downsides (worse UX, higher chance of typos). It may even decrease security because it discourages the usage of password managers. See security.SE, NCSE and web.dev for reference. By the way that's only slightly related to this issue. The profile page does allow passwords to be pasted; but the inputs for the new password are only activated after the old password field has been typed into, and that event handler only listens for input events, not paste events.
-
Where exactly are you stuck? Differentiating between normal and AJAX requests, rendering content (are you doing that server- or client-side?), encoding the content for the AJAX response? An example of your current code and what's not working about it would be helpful. A couple of observations, in no particular order: The first thing I notice is that the infinite scroll library you linked seems to employ a non-standard way of doing "load more" buttons. Instead of requesting only the new items, it works with an existing classic pagination and just loads the entire next page, throws away everything but the new items and adds them to the existing container. While this does work, it's incredibly wasteful, loading entire pages just to discard most of them immediately. So don't let that library trip you up if you want to build "real" AJAX-powered pagination. What endpoint are you calling in your AJAX request? I remember some tutorials around here recommending to hit the same URL as a regular page view, and differentiating between normal page views and AJAX calls by checking the X-Requested-With header – in my opinion, that's not a good approach. It doesn't even work properly if you use the Fetch API (the modern alternative to XMLHttpRequest). Depending on how much side-loaded content you need on your site, I would either use a URL parameter (?ajax=1) or build an entirely separate endpoint (/api/events/...). The latter approach scales much better. Are you returning HTML or structured data from your endpoint? Depending on that: Returning structured data, i.e. a JSON-encoded object with information about the events is the cleaner way to go about this. But since the first five elements are already rendered server-side, that means you have to replicate your template-logic in JavaScript to create the same HTML structure that the server-rendered events have. Not ideal. In general, I only use this approach if the entire app is client-side rendered (like the Architekturführer Köln). Returning server-rendered HTML is not great, because it makes your API non-reusable (for example, if you want to display side-loaded events in different places with slightly different layouts, you'll need separate endpoints or parameters). It's also just not very clean to insert raw HTML into your page. Though it is a bit easier for simple use cases. I need to mention this: Do you really need to side-load your events? It's one of those features that clients go crazy about because it's "cool and modern", but why not use a regular pagination, which works out of the box and is also better for SEO? If the reason is that your visitors need to load too many pages this way, is there any reason why you can't just show 25 events per page instead of 5?
- 5 replies
-
- 10
-
Absolutely you can! You just need to get the page the repeater items are on, then you can access the repeater items on it. Based on your code above it should be simple: $id = 1234; // replace with desired page ID $alertspage = $pages->get(id); // replace "alerts" with your repeater field name foreach ($alertspage->alerts as $alert) { // do something with the repeater items ... }
-
Yes, this is called bootstrapping, see the documentation. Basically, you only need to include ProcessWire's index.php, then you can use the API as usual. The only difference is that you won't have access to the $page variable, since it's not a regular ProcessWire page request, so ProcessWire can't associate a particular page with it.
-
You $test variable may have been overwritten somewhere. In general, global variables are considered bad style because of their lack of scoping. For things you need to access from multiple places, I would either use the $config object or the setting() function: $config->myCutomSetting = 'test'; setting('my-custom-setting', 'test'); // use from anywhere, even within functions echo wire('config')->myCustomSetting; // 'test' echo setting('my-custom-setting'); // 'test' Note that the setting() function requires $config->useFunctionsAPI = true
-
[SOLVED] Settings fields that don't save to database
MoritzLost replied to jploch's topic in Module/Plugin Development
@jploch Exactly! Regular ProcessWire fields have both a fieldtype (responsible for storing stuff in the database) and an inputfield (responsible for displaying the input form element, validating the input etc). The hCaptcha module only comes with an inputfield without a corresponding fieldtype, because the captcha response doesn't really need to be stored. The module just needs to display some markup in the frontend and validate the input after submission, which is both done in the inputfield. Because you can't create a regular ProcessWire field without a corresponding fieldtype and database table (at least as far as I'm aware), an instance of the inputfield is inserted in the edit form through a hook. I don't think it will make any noticable difference, since the the inputfields need to be constructed for each page load anyway, regardless of whether they come from regular fields or a hook. Maybe a super tiny overhead because of the hook, but then we're talking nanoseconds ? -
[SOLVED] Settings fields that don't save to database
MoritzLost replied to jploch's topic in Module/Plugin Development
If I understand you correctly, you only need the inputfields to appear in the form, but you don't need actual tables in the database for persistent storage for those fields? In this case, I wouldn't create a new field at all, but instead add the inputfields you want using hooks. For custom inputs / markup you can use InputfieldMarkup, for everything else use the appropriate Inputfield module. This should work in any ProcessWire form context. For example, here's a hook that adds my InputfieldHCaptcha module to the edit form of a page in the backend: wire()->addHookAfter('ProcessPageEdit::buildForm', function (HookEvent $event) { $form = $event->return; $submitButton = $form->getChildByName('submit_save'); if ($submitButton) { $hCaptcha = $event->wire('modules')->get('InputfieldHCaptcha'); $hCaptcha->set('label', __('Spam Protection')); // ... configuration goes here $form->insertBefore($hCaptcha, $submitButton); } $event->return = $form; }); See InputfieldHCaptcha. Like that you should be able to add any inputfield you want to the form. This approach has the added benefit that you don't leave behind dead fields after your module is uninstalled. -
In CSV linebreaks are used to separate individual rows, so a linebreak inside a cell may cause problems. Depending on your CSV parser it could result in an error altogether, it may silently discard the newline, or it may handle it fine. As far as I know fgetcsv can handle newlines as long as the cell is quoted properly. Can you post an example of your CSV? Make sure the fields are properly quoted. Regarding the paragraph tags, that problem is the result of bypassing the interface and importing directly to the database. The textarea field doesn't care if it contains HTML or regular text with linebreaks. The HTML structure is created by the CK Editor during editing, so if you don't want to edit all imported pages manually, you will have to convert your body fields programmatically. This involves just using str_replace or a regular expression to replace newlines with paragraph tags. You can do that before the import (by modifying your CSV), during the import (apparently you can hook ImportPagesCSV::importPageValue) or after the import (by using $pages->find to find all imported pages, iterate through them and change the body field). Here's a quick and dirty code sample: $text = $page->body; $textHTML = '<p>' . preg_replace("/[\n\r]+/", "</p><p>", $text) . '<p>'; $page->body = $textHTML; $page->save('body'); You can get very sophisticated with that, like converting single line breaks into <br> tags instead and multiple linebreaks into <p> tags, but it depends on your requirements and source data.