URL segments and the page reference field

Posted 16th Dec 2017

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

So our page works for the segments we do want to use i.e.'/cats/burmese/' or /cats/tabby/'. But we need to show a 404 for invalid segments i.e. '/cats/wrong/' and '/cats/something-else/'.

Invaild would firstly be if there was a second URL segment which we can check for.

if ($input->urlSegment2) {
  throw new Wire404Exception();
}

If there is a URL segment 1, we need to check if the URL segment string matches a page that exists under '/type/', if so, concatenate a new part to the selector, and if not, show a 404 page.

// get URL segment 1
$segment1 = $input->urlSegment1;
// if there is a URL segment 1
if ($segment1) {
  // get cat type page - thanks to PW forum member Robin S
  $catType = $pages->findOne("parent=/type/, name=$segment1");  
  // if cat type page exists
  if ($catType->id) {        
    // add this to the selector
    $selector .= ", catType=$segment1";
  }
  else {
    // invalid URL segment 1
    throw new Wire404Exception();
  }
}

Once these checks have been done, we can loop over the results.

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

And we could add a little menu to make finding the cats easier.

<div class="row">
  <ul class="nav">

    <li class="nav-item">
      <a class="nav-link" href="/cats/">Show all</a>
    </li>

    <?php
      $catTypes = $pages->get("/type/")->children;
      foreach ($catTypes as $catType):
    ?>
    
    <li class="nav-item">
      <a class="nav-link" href='<?php echo "/cats/{$catType->name}/"; ?>' ?>
        <?php echo $catType->title; ?>
      </a>
    </li>

  <?php endforeach; ?>

  </ul>
</div>

For completeness, here's the code for the entire template.

/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">
    <ul class="nav">

      <li class="nav-item">
        <a class="nav-link" href="/cats/">Show all</a>
      </li>

      <?php
        $catTypes = $pages->get("/type/")->children;
        foreach ($catTypes as $catType):
      ?>
      
      <li class="nav-item">
        <a class="nav-link" href='<?php echo "/cats/{$catType->name}/"; ?>' ?>
          <?php echo $catType->title; ?>
        </a>
      </li>

    <?php endforeach; ?>

    </ul>
  </div>

  <div class="row py-5">

  <?php
    // only 1 URL segment should be allowed
    if ($input->urlSegment2) {
      throw new Wire404Exception();
    }
    // create a string that will be our selector
    $selector = "template=cat-entry";
    // get URL segment 1
    $segment1 = $input->urlSegment1;
    // if there is a URL segment 1
    if ($segment1) {
      // get cat type page
      $catType = $pages->findOne("parent=/type/, name=$segment1");  
      // if cat type page exists
      if ($catType->id) {        
        // add this to the selector
        $selector .= ", catType=$segment1";
      }
      else {
        // invalid URL segment 1
        throw new Wire404Exception();
      }
    }
    // find the pages based on our selector
    $catPages = $pages->find($selector);
    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 800px 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>
Project completed
Project completed Zoom

Try it out, add a few new cat pages and types. Try a few URLs, try and break it, try a second URL segment to see what happens. Extend this to have not only type but to have colour, or age, or whatever. What about '/cats/under-5/' where you could use an age field on the 'cat-entry' template, get the URL segment and use it to work out which age bracket cats to show.

Start thinking like this and your curiosity will lead to learning! Have fun :)

Feedback & support

I hope you enjoyed this tutorial. You can support pwtuts by following on @pwtuts.

Related tutorials / See all