Simplified meta tags

If we want to set meta tags on a per page (controller-action) basis, we may use the clientScript application component.

Controller

<?php
 
class ExampleController extends CController
{
 
  public function actionIndex()
  {
 
    Yii::app()->clientScript->registerMetaTag('This is an example', 'description');
 
    $this->render('example');
 
  }
 
}
 
?>

This will insert the description meta tag automatically into the layout when the render() function gets called.

Another solution would be to use a parent controller with the property $pageDescription. That way we don't have to make a function-call to set the description. Instead, we can easily modify the description inside of the controller. In the layout-file we'll simply echo the meta tag (if defined).

Parent-Controller

<?php
 
class ParentController extends CController
{
 
  public $pageDescription;
 
}
 
?>

Controller

<?php
 
class ExampleController extends ParentController
{
 
  public function actionIndex()
  {
 
    $this->pageDescription = 'This is an example';
 
    $this->render('example');
 
  }
 
}
 
?>

Layout

<html>
<head>
<?php
 
if (!empty($this->pageDescription))
{
  echo '<meta name="description" content="' . $this->pageDescription . '" />';
}
 
?>
<title>Example</title>
</head>
 
<body>
 
</body>
</html>

As you can see, the second solution is probably better to work with because we can directly access $pageDescription and won't have to call an ugly long function every time. On the other hand, we have now additional php-code in the layout. Well that's not bad at all, but it could lead to problems.

What if we have 10 different layouts? What if we use several themes? In each of these files we would've to insert that snippet. Now let's think instead of a single string (the description), we would implement the same functionality for several rss-feed meta tags (an array). That would mean we have to do a foreach inside of the layout(s).

For a more flexible solution, we extend CController with a custom function.

<?php
 
class ExtendedCController extends CController
{
 
    public function render($view, $data = null, $return = false)
    {
        if ($this->beforeRender())
        {
            parent::render($view, $data, $return);
        }
    }
 
    public function beforeRender()
    {
        return true;
    }
 
}
 
?>

The parent-controller will make use of our extended CController and the special function.

<?php
 
class ParentController extends ExtendedCController
{
 
    public $pageDescription;
 
    public function beforeRender()
    {
 
        if (!empty($this->pageDescription))
        {
            Yii::app()->clientScript->registerMetaTag($this->pageDescription, 'description');
        }
 
        return true;
 
    }
 
}
 
?>

The actual controller remains the same (like in the second solution).

<?php
 
class ExampleController extends ParentController
{
 
  public function actionIndex()
  {
 
    $this->pageDescription = 'This is an example';
 
    $this->render('example');
 
  }
 
}
 
?>

When the render() function gets called, ExtendedCController will first execute the custom beforeRender() function in our parent-controller to insert the meta tag and after that it will call the original CController::render() function.

That means with this solution we can access the $pageDescription property inside of the controller and we don't have to add any special code to the layout. Of course this solution comes in handy especially for things like the already noted rss-feeds.

Think about this:

$this->pageFeeds[] = 'http://example.com/feeds/recent.xml';
$this->pageFeeds[] = 'http://example.com/feeds/popular.xml';

I hope you enjoyed the read. Feel free to share your thoughts - thank you.

Tip: Since the two classes ParentController and ExtendedCController are no real controllers (they only function as parent-classes), you have to put them into the components folder (eg protected/components).

Total 7 comments:

#818
so good!
by jerry2801 at 11:53am on November 20, 2009.

Thanks for share~

#917
Just a thought
by cmx at 12:28pm on December 20, 2009.

It is possible to populate the HEAD element using a portlet component.

This would be useful if your meta information is stored in a database table along with its associated content. That is, dynamically updating the meta information on the fly based on the current module that has focus. Another possibility could be storing meta information for a module (MVC triad) in a database table along with module parameters and other information.

#955
Placement of the ParentController & ExtendedCController
by vario at 1:29am on January 7, 2010.

It might be worth noting in the tutorial that you have to place the ParentController & ExtendedCController in 'protected/components' directory (NOT 'protected/controllers', even though they are controllers of sorts) or else they won't be found when running the main ExampleController.

As resolved in the forum:

http://www.yiiframework.com/forum/index.php?/topic/6387-solved-creating-a-parent-controller-but-isnt-found/

#961
vario
by Y!! at 1:40am on January 8, 2010.

Thanks, I've added a hint at the bottom.

#1485
Child "render" error
by Rsol at 5:59am on May 14, 2010.

Code:

class ExtendedCController extends CController{ public function render($view,$data=null,$return = false){ if ($this->beforeRender()) parent::render($view, $data = null, $return = false); } ...

Don't work. Should be:

class ExtendedCController extends CController{ public function render($view,$data=null,$return = false){ if ($this->beforeRender()) parent::render($view, $data, $return); } ...

#1557
Rsol
by Y!! at 6:42am on June 4, 2010.

Thanks fixed

#1602
good
by dufei22 at 6:55am on June 21, 2010.

public function beginContent($view = null, $data = array()) { if ($this->pageDescription=='') $this->pageDescription=Yii::app()->params'pageDescription'; if ($this->pageKeywords=='') $this->pageKeywords= Yii::app()->params'pageKeywords';

Yii::app()->clientScript->registerMetaTag($this->pageDescription, 'description');
Yii::app()->clientScript->registerMetaTag($this->pageKeywords, 'keywords');
parent::beginContent($view, $data);
}

Your Comment:

You may enter comment using Markdown syntax.

Please login with your forum account.
Note: you must have at least ONE forum post with your account.