Jump to content

Controlling page URL structure


Roope
 Share

Recommended Posts

I remember that I read something about this earlier but can't find any info now when it's needed.

I would like to drop some parent page names from URL structure but don't know how to do this.

Tree is like this:

- Products

  - Vendor

    - Product 1

And sysytem default URL for product page:

/products/vendor/product-1/

How can I setup templates so that I could have product page URL:

/products/product-1/

Or simpy:

/product-1/

Link to comment
Share on other sites

I would actually separate out each Vendor and each invidivual Product to be under their own tree like:

/vendors/vendorname/

/products/product-1/

You then just use a Page fieldtype to link products to relevant vendors: http://processwire.com/videos/page-fieldtype/ and then use code on the product name something like this to pull the vendor into the product page:

<?php
$productvendors = $pages->find("template=vendors, id=$page->vendors"); // Assuming you could have more than one vendor per product
$productvendor = $pages->find("template=vendors, id=" . $page->vendors->first()); // Or just one vendor


You can also do it the other way to view a vendor page and list all products they sell:

<?php
$vendorproducts = $pages->find("template=products, vendor=$page"); // Assumes your Page field is called vendor
  • Like 3
Link to comment
Share on other sites

Thanks Pete!

Actually vendor pages are not needed in front-end so I don't need any data from these.

We're building a site for our customer that holds product data from multiple vendors. We're planing to build some integration for product data import in scv-file.

Reason why I would like to have page tree structured like in the example is that it would be easier to locate products under each vendor since there can be thousands of items per each. I think it's too messy to mix all products from all vendors under same folder.

In MODX we're used to have setting for this in configuration. If URL paths is enabled, all pages use site tree like URL path structure. If disabled, it's just domain.com/pagename no matter where page sits in site tree. PW doesn't have this kind of feature?

What if we would use templates without template files as vendor folder? Then page wouldn't be visible in URL path?

We could still build inputs to admin area for csv import functions (using module) to this template am I right?

Link to comment
Share on other sites

You can't hide path in between unless you use urls segments.

Pete is right, and it will result in url segments anyway.

Sure you can build any feature other CMS have. You can build that with url segments too.

I would build it the way Pete suggested. You argument that it's not nice to manage under one branch, I have to say I would then build a admin page that let's you list per vender or category, like a data table. Everything possible with ease. See for example my data table POC http://modules.processwire.com/modules/data-table/

Link to comment
Share on other sites

Thanks guys! You have to give me some credit since love between me and PW is only couple of weeks old.

I think what happened here is that when I was looking first glance at PW admin I misunderstood URL segments. In MODX you can disable folder paths globally for the site and I thought URL segment would do same in PW for template basis. Shorty after I got URL segments right but still thought that I saw URL path option similar to MODX somewhere. Thanks for posting this article SiNNuT - haven't read it before and it clarified much about how to deal with URLs in PW.

I'm myself a big fan of short and simple URLs. I prefer much more URL like domain.com/drills than domain.com/products/powertools/drills for example. It's good to now I can achive this using URL segments but it needs some hard coding and extra work compared to build in feature (like described above).

With this project I'll do like Pete suggested and move vendors to seperate folder. All products can only belong to one vendor. Also product data from vendors come in different kind of CSVs. Info about vendor is something we don't want end-users to see. That's why first plan was to put products under vendor folders (to ease crawling for specific vendor data) and to put CSV import functionalities to vendor pages (that would be only visible for logged users).

Link to comment
Share on other sites

Sure you have to do some extra efforts but it's not that hard as it might first seems coming from others systems. No problem.

But this way you are in full control and can change it the way you like and are not restricted to some built in feature.

Link to comment
Share on other sites

What's the right way to build navigation links when using shorter URLs by URL segments? Page url still has folders in it so do I have to code links manually? Same with links inside richtext editor.

EDIT:

Or meta canonical tag: this will be pointing to uncorrect address if I make shorter URLs by URL segments:

<link href="<?php echo $page->httpUrl; ?>" rel="canonical" />
Link to comment
Share on other sites

Do you really think "domain.com/drills" is a good strategy? Have all pages on the root? You miss a lot of if you reduce it that way. There's no way to surely determine a single page name, because there can be multiple of it, and you can't control it anymore. I'd consider this for shortcut urls you use in print or something, but not as a general approach to the site on all ends.

At least have a category domain.com/powertools/drills/ that gives you powertools as a category.

There's maybe too many ways and scenarios with build a urlSegment system, and I would advise to use it only where really needed.

How you approach it also depends also a lot how you structure your page tree with what templates.

To construct some category/product urls segments are great. Where category is itself a page you use with a page field to categorize product. Then the category pages with url segments enabled and list products that belong to that category, or if url segment present show a detail page. That's how I use url segments to virtualize a structure that is different from the admin. But leaving the real url intact would sure make sense to use canonical urls or redirects to solve it.

You can alter the url path PW generates, so a hook into page::path or page::url would do the trick to strip out segments.

Once you have that url hook in place it would also effect the Wysiwyg urls generated. But this comes maybe with some overhead added to what might get called thousands of times, though not noticeable unless you go wild. 

You can also have the template file for those pages redirect to a shorter url and use that template only to construct it.

Link to comment
Share on other sites

As example to "rewrite" the url of certain pages, this is possible within the template code:

function segmentUrl(HookEvent $event){
    $url = $event->return; // requested url
    $pages = wire("pages");
    $page = $pages->get($url);
    $segment = $pages->get(1001); // get segment we want to strip
    // for example only for certain pages under a certain section
    if($page->template == "basic-page" && $page->parents->has($segment)){
        // set event return the stripped new url; /about/childpage/ becomes /childpage/
        $event->return = str_replace(rtrim($segment->url,"/"),'',$url); 
    }
}

$wire->addHookAfter('page::path', null, 'segmentUrl');
 

Or similar as in a autoload module (HelloWorld.module) it would be almost same code, just

$this->addHookAfter("page::path", $this, 'segmentUrl');
Link to comment
Share on other sites

domain.com/drills was there just for example - I'm not saying it would be best policy or anything. Now I know how to achieve this in PW way if I choose to do so.

Thanks alot Soma!

Link to comment
Share on other sites

The above example already has lots of overhead so the more optimized way would be to avoid as much get or find and template stuff and do something like this:

function segmentUrl(HookEvent $event){
    $url = $event->return; // requested url
    $segment = "/about/";
    if(strpos($url,$segment) == 0){
        $event->return = str_replace(rtrim($segment,'/'),'',$url);
    }
}
$wire->addHookAfter('page::path', null, 'segmentUrl');

Will be a lot faster.

  • Like 1
Link to comment
Share on other sites

  • 2 months later...

Hi Soma,

function segmentUrl(HookEvent $event){
    $url = $event->return; // requested url
    $segment = "/about/";
    if(strpos($url,$segment) == 0){
        $event->return = str_replace(rtrim($segment,'/'),'',$url);
    }
}
$wire->addHookAfter('page::path', null, 'segmentUrl');
 

is this a working example? I tried placing it in my template (url segments are enabled) and changed the segment part to the one I want to strip from my url

cheers & thanks, j

Link to comment
Share on other sites

I think that the "page::path" needs to be "Page::path" (uppercase first character). Also, where you place this will matter. You want hooks to be attached before any other code executes. I like to use the $config->prependTemplateFile = 'init.php'; in my /site/config.php, and then setup hooks or any common functions I want in /site/templates/init.php.

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...