Jump to content

Remove part of URl with .htaccess


Yannick Albert
 Share

Recommended Posts

Ahoi, pros!

Currently I've to create some frontend related user profiles. However I stuck at the routing part. All users are a child of a `users`-page and their url's look like this:

http://localhost/projects/ca/users/foo/

...I've to accomplish a url-structure like the following, so I tried redirect all these request to this:

http://localhost/projects/ca/foo/

Using .htaccess doesn't work for me in this case:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /projects/ca/
    RewriteRule ^users/(.*)$ $1
</IfModule>

Any ideas how to get this to work, maybe without .htaccess?

Link to comment
Share on other sites

  Currently I've to create some frontend related user profiles. However I stuck at the routing part. All users are a child of a `users`-page and their url's look like this:

http://localhost/projects/ca/users/foo/

...

Any ideas how to get this to work, maybe without .htaccess?

Hi yckart, welcome to the forums.

One approach could be using urlSegments:

Depending on what template/page you are using under /ca/, you may enable "Allow URL-Segments" under Templates -> YOURcaTemplate -> URLs.

- with your users pages you define urls like http://localhost/projects/ca/foo/ instead of http://localhost/projects/ca/users/foo/

- on the /ca/ page you first do a check if there is a URL-Segment ($input->urlSegment1) populated and switch to processing with /users/foo/

- if there is no $input->urlSegment1 process the request like you do it yet with /ca/

Link to comment
Share on other sites

Quote

Hi yckart, welcome to the forums.

 

One approach could be using urlSegments:

 

Depending on what template/page you are using under /ca/, you may enable "Allow URL-Segments" under Templates -> YOURcaTemplate -> URLs.

 

- with your users pages you define urls like http://localhost/projects/ca/foo/ instead of http://localhost/pro...s/ca/users/foo/

 

- on the /ca/ page you first do a check if there is a URL-Segment ($input->urlSegment1) populated and switch to processing with /users/foo/

 

- if there is no $input->urlSegment1 process the request like you do it yet with /ca/

Hi horst, thanks for the salutation and fast answer!

At the first, I've to say that my php-skills are really restricted. It would be great if you could share a simple snippet, or further instructions how to switch to processing with /users/foo/ and how to process the request like you do it yet with /ca/.

Just as a sidenote, I forgot to say that `http://localhost/projects/ca/` is where the pw-installation is located at and uses currently the default home-template.

Thanks for your help in advance :)

Link to comment
Share on other sites

Hi yckart,
 
I guess you are using the basic siteprofile that comes with PW per default. Following is the code of the home-template file. It is located under /site/templates/ and is named home.php. I have added a check for the url segment and the code you need to output a user page, whereas the original code of the home-template completly goes into the else-part:

<?php

/**
 * Home template
 *
 */

// first lets check if we have a urlSegment1
if( ! empty($input->urlSegment1) ) {

	// we have a url segment and want to get the page for it
	// we use ->get() for this, because get returns a single page, whereas ->find() returns an array of pages
	// but as we use the unique name of the users pages, there only can exist one page with that name
	$userpage = $pages->get("/users/{$input->urlSegment1}/");
	
	// lets check if we have got a valid page
	// if PW hasn't found a page, it returns a nullPage and that has always a id 0
	if($userpage->id == 0) {
		// we have no valid page, lets throw a 404 exception
		throw new Wire404Exception();
	}
	else {
		// we have a valid page, so lets output the complete users page
		echo $userpage->render();
	}
}
else {

	// if there is no url segment, output the homepage

	include("./head.inc");

	echo $page->body;

	include("./foot.inc");

}

 
This template will work if you use links like "/userpagename/" userpagename is the content of the namefield of your user page.
 
If you have a page /users/foo-bar/, you can call it /foo-bar/ and it will be rendered, if you use /fooBaz/ you will be redirected to a 404 page, and if you call / you go to the homepage. But you also can access the user pages with there native urls: /users/foo-bar/.
 
 
Hope that helps.

Edited by horst
  • Like 2
Link to comment
Share on other sites

Ok, good starting point, thanks so far! However, I think (also because of duplicate content) this approach is not the best. After a bit of research I found the perfect solution.

