Jump to content
Ryan Pierce

Hide parent page from URL

Recommended Posts

Is it possible to hide a parent page from a child's URL?

For example, in the Skyscraper profile, a buildings page has this URL:

  • /skyscrapers/cities/denver/republic-plaza-denver/

And I'm wondering if we can set the page to load at this URL without htaccess or something:

  • /skyscrapers/denver/republic-plaza-denver/ <-- Hiding the 'Cities' parent page

Thanks for the help!

Share this post


Link to post
Share on other sites

this is possible using URL segments;

I think this really depends on what your specific need is;

if you use URL segments, then you'll have duplicate URLs (so use canonical meta tag pointing to the actual page location)..

to make it work, you would enable URL segments on the template being used on the skycrapers page; then you run a check to see what is in the url, and then return the data for the page that matches; you can find a lot of examples in the forum.

  • Like 1

Share this post


Link to post
Share on other sites

Yea I'm really worried about duplicate URLs so I was hoping for a different way of going about it.

I think what it comes down to (at least at this point in my project) is the 'cities' page just existing for organization in the admin - it would be intense to have all those cities' pages displayed on the admin home without a collapsible "folder" for them. So at that realization, I probably just need to look at adjusting the admin page layout / templates especially since it's more inline with PW's philosophy.

Share this post


Link to post
Share on other sites

a lot of examples of the URL segments when organizing content by tag, or category;

i think it is ok as long as you have the canonical. plus if there is no way for a user to get to the 'real' url, then you don't really need to worry about it;  it sort of comes down to the specific situation... it does speak to the flexibility of the system that you can basically write your own url router, using the segments feature...

Share this post


Link to post
Share on other sites

You can also redirect the page to the new URL or throw a 404 manualy if accessed directly.

Share this post


Link to post
Share on other sites
I think what it comes down to (at least at this point in my project) is the 'cities' page just existing for organization in the admin - it would be intense to have all those cities' pages displayed on the admin home without a collapsible "folder" for them.

Actually in this case /cities/ is not just about admin organization, it's an important landing page in the site's navigation and breadcrumb trail: 

http://processwire.com/skyscrapers/cities/

In ProcessWire we really try to push that URLs are structure and should represent actual structure. What makes sense for the site's structure also makes sense for the URLs, because they are one in the same. If there's a strong desire to have actual city pages off the root level, then you can create them off the root level. While I would question whether that's really the best strategy for either side, there's nothing stopping you from doing it. You can always take the URL segments route too, but when URL segments are used as beginning points (foundations of structure) rather than ending points, you always have to question whether it's really what is best for structure and URLs, or whether it's giving preference to short-term style over proper structure. 

  • Like 2

Share this post


Link to post
Share on other sites
On 7.4.2013 at 6:17 PM, ryan said:

Actually in this case /cities/ is not just about admin organization, it's an important landing page in the site's navigation and breadcrumb trail: 

http://processwire.com/skyscrapers/cities/

I think, this URL only makes sense, if there's actually a page that this url refers to. I often create pages, whose only purpose is to keep the admin tidy. If a page is set to unpublished and/or hast no template file and is therefore not meant to be visible, why does it need a place within the URL string?
 

Share this post


Link to post
Share on other sites
1 hour ago, Christoph said:

I think, this URL only makes sense, if there's actually a page that this url refers to. I often create pages, whose only purpose is to keep the admin tidy. If a page is set to unpublished and/or hast no template file and is therefore not meant to be visible, why does it need a place within the URL string?

I can think of a few reasons, and while some are purely technical and some are related to what Ryan already explained before, think about it this way: if a page is omitted from URL because it's currently not viewable, what happens if it becomes viewable later?

  • Like 1

Share this post


Link to post
Share on other sites

I rather see a problem for users that might go to a page that doesn't exist.
This is my biggest concern. Basically I don't mind having a longer URL-structure

If you make it viewable later on, well, then it would be like rearranging your content structure. You're then adding a layer that helps user finding your content better.

But if I decide that this layer isn't needed, then I see more sense in leaving this layer out of the URL structure. 

In the end, it's not the biggest issue, I just want to understand the basic idea behind it, so ist would be great to get some insights on that reasons you mentioned, as I still don't understand it :-)

  • Like 1

Share this post


Link to post
Share on other sites
12 hours ago, ethfun said:

Any progress made on this front, @Christoph?

No. Well, it depends. I've just accepted that Processwire makes no difference between backend structure and frontend/URL structure. I'd still wish for a more flexible approach on this, but currently I get along with it.

While thinking about it: The question is, if »normal« users use and think about URLs the same way we do. Safari doesn't even show the URL by default …
It could be an issue in breadcrumbs nonetheless, but I rarely use them in my projects.

