URL segments and the page reference field

Posted 16th Dec 2017

#api #bootstrap4 #completeguide #fields #selector #urlsegments

Let's render out all the cats at '/cats/'.

/site/templates/cat-index.php

<?php namespace ProcessWire; ?>

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title><?php echo $page->title; ?></title>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
</head>
<body>

<header>
  <div class="jumbotron jumbotron-fluid">
    <div class="container">
      <h1 class="display-3"><?php echo $page->title; ?></h1>
    </div>
  </div>
</header>

<div class="container">
  <div class="row py-5">
  <?php
    // get the child pages of the current page
    $catPages = $pages->get("/cats/")->children;
    foreach ($catPages as $catPage):
  ?>
  
  <div class="col-md-4 pb-3">
    <div class="card">

    <?php
      // if the page object has a featured image
      if ($catPage->featuredImage):
        // https://processwire.com/api/fieldtypes/images/
        // set some default image options
        $options = array('quality' => 80, 'cropping' => 'center');
        // create a new image on the fly 400px wide
        $img = $catPage->featuredImage->width(400, $options);
        // get the url to the image
        $imgUrl = $img->url;
        // get the description field
        $imgDesc = $img->description;
    ?>
      
      <a href="<?php echo $catPage->url; ?>">
        <img src="<?php echo $imgUrl; ?>" alt="<?php echo $imgDesc; ?>" class="img-fluid card-img-top" />
      </a>

    <?php endif; ?>
      
      <div class="card-body">
        <h4 class="card-title">
          <a href="<?php echo $catPage->url; ?>"><?php echo $catPage->title; ?></a>
        </h4>
      </div>

    </div>
  </div>

  <?php endforeach; ?>

  </div>
</div>

</body>
</html>
The rendered page at /cats/
The rendered page at /cats/ Zoom

And something simple for when you click on one of the cats.

/site/templates/cat-entry.php

<?php namespace ProcessWire; ?>

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title><?php echo $page->title; ?></title>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
</head>
<body>

<header>
  <div class="jumbotron jumbotron-fluid">
    <div class="container">
      <h1 class="display-3"><?php echo $page->title; ?></h1>
    </div>
  </div>
</header>

<div class="container">
  <div class="row py-5 justify-content-center align-items-center">
  <?php
    // if the page has a featured image
    if ($page->featuredImage):
    // https://processwire.com/api/fieldtypes/images/
    // set some default image options
    $options = array('quality' => 80, 'cropping' => 'center');
    // create a new image on the fly 800px wide
    $img = $page->featuredImage->width(800, $options);
    // get the url to the image
    $imgUrl = $img->url;
    // get the description field
    $imgDesc = $img->description;
  ?>

    <div class="col-md-6">
      <img src="<?php echo $imgUrl; ?>" alt="<?php echo $imgDesc; ?>" class="img-fluid" />
    </div>

    <?php endif; ?>
  
    <?php
      // change class name if image is present
      if ($page->featuredImage) {
        $colClassName = "col-md-6";
      }
      else {
        $colClassName = "col";
      }       
    ?>
    <div class="<?php echo $colClassName; ?>">
      <h2><?php echo $page->title; ?></h2>
    </div>

  </div>
</div>

</body>
</html>

Right now though, URL segments are not enabled so at '/cats/burmese/' you'd get a 404. Try it. Now, let's sort that out.

Admin > Setup > Templates > URLs (tab)

Choose your 'cat-index' template and on the URLs tab, check the 'Allow URL Segments' checkbox. Now try the path '/cats/burmese/'. It's not a 404 anymore, yet we're still using the 'cat-index' template to render the page.

Enabling URL segments on the cat-index template
Enabling URL segments on the cat-index template Zoom

NOTE: You shouldn't just allow 'any' URL segment, you can either set some regular expressions in the 'Which URL segments do you want to allow' field or handle it in the template file. We'll do it in the template file because we don't know all the types that may be added.

