
Vigilante
Members-
Posts
54 -
Joined
-
Last visited
Everything posted by Vigilante
-
Managing URL query strings when outputting links
Vigilante replied to Vigilante's topic in General Support
Ok that really helped. I can use the `$input->queryString(array())` method to good effect. The only problem is that I have to create links in an ugly way, all over my template, stuff like this: `<a href="<?php $page->url() . '?' . $input->queryString(['key'=>'val'])?>">Link</a>` I guess I could build a custom function but it would be nice to have all that rolled into one, something like `<?php$page->url(true, ['key'=>'val']);?>`. Where 'true' is something like "include segments and query string" and the array would add or replace a particular attribute. I actually did try to do a function but ran into trouble with scope issues or something, not sure, but the page just wouldn't load. So instead I have that long ugly url generation string above everywhere I have to output links on pages where query strings are important. I don't want to lose existing parameters when any links are clicked, and I want to easily update or add a new parameter as needed. And it all still needs to work with the automatically pagination function in PW. The pagination links can't erase any URL parameters either. -
What are the methods to sort/filter $pages query in front end?
Vigilante replied to Vigilante's topic in General Support
Yes, not sure why I didn't realize that before. Well for now I'm doing full page refreshes, it's ok for this particular site, but I would like to explore the ajax no-refresh solutions that can keep URLs in tact and support back/forward actions. -
I found one or two threads with similar issue such as this one: But that is 2012 and I wonder if a newer technique is built into the core yet. For some reason this feels really complex when it shouldn't be. Simple example, outputting a grid of stuff. It's paginated and I use query string for sorting and other values (i.e. "cat=100&sort=az"). The problem is when I need to output a standard link with another query string. I want to included existing query strings. Well this is easy enough as I can grab $input->whitelist->getArray() and then run http_build_query. But the problem is what if the query string is already there? I don't want to output it twice. So I have to take my array, check if the query string key exists, then change it, before running http_build_query. Then do this for every link I output everywhere on the page. I check if that query string is already in the URL, and add it if not, and then assemble a new link. It also becomes more difficult with logic when deciding if I need to add the question mark, or the ampersand. I could probably write a custom function and include it globally in the theme, but this should be easier! Something like a link builder. For example $input->makeLink($page->id, true, ['cat'=>100]); or whatever. But say, I need to make a link, set it to the current page, included existing query string, but set cat to 100 whether it already exists or not. If the current page is "/page/page2?cat=100&sort=az" and they click a link to sort z-a, it just needs to keep the same URL, realize sort is already there, change it to za, and return my string URL to put in a link. Perhaps `<a href="<?=$input->makeLink(['sort'=>'za')?>">Sort ZA</a>`. And it would output current page with existing query string, changing or adding sort to za. Of course, such a function could make use of $input->whitelist too, whatever it may be. If a function like already exists, I haven't found it. But I must be missing something or an doing this the hard way. I've got foreach and if blocks all over my template just trying to place links here and there without messing up the query string. Help!
-
One of my specific problems is a page field array (multi select). There seems to be no way do this: `$pages->find("template=foo, categories=$var");` If $var contains an ID, it works. But if I'm not trying to filter categories and $var is empty, the result is inconsistent and wrong. I've tried setting $var to blank, empty string, null, false, 0. No matter what, it doesn't work. In my case, if $var is empty and I'm not trying to select categories, then I want it to select ALL categories. In other words, doesn't matter, as if it didn't exist. Just select everything. But that's not the case, I can't find any way to set $var so that categories= is basically ignored.
-
What is the best way to do query strings when you need multiple variables? `$pages->find("template=foo, $a, $b, $c");` My problem is multi-fold. If I set the variable to just the value, like $a = 10, and I do `template=foo, field=$a` I find that I get different results if $a happens to be empty. $a might be 10, but it might be an empty string. I found that "field=$a" would return 199 results while not having field in there at all would return 200 (the correct number). Why would field="" return one less entry? So what I started doing is putting the whole thing in the string like `$a = "field=10"` so that I could just drop it in `template=foo, $a` and this worked. The problem is the commas! If $a is just empty then now I have `template=foo,` with a comma for no reason. Compound that by the fact I want multiple variable query strings and then, where do I put the commas? I can do it in the variable like `$a = ", field=10` but then I have to have the variable smashed up against previous arguments like `template=foo{$a}{$b}{$c}` and it just doesn't look as nice. Another thing is that I'd rather have the raw value in my variables. For example I'd rather $a = 10 than $a = ", field=10" because then I can't reuse $a anywhere to reference 10. So where do I store "field="? It seems to me PW doesn't like having arguments exist with empty strings since I get different results that way. Ideally I want raw values in the variable, $a=10, $b=bar. And then I want a nice and pretty query string that returns accurate results whether those variables contain a value, or are empty strings or even uninitialized or null or whatever other conditions the logic might have. Anyway, all that to say, what is the best way to use many possible variables in a query string which might have values and might not? Which looks nice, and is most useful in code.
-
What are the methods to sort/filter $pages query in front end?
Vigilante replied to Vigilante's topic in General Support
I wonder if segments are the best in my case given that it could potentially have more than just alpha sort. Right now I'm only sorting a list of companies, so alpha sort is probably all I'll need. But on the same site will be a catalog of products, and of course that could have a dozen different sortable/filterable values. I don't want URLs like page/a-z/blue/under-100/newest/.... The classic URL properties would work best I think. Plus segments are not really hackable. In the above URL, what if they don't sort by under-100 and that part is missing? I would have to test every segment to figure out which filter it is, in what order. -
What are the methods to sort/filter $pages query in front end?
Vigilante replied to Vigilante's topic in General Support
That's cool but seems to be a Shopify plugin. I would prefer the endless click one to load more, but that does mean it's not so easy to bookmark or link to page 4 or 18. To come back to the page only to have to click 'more' 6 more times is annoying without very robust URL hashing techniques. It's overkill for this project. So I'll stick to either classic page-refresh pagination, or an ajax based no-refresh pagination as long as the URL works for it. -
Not in this case. They don't want the category to appear in the sidebar at all if it's empty. This way it avoids the frustration of user clicking a category first just to be told it's empty. Rookie mistake I guess, I've seen this way used in examples. Is $page->children more performant than the $pages->find query? I think I did the query this way because once a person clicks on a category, the sidebar will change to show the subcats of that one only. Same diff I guess. I'm wondering that myself. I see no noticeable lag but I do cringe at the idea of having to lookup every single page in a loop, it's not a lot of queries now but I really wouldn't want to do it if it were hundreds, or thousands of iterations. I'll keep $database and the connect page fields options in my pocket for later. Thanks
-
This is a pretty typical thing. Open a page, it does a $pages query, finds 112 things and I list them on the page. There is pagination too, 20 per page. I want a sort dropdown box so the visitor can change alpha sort or whatever other sorts and filters I eventually use. My first thought is to just refresh the page with a url query like "page/?sort=az" and then adjust the query in the template code. But to do this, it will require a page refresh, which means the sort box goes back to its default, and not sure how it effects pagination. If I do a page refresh, I'll have to keep the sort settings in the session or something, to make sure I always apply correct sort on page load. But at the same time, I've already got the $pages array, it would be much nicer to shuffle it and update the page without a page refresh, rather than run the query over and over again. But then again, the pagination buttons already cause page refreshes, so that is already happening anyway, unless I convert the pagination buttons to also be no-refresh somehow. I figure this is a very common problem, to paginate results and give users a sorting/filtering option. What is the common methods for handling it? Session, url query, ajax? If I just add the sort to the url query, how do I make that work in the pagination links?
-
How do I get summary of pagination like '11-20 of 200 results'?
Vigilante replied to Vigilante's topic in General Support
Thanks, that makes sense, but templates are edited in the file system. Do we have access to the file system templates of the skyscraper demo? Or is there a way to view the template files from the demo admin? -
I'm using pagination but I want to place a summary text somewhere in the template. Basically my query has a limit=20 so somewhere on the page I want to say something like "Showing 21 through 40 of 290 results". I can get the total results by doing my query again with $pages->count() unless this is not performant? But how do I know that I'm viewing 21-40 results? And on the last page where it might not be returning a full 20 pages, it would probably say something like "Showing 281-290". I thought I could just do some math using the $input->pageNum and then calculating based on my limit=20. This just seems messy somehow. I'm looking for a better way unless there is no better way. Thanks
-
Is that really the way to solve this? In normal SQL this feels like it would just be a simple JOIN query. SELECT * FROM categories JOIN blogs ON [???blogs.categories = categories.title???] Is there no way to do a JOIN-like query in PW? With the strict separation of pages in the page tree, I would think this a common need. I'm only dealing with 20 or 30 categories but I can imagine needing to join up two different parents where there might be thousands and thousands, and that would be a bear to iterate over just to filter it down! Even the connect page fields plugin wouldn't help if you want to cross-related dozens or even hundreds of entries. Maybe I'm just missing something. Could I assemble a MySQL query directly to solve it?
-
I guess my previous question really doesn't matter though. I need to test each individual category to see if it's contained in the field, not just check my entire category pagearray to see if "something" is in there. That doesn't actually help! So my original question still stands. Can test each category one by one in a more performant way, perhaps in the original query for the categories? $catlist = $pages->find("template=category, parent=$page->id"); Simple query, gets all the category children of currently open category. But can I exclude any that are NOT contained in a page reference field in 'template=blog'?
-
I figured out how to do it via looping but like I said, I don't want to have to run this many queries, here is the working code: foreach ($catlist as $cat) { if (!$pages->count("template=blog, categories=$cat")) { continue; } // Some HTML output } The problem here is that I run $pages->count over and over again. I don't know if that's a performance hit, it might loop anywhere from 5 to 30 times. My question is, in the selector "categories=$cat", can I do this selector on the entire pagearray? Like "categories=$catlist"?? Will PW do its own internal looping to see if any page in the pagearray is in categories field?
-
I'm wondering about creating a query that involves looking across two different parent page trees. One parent is for blog posts and it has each post under that. Another parent is used for categories and subcategories for the blog. Then in the blogs there is a page field that can reference the categories. This is all pretty normal setup so far. I created a navigation that lists the current category and its children, but I want to not show categories that have no posts. For some reason I'm drawing a blank. So let's say a user clicks category1, and it shows a blog listing for that category. I query for all the child categories of the current one. Now I want to exclude any categories where NO blogs exist that make reference to the category (an unused category). How do I do this in a way that is performant? I don't want to have to query the blogs tree over and over to test for the presence of each category in the list! Here is the tree: blogs - article1 [pagefieldcat = "cat1"] - article2 [pagefieldcat = ""] categories - cat1 - cat2 Now when I get all children of categories, I want to exclude cat2 since it's not referenced from any blogs. Can I do this without having to loop and query every category against every blog one by one? Thanks
-
Just a noob question here. I installed a fresh copy of PW and getting started on a new site. I was just wondering if composer.json (Composer in general) is necessary for PW to function. If I don't intend to use Composer with the site, is this still required? The default composer file doesn't really do anything except require ext-gd and point to the autoload file. But if I don't run Composer commands, it's not installed on my host, then why have it? I didn't see in the install docs whether this is needed or not, so I'd rather just delete the json file if unused and keep my file system clean.
-
After posting this question and continuing to search for answers, I did come across one passing statement to that effect. I don't know why this isn't better documented somewhere. I did turn on segments and then coded some logic to pick the right page to render. For anybody curious here is what I ended up doing. First, I added a universal file to be loaded before any template, using the site/config.php variable: $config->prependTemplateFile = '_init.php'; Then in _init.php I added the hook: wire()->addHookAfter('Page::path', function($event) { $page = $event->object; // Array key is slug to be removed, value is subpage for which to remove it. $pagesForRoot = [ '/aparent' => 'adjusted-page', // Remove /aparent but only for adjusted-page subpages // add new slugs and pages as needed ]; $the_url = $event->return; foreach($pagesForRoot as $url => $subpage) { if(strpos($the_url, $url) !== false && strpos($the_url, $subpage) !== false) { if (str_replace("/", "", $the_url) != str_replace("/", "", $url)) { $the_url = str_replace($url, "", $the_url); // Sanitized without slug } $event->return = $the_url; // Possibly return original slug if it's the landing page } } }); Then in the template where the segments are controlled I added some logic: if($input->urlSegment1 == "adjusted-page") { if(count($input->urlSegments) > 1) { $path = $input->urlSegmentStr; $post = $pages->get("/removed-slug/".$path."/"); } else { $post = $pages->get("/removed-slug/".$input->urlSegment1."/"); } if($post->id) { echo $post->render(); } else { throw new Wire404Exception(); } } else { // normal output of the page } I feel like the code could be better, there is disconnect between the logic in the _init file and then the page controller. Like I have to adjust for my removed slugs twice or something. If I add any more removed slugs, the logic in the page is going to start getting silly. But this is a start, and it works.
-
I know this issue has come up a few times before, I've read those posts, I've tried the technique but I must be missing something. Plus those posts are years old and maybe PW has different hooks and functions now? Anyway, this site has a page that has existed for a long time under root, i.e. /supercool. The page also has 1 and even 2 layers of subpages like /supercool/athing/apost. In other words, it's a big and important section of the site. But the site is growing and we have to consolidate and organize pages, menus etc to be more efficient. So supercool is going to be moved under a new /resources/ page. The problem is we want the URL to not change, nor for all the subpages. We still want /supercool/athing and not switch to /resources/supercool/athing/apost. I tried using the wire()->addHookBefore('Page::path..... method and this does change the path of all the links found on the website. In other words, a link in the footer at first changed to /resources/supercool but after using the hook it now says /supercool/ again, great! But it won't render, I just get a 404 page. I tried the technique found here to add some logic to the home page template but it does nothing, like it's ignoring the tests for segments entirely. So that said, the Page::path hook technique is working to change the URLs as found across the site, but I just get a 404 on actual page load. How do I complete this so that /supercool/ will load from its new URL location?
-
How to let end users change order of fields?
Vigilante replied to Vigilante's topic in API & Templates
This could work as long as I only include fields that are actually sortable. For example the page title itself isn't sortable, only particular wysiwyg or other fields would be included in the sort feature. And then in the template I guess I could just read this one sort list, and as I parse the values, those values would have names corresponding exactly to the other fields? In other words, I just loop the sort list values and immediately invoke each field referenced? I'll have to play with this idea. Because the concept of sorting fields feels more valid than trying to do a kind of page-based repeater field thing. It's not really something repeating, it could be totally different sets of content! Sorting feels more correct. -
How to let end users change order of fields?
Vigilante replied to Vigilante's topic in API & Templates
Both of those seem to hint at this kind of arrangement. I would only fear that I'm hiding a lot of the page layout and content within these repeater fields that the client has to navigate and click in to see any content. A small price to pay I guess. Versus having all the content in top level standalone fields. -
I'm not a super pro at PW so go easy on me. I think PW is great in the way you can simply create all the fields needed for a given template and then go make the template how you wish. BUT! The thing that is missing is that it's too dependent on the developer who has to change the template code for every small adjustment to the fields. For example. Let's say I create a couple custom fields. Both are repeater fields for something like testimonies, and another for 'clients who use us'. The field order in the backend doesn't matter, but when I design the template, I might have testimonies at the top and clients block just above the footer. But now the client/user decides they want to move the testimonies block down and change the position of clients. In other words, move the custom fields around a little. This cannot be done because where the fields go in the template is essentially hard-coded. I have to go in the template, change the HTML structure and rebuild the sections and CSS grid and everything to put the fields in their new location and make it look right. I feel like this is more rigid than it needs to be. If this is a modern site, then most of these "sections" are just full width blocks. So why shouldn't the user be able to stack the blocks however they like? It seems the only way to give the user more control is to start getting hacky with how the custom fields are set up. Perhaps instead of custom fields, put the content in hanna code so they can move the tags around? Or create another custom field to define a source order and then build a bunch of logic in the template? Is there a normal method of designing a template that gives the user some control over the position of fields/blocks/sections/content/whatever? -------- I also got to thinking how can I set up a template and fields to create content that alternates between full-width and column-width content? A client has a page design where they will have limited-width text content blocks followed by full-width images, followed by text again, and then full width, etc. With a CSS grid template set up, I can't simply output the plain contents of a wysiwyg box. Nor can I create 20 custom fields that alternate between limited and full width sections. How would I accomplish this so the user can write some paragraph content that gets put in a CSS grid column, but then alternate with full-width blocks and images that have no container or grid limitations? There doesn't seem to be a way to logically do this kind of content in a single wysiwyg box, nor by using a bunch of separate fields. Would I require shortcodes or hanna codes or maybe a repeater field? I don't know.
-
Good. Looks like whoever built this injected an alternate template engine and so the e() function belongs to the template engine. That's why it references "$this" instead of using the normal $page object of PW. Thought I was going a little nutty for a minute!
-
I'm taking over working on an existing PW site. I see the function e() used a lot in the templates but I can't find info on it. For example $this->e($page->get('something|other')) As you might imagine, trying to search for the letter "e" anywhere doesn't get me very far. I've looked high and low in the API docs and tried to search through source files for the function definition. I'm not even sure it's a PW function at this point. I assume in these templates that $this refers to the PW object, and I couldn't find e() in the docs. The way the code is written makes it seem like it's just a function to prepare output to the browser, perhaps it's an HTML entity encoder or something? Is this a PW function and where are the docs?
-
I will have to give that structure a try. So basically turn off the root Core Page and don't put content in it. Then have Home under Core, then everything else branch from Home itself. I'll let you know how it goes. I still don't need any kind of /home/ URL though, so I need that Page to be the root URL of the site. Maybe I missed how to do that.