SSbits - Home page
Site by Carbon Crayon
Submit a Post >

Tutorials - Big bits of code to help you do more

Add flexible MetaTags control to Pages

When you display DataObjects as if they are a single Page or use a Page Action to display a different view of the same Page, by default your MetaTags are the same as the tags you entered in the CMS.

One way to change the MetaTags dynamicly is to add a lot of template controls to display different MetaTags for each view, but you can get a lot more flexibility by overriding the SiteTree MetaTags function in your Page_Controller.

Usecases

One thing I always like is to show the SiteConfig SiteTitle on the HomePage first, but on other pages I want it to show at the end of the Title:

My Awesome Site >> Home
My Detail Page >> My Awesome Site

Or when you have an Product OrderPage you want to add the orderprocess steps in the BrowserTitle:

OrderPage >> ShoppingCart >> My Awesome Site
OrderPage >> My Details >> My Awesome Site
OrderPage >> Confirm Order >> My Awesome Site

And when you show a DataObject as if it is a Page you want to show:

My DataObjectTitle >> MyPageTitle >> My Awesome Site

Lets make this happen quite easily

Copy the complete MetaTags function from SiteTree.php (around r1234 (no joke in v2.4.4)) to your Page_Controller class :

public function MetaTags($includeTitle = true) {
	$tags = "";
	if($includeTitle === true || $includeTitle == 'true') {
		$tags .= "<title>" . Convert::raw2xml(($this->MetaTitle)
			? $this->MetaTitle
			: $this->Title) . "</title>\n";
	}

	$tags .= "<meta name=\"generator\" content=\"SilverStripe - http://silverstripe.org\" />\n";

	$charset = ContentNegotiator::get_encoding();
	$tags .= "<meta http-equiv=\"Content-type\" content=\"text/html; charset=$charset\" />\n";
	if($this->MetaKeywords) {
		$tags .= "<meta name=\"keywords\" content=\"" . Convert::raw2att($this->MetaKeywords) . "\" />\n";
	}
	if($this->MetaDescription) {
		$tags .= "<meta name=\"description\" content=\"" . Convert::raw2att($this->MetaDescription) . "\" />\n";
	}
	if($this->ExtraMeta) { 
		$tags .= $this->ExtraMeta . "\n";
	} 

	$this->extend('MetaTags', $tags);

	return $tags;
}

As you see the Metatags are returned from the current Page with $this->MetaTitle or $this->MetaDescription. Thats not very flexible, so lets change that.

Replace the $this->MetaDescription etc. values with function calls like $this->MetaDescription(); and add those functions to Page_Controller as well, so it looks like this:

public function MetaTags($includeTitle = true) {
	$tags = "";
	if($includeTitle === true || $includeTitle == 'true') {
		$tags .= "<title>" . Convert::raw2xml($this->MetaTitle()) . "</title>\n";
	}

	$tags .= "<meta name=\"generator\" content=\"SilverStripe - http://silverstripe.org\" />\n";

	$charset = ContentNegotiator::get_encoding();
	$tags .= "<meta http-equiv=\"Content-type\" content=\"text/html; charset=$charset\" />\n";
	if($this->MetaKeywords()) {
		$tags .= "<meta name=\"keywords\" content=\"" . Convert::raw2att($this->MetaKeywords()) . "\" />\n";
	}
	if($this->MetaDescription()) {
		$tags .= "<meta name=\"description\" content=\"" . Convert::raw2att($this->MetaDescription()) . "\" />\n";
	}
	if($this->ExtraMeta()) { 
		$tags .= $this->ExtraMeta() . "\n";
	} 

	$this->extend('MetaTags', $tags);

	return $tags;
}
	
	
function MetaTitle(){
	return ($this->MetaTitle) ? $this->MetaTitle : $this->Title;
}

function MetaKeywords(){
	return $this->MetaKeywords;
}

function MetaDescription(){
	return $this->MetaDescription;
}

function ExtraMeta(){
	return $this->ExtraMeta;
}

Now you have moved the MetaTag values to seperate functions, which you can customize on each PageType based on what you want to show on a certain action or DataObject you are showing.

Let say you want the SiteConfig Title to show up in the MetaTitle as well, you can do something like this :

