Jump to content
Vigilante

Can $pages->get() be used with a path with segments? Returns 404

Recommended Posts

I have segments turned on for the root/home page. This is because I'm doing some custom routing to remove a path from the URL.

One of the grandchild pages itself has segments turned on.

So when I'm doing my custom routing from the home page, I look to see if the URL is valid by using a standard get lookup on the segment string. Something like `$pages->get("/myroute/".$input->urlSegmentStr()."/");`

The problem is, the segment string may have a path that itself includes segments, like "/route/allows-segments/segment".

So get() returns nothing, essentially going to 404, because it can't find that path which has a segment in it.

Is there a way to make get() smart enough to see that even though /segment/ isn't found as a page, its parent /allows-segments/ has segments turned on and thus it can get that page instead?

I already programmed my workaround, it's not that big of a deal. I had to specifically test for the segmented URL though. Luckily I only have one page like this, but I can see it being an issue if I had a lot of them.

Perhaps get() needs some kind of options (or another finder function entirely) that can deal with paths with segments. Where it will process the path and check for segments, returning the proper page.

Share this post


Link to post
Share on other sites
16 hours ago, Vigilante said:

Perhaps get() needs some kind of options (or another finder function entirely) that can deal with paths with segments.

$pages->get("selector") is not designed to be a Swiss Army Knife of solving custom routing logic or similar for that matter.

16 hours ago, Vigilante said:

Where it will process the path and check for segments, returning the proper page.

I think such a need is to broad to be implemented without knowing the actual logic required for a particular use case, so I cannot see how it could be standardized.

  • Like 1

Share this post


Link to post
Share on other sites
On 3/21/2018 at 2:48 PM, szabesz said:

I think such a need is to broad to be implemented without knowing the actual logic required for a particular use case, so I cannot see how it could be standardized.

I don't think it's that broad or mysterious really.

Let's say I have a path as a string that came from somewhere or is auto generated, etc. Something like "/this/should/be/a/page". 

Now I just need to check if that's a valid URL or not. If I simply throw it in get() it will return 404 because it won't find that exact hierarchy in the page tree.

It would be a relatively simple thing for the code to knock off "page" and instead search for "/this/should/be/a/". And if that doesn't exist, look for "/this/should/be/" and then bingo. If "be" exists, PW checks to see if segments are turned on and if they are, check if segments are limited to certain strings. If not, then get() ultimately would return the "be" page.

Of course, all this should be optional. So the default get() would return 404 as it does now. But if you had something like `get("/this/should/be/a/page/", array("look_for_segments"=>true));` then get() would search and return a segmented page if that exists.

 

The bottom line is this, I'm looking for a page "this/should/be/a/page/" which is a totally valid URL ("be" has segments turned on). But instead PW tells me it's a 404 not found. That automatically says something isn't right here. I can't have PW telling me a URL is a 404, but if I actually GO to the URL, it works fine due to segments.

The PW routing system already knows how to handle URLs with segments, I'm just thinking that functions such as get() need to make use of that logic as well.

It doesn't even need to be get(), it could be an alternate function, perhaps gets() where the 's' stands for "segments" and it will return the page relating to a URL where segmented pages are searched for and not just precise page tree location.

Share this post


Link to post
Share on other sites

You're mixing up routing and $pages->get($path), which are totally unrelated. The Pages class is using the PageFinder to retrieve pages from the database. In no way is that operation concerned with url segments or any routing operations. Url segments are resolved as part of the ProcessPageView module, which is doing the initial matching of request url to an actual page in the database.

  • Like 3

Share this post


Link to post
Share on other sites

yep, and if you are doing any custom routing, you can write your own function to get the real page, my theme engine module includes a getVirtualPage() method that can find real pages based on conditions of the segment(s), which templates exist at each segment level, using name matching combined with template; this doesnt help if you are rendering real virtual pages like tag, category or archive filters, or feeds etc.

	/**
	 * Given an array of expected templates used at each segment index, return the page we are on
	 * @param  array  $segmentTpls [plain array of template names used for segments]
	 * @return [Page]
	 */
	public function getVirtualPage(array $segmentTpls) {
		$pages 		= wire('pages');
		$sanitizer 	= wire('sanitizer');
		$input 		= wire('input');
		$maxSegs	= count($segmentTpls);
		$segsCount	= count($input->urlSegments);

		if($segsCount > $maxSegs) return false;

		if($segsCount) {
			$lastSeg = $input->urlSegments[$segsCount];
			$segPlate = $segmentTpls[$segsCount - 1];
			$pageName = $sanitizer->pageName($lastSeg);

			$vPage = $pages->get("template=$segPlate, name=$pageName");
			return $vPage;
		}
	}

 

  • Like 2

Share this post


Link to post
Share on other sites

It's not that I'm doing "custom routing", it's that I want to return the correct page that handles a particular URL.

If I have "/some/page/here" and I "look it up" with whatever function might exist, it should return "/some/page/" if that is the correct page that handles that particular URL (because segments are on).

