Page Attributes provide a way to attach information to a page without actually displaying it as content. For example, if you want to put an image on a page, then you just add an Image block (or insert an image into a Content block). But if you want an image to be associated with that page, but not actually displayed on the page, then you can use an Image Attribute.

You may be asking yourself "why would I want to put an image on a page without actually displaying the image on the page?" There are many reasons you might want to do this, but the most common one is that you want to display a thumbnail image in a Page List elsewhere on the site. For example, on this blog we have a Blog Post Image page attribute which lets us upload a small image that gets displayed on the home page. This thumbnail image does not necessarily appear within the page content itself, so we need some way other than blocks to choose the image (and more importantly, to retrieve it in the home page Page List).

Step 1: Create the Attribute

First, you must create the attribute via Dashboard > Pages & Themes > Attributes. At the bottom of that page, click the "Add Attribute" dropdown list and choose "Image/File", then click the "Add" button.

screenshot of dashboard 'Add Attribute' page

Handle is a lowercase_and_underscore name -- you will use this later on in your page list code to retrieve this attribute. Name is a human-readable name -- your users will see this when editing page properties. You can leave the rest of the fields as-is, and click the "Add" button at the bottom-right of the window.

Step 2: Make It Easy for Users to Set the Attribute

This step is optional, but usually a good idea. If you have a certain page type that you know will be utilizing this attribute, it helps to add it as a default option so it always appears when users add new pages of that type. For example, on this blog we have the "Blog Post" page type, and we always want to be prompted for the "Blog Post Image" when adding new Blog Post pages:
screenshot of 'Add New Page' dialog, showing the Blog Post Image attribute

To set this up, navigate to Dashboard > Pages & Themes > Page Types, click the "Settings" button next to the page type you want, check the box next to the attribute, and click "Save":
screenshot of 'Page Type Settings' dashboard page

Step 3: Create a Custom Template to Display the Attribute

Now comes the fun part! We want to display this attribute in a Page List block elsewhere on the site, and the way we will accomplish this is by creating a custom template.

First, create the custom template by copying the file /concrete/blocks/page_list/view.php to /blocks/page_list/templates/thumbnail_images.php. Note that you will probably need to create the /blocks/page_list/templates directory first, then copy the file and rename the copy to thumbnail_images.php.

Now open that new /blocks/page_list/templates/thumbnail_images.php file in your text editor. If you're running Concrete5.5 or higher, you can see there are comments in the code that explain how to use attributes, and starting around line #30 there is a section specifically about image attributes.

1) Enable the image helper by uncommenting the $ih = Loader::helper('image'); line up top -- so remove the two leading slashes (//) before that code (should be the 5th line from the top of the file). We will use the image helper to generate a thumbnail of the chosen image (so we can ensure that the image is always displayed at a certain size, regardless of which image the user chose).

2) Retrieve the image attribute and create a thumbnail of it by adding the following code (place it under the existing $description = $th->entities($description); line, which should be around line #20):

$img = $page->getAttribute('blog_post_image');
if ($img) {
    $thumb = $ih->getThumbnail($img, 64, 9999, false);
}

A few things to note about this code:

  • It differs slightly from the example in the actual file you copied, because here we are checking if the image attribute exists for the page. If you know for a fact that users will always be providing an image attribute for every page that will be listed, then you don't need to worry about this -- but in many cases the image will be optional, so if you don't put in the if ($img) check then you will see errors on the page that has the Page List block.
  • We've passed in our image attribute's handle (blog_post_image) to the getAttribute function.
  • The two numbers we pass into the $ih->getThumbnail function look kind of funny. The first number is the width we want this thumbnail resized down to (64 pixels in this example), but the height is an absurdly large number (9999). This tells the getThumbnail function that we don't actually care what the height is -- that we just want it reduced down to a certain width and the height can be whatever keeps the proportions the same. The reason it works this way is because the getThumbnail function will only scale images down in size -- never up. So what you're really saying is "resize this image so the width is 64 pixels or less, and so the height is 9999 pixels or less".
  • The final argument of that function (false) is for cropping. If you change this to true, then the image will be resized down to match the exact dimensions you provide, instead of proportionally. This means that if you do want to crop the thumbnails to a specific size, you should change that height argument from 9999 to the actual height you want it cropped to.

3) Output the image tag by adding the following code to the html markup in that file:

<?php if ($img): ?>
    <img src="<?php  echo $thumb->src ?>" width="<?php  echo $thumb->width ?>" height="<?php  echo $thumb->height ?>" alt="" />
<?php endif; ?>

You probably want to add that either before or after the <div class="ccm-page-list-description"> element (around line #54), but the exact location will depend on your theme's design and CSS. Note that this code also differs from the example in the actual file in the same way that the previous code does -- we've added an if ($img) statement to avoid errors when no image attribute exists for a page.

After you've completed those 3 steps, you should wind up with code like this (note that I'm only showing the code between the foreach and endforeach):

<?php foreach ($pages as $page):

    // Prepare data for each page being listed...
	$title = $th->entities($page->getCollectionName());
	$url = $nh->getLinkToCollection($page);
	$target = ($page->getCollectionPointerExternalLink() != '' && $page->openCollectionPointerExternalLinkInNewWindow()) ? '_blank' : $page->getAttribute('nav_target');
	$target = empty($target) ? '_self' : $target;
	$description = $page->getCollectionDescription();
	$description = $controller->truncateSummaries ? $th->shorten($description, $controller->truncateChars) : $description;
	$description = $th->entities($description);	
	
	$img = $page->getAttribute('blog_post_image');
	if ($img) {
		$thumb = $ih->getThumbnail($img, 64, 9999, false);
	}
	/* End data preparation. */

	/* The HTML from here through "endforeach" is repeated for every item in the list... */ ?>
	<h3 class="ccm-page-list-title">
		<a href="<?php echo $url ?>" target="<?php echo $target ?>"><?php echo $title ?></a>
	</h3>
	
	<?php if ($img): ?>
		<img src="<?php echo $thumb->src; ?>" width="<?php echo $thumb->width; ?>" height="<?php echo $thumb->height; ?>" alt="" />
	<?php endif; ?>
	
	<div class="ccm-page-list-description">
		<?php echo $description ?>
	</div>
	
<?php endforeach; ?>

Step 4: Apply the Custom Template to the Page List Block

Now that we have our attribute set up and our code in place, we need to tell the Page List block to use our new custom template. Navigate to the page that has the Page List block on it and enter Edit Mode (or add a new Page List block to a page if you haven't done so already). Then while you're still in Edit Mode, click on the Page List block and choose "Custom Template" from the popup menu:
screenshot of choosing the 'Custom Template' popup menu item

Then choose your custom template ("Thumbnail Images" in our example) and click the "Save" button. Voila!