function MetaTitle(){
    $title = ($this->MetaTitle) ? $this->MetaTitle : $this->Title;        
    return $title . ' - ' . $this->SiteConfig()->Title;
}

In your template you would now use:

$MetaTags(false)
<title>$MetaTitle</title>

This is quite similar like it is already done Page.ss from the BlackCandy template, but we want to control the Tags in the Controller.

Now when you have a seperate HomePage PageType, like I always have, and you there want to display the the SiteConfig Title first and add the SiteConfig Tagline as well, you just have to add the function MetaTitle() to HomePage_Controller :

function MetaTitle(){
	$title = ($this->MetaTitle) ? $this->MetaTitle : $this->Title;		
	return $this->SiteConfig()->Title . ' - ' . $this->SiteConfig()->Tagline . ' - ' . $title;
}

Now that was not that hard, lets change the MetaTitle so its shows something complety different.

Change MetaTags based on Controller Actions

Lets use the tutorial DataObjects as Pages for these examples. When we show a single StaffMember, we want to show the StaffMember Name in the Browser Title Bar instead of the StaffPage MetaTitle.
Just add the function MetaTitle() to the StaffPage_Controller and check for the current Action and getStaffMember() to decide if you want to show a different MetaTitle:

function MetaTitle(){
if($this->urlParams['Action'] == 'show' && $this->getStaffMember()) {
$title = $this->getStaffMember()->Name;
} else {
$title = ($this->MetaTitle) ? $this->MetaTitle : $this->Title;
}
return $title . ' - ' . $this->SiteConfig()->Title;
}

And ofcourse we want a different MetaDescription as well :

function MetaDescription(){
	if($this->urlParams['Action'] == 'show' && $this->getStaffMember() && $this->getStaffMember()->Description) {
		return $this->getStaffMember()->Description;
	} else {
		return $this->MetaDescription;
	}
}

In this way you can control the MetaTags very easy, based uppon Controller Actions or if a certain DataObject is displayed. You don't have to copy the MetaTags() function to each PageType, just the MetaTitle(), MetaKeyWords() and MetaDescription() methods and apply a different set of rules for each PageType. You can concat several fields from a DataObject to use for the MetaDescription or add a MetaDescription and MetaKeyWords fields to your DataObject and use those.

If you easily want to add the KeyWords based uppon a Text Field. Copy this class to your code base:

http://www.sspaste.com/paste/show/4d2649a25d034

and call KeywordsGenerator::generateKeywords($string); to get an ordered list of keywords:

function MetaKeywords(){
	if($this->MetaDescription()){
		return KeywordsGenerator::generateKeywords($this->MetaDescription());
	} else {
		return Convert::raw2att($this->MetaKeywords);
	}
}

Good luck!

Martijn van Nieuwenhoven avatar

Martijn van Nieuwenhoven

Martijn van Nieuwenhoven is a freelance Silverstripe developer based in the Netherlands and runs the largest Dutch Jobboard for Media, Marcom and Graphic related jobs.

  • Darren-Lee
    09/04/2011 7:18pm (3 years ago)

    @Martijn van Nieuwenhoven - I like that technique - makes the SEO more relevant. I am going to try this on my current project where I am displaying DataObjects as pages. Thanks for sharing.

  • Sonet
    29/01/2012 9:16pm (2 years ago)

    @Martijn - I think it is not necessary to override the MetaTags function from SiteTree.php. The controller methods get priority over the model.

    class Page extends SiteTree {
    public static $db = array(
    "Foo" => "Text",
    );
    }
    class Page_Controller extends ContentController {
    public function getFoo() {
    return 'controller value';
    }
    }

    Calling $Foo from template will result in 'controller value'. I remember using this approach to set the $MetaTitle for DataObject as pages.

Post a comment ...

You cannot post comments until you have logged in. Login Here.

Advertisement

Site of the Month

Find SSbits on

Top Contributers

Rank Avatar Name
1 article image Aram Balakjian
2 article image Daniel Hensby
3 article image Marcus Dalgren
4 article image Hamish Campbell
5 article image Ty Barho
6 article image njorndare
7 article image Martijn van Nieuwenhoven
8 article image Darren-Lee
9 article image Roman Schmid
10 article image Matt Clegg

View full leaderboard


Advertisement