Share this post


Link to post
Share on other sites

Same boat. I love how straightforward the Processwire Approach makes things, but every once in a while, I am building something where I'd like URLs to be a little more flexible.

It's the over-cited example in these forums (I've seen this exact argument bandied out at least 5 times), but if I wanted a link like site.com/link, and there could be as many as 250 of these individual pages, it would be nice to have them enclosed somewhere without having to change the page's URL.

 

The closest I've come to solving this was with the following:

  1. I enabled URL Segments on the home template.
  2. I created a parent page called "Portals"; its name is "p" (so its URL would be site.com/p)
  3. home.php looks like this:
    <?php
    
    $search_page = $input->urlSegment1;
    $new = $pages->findOne("/p/$search_page");
    if($new->id) $session->redirect($new->url, false);
    ?>
    
    <div class="container">
      <h1>Home</h1>
    </div>
  4. Navigating to site.com/ethfun, the home template looks to see if URL Segment 1 resolves to one of Portals' children. If it does, it redirects to that page (which changes the URL, I realize - but at least the page is accessible with a shorter URL)
  5. portals.php looks like this:
    <?php
    
    $session->redirect($pages->get(1)->url);

    I didn't want to list the children of "Portals", so instead, if someone navigated to site.com/p, they're just redirected to the home page (which does have content of its own to show ).

 

Let me know if you have questions, or if this is the most stupid thing I could ever hope to do!

Share this post


Link to post
Share on other sites

Maybe I am not really this properly, but doesn't this take care of things?

 

Share this post


Link to post
Share on other sites

I think you are right @adrian. I quickly read this and for some reason thought they'd already seen the CMS Critic case study and that didn't suit their needs. I raise that since the same technique is used there. I think stuff like this could make nice short tuts, somewhere outside the forums. There's some nice gems buried deep in the forums. 

Edited by kongondo
  • Like 1

Share this post


Link to post
Share on other sites
1 hour ago, adrian said:

Maybe I am not really this properly, but doesn't this take care of things?

 

@adrian @kongondo I tried that to no avail! I was excited to use that method, but it resulted in a 404 every time, no matter how I attempted to configure it.

  • Like 1

Share this post


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

@adrian @kongondo I tried that to no avail! I was excited to use that method, but it resulted in a 404 every time, no matter how I attempted to configure it.

Sounds like you must have something incorrect because I know that technique has been used by many people.

Maybe if you explain how you set it up we can help?

Share this post


Link to post
Share on other sites

Sure.

All of my templates are prepended with _init.php. Within _init.php, I placed the following code:

$pages->addHookAfter('Page::path', null, 'hookPagePath');
function hookPagePath(HookEvent $e) {
    $page = $e->object;
    if($page->template == 'folder-page') $e->return = "/$page->name/";
}

 

So I had the following page & URL structure:

/folder/uno/
/folder/abc/
/folder/three/

uno, abc and three were all of the template folder-page.

folder-page.php was, for testing, just set up to display the page title:

<?php

echo $page->title;

Navigating to site.dev/folder/uno or site.dev/folder/abc or site.d/folder/three displays the page's title as I'd expect.

But if I try to navigate to site.dev/uno - I am met with a 404.

If on site.dev/folder, I list the children with links to them, their URLs (<?php echo $child->url; ?>) are displayed as:

  • uno --> site.dev/uno
  • abc --> site.dev/abc
  • three --> site.dev/three

Clicking on any of those links brings up the same 404 page. So if I am indeed configuring this wrong somehow, I'd love the help!

Edited by ethfun
Formatting

Share this post


Link to post
Share on other sites

Have you enabled url segments on the home template? Ryan explains this in the same topic here. Or are you using mod rewrite?

  • Like 1

Share this post


Link to post
Share on other sites
4 minutes ago, tpr said:

Have you enabled url segments on the home template? Ryan explains this in the same topic here. Or are you using mod rewrite?

I did when using this method:

Did I need to do so for this?

If so...we're not doing it all that differently, as it turns out.

Share this post


Link to post
Share on other sites

If I get it right, your method uses a redirect which is bad for SEO (and perhaps it's not so resource-friendly). Using render() and return instead doesn't.

Share this post


Link to post
Share on other sites
11 hours ago, ethfun said:

It's the over-cited example in these forums (I've seen this exact argument bandied out at least 5 times), but if I wanted a link like site.com/link, and there could be as many as 250 of these individual pages, it would be nice to have them enclosed somewhere without having to change the page's URL.

What you're describing is an issue about convenience and workflow in the admin. You have some pages that you want to view as a group with some kind of separation from the other pages. There are better ways to deal with this besides changing the page structure in the tree.