I'm not trying to do custom routing here, I'm trying to lookup the correct page that handles a given URL.

 

I'm only talking about routing because the PW router obviously already uses/has this logic. It knows the correct page to open for a given URL. I'm simply looking for similar function in the API that works like get(). I pass in a path and it returns the page that handles it. For some reason I thought this would be a pretty common thing to want to do, unless very few people make use of segments?

Share this post


Link to post
Share on other sites
2 hours ago, Vigilante said:

It's not that I'm doing "custom routing", it's that I want to return the correct page that handles a particular URL.

you can just pass the path of the page that handles the segments; if you are on the page, then $page is what you want.

2 hours ago, Vigilante said:

If I have "/some/page/here" and I "look it up" with whatever function might exist, it should return "/some/page/" if that is the correct page that handles that particular URL (because segments are on).

how can the system know which part of the URL is the segment? The whole point of URL segments is that they are not real pages, so there is no way to "look them up".

  • Like 1

Share this post


Link to post
Share on other sites
8 hours ago, Vigilante said:

I'm simply looking for similar function in the API that works like get(). I pass in a path and it returns the page that handles it. For some reason I thought this would be a pretty common thing to want to do, unless very few people make use of segments?

All the logic you're talking about here is already there that's true, but it's quite inacceasable in the ProcessPageView class. 

Share this post


Link to post
Share on other sites
17 hours ago, Macrura said:

you can just pass the path of the page that handles the segments; if you are on the page, then $page is what you want.

Yes, if I build the logic myself to parse a given URL string and figure out which part of the path goes to the segmented page. I just thought a function like this might have already existed.

 

17 hours ago, Macrura said:

how can the system know which part of the URL is the segment? The whole point of URL segments is that they are not real pages, so there is no way to "look them up".

The logic would handle that. If "this/is/long/url" is a 404, then it looks for "this/is/long" and if that's a 404 then it looks for "this/is" and if it finds a page here, it would then check to see if segments are on. Then if so, it would return "this/is" as a page object. If segments are not on for that page (or accepted segment strings are defined and my string doesn't match them) then it would also return a 404 and give up.

Obviously this kind of recursive checking would be more costly in processing so that's why a dedicated function or a switch would turn it on only when necessary.

Share this post


Link to post
Share on other sites
38 minutes ago, Vigilante said:

I just thought a function like this might have already existed.

It's ProcessPageView::getPage(), but it's a protected function and therefore not for public consumption as per right now.

  • Like 2

Share this post


Link to post
Share on other sites

The method @LostKobrakai mentions above gives you a clue about how you can make a simple function for the purpose...

// Get the page from a path which might include URL segments
function getPage($path) {
    $page = wire('pages')->get("path=$path");
    if($page->id) return $page; // If the path matches a page return that
    $pieces = explode('/', $path); // Break the path into pieces
    while(!$page->id) { // Until a page is matched...
        array_pop($pieces); // Pop off the last piece (a URL segment)
        $path = implode('/', $pieces); // Make a path from the remaining pieces
        $page = wire('pages')->get("path=$path"); // Try and get a page at that path
    }
    return $page; // Return a matching page or a NullPage if no match
}

If you wanted to get the URL segments from the path it would be easy to modify the function to return those also.

  • Like 2

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By pwFoo
      With JS fetch() it is a bit tricky to get for example $_POST populated (params need to be FormData / forms), but would it possible to get PW $input (get, post, urlSegments, queryString) working for fetch requests?
      Is there a fix / hook / workaround to solve it PW side?
    • By Klenkes
      A client wants to use landing pages coming from Google ads, and needs to hand over a keyword and a title for the landing page.
      The URL would look like this: ..../l2/keyword/Funny title with løts of special chåracters änd spaces/ (Just an example)
      I tried to encode the URL in different ways but not even spaces work and result in a "404 Page not found".
      Then I found this Github issue: https://github.com/processwire/processwire-issues/issues/720
      At least I know that I am not the only one with this kind of problem.
      The client is a very pragmatic fellow and suggested to custom-encode the segments like: (don't try to read it)
      ..../l2/keyword/Funny_S_title_S_with_S_l_o1_ts_S_of_S_special_S_ch_a2_racters_ae_nd_S_spaces/
      and then replace all the _S_ _a2_ with the REAL characters in the template.
      Mhh... well... sure I could do that, but I don't like it, and editors would have to write the segments with a translation sheet!
      Anyone have a better idea?
      PW 3.0.98 PHP 7.x
    • By ttttim
      I have a parent page containing a list of it's children. When you click on one of the children the page opens up in a modal box trough ajax. So far so good. 
      But if i directly load the page through the url (parent/child) i get the child page. Is there a way of loading the parent page instead with the child page opened inside the modal box? I was first thinking of using URLSegments so it would load the parent page with the child name as segment however since the segment is an actual page it will load the page instead.
      Any ideas?
×
×
  • Create New...