How to remove the meta name=title element from Symfony pages

November 5th, 2008 | Tags: , ,

Note: If you are using Symfony 1.2, follow these instructions instead.

I came across a slight problem with how the Symfony framework outputs title tag data: it outputs it both to the title element as well as to the meta element with name=”title”. This duplicated data is not optimal and may be considered “spammy”.

In looking to remove one of these, there wasnt an obvious solution, but I finally found this blog post with a solution except there were a few minor drawbacks (especially that it removes the title setting completely and so the title is unavailable after a call to include_metas) to that particular solution so I tweaked it as follows to answer those concerns.

1. In your app’s lib dir, create a file named myWebResponse.class.php:

class myWebResponse extends sfWebResponse
{
   /**
   * Retrieves title for the current web response.
   *
   * @return string Title
   */
   public function getTitle()
   {
      return $this->getParameter('title', '', 'helper/asset/auto/title');
   }

   /**
   * Sets title for the current web response.
   *
   * @param string Title name
   * @param boolean true, for escaping the title
   * @param boolean true, for allowing to overwrite the title
   */
   public function setTitle($title, $escape = true, $replace = true)
   {
      $old_title = $this->getTitle();

      if($replace || empty($old_title))
      {
         // FIXME: If you use the i18n layer and escape the data here, it won't work
         // see include_metas() in AssetHelper
         if($escape)
         {
            $title = htmlentities($title, ENT_QUOTES, sfConfig::get('sf_charset'));
         }

         $this->setParameter('title', $title, 'helper/asset/auto/title');
      }
   }
}

2. In your app’s lib dir, create a file named myViewConfigHandler.class.php:

class myViewConfigHandler extends sfViewConfigHandler
{
   /**
   * Adds http metas and metas statements to the data.
   *
   * @param string The view name
   *
   * @return string The PHP statement
   */
   protected function addHtmlHead($viewName = '')
   {
      $retVal = parent::addHtmlHead($viewName);

      $title = $this->getConfigValue('title', $viewName);

      if(!empty($title)) $retVal  .= "\n" . sprintf("  \$response->setTitle('%s', true, false);", str_replace('\'', '\\\'', preg_replace('/&(?=\w+;)/', '&', htmlspecialchars($title, ENT_QUOTES, sfConfig::get('sf_charset'))))) . "\n";

      return $retVal;
   }
}

3. In your app’s config dir, create a file named config_handlers.yml:

modules/*/config/view.yml:
  class:    myViewConfigHandler

4. Modify the app’s factories.yml to use this response class instead of sfWebResponse

5. Clear the app’s Symfony cache

Note that this method doesn’t work with static titles set in view.yml—it is intended for use with dynamic titles set in actions.

Note that you can still set the title in view.yml, additionally, this method allows you to set the meta title separately from the title element. For example:

default:
  http_metas:
    content-type: text/html

  metas:
    robots:       index, follow
    description:
    keywords:
    language:     en
    title:           This title will show up in the meta element with name=title

  title:          This title will show up in the title element
  1. November 7th, 2008 at 19:02
    Reply | Quote | #1

    Edited to handle the title setting in view.yml

  2. Me
    November 13th, 2008 at 11:02
    Reply | Quote | #2

    Does not work for some reason getting an error: Call to undefined method myWebResponse::getParameter.

    in SF_SYMFONY_LIB_DIR/response/sfResponse.class.php line 136 …

  3. November 13th, 2008 at 11:36
    Reply | Quote | #4

    Are you using Symfony v1.0 or v1.1? I have only tested this in v1.0 — we have not yet upgraded to v1.1 but plan to do so sometime this year.

  4. November 18th, 2008 at 17:58
    Reply | Quote | #5

    well, I would say, don’t have to be so complicated.

    just add a helper function

    getResponse()->getMetas() as $name => $content)
    {
    if($name != ‘title’) echo tag(‘meta’, array(‘name’ => $name, ‘content’ => $content)).”\n”;
    }
    }
    ?>

    and use this include_metas_no_title() instead of include_metas() in your template. that’s it.

  5. November 19th, 2008 at 09:23
    Reply | Quote | #6

    The problem with that is that it doesnt do any of the internationalization or escaping that include_metas() does. The other advantage of my more complicated solution is that you can drop it in to a larger project and dont have to go around changing all of the templates.

  6. November 24th, 2008 at 19:28
    Reply | Quote | #7

    internationalization or escaping that include_metas() are not problem, basically my function is only deleted one data in an array, if the data called title exists. didn’t change any thing functionally in include_metas() at all.

    regarding to change the every single layout, I guess most symfony project will keep all layout files in apps/frontend/templates folder. and shouldn’t be too many files in there.

    also, if as you said, to change every single layout page became a problem. then override include_metas() or simply change include_metas() in symfony framework.

  7. August 21st, 2010 at 03:59
    Reply | Quote | #8

    There is an even simpler solution to this:

    go to the lib/vendor/helper/AssetHelper.php class,
    and change the function include_metas() so that it skips
    for the title tag (if…continue):

    function include_metas()
    {
    $context = sfContext::getInstance();
    $i18n = sfConfig::get(‘sf_i18n’) ? $context->getI18N() : null;
    foreach ($context->getResponse()->getMetas() as $name => $content)
    {
    if($name = “title”) continue;
    echo tag(‘meta’, array(‘name’ => $name, ‘content’ => null === $i18n ? $content : $i18n->__($content))).”\n”;
    }
    }

    Cheers, Olivier

  8. December 6th, 2010 at 23:39
    Reply | Quote | #9

    Here’s the code to do it easy in old symfony version

    function include_metas()
    {
    foreach (sfContext::getInstance()->getResponse()->getMetas() as $name => $content)
    {
    if($name != “title”){
    echo tag(‘meta’, array(‘name’ => $name, ‘content’ => $content)).”\n”;
    }}
    }

TOP