Posted 16th Dec 2017
#api #bootstrap4 #completeguide #fields #selector #urlsegments
Let's render out all the cats at '/cats/'.
<?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>
And something simple for when you click on one of the cats.
<?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.
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.
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>
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.