The solution that I like best is Lister Pro - you pre-configure a Lister Pro instance for each group of related pages and then you or your editor can work with these pages without the distraction of other pages. And the interface is much more powerful than the page tree, especially when you start working with Actions and inline editing.

For a no-cost solution you could:

1. Work with the core Find lister - it's pretty quick to filter by template or whatever to see your related pages.

2. Put together a simple Process module to live in the menu under "Pages". For example:

class ProcessMyPages extends Process {

    public static function getModuleInfo() {
        return array(
            'title' => 'My Pages',
            'summary' => 'An example of a Process module that lists pages.',
            'version' => 1,
            'permission' => 'page-edit',
            'page' => array(
                'name' => 'my-pages',
                'parent' => 'page',
                'title' => 'My Pages'
            ),
        );
    }

    public function execute(){
        $table = $this->modules->get('MarkupAdminDataTable');
        $table->setEncodeEntities(false);
        // headers
        $table->headerRow( array('Title', 'Modified', 'Created', 'Created by') );
        // find the pages you want to list
        $my_pages = $this->pages->find("template=news_item");
        foreach($my_pages as $page){
            // create whatever columns you want
            $data = array(
                "<a href='{$this->config->urls->admin}page/edit/?id={$page->id}&modal=1' class='pw-modal'>{$page->title}</a>",
                date("j F Y", $page->modified),
                date("j F Y", $page->created),
                $page->createdUser->name,
            );
            $table->row($data);
        }
        return $table->render();
    }

}

 

  • Like 4

Share this post


Link to post
Share on other sites

@ethfun,

You are missing some code. See a fuller example here (the original CMS Critic case study). 

What you need:

  1. Create your Hook. Have that run as early as possible, preferably in a file that is prepended to templates, for instance _init.php
  2. Enable URL segments in home.php. Note that this depends on how you want the URL to be rewritten. If you want to rewrite directly off root, then 'home' is where to go. For instance, if you want /blog/post/ to be rewritten to /post/, you will need to enable URL segments for the template file home.php since that is where ProcessWire will be looking. If you want /blog/posts/post-a/ to be rewritten to /blog/post-a/ you will have to enable URL segments on the template used by blog. The reason you are hitting 404s is that you haven't instructed ProcessWire to accept a URL Segment for that template, in your case, 'home'.
  3. Tell ProcessWire what to do when it hits that URL Segment enabled in #2

Mapping the above to code:

In these examples, we want to rewrite /posts/post-a/ to /post-a/

1# Hook: We have this code in _init.php. Any prepended file will do.

//wire()->addHookBefore('Page::path', function($event) { @note: this or below, both work.
$pages->addHookBefore('Page::path', function($event) {
  $page = $event->object;
  if($page->template == 'post') {// template used by 'post-a'
    // ensure that pages with template 'post' live off the root rather than '/posts/'
    $event->replace = true;
    $event->return = "/$page->name/";
  }
});

 

2#. Allow URL segments in the template: Do this in the URLs tab when editing the template. In our case, that is the template 'home'.

3#. Handling URL Segments: in home.php

Note that here I haven't taken into account situations where we have more than 1 URL Segment. See CMS Critic case study link above for the full example, specifically under the sub-section  /site/templates/home.php.

// check if we have a URL Segment
if(strlen($input->urlSegment1)) {
	// render the blog post named in urlSegment1 
	$name = $sanitizer->pageName($input->urlSegment1);
	$post = $pages->get("/posts/")->child("name=$name");
	if($post->id) echo $post->render();// render the post using its template file
	else throw new Wire404Exception();
}

Just in case you are not sure how to have ProcessWire automatically prepend a file like _init.php, you add this to your /site/config.php/

$config->prependTemplateFile = '_init.php';

It should work as expected, without 404s. 

ps: I haven't completely digested earlier posts but I am guessing this is what you were after.

Edited by kongondo
inline comment
  • Like 3

Share this post


Link to post
Share on other sites

@Robin S and @kongondo -- THANK YOU! Both of your posts were super helpful.

I guess I missed the part about needing to enable URL Segments on the correct template - so that was one of the issues I was having.

Then after reading both of your posts, I think @kongondo's solution was the one I was originally after - but @Robin S' post illuminated a way of handling this problem I hadn't thought of.

I will try them both and let you know, but I think that @kongondo's code should be usable right out of the box.

 

POST-TINKERING EDIT:
The need for URL Segments and mapping them to a new URL turned out to be the primary needed solution. I tried the Process Module Listing Solution, and while I think there's a lot of promise there, it would take some unnecessary work to create a fake folder for the pages in question.

Thanks again!

  • Like 1

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.

×
×
  • Create New...