As it stands, you could enter any word after you base URL. You could set '/cats/are/the/best/' as your URL and it'll still work. We'll get to handling that later. First, we'll look at how to change the appearance of the page depending on the URL. In the 'cat-index' template, you need to get the URL segment. Change the header tags to this.

<header>
  <div class="jumbotron jumbotron-fluid">
    <div class="container">

      <?php $segment1 = $input->urlSegment1; ?>
      <h1 class="display-3"><?php echo "URL segment is " . $segment1; ?></h1>
      
    </div>
  </div>
</header>

And try a few different URLs i.e. /cats/tabby/' or '/cats/whatever/'. Now, if you try, '/cats/tabby/best/', '/best/' is actually URL segment 2. You can see this by changing the code to.

<header>
  <div class="jumbotron jumbotron-fluid">
    <div class="container">

      <?php
        $segment1 = $input->urlSegment1;
        $segment2 = $input->urlSegment2;
      ?>
      <h1 class="display-3"><?php echo "URL segment 1 is " . $segment1; ?></h1>
      <h1 class="display-3"><?php echo "URL segment 2 is " . $segment2; ?></h1>

    </div>
  </div>
</header>
Showing the URL segments on the page
Showing the URL segments on the page Zoom

You can read more about URL segments on the official docs. Right now, we only need the first one. You can also see on that page that you can do conditional logic based on the URL segment.

if ($input->urlSegment1 == "photos") {
  // display photo gallery
}
else if ($input->urlSegment1 == "map") {
  // display map
}
else {
  // display main content
}

Of course, the problem we have is that we don't know how many types of cat there are going to be and we can't keep updating our code every 5mins every time a new one is added.

if ($input->urlSegment1 == "burmese") {
  // show burmese cats
}
else if ($input->urlSegment1 == "persian") {
  // show persian cats
}
else if ($input->urlSegment1 == "tabby") {
  // show tabby cats
}
else if ($input->urlSegment1 == "another-type-of-cat") {
 // and on and on and on
}
else {
  // display main content
}

One thing we could do, is instead of listing the cats by getting the children of the '/cats/' page, we could use a selector to list them, and populate the selector based on the URL segment. So change the following in 'cat-index'.

FROM

<?php
  // get the child pages of the current page
  $catPages = $pages->get("/cats/")->children;
  foreach ($catPages as $catPage):
?>

TO

<?php
  // find all pages created with cat-entry template with field
  // called 'catType' with value 'burmese'
  $catPages = $pages->find("template=cat-entry, catType=burmese");
  foreach ($catPages as $catPage):
  ?>

Nice! Now we have two burmese cats listed. So we need to construct a selector that gets the cat type from the URL segment and if no URL segment is present, leave that bit out entirely.

<?php
    // create a string that will be our selector
    $selector = "template=cat-entry";
    // get URL segment 1
    $segment1 = $input->urlSegment1;

    // if URL segment1 is present
    if ($segment1) {
      // concatenate this to the selector
      $selector .= ", catType=$segment1";
    }

    // find the pages based on our selector
    $catPages = $pages->find($selector);
    foreach ($catPages as $catPage):
  ?>

Now try '/cats/burmese/' or '/cats/persian/'. Congratulations, URL segments are up and running!

Now, what about only using a valid URL segment? We can still use any word '/some-word/' and the page is still found. It should be a 404 if there is no corresponding (cat type) page to the URL segment or if there is more than one URL segment. The official docs show how on this page and on the next page, we'll look at how to implement this.

Feedback & support

I hope you enjoyed this tutorial. You can support pwtuts by following on @pwtuts. You can also donate at paypal.me/swcarrey to help support the site which would be awesome!

Related tutorials / See all

Suggest a tutorial

Please note: I do not store any of this information, it's simply used to send me an email. Your email address is required so I can get clarification on your request if needed.