Using a simple hook does the trick:

http://processwire.com/talk/topic/1799-routes-and-rewriting-urls/?p=16708

wire()->addHookAfter('Page::path', null, function(HookEvent $event) {
  $page = $event->object;
  if ($page->template == 'account-profile') {
    $event->return = '/'.$page->name.'/';
  }
});

Anyway, thanks for the fast support and explanation!

Cheers,

Yannick

  • Like 1
Link to comment
Share on other sites

Actually you need both of these, urlSegments to render those pages on a different level, and the hook is just to conveniently modify the path (esier than manually createing them).

I don't see where duplicated content is a problem. EIther use canonical urls, or take care of it with a redirect or some hooks. :) But if you never have links to those (real locations) you won't have them visible anyway.

  • Like 1
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.
  • Similar Content

    • By Liam88
      Hi,

      After years of just playing around with Processwire I have asked 3 q's in the same week. It's all about working with forms, parameters etc and so I'm hoping this ordeal is nearly over!
      I currently have a checkbox filter:
      <form id="abFilter" method="get" role="form" action="'.$page->url().'"> <div class="list-group"> <h3>Content Type</h3>'; $cont = $fields->get('ab_content'); $contents = $cont->type->getOptions($cont); foreach($contents as $ab_cont){ echo' <div class="list-group-item checkbox"> <input type="checkbox" class="" id="'.$ab_cont->title.'" name="content" value="'.$ab_cont->title.'"'; if (in_array($ab_cont->title, $contArray)){ echo "checked"; } echo'> <label for="'.$ab_cont->title.'">'.$ab_cont->title.'</label> </div>'; } echo' </div>'; //end of filter 1 //start of filter 2 echo' <div class="list-group"> <h3>Channels</h3>'; $chan = $fields->get('ab_channels'); $channel = $chan->type->getOptions($chan); foreach($channel as $ab_chan){ echo' <div class="list-group-item checkbox"> <input type="checkbox" class="" id="'.$ab_chan->title.'" name="channel" value="'.$ab_chan->title.'"'; if (in_array($ab_chan->title, $chanArray)){ echo "checked"; } echo'> <label for="'.$ab_chan->title.'">'.$ab_chan->title.'</label> </div>'; } echo' </div>'; ?> <button id="select">Get Checked Checkboxes</button> </form><!-- end of form --> I also have a piece of script which selects all the checkboxes and then outputs them into readable parameters for the URL which then passes into the $inputs. The reason for the script is to not have duplicate filters like ?ab=1&ab=2 and the script changes it to ab=1_2 which on the input gets exploded into an array. 
      document.querySelector("form").onsubmit=ev=>{ ev.preventDefault(); let o={}; ev.target.querySelectorAll("[name]:checked").forEach(el=>{ (o[el.name]=o[el.name]||[]).push(el.value)}) console.log(location.pathname+"?"+Object.entries(o).map(([v,f])=>v+"="+f.join("_")).join("&")); document.location.href = location.pathname+"?"+Object.entries(o).map(([v,f])=>v+"="+f.join("_")).join("&"); } Here is $inputs and so on on the page:
      //Default selector to get ALL products $baseSelector = "template='adbank_pages',sort=published,include=all,status!=hidden,limit=2"; $selector = "template='adbank_pages',sort=published,include=all,status!=hidden,limit=2"; $input->whitelist('channel',explode("_", $channel)); // Use this to append to the $items filter if($channel){ $chanArray = explode("_", $channel); $chan = $channel = str_replace('_', '|', $channel); $selector = $selector .= ",ab_channels=$chan"; } $test = $pages->find($selector); // This is just testing if the $selector choise returns and if not use page filter without filters. if(count($test) > 0){ $items = $pages->find($selector); // $items with the parameter filter // Example - "template='adbank_pages',sort=published,include=all,status!=hidden,limit=2,ab_channels=facebook-ads" // Example (multi choice) - "template='adbank_pages',sort=published,include=all,status!=hidden,limit=2,ab_channels=facebook-ads|instagram-ads" // Example (with other filters) - "template='adbank_pages',sort=published,include=all,status!=hidden,limit=2,ab_channels=facebook-ads,ab_content=video|static" }else{ $items = $pages->find($baseSelector); // Example - "template='adbank_pages',sort=published,include=all,status!=hidden,limit=2" } $total = $items->getTotal(); I have stripped out a few of the other filters from the above to try keep it a little more concise (haha). Now I appreciate the post may be long but here we are at the end!
      The URL I get on page 1 of the filter results would look like: example.com/blog/?channel=facebook-ads_instagram-ads
      If I click page 2 the url changes to - example.com/blog/page2/?channel=
      If I then click back to page 1 it changes to - example.com/blog/?channel=
      So I'm hoping you can see my problem and hoping someone can assist. I need to work out how to keep the parameters in the url but also if I remove that filter for that parameter to remove.
      This whole process works without pagination but with pagination it has a different behaviour.
      Thank you in advance
    • By jploch
      Hey folks,
      currently Iam working on a website for one of my clients and I need some advice on how to approach this in PW.
      The website is for a company, that offers holiday houses in two locations. 

      The client wants the homepage to show the first location. Normally I just have a home template for the first page, but here the URL should reflect that you are in Location 1. So when you visit the URL casamani.com it should redirect to casamani.com/location-1. Not sure if this makes sense at all.

      Whould it be bad for SEO and performance reasons to redirect home to the Location-1 page?
      Another approach would be to render the Location-1 template on the home template or do an include like discussed here.
      Here is how the tree looks:
      – Home
      – Location 1 (Homepage)
           – Creation
           – Adventure
           – Sustainability
      – Location 2 
           – Creation
           – Adventure
           – Sustainability

      Thanks for looking into this!
    • By wwwouter
      Some context: I want to use PHP variables in my CSS (more info below) and found a solution on CSS-tricks that looks fairly elegant and somewhat solid to me. It's pretty simple, I created a file style.css.php inside the site/templates/ directory and load that in my page head. In style.css.php is the following:
      <?php header("Content-type: text/css; charset: UTF-8"); header("Charset:utf-8"); if ($homepage->hero_image) { echo <<<CSS .hero { background: url($homepage->hero_image->url) no-repeat; } CSS; } ?> Because of the following RewriteCond (line 373) in the htaccess file the server sends a 403 error back when the file is requested:
      # Block access to any PHP or markup files in /site/templates/ or /site-*/templates/ RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/templates($|/|/.*\.(php|html?|tpl|inc))($|/) [NC,OR] (My htaccess file is @version 3.0 and @htaccessVersion 301)
      This is how I thought I could fix that (based on these answers on stack overflow) but it does not work:
      # Block access to any PHP or markup files in /site/templates/ or /site-*/templates/ RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/templates($|/|/((?!style\.css).)*\.(php|html?|tpl|inc))($|/) [NC,OR] I tested the rule with htacess tester and htaccess check and both worked for me, but on my site I still get a 403 instead of the file.
      I'm working on localhost, using MAMP (not sure if that's relevant).
      A bit more about what I want to do achieve specifically:
      I want to use an image as a background-image for an element, not place it as an image. This image is provided by the user via a field and can therefore change.
      I know I can achieve this like this:
      echo "<section class='hero' style='background-image: url($page->hero_image->url)'></section>"; But I would prefer a method other than inlining because of scalability and cleanliness. (I admit the extra link in the page head is not ideal either)
       
      P.s. this is my first post here, I hope it's submitted in the right forum and my explanation is clear.
    • By RDC
      Is the right way to get Processwire to skip a folder (ie not process it as its running a different CMS) to put
      RewriteCond %{REQUEST_URI} !^/shop/.*$
      just before 
      RewriteRule ^(.*)$ index.php?it=$1 [L,QSA]
      in .htaccess?
    • By humanafterall
      Hi,
      I have a URL field that will sometimes have relative/local URLs on a multilingual site, for example /contact/ 

      However the URL field does not seem to pick up when I'm on another language, for example /fr/ so I'm taken to the default language page for /contact/ rather than /fr/contact/
      Is there a way to make the URL fields play well with a multi-language site?
      Thanks!
       
×
×
  • Create New...