From 6d3041c6242c573bca378923f782f2c3dc57bc60 Mon Sep 17 00:00:00 2001 From: ElectricMaxxx Date: Thu, 3 Apr 2014 09:53:52 +0200 Subject: [PATCH 01/14] (re) - init seo documentation --- bundles/seo/index.rst | 7 + bundles/seo/introduction.rst | 396 +++++++++++++++++++++++++++++++++++ 2 files changed, 403 insertions(+) create mode 100644 bundles/seo/index.rst create mode 100644 bundles/seo/introduction.rst diff --git a/bundles/seo/index.rst b/bundles/seo/index.rst new file mode 100644 index 00000000..6a4fa871 --- /dev/null +++ b/bundles/seo/index.rst @@ -0,0 +1,7 @@ +SeoBundle +============= + +.. toctree:: + :maxdepth: 2 + + introduction diff --git a/bundles/seo/introduction.rst b/bundles/seo/introduction.rst new file mode 100644 index 00000000..6d304933 --- /dev/null +++ b/bundles/seo/introduction.rst @@ -0,0 +1,396 @@ +SeoContentBundle +================ + + This bundle helps you optimize your websites + for search engines by collecting SEO data in + a central location and making it available in + twig. It is built on top of the SonataSeoBundle. + +Preface +------- + +Search engines punish you when you provide +the same content under several URLs. +The CMF allows you to have several URLs +for the same content if you need that. +There are two solutions to avoid penalties +with search engines: + +- Create a canonical link that identifies the original URL: ```` + +- Redirect to THE original url. + +Both take care on search engines, which does not like +it to have same content under different routes. + +The SeoBundle uses sonatas SeoBundle and its TwigHelper +to render the the `SeoMetadata` into your Pag. So you +should have a look at the documentation +at `sonata seo documentation_` + +Installation +------------ + +You can install the bundle in 2 different ways: + +* Use the official Git repository `with github`_ +* Install it `with composer`_ (``symfony-Symfony CMF/seo-content-bundle`` on `Packagist`_). + +Both bundles need to be registered in the ``appKernel`` + +.. code-block:: php + public function registerBundles() + { + $bundles = array( + //register both SeoBundles + new Sonata\SeoBundle\SonataSeoBundle(), + new Symfony\Cmf\Bundle\SeoBundle\CmfSeoBundle(), + ); + + return $bundles; + } + +A very basic use case +_____________________ + +The simplest use case would be to just set some configuration +to the sonata_seo configuration section and set the TwigHelper +into your template. + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + sonata_seo: + page: + title: Page's default title + metas: + names: + description: The default description of the page + keywords: default, sonata, seo + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension('sonata_seo', array( + 'page' => array( + 'title' => 'Page's default title', + 'metas' => array( + 'names' => array( + 'description' => 'default description', + 'keywords' => 'default, key, other', + ), + ), + ), + )); + +To get a deeper look into the sonata seo-bundle configuration you +should visit its documentation at `sonata seo documentation_` +The only thing to do now is to insert the TwigHelper into your +template: + +.. code-block:: html + + + + {{ sonata_seo_title() }} + {{ sonata_seo_metadatas() }} + {{ sonata_seo_link_canonical() }} // needed later + + +

Some page body.

+ + + +This will render a Page with the tilte defined above. The +information definded for description and keywords will go +into the meta tags. + +Using SeoMetadata - Admin extension and a form type +--------------------------------------------------- + +The basic example would work perfect without the Symfony CMF +SeoBundle. But the SeoBundle creates more possibilities to +create the pages's title, description, keywords and even +the original url for a canonical link or a redirect. +To persist that data the Bundle serves a value object +called `SeoMetada`: + +.. code-block:: php + + /** + * This string contains the information where we will find the original content. + * Depending on the setting for the cmf_seo.content.pattern, we will do an redirect to this url or + * create a canonical link with this value as the href attribute. + * + * @var string + */ + private $originalUrl; + + /** + * If this string is set, it will be inserted as a meta tag for the page description. + * + * @var string + */ + private $metaDescription; + + /** + * This comma separated list will contain the Keywords for the page's meta information. + * + * @var string + */ + private $metaKeywords; + +A object should implement +the `SeoAwareInterface`, which simply forced to implement setter/getter for the +seo metadata. A simple example would be: + +.. code-block:: php + + use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route; + use Symfony\Cmf\Bundle\SeoBundle\Doctrine\Phpcr\SeoAwareContent; + use Symfony\Cmf\Bundle\SeoBundle\Model\SeoMetadata; + + //retrieve the root document + $rootDocument = $documentManager->find(null, '/cms/content'); + + //create the seo aware document + $seoDocument = new SeoAwareContent(); + $seoDocument->setParent($rootDocument); + $seoDocument->setTitle('Same title as in original'); + $seoDocument->setName('seo-content'); + $seoDocument->setBody('Same Content as in Original'); + + //set the seo metadata + $seoMetadata = new SeoMetadata(); + $seoMetadata->setTitle("Documents own tile"); + $seoMetadata->setMetaKeywords('Seo, Content'); + $seoMetadata->setMetaDescription( + 'This ist the text for the description meta tag' + ); + $seoMetadata->setOriginalUrl("/original/url/of/content"); + $seoDocument->setSeoMetadata($seoMetadata); + + // retrieve the route root node + $routeRoot = $documentManager->find(null, '/cms/routes'); + + //create the route for the document + $route = new Route(); + $route->setParentDocument($routeRoot); + $route->setName('seo-content'); + $route->setContent($soDocument); + $route->setDefault('_template', '::base.html.twig'); + + $manager->persist($seoDocument); + $manager->persist($route); + $manager->flush(); + +Visiting the site with the url ``/seo-content`` (same template shown above) will +show a Page with "Documents own tile" as title, "This ist the text for the description +meta tag" in the description, "Seo, Content" in the keywords and a canonical link with +``href="/original/url/of/content"``. But what about some default string to just concatenate +defaults and documents own values? Just add some more configs to the cmf_seo configuration +section. + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + sonata_seo: + page: + metas: + names: + keywords: default, sonata, seo + cmf_seo: + title: default_title_key + description: default_title_key + + .. code-block:: xml + + + + + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension( + 'sonata_seo', array( + 'page' => array( + 'metas' => array( + 'names' => array( + 'keywords' => 'default, key, other', + ), + ), + ), + ), + 'cmf_seo' => array( + 'title' => 'default_title_key', + 'description' => 'default_description_key', + ), + ); + +As you will notice, you got the opportunity to set Symfony translation key for your +default values for title and description. So you will got Multi-Language-Support +out of the box. Just define your values for default title/description as translations: + +.. code-block:: xml + + + + + + + + default_title_key + %content_title% | Default title + + + default_description_key + Default description. %content_description% + + + + + +If you want to concatenate your documents values with the default ones you need them as +parameters in you translation target. + +.. tip:: + If you does not what to open a translation file for two entry, just set + ``Default title | %%content_title%%`` or ``Default description. %%content_description%%" + +For changing the default translation domain (messages), the SeoBundle provides a configuration +value: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + cmf_seo: + translation_domain: AcmeDemoBundle + + .. code-block:: xml + + + + + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension( + 'cmf_seo' => array( + 'translation_domain' => 'AcmeDemoBundle', + ), + ); + +For redirects instead of canonical links (default) set the following option: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + cmf_seo: + original_route_pattern: redirect + + .. code-block:: xml + + + + + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension( + 'cmf_seo' => array( + 'original_route_pattern' => 'redirect', + ), + ); + +This value will cause a redirect to the url persisted in the ``originalUrl`` property of the +``SeoMetadata``. + +The SeoMetadata contains a form type for your Symfony Form. Just create you form with the following key: + +.. code-block:: php + $formBuilder + ... + ->add('seoMetadata', 'seo_metadata', array('label' => false)); + ... + ; + +For SonataAdminBundle user the SeoBundle provides an admin extension to add that form to your +form configuration. + +Using extractors for getting your documents seo metadata +-------------------------------------------------------- + +Instead of setting every value to the ``SeoMetadata`` manually +a strategy solution to extract the values from your content document +can be chosen. To do so you got the possibility to add strategies to +your document for each value one by one. Depending on the +strategy a method on the document is called to extract the +value. It is up to the developer how to implement that extraction methods. + ++--------------------------+------------------------+-----------------------------------------------+ +|StrategyInterface | method call | Description | ++==========================+========================+===============================================+ +|SeoDescriptionExtractor | getSeoDescription() | the documents part for the page description | ++--------------------------+------------------------+-----------------------------------------------+ +|SeoOriginalRouteExtractor | getSeoOriginalRoute() |return a ``Route`` object to redirect to | +| | |or create a canonical link from | ++--------------------------+------------------------+-----------------------------------------------+ +|SeoOriginalUrlExtractor | getSeoOriginalUrl() |return a absolute url object to redirect to | +| | |or create a canonical link from | ++--------------------------+------------------------+-----------------------------------------------+ +|SeoTitleExtractor | getSeoTitle() |return a string for setting the page title | ++--------------------------+------------------------+-----------------------------------------------+ +|TitleReadExtractor | - |if implemented the ``getTitle()`` the | +| | |extractor will use this | ++--------------------------+------------------------+-----------------------------------------------+ + +For customizing the extraction process you have got the opportunity to create your own extractor. +Just by implementing the ``SeoExtractorInterface`` and tagging the service as ``cmf_seo.extractor`` + +.. code-block:: xml + + + + + + Acme\DemoBundle\Extractor\MyTitleExtractor + + + + + + + + + + +.. _`with composer`: http://getcomposer.org +.. _`symfony-cmf/menu-bundle`: https://packagist.org/packages/symfony-cmf/menu-bundle +.. _`with github`: git clone https://github.com/symfony-cmf/SeoContentBundle version path/to/ +.. _`sonata seo documentation`: http://sonata-project.org/bundles/seo/master/doc/index.html \ No newline at end of file From 88580708e27be49c60717aa11765baa581467921 Mon Sep 17 00:00:00 2001 From: ElectricMaxxx Date: Thu, 3 Apr 2014 10:06:02 +0200 Subject: [PATCH 02/14] refactorings --- bundles/seo/introduction.rst | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/bundles/seo/introduction.rst b/bundles/seo/introduction.rst index 6d304933..963990ef 100644 --- a/bundles/seo/introduction.rst +++ b/bundles/seo/introduction.rst @@ -246,19 +246,19 @@ out of the box. Just define your values for default title/description as transla - - - - default_title_key - %content_title% | Default title - - - default_description_key - Default description. %content_description% - - - - + + + + default_title_key + %content_title% | Default title + + + default_description_key + Default description. %content_description% + + + + If you want to concatenate your documents values with the default ones you need them as parameters in you translation target. From c57f8ca627c17beb99d87cc6ad812e32211f9c7c Mon Sep 17 00:00:00 2001 From: ElectricMaxxx Date: Thu, 3 Apr 2014 10:34:18 +0200 Subject: [PATCH 03/14] fix bug --- bundles/seo/introduction.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bundles/seo/introduction.rst b/bundles/seo/introduction.rst index 963990ef..88177615 100644 --- a/bundles/seo/introduction.rst +++ b/bundles/seo/introduction.rst @@ -39,6 +39,8 @@ You can install the bundle in 2 different ways: Both bundles need to be registered in the ``appKernel`` .. code-block:: php + + // app/appKernel.php public function registerBundles() { $bundles = array( From 27034f4e92990a7921bf10e2a8f6bc4b919c6f28 Mon Sep 17 00:00:00 2001 From: ElectricMaxxx Date: Thu, 3 Apr 2014 10:35:23 +0200 Subject: [PATCH 04/14] fix code blocks --- bundles/seo/introduction.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bundles/seo/introduction.rst b/bundles/seo/introduction.rst index 88177615..abab3ef5 100644 --- a/bundles/seo/introduction.rst +++ b/bundles/seo/introduction.rst @@ -93,6 +93,7 @@ The only thing to do now is to insert the TwigHelper into your template: .. code-block:: html + @@ -266,6 +267,7 @@ If you want to concatenate your documents values with the default ones you need parameters in you translation target. .. tip:: + If you does not what to open a translation file for two entry, just set ``Default title | %%content_title%%`` or ``Default description. %%content_description%%" @@ -334,6 +336,7 @@ This value will cause a redirect to the url persisted in the ``originalUrl`` pro The SeoMetadata contains a form type for your Symfony Form. Just create you form with the following key: .. code-block:: php + $formBuilder ... ->add('seoMetadata', 'seo_metadata', array('label' => false)); @@ -374,6 +377,7 @@ For customizing the extraction process you have got the opportunity to create yo Just by implementing the ``SeoExtractorInterface`` and tagging the service as ``cmf_seo.extractor`` .. code-block:: xml + Date: Thu, 3 Apr 2014 10:40:08 +0200 Subject: [PATCH 05/14] fix tip section --- bundles/seo/introduction.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bundles/seo/introduction.rst b/bundles/seo/introduction.rst index abab3ef5..3b4ec1b0 100644 --- a/bundles/seo/introduction.rst +++ b/bundles/seo/introduction.rst @@ -268,8 +268,9 @@ parameters in you translation target. .. tip:: - If you does not what to open a translation file for two entry, just set - ``Default title | %%content_title%%`` or ``Default description. %%content_description%%" + If you does not what to open a translation file for two entry, + just set ``Default title | %%content_title%%`` + or ``Default description. %%content_description%%" For changing the default translation domain (messages), the SeoBundle provides a configuration value: From 9e7e7235e659d06dd034dc9e934f8c0c76259530 Mon Sep 17 00:00:00 2001 From: ElectricMaxxx Date: Thu, 3 Apr 2014 11:05:24 +0200 Subject: [PATCH 06/14] delete tip section --- bundles/seo/introduction.rst | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/bundles/seo/introduction.rst b/bundles/seo/introduction.rst index 3b4ec1b0..de9c4383 100644 --- a/bundles/seo/introduction.rst +++ b/bundles/seo/introduction.rst @@ -266,11 +266,9 @@ out of the box. Just define your values for default title/description as transla If you want to concatenate your documents values with the default ones you need them as parameters in you translation target. -.. tip:: - - If you does not what to open a translation file for two entry, - just set ``Default title | %%content_title%%`` - or ``Default description. %%content_description%%" +If you does not what to open a translation file for two entry, +just set ``Default title | %%content_title%%`` +or ``Default description. %%content_description%%" For changing the default translation domain (messages), the SeoBundle provides a configuration value: From 7568487c6427a68992a2afb488ecc791fc966dc8 Mon Sep 17 00:00:00 2001 From: ElectricMaxxx Date: Thu, 3 Apr 2014 11:52:47 +0200 Subject: [PATCH 07/14] fix tip bug --- bundles/seo/introduction.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bundles/seo/introduction.rst b/bundles/seo/introduction.rst index de9c4383..66dbd1bc 100644 --- a/bundles/seo/introduction.rst +++ b/bundles/seo/introduction.rst @@ -266,9 +266,10 @@ out of the box. Just define your values for default title/description as transla If you want to concatenate your documents values with the default ones you need them as parameters in you translation target. -If you does not what to open a translation file for two entry, -just set ``Default title | %%content_title%%`` -or ``Default description. %%content_description%%" +.. tip:: + + If you does not what to open a translation file for two entry, just set + ``Default title | %%content_title%%``or ``Default description. %%content_description%%``. For changing the default translation domain (messages), the SeoBundle provides a configuration value: From 1c419d5dcf91bd80965967c70c24c1407a7adc29 Mon Sep 17 00:00:00 2001 From: ElectricMaxxx Date: Thu, 3 Apr 2014 12:03:06 +0200 Subject: [PATCH 08/14] fix target bug --- bundles/seo/introduction.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/seo/introduction.rst b/bundles/seo/introduction.rst index 66dbd1bc..f43a913c 100644 --- a/bundles/seo/introduction.rst +++ b/bundles/seo/introduction.rst @@ -397,6 +397,6 @@ Just by implementing the ``SeoExtractorInterface`` and tagging the service as `` .. _`with composer`: http://getcomposer.org -.. _`symfony-cmf/menu-bundle`: https://packagist.org/packages/symfony-cmf/menu-bundle +.. _`packagist`: https://packagist.org/packages/symfony-cmf/menu-bundle .. _`with github`: git clone https://github.com/symfony-cmf/SeoContentBundle version path/to/ .. _`sonata seo documentation`: http://sonata-project.org/bundles/seo/master/doc/index.html \ No newline at end of file From c3aaa442f1e9daa95b493a9e65a9b661ea553f2c Mon Sep 17 00:00:00 2001 From: ElectricMaxxx Date: Thu, 3 Apr 2014 15:11:42 +0200 Subject: [PATCH 09/14] redo target stuff, refactoring --- bundles/index.rst | 1 + bundles/seo/index.rst | 2 +- bundles/seo/introduction.rst | 74 +++++++++++++++++++++--------------- 3 files changed, 46 insertions(+), 31 deletions(-) diff --git a/bundles/index.rst b/bundles/index.rst index 2ab2f84a..7d509868 100644 --- a/bundles/index.rst +++ b/bundles/index.rst @@ -17,5 +17,6 @@ Bundles search/index simple_cms/index tree_browser/index + seo/index .. include:: map.rst.inc diff --git a/bundles/seo/index.rst b/bundles/seo/index.rst index 6a4fa871..b9ef4333 100644 --- a/bundles/seo/index.rst +++ b/bundles/seo/index.rst @@ -1,5 +1,5 @@ SeoBundle -============= +========= .. toctree:: :maxdepth: 2 diff --git a/bundles/seo/introduction.rst b/bundles/seo/introduction.rst index f43a913c..8e60a672 100644 --- a/bundles/seo/introduction.rst +++ b/bundles/seo/introduction.rst @@ -16,7 +16,8 @@ for the same content if you need that. There are two solutions to avoid penalties with search engines: -- Create a canonical link that identifies the original URL: ```` +- Create a canonical link that identifies the + original URL: ```` - Redirect to THE original url. @@ -123,8 +124,9 @@ called `SeoMetada`: .. code-block:: php /** - * This string contains the information where we will find the original content. - * Depending on the setting for the cmf_seo.content.pattern, we will do an redirect to this url or + * This string contains the information where we will find the + * original content. Depending on the setting for the + * cmf_seo.content.pattern, we will do an redirect to this url or * create a canonical link with this value as the href attribute. * * @var string @@ -132,22 +134,24 @@ called `SeoMetada`: private $originalUrl; /** - * If this string is set, it will be inserted as a meta tag for the page description. + * If this string is set, it will be inserted as a meta + * tag for the page description. * * @var string */ private $metaDescription; /** - * This comma separated list will contain the Keywords for the page's meta information. + * This comma separated list will contain the Keywords for + * the page's meta information. * * @var string */ private $metaKeywords; A object should implement -the `SeoAwareInterface`, which simply forced to implement setter/getter for the -seo metadata. A simple example would be: +the `SeoAwareInterface`, which simply forced to implement +setter/getter for the seo metadata. A simple example would be: .. code-block:: php @@ -189,11 +193,13 @@ seo metadata. A simple example would be: $manager->persist($route); $manager->flush(); -Visiting the site with the url ``/seo-content`` (same template shown above) will -show a Page with "Documents own tile" as title, "This ist the text for the description -meta tag" in the description, "Seo, Content" in the keywords and a canonical link with -``href="/original/url/of/content"``. But what about some default string to just concatenate -defaults and documents own values? Just add some more configs to the cmf_seo configuration +Visiting the site with the url ``/seo-content`` (same template +shown above) will show a Page with "Documents own tile" as +title, "This ist the text for the description meta tag" in +the description, "Seo, Content" in the keywords and a canonical +link with ``href="/original/url/of/content"``. But what about +some default string to just concatenate defaults and documents +own values? Just add some more configs to the cmf_seo configuration section. .. configuration-block:: @@ -240,9 +246,11 @@ section. ), ); -As you will notice, you got the opportunity to set Symfony translation key for your -default values for title and description. So you will got Multi-Language-Support -out of the box. Just define your values for default title/description as translations: +As you will notice, you got the opportunity to set Symfony +translation key for your default values for title and +description. So you will got Multi-Language-Support +out of the box. Just define your values for default +title/description as translations: .. code-block:: xml @@ -263,16 +271,18 @@ out of the box. Just define your values for default title/description as transla -If you want to concatenate your documents values with the default ones you need them as -parameters in you translation target. +If you want to concatenate your documents values with the +default ones you need them as parameters in you translation +target. .. tip:: - If you does not what to open a translation file for two entry, just set - ``Default title | %%content_title%%``or ``Default description. %%content_description%%``. + If you does not what to open a translation file for two entry, + just set ``Default title | %%content_title%%``or ``Default + description. %%content_description%%``. -For changing the default translation domain (messages), the SeoBundle provides a configuration -value: +For changing the default translation domain (messages), the SeoBundle +provides a configuration value: .. configuration-block:: @@ -301,7 +311,8 @@ value: ), ); -For redirects instead of canonical links (default) set the following option: +For redirects instead of canonical links (default) set the following +option: .. configuration-block:: @@ -330,10 +341,11 @@ For redirects instead of canonical links (default) set the following option: ), ); -This value will cause a redirect to the url persisted in the ``originalUrl`` property of the -``SeoMetadata``. +This value will cause a redirect to the url persisted in the +``originalUrl`` property of the ``SeoMetadata``. -The SeoMetadata contains a form type for your Symfony Form. Just create you form with the following key: +The SeoMetadata contains a form type for your Symfony Form. +Just create you form with the following key: .. code-block:: php @@ -343,8 +355,8 @@ The SeoMetadata contains a form type for your Symfony Form. Just create you form ... ; -For SonataAdminBundle user the SeoBundle provides an admin extension to add that form to your -form configuration. +For SonataAdminBundle user the SeoBundle provides an admin extension +to add that form to your form configuration. Using extractors for getting your documents seo metadata -------------------------------------------------------- @@ -373,8 +385,10 @@ value. It is up to the developer how to implement that extraction methods. | | |extractor will use this | +--------------------------+------------------------+-----------------------------------------------+ -For customizing the extraction process you have got the opportunity to create your own extractor. -Just by implementing the ``SeoExtractorInterface`` and tagging the service as ``cmf_seo.extractor`` +For customizing the extraction process you have got the opportunity +to create your own extractor. Just by implementing the +``SeoExtractorInterface`` and tagging the service as +``cmf_seo.extractor`` .. code-block:: xml @@ -398,5 +412,5 @@ Just by implementing the ``SeoExtractorInterface`` and tagging the service as `` .. _`with composer`: http://getcomposer.org .. _`packagist`: https://packagist.org/packages/symfony-cmf/menu-bundle -.. _`with github`: git clone https://github.com/symfony-cmf/SeoContentBundle version path/to/ +.. _`with github`: git clone https://github.com/symfony-cmf/SeoContentBundle .. _`sonata seo documentation`: http://sonata-project.org/bundles/seo/master/doc/index.html \ No newline at end of file From 2aceba990c157ad254471e01f71342322f340b55 Mon Sep 17 00:00:00 2001 From: WouterJ Date: Sun, 6 Apr 2014 15:44:32 +0200 Subject: [PATCH 10/14] Fixed standards --- bundles/seo/introduction.rst | 207 +++++++++++++++++------------------ 1 file changed, 99 insertions(+), 108 deletions(-) diff --git a/bundles/seo/introduction.rst b/bundles/seo/introduction.rst index 8e60a672..59e0b00a 100644 --- a/bundles/seo/introduction.rst +++ b/bundles/seo/introduction.rst @@ -1,64 +1,59 @@ SeoContentBundle ================ - This bundle helps you optimize your websites - for search engines by collecting SEO data in - a central location and making it available in - twig. It is built on top of the SonataSeoBundle. + This bundle helps you optimize your websites for search engines by + collecting SEO data in a central location and making it available in twig. + It is built on top of the SonataSeoBundle. Preface ------- -Search engines punish you when you provide -the same content under several URLs. -The CMF allows you to have several URLs -for the same content if you need that. -There are two solutions to avoid penalties -with search engines: +Search engines punish you when you provide the same content under several +URLs. The CMF allows you to have several URLs for the same content if you +need that. There are two solutions to avoid penalties with search engines: -- Create a canonical link that identifies the - original URL: ```` +* Create a canonical link that identifies the original URL: + ````; +* Redirect to THE original url. -- Redirect to THE original url. +Both take care on search engines, which does not like it to have same content +under different routes. -Both take care on search engines, which does not like -it to have same content under different routes. - -The SeoBundle uses sonatas SeoBundle and its TwigHelper -to render the the `SeoMetadata` into your Pag. So you -should have a look at the documentation -at `sonata seo documentation_` +The SeoBundle uses sonatas SeoBundle and its TwigHelper to render the the +`SeoMetadata` into your Pag. So you should have a look at the documentation at +`sonata seo documentation_` Installation ------------ -You can install the bundle in 2 different ways: - -* Use the official Git repository `with github`_ -* Install it `with composer`_ (``symfony-Symfony CMF/seo-content-bundle`` on `Packagist`_). - -Both bundles need to be registered in the ``appKernel`` +You can install this bundle `with composer`_ using the ``symfony-Symfony +CMF/seo-content-bundle`` package on `Packagist`_. -.. code-block:: php +Both the CmfSeoBundle and SonataSeoBundle need to be registered in the +``AppKernel``:: // app/appKernel.php + + // ... public function registerBundles() { $bundles = array( - //register both SeoBundles + // ... new Sonata\SeoBundle\SonataSeoBundle(), new Symfony\Cmf\Bundle\SeoBundle\CmfSeoBundle(), ); + // ... + return $bundles; } -A very basic use case -_____________________ +A Very Basic Use Case +~~~~~~~~~~~~~~~~~~~~~ -The simplest use case would be to just set some configuration -to the sonata_seo configuration section and set the TwigHelper -into your template. +The simplest use case would be to just set some configuration to the +``sonata_seo`` configuration section and use the twig helper in your +templates. .. configuration-block:: @@ -88,14 +83,17 @@ into your template. ), )); -To get a deeper look into the sonata seo-bundle configuration you -should visit its documentation at `sonata seo documentation_` -The only thing to do now is to insert the TwigHelper into your -template: +.. seealso:: -.. code-block:: html + To get a deeper look into the SonataSeoBundle configuration, you should visit + the `Sonata documentation`_. + +The only thing to do now is to use the twig helper in your templates: + +.. code-block:: html+jinja + {{ sonata_seo_title() }} @@ -107,11 +105,11 @@ template: -This will render a Page with the tilte defined above. The -information definded for description and keywords will go -into the meta tags. +This will render a page with the default title ("Page's default title") as +title element. The information definded for description and keywords will go +into the correct metatags. -Using SeoMetadata - Admin extension and a form type +Using SeoMetadata - Admin Extension and a form type --------------------------------------------------- The basic example would work perfect without the Symfony CMF @@ -123,14 +121,14 @@ called `SeoMetada`: .. code-block:: php - /** + /** * This string contains the information where we will find the * original content. Depending on the setting for the * cmf_seo.content.pattern, we will do an redirect to this url or * create a canonical link with this value as the href attribute. * * @var string - */ + * private $originalUrl; /** @@ -138,7 +136,7 @@ called `SeoMetada`: * tag for the page description. * * @var string - */ + * private $metaDescription; /** @@ -146,12 +144,12 @@ called `SeoMetada`: * the page's meta information. * * @var string - */ + * private $metaKeywords; -A object should implement -the `SeoAwareInterface`, which simply forced to implement -setter/getter for the seo metadata. A simple example would be: +A object should implement the ``SeoAwareInterface``, which simply forces to +implement the setter and getter for the seo metadata. A simple example would +be: .. code-block:: php @@ -193,14 +191,12 @@ setter/getter for the seo metadata. A simple example would be: $manager->persist($route); $manager->flush(); -Visiting the site with the url ``/seo-content`` (same template -shown above) will show a Page with "Documents own tile" as -title, "This ist the text for the description meta tag" in -the description, "Seo, Content" in the keywords and a canonical -link with ``href="/original/url/of/content"``. But what about -some default string to just concatenate defaults and documents -own values? Just add some more configs to the cmf_seo configuration -section. +Visiting the site with the url ``/seo-content`` (same template shown above) +will show a Page with "Documents own tile" as title, "This ist the text for +the description meta tag" in the description, "Seo, Content" in the keywords +and a canonical link with ``href="/original/url/of/content"``. But what about +some default string to just concatenate defaults and documents own values? +Just add some more configs to the cmf_seo configuration section. .. configuration-block:: @@ -246,10 +242,9 @@ section. ), ); -As you will notice, you got the opportunity to set Symfony -translation key for your default values for title and -description. So you will got Multi-Language-Support -out of the box. Just define your values for default +As you will notice, you got the opportunity to set Symfony translation key for +your default values for title and description. So you will got +Multi-Language-Support out of the box. Just define your values for default title/description as translations: .. code-block:: xml @@ -271,18 +266,17 @@ title/description as translations: -If you want to concatenate your documents values with the -default ones you need them as parameters in you translation -target. +If you want to concatenate your documents values with the default ones you +need them as parameters in you translation target. .. tip:: - If you does not what to open a translation file for two entry, - just set ``Default title | %%content_title%%``or ``Default - description. %%content_description%%``. + If you does not what to open a translation file for two entry, just set + ``Default title | %%content_title%%``or ``Default description. + %%content_description%%``. -For changing the default translation domain (messages), the SeoBundle -provides a configuration value: +For changing the default translation domain (messages), the SeoBundle provides +a configuration value: .. configuration-block:: @@ -311,8 +305,7 @@ provides a configuration value: ), ); -For redirects instead of canonical links (default) set the following -option: +For redirects instead of canonical links (default) set the following option: .. configuration-block:: @@ -341,11 +334,11 @@ option: ), ); -This value will cause a redirect to the url persisted in the -``originalUrl`` property of the ``SeoMetadata``. +This value will cause a redirect to the url persisted in the ``originalUrl`` +property of the ``SeoMetadata``. -The SeoMetadata contains a form type for your Symfony Form. -Just create you form with the following key: +The SeoMetadata contains a form type for your Symfony Form. Just create you +form with the following key: .. code-block:: php @@ -355,40 +348,39 @@ Just create you form with the following key: ... ; -For SonataAdminBundle user the SeoBundle provides an admin extension -to add that form to your form configuration. +For SonataAdminBundle user the SeoBundle provides an admin extension to add +that form to your form configuration. -Using extractors for getting your documents seo metadata +Using Extractors for Getting Your Documents Seo Metadata -------------------------------------------------------- -Instead of setting every value to the ``SeoMetadata`` manually -a strategy solution to extract the values from your content document -can be chosen. To do so you got the possibility to add strategies to -your document for each value one by one. Depending on the -strategy a method on the document is called to extract the -value. It is up to the developer how to implement that extraction methods. - -+--------------------------+------------------------+-----------------------------------------------+ -|StrategyInterface | method call | Description | -+==========================+========================+===============================================+ -|SeoDescriptionExtractor | getSeoDescription() | the documents part for the page description | -+--------------------------+------------------------+-----------------------------------------------+ -|SeoOriginalRouteExtractor | getSeoOriginalRoute() |return a ``Route`` object to redirect to | -| | |or create a canonical link from | -+--------------------------+------------------------+-----------------------------------------------+ -|SeoOriginalUrlExtractor | getSeoOriginalUrl() |return a absolute url object to redirect to | -| | |or create a canonical link from | -+--------------------------+------------------------+-----------------------------------------------+ -|SeoTitleExtractor | getSeoTitle() |return a string for setting the page title | -+--------------------------+------------------------+-----------------------------------------------+ -|TitleReadExtractor | - |if implemented the ``getTitle()`` the | -| | |extractor will use this | -+--------------------------+------------------------+-----------------------------------------------+ - -For customizing the extraction process you have got the opportunity -to create your own extractor. Just by implementing the -``SeoExtractorInterface`` and tagging the service as -``cmf_seo.extractor`` +Instead of setting every value to the ``SeoMetadata`` manually a strategy +solution to extract the values from your content document can be chosen. To do +so you got the possibility to add strategies to your document for each value +one by one. Depending on the strategy a method on the document is called to +extract the value. It is up to the developer how to implement that extraction +methods. + ++-----------------------------------+---------------------------+---------------------------------------------+ +| StrategyInterface | method call | Description | ++===================================+===========================+=============================================+ +| ``SeoDescriptionReadInterface`` | ``getSeoDescription()`` | the documents part for the page description | ++-----------------------------------+---------------------------+---------------------------------------------+ +| ``SeoOriginalRouteReadInterface`` | ``getSeoOriginalRoute()`` | return a ``Route`` object to redirect to | +| | | or create a canonical link from | ++-----------------------------------+---------------------------+---------------------------------------------+ +| ``SeoOriginalUrlReadInterface`` | ``getSeoOriginalUrl()`` | return a absolute url object to redirect to | +| | | or create a canonical link from | ++-----------------------------------+---------------------------+---------------------------------------------+ +| ``SeoTitleReadInterface`` | ``getSeoTitle()`` | return a string for setting the page title | ++-----------------------------------+---------------------------+---------------------------------------------+ +| - | ``getTitle()`` | if implemented the ``getTitle()`` the | +| | | extractor will use this | ++-----------------------------------+---------------------------+---------------------------------------------+ + +For customizing the extraction process, you have got the opportunity to create +your own extractor. Just by implementing the ``SeoExtractorInterface`` and +tagging the service as ``cmf_seo.extractor`` .. code-block:: xml @@ -412,5 +404,4 @@ to create your own extractor. Just by implementing the .. _`with composer`: http://getcomposer.org .. _`packagist`: https://packagist.org/packages/symfony-cmf/menu-bundle -.. _`with github`: git clone https://github.com/symfony-cmf/SeoContentBundle -.. _`sonata seo documentation`: http://sonata-project.org/bundles/seo/master/doc/index.html \ No newline at end of file +.. _`Sonata documentation`: http://sonata-project.org/bundles/seo/master/doc/index.html From c2a536b7908ed74d31591283e9a6f0dabc855f9d Mon Sep 17 00:00:00 2001 From: WouterJ Date: Sun, 6 Apr 2014 22:29:58 +0200 Subject: [PATCH 11/14] Rewrote docs --- bundles/seo/extractors.rst | 112 ++++++++++++++ bundles/seo/index.rst | 1 + bundles/seo/introduction.rst | 275 ++++++++++++++--------------------- bundles/seo/seo_aware.rst | 161 ++++++++++++++++++++ 4 files changed, 387 insertions(+), 162 deletions(-) create mode 100644 bundles/seo/extractors.rst create mode 100644 bundles/seo/seo_aware.rst diff --git a/bundles/seo/extractors.rst b/bundles/seo/extractors.rst new file mode 100644 index 00000000..15f9511c --- /dev/null +++ b/bundles/seo/extractors.rst @@ -0,0 +1,112 @@ +Using Extractors to Retrieve the Seo Metadata +============================================= + +Instead of setting every value to the ``SeoMetadata`` manually, an extractor +can do the work for you. Extractors are executed when an object implements a +specific interface. The method required by that interface will return the +value for the specific SEO data. The extractor will then update the +``SeoMetadata`` object for the current object with the returned value. + +Available Extractors +-------------------- + ++-----------------------------------+---------------------------+----------------------------------------------+ +| ExtractorInterface | Method | Type | ++===================================+===========================+==============================================+ +| ``SeoDescriptionReadInterface`` | ``getSeoDescription()`` | Returns the meta description | ++-----------------------------------+---------------------------+----------------------------------------------+ +| ``SeoTitleReadInterface`` | ``getSeoTitle()`` | Returns the page title | ++-----------------------------------+---------------------------+----------------------------------------------+ +| - | ``getTitle()`` | If the document has a ``getTitle()`` method, | +| | | it'll be used as the page title | ++-----------------------------------+---------------------------+----------------------------------------------+ +| ``SeoOriginalUrlReadInterface`` | ``getSeoOriginalUrl()`` | Returns a absolute url object to redirect to | +| | | or create a canonical link from | ++-----------------------------------+---------------------------+----------------------------------------------+ +| ``SeoOriginalRouteReadInterface`` | ``getSeoOriginalRoute()`` | Return a ``Route`` object to redirect to | +| | | or create a canonical link from | ++-----------------------------------+---------------------------+----------------------------------------------+ + +.. note:: + + The interfaces live in the ``Symfony\Cmf\Bundle\SeoBundle\Extractor`` + namespace. + +An Example +---------- + +Assume you have an ``Article`` object and you want to use both the ``$title`` +and ``$date`` properties as page title and the ``$intro`` property as +description, you can implement both interfaces and your result will be:: + + // src/Acme/BlogBundle/Document/Article.php + namespace Acme\BlogBundle\Document; + + use Symfony\Cmf\Bundle\SeoBundle\Extractor\SeoTitleReadInterface; + use Symfony\Cmf\Bundle\SeoBundle\Extractor\SeoDescriptionReadInterface; + + class Article implements SeoTitleReadInterface, SeoDescriptionReadInterface + { + protected $title; + protected $publishDate; + protected $intro; + + // ... + public function getSeoTitle() + { + return $this->title.' ~ '.date($this->publishDate, 'm-Y'); + } + + public function getSeoDescription() + { + return $this->title; + } + } + +Creating Your Own Extractor +--------------------------- + +To customize the extraction process, you can create your own extractor. Just +create a class which implements the ``SeoExtractorInterface`` and tag it with +``cmf_seo.extractor``: + +.. configuration-block:: + + .. code-block:: yaml + + parameters: + acme_demo.extractor.custom.class: Acme\DemoBundle\Extractor\MyCustomExtractor + + services: + acme_demo.extractor.custom: + class: "%acme_demo.extractor.custom.class%" + tags: + - { name: cmf_seo.extractor } + + .. code-block:: xml + + + + + Acme\DemoBundle\Extractor\MyCustomExtractor + + + + + + + + + + .. code-block:: php + + $container->addParameter( + 'acme_demo.extractor.custom.class', + 'Acme\DemoBundle\Extractor\MyCustomExtractor' + ); + + $container->register('acme_demo.extractor.custom', '%acme_demo.extractor.custom.class%') + ->addTag('cmf_seo.extractor') + ; diff --git a/bundles/seo/index.rst b/bundles/seo/index.rst index b9ef4333..22d54d0f 100644 --- a/bundles/seo/index.rst +++ b/bundles/seo/index.rst @@ -5,3 +5,4 @@ SeoBundle :maxdepth: 2 introduction + seo_aware diff --git a/bundles/seo/introduction.rst b/bundles/seo/introduction.rst index 59e0b00a..f3518f35 100644 --- a/bundles/seo/introduction.rst +++ b/bundles/seo/introduction.rst @@ -1,35 +1,16 @@ -SeoContentBundle -================ +SeoBundle +========= - This bundle helps you optimize your websites for search engines by - collecting SEO data in a central location and making it available in twig. - It is built on top of the SonataSeoBundle. - -Preface -------- - -Search engines punish you when you provide the same content under several -URLs. The CMF allows you to have several URLs for the same content if you -need that. There are two solutions to avoid penalties with search engines: - -* Create a canonical link that identifies the original URL: - ````; -* Redirect to THE original url. - -Both take care on search engines, which does not like it to have same content -under different routes. - -The SeoBundle uses sonatas SeoBundle and its TwigHelper to render the the -`SeoMetadata` into your Pag. So you should have a look at the documentation at -`sonata seo documentation_` + This bundle provides a layer on top of the `SonataSeoBundle`_, to make it + easier to collect SEO data from content documents. Installation ------------ -You can install this bundle `with composer`_ using the ``symfony-Symfony -CMF/seo-content-bundle`` package on `Packagist`_. +You can install this bundle `with composer`_ using the +``symfony-cmf/seo-content-bundle`` package on `Packagist`_. -Both the CmfSeoBundle and SonataSeoBundle need to be registered in the +Both the CmfSeoBundle and SonataSeoBundle must be registered in the ``AppKernel``:: // app/appKernel.php @@ -48,12 +29,11 @@ Both the CmfSeoBundle and SonataSeoBundle need to be registered in the return $bundles; } -A Very Basic Use Case -~~~~~~~~~~~~~~~~~~~~~ +Usage +~~~~~ -The simplest use case would be to just set some configuration to the -``sonata_seo`` configuration section and use the twig helper in your -templates. +The simplest use of this bundle would be to just set some configuration to the +``sonata_seo`` configuration section and use the twig helper in your templates. .. configuration-block:: @@ -82,11 +62,6 @@ templates. ), ), )); - -.. seealso:: - - To get a deeper look into the SonataSeoBundle configuration, you should visit - the `Sonata documentation`_. The only thing to do now is to use the twig helper in your templates: @@ -109,87 +84,94 @@ This will render a page with the default title ("Page's default title") as title element. The information definded for description and keywords will go into the correct metatags. -Using SeoMetadata - Admin Extension and a form type ---------------------------------------------------- +.. seealso:: + + To get a deeper look into the SonataSeoBundle, you should visit the + `Sonata documentation`_. -The basic example would work perfect without the Symfony CMF -SeoBundle. But the SeoBundle creates more possibilities to -create the pages's title, description, keywords and even -the original url for a canonical link or a redirect. -To persist that data the Bundle serves a value object -called `SeoMetada`: +Using SeoMetadata +----------------- -.. code-block:: php +The basic example shown above works perfectly without the CmfSeoBundle. The +CmfSeoBundle provides more extension points to configure the SEO data with +data from the document (e.g. a ``StaticContent`` document). This is done by +using SEO metadata. This is SEO data which will be used for a particular +document. This metadata can hold: - /** - * This string contains the information where we will find the - * original content. Depending on the setting for the - * cmf_seo.content.pattern, we will do an redirect to this url or - * create a canonical link with this value as the href attribute. - * - * @var string - * - private $originalUrl; - - /** - * If this string is set, it will be inserted as a meta - * tag for the page description. - * - * @var string - * - private $metaDescription; - - /** - * This comma separated list will contain the Keywords for - * the page's meta information. - * - * @var string - * - private $metaKeywords; - -A object should implement the ``SeoAwareInterface``, which simply forces to -implement the setter and getter for the seo metadata. A simple example would -be: +* The title; +* The meta keywords; +* The meta description; +* The original URL (when more than one URL contains the same content). -.. code-block:: php +This bundle provides two ways of using this metadata: + +#. Implementing the ``SeoAwareInterface`` and persisting the ``SeoMetadata`` + with the object. +#. Using the extractors, to extract the ``SeoMetadata`` from already existing + values (e.g. the title of the page). + +You can also use both ways at the same time for the document. In that case, +the persisted ``SeoMetadata`` can be changed by the extractors. + +Persisting the ``SeoMetadata`` with the document makes it easy to edit for the +admin, while using the extractors makes it perfect to use without doing +anything. + +Both ways are documented in detail in seperate sections: + +* :doc:`seo_aware` +* :doc:`extractors` + +Choosing the Original Route Pattern +----------------------------------- + +Search engines punish you, when you provide the same content under several +URLs. The CMF allows you to have several URLs for the same content if you +need that. There are two solutions to avoid penalties with search engines: - use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route; - use Symfony\Cmf\Bundle\SeoBundle\Doctrine\Phpcr\SeoAwareContent; - use Symfony\Cmf\Bundle\SeoBundle\Model\SeoMetadata; - - //retrieve the root document - $rootDocument = $documentManager->find(null, '/cms/content'); - - //create the seo aware document - $seoDocument = new SeoAwareContent(); - $seoDocument->setParent($rootDocument); - $seoDocument->setTitle('Same title as in original'); - $seoDocument->setName('seo-content'); - $seoDocument->setBody('Same Content as in Original'); - - //set the seo metadata - $seoMetadata = new SeoMetadata(); - $seoMetadata->setTitle("Documents own tile"); - $seoMetadata->setMetaKeywords('Seo, Content'); - $seoMetadata->setMetaDescription( - 'This ist the text for the description meta tag' - ); - $seoMetadata->setOriginalUrl("/original/url/of/content"); - $seoDocument->setSeoMetadata($seoMetadata); - - // retrieve the route root node - $routeRoot = $documentManager->find(null, '/cms/routes'); - - //create the route for the document - $route = new Route(); - $route->setParentDocument($routeRoot); - $route->setName('seo-content'); - $route->setContent($soDocument); - $route->setDefault('_template', '::base.html.twig'); - - $manager->persist($seoDocument); - $manager->persist($route); - $manager->flush(); +* Create a canonical link that identifies the original URL: + ````; +* Define an "original url" and redirect the other to that one. + +The ``SeoMetadata`` can be configured with the original URL for the current +page. By default, this bundle will create a canonical link for the page. If +you want to change that to redirect instead, you can set the +``original_route_pattern`` option: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + cmf_seo: + original_route_pattern: redirect + + .. code-block:: xml + + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension( + 'cmf_seo' => array( + 'original_route_pattern' => 'redirect', + ), + ); + +.. todo + +Configuring the Default Values +------------------------------ + +You know now how to work with objects configuring SEO data. However, in some +cases the object doesn't provide any information. Then you have to configure a +default. You can configure the defaults for the SonataSeoBundle, these +defaults will be overriden by the metadata from the CmfSeoBundle. However, you +might want to combine. Visiting the site with the url ``/seo-content`` (same template shown above) will show a Page with "Documents own tile" as title, "This ist the text for @@ -305,6 +287,24 @@ a configuration value: ), ); +Preface +------- + +Search engines punish you when you provide the same content under several +URLs. The CMF allows you to have several URLs for the same content if you +need that. There are two solutions to avoid penalties with search engines: + +* Create a canonical link that identifies the original URL: + ````; +* Redirect to THE original url. + +Both take care on search engines, which does not like it to have same content +under different routes. + +The SeoBundle uses sonatas SeoBundle and its TwigHelper to render the the +`SeoMetadata` into your Pag. So you should have a look at the documentation at +`sonata seo documentation_` + For redirects instead of canonical links (default) set the following option: .. configuration-block:: @@ -351,57 +351,8 @@ form with the following key: For SonataAdminBundle user the SeoBundle provides an admin extension to add that form to your form configuration. -Using Extractors for Getting Your Documents Seo Metadata --------------------------------------------------------- - -Instead of setting every value to the ``SeoMetadata`` manually a strategy -solution to extract the values from your content document can be chosen. To do -so you got the possibility to add strategies to your document for each value -one by one. Depending on the strategy a method on the document is called to -extract the value. It is up to the developer how to implement that extraction -methods. - -+-----------------------------------+---------------------------+---------------------------------------------+ -| StrategyInterface | method call | Description | -+===================================+===========================+=============================================+ -| ``SeoDescriptionReadInterface`` | ``getSeoDescription()`` | the documents part for the page description | -+-----------------------------------+---------------------------+---------------------------------------------+ -| ``SeoOriginalRouteReadInterface`` | ``getSeoOriginalRoute()`` | return a ``Route`` object to redirect to | -| | | or create a canonical link from | -+-----------------------------------+---------------------------+---------------------------------------------+ -| ``SeoOriginalUrlReadInterface`` | ``getSeoOriginalUrl()`` | return a absolute url object to redirect to | -| | | or create a canonical link from | -+-----------------------------------+---------------------------+---------------------------------------------+ -| ``SeoTitleReadInterface`` | ``getSeoTitle()`` | return a string for setting the page title | -+-----------------------------------+---------------------------+---------------------------------------------+ -| - | ``getTitle()`` | if implemented the ``getTitle()`` the | -| | | extractor will use this | -+-----------------------------------+---------------------------+---------------------------------------------+ - -For customizing the extraction process, you have got the opportunity to create -your own extractor. Just by implementing the ``SeoExtractorInterface`` and -tagging the service as ``cmf_seo.extractor`` - -.. code-block:: xml - - - - - - - Acme\DemoBundle\Extractor\MyTitleExtractor - - - - - - - - - +.. _`SonataSeoBundle`: https://github.com/sonata-project/SonataSeoBundle .. _`with composer`: http://getcomposer.org .. _`packagist`: https://packagist.org/packages/symfony-cmf/menu-bundle .. _`Sonata documentation`: http://sonata-project.org/bundles/seo/master/doc/index.html diff --git a/bundles/seo/seo_aware.rst b/bundles/seo/seo_aware.rst new file mode 100644 index 00000000..04ae30f2 --- /dev/null +++ b/bundles/seo/seo_aware.rst @@ -0,0 +1,161 @@ +Saving the SeoMetadata in the Object +==================================== + +The ``SeoMetadata`` can be saved in the object, so you can persist it into the +database. This option gives admins the possiblity of changing the SEO data for +the document. + +In order to save the ``SeoMetadata`` in the object, the object should +implement the ``SeoAwareInterface``. This requires a getter and a setter for +the ``SeoMetadata``:: + + // src/Acme/SiteBundle/Document/Page.php + namespace Acme\SiteBundle\Document; + + use Symfony\Cmf\Bundle\SeoBundle\Model\SeoAwareInterface; + + class Page implements SeoAwareInterface + { + protected $seoMetadata; + + // ... + public function getSeoMetadata() + { + return $this->seoMetadata; + } + + public function setSeoMetadata($metadata) + { + $this->seoMetadata = $metadata; + } + } + +Now you can set some SEO data for this ``Page`` using the metadata. For +instance inside a data fixture:: + + // src/Acme/SiteBundle/DataFixture/PHPCR/LoadPageData.php + namespace Acme\SiteBundle\DataFixtures\PHPCR; + + use Acme\SiteBundle\Document\Page; + use Symfony\Cmf\Bundle\SeoBundle\Model\SeoMetadata; + use Doctrine\Common\Persistence\ObjectManager; + use Doctrine\Common\DataFixtures\FixtureInterface; + + class LoadPageData implements FixtureInterface + { + public function load(ObjectManager $manager) + { + $page = new Page(); + // ... set some page properties + + $pageMetadata = new SeoMetadata(); + $pageMetadata->setDescription('A special SEO description.'); + $pageMetadata->setTags('seo, cmf, symfony'); + + $page->setSeoMetadata($pageMetadata); + + $manager->persist($page); + $manager->flush(); + } + } + +.. tip:: + + While this examples shows a Doctrine PHPCR ODM data fixture, the bundle + works fully storage agnostic. You can use it with every storage system you + like. + +Persisting the SeoMetadata with Doctrine +---------------------------------------- + +Since Doctrine doesn't allow you to persist an object as a database field, +there is a problem. The bundle provides a solution to solve this by providing +a Doctrine Listener. This listener will serialize the metadata object when +persisting it and it'll unserialize the metadata when the object is fetched +from the database. + +In order to use this listener, you should activate either ``orm`` or ``phpcr`` +as persisting layer for the SeoBundle: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + cmf_seo: + persistence: + phpcr: true + # when using the ORM: + # orm: true + + .. code-block:: xml + + + + + + + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension('cmf_seo', array( + 'persistence' => array( + 'phpcr' => true, + // when using the ORM: + // 'orm' => true, + ), + )); + +This will automatically enable the listener. If you don't want to enable the +listener, but you want to enable a persistence layer, you can set the +``metadata_listener`` option to ``false``: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + cmf_seo: + persistence: + # ... + metadata_listener: false + + .. code-block:: xml + + + + + + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension('cmf_seo', array( + 'persistence' => array( + // ... + ), + 'metadata_listener' => false, + )); + +Form Type +--------- + +The bundle also provides a special form type called ``seo_metadata``. This +form type can be used in forms to edit the ``SeoMetadata`` object. + +Sonata Admin Integration +------------------------ + +Besides providing a form type, the bundle also provides a Sonata Admin +Extension. This extension adds a field for the ``SeoMetadata`` when an admin +edits an objec that implements the ``SeoAwareInterface`` in the Sonata Admin +panel. From 0b45fa34372df572acb9b76d07a6e8c589a66f5b Mon Sep 17 00:00:00 2001 From: WouterJ Date: Tue, 6 May 2014 10:18:22 +0200 Subject: [PATCH 12/14] Finished rewriting SeoBundle --- bundles/seo/introduction.rst | 242 +++++++++++++++++------------------ 1 file changed, 120 insertions(+), 122 deletions(-) diff --git a/bundles/seo/introduction.rst b/bundles/seo/introduction.rst index f3518f35..d4540fa4 100644 --- a/bundles/seo/introduction.rst +++ b/bundles/seo/introduction.rst @@ -72,8 +72,8 @@ The only thing to do now is to use the twig helper in your templates: {{ sonata_seo_title() }} + {{ sonata_seo_metadatas() }} - {{ sonata_seo_link_canonical() }} // needed later

Some page body.

@@ -125,9 +125,9 @@ Both ways are documented in detail in seperate sections: Choosing the Original Route Pattern ----------------------------------- -Search engines punish you, when you provide the same content under several -URLs. The CMF allows you to have several URLs for the same content if you -need that. There are two solutions to avoid penalties with search engines: +Search engines don't like it when you provide the same content under several +URLs. The CMF allows you to have several URLs for the same content if you need +that. There are two solutions to avoid penalties with search engines: * Create a canonical link that identifies the original URL: ````; @@ -162,23 +162,13 @@ you want to change that to redirect instead, you can set the ), ); -.. todo - -Configuring the Default Values ------------------------------- +Defining a Default +------------------ -You know now how to work with objects configuring SEO data. However, in some -cases the object doesn't provide any information. Then you have to configure a -default. You can configure the defaults for the SonataSeoBundle, these -defaults will be overriden by the metadata from the CmfSeoBundle. However, you -might want to combine. - -Visiting the site with the url ``/seo-content`` (same template shown above) -will show a Page with "Documents own tile" as title, "This ist the text for -the description meta tag" in the description, "Seo, Content" in the keywords -and a canonical link with ``href="/original/url/of/content"``. But what about -some default string to just concatenate defaults and documents own values? -Just add some more configs to the cmf_seo configuration section. +You've learned everything about extracting SEO information from objects. +However, in some cases the object doesn't provide any information or there is +no object (e.g. on a login page). For these cases, you have to configure a +default value. These default values can be configured for the SonataSeoBundle: .. configuration-block:: @@ -187,23 +177,11 @@ Just add some more configs to the cmf_seo configuration section. # app/config/config.yml sonata_seo: page: + title: A Default Title metas: names: keywords: default, sonata, seo - cmf_seo: - title: default_title_key - description: default_title_key - - .. code-block:: xml - - - - - - + description: A default description .. code-block:: php @@ -211,54 +189,31 @@ Just add some more configs to the cmf_seo configuration section. $container->loadFromExtension( 'sonata_seo', array( 'page' => array( + 'title' => 'A Default Title', 'metas' => array( 'names' => array( - 'keywords' => 'default, key, other', + 'keywords' => 'default, key, other', + 'description' => 'A default description', ), ), ), ), - 'cmf_seo' => array( - 'title' => 'default_title_key', - 'description' => 'default_description_key', - ), ); -As you will notice, you got the opportunity to set Symfony translation key for -your default values for title and description. So you will got -Multi-Language-Support out of the box. Just define your values for default -title/description as translations: - -.. code-block:: xml - - - - - - - - default_title_key - %content_title% | Default title - - - default_description_key - Default description. %content_description% - - - - - -If you want to concatenate your documents values with the default ones you -need them as parameters in you translation target. - -.. tip:: - - If you does not what to open a translation file for two entry, just set - ``Default title | %%content_title%%``or ``Default description. - %%content_description%%``. - -For changing the default translation domain (messages), the SeoBundle provides -a configuration value: +The Standard Title and Description +---------------------------------- + +Most of the times, the title of a site has a static and a dynamic part. For +instance, "The title of the Page - Symfony". Here "- Symfony" is static and +"The title of the Page" will be replaced by the current title. It is of course +not nice if you need to add this static part to all your titles in documents. + +That's why the CmfSeoBundle provides standard titles and descriptions. When +using these settings, there are 2 placeholders available: ``%content_title%`` +and ``%content_description%``. This will be replaced with the title extracted +from the content object and the description extracted from the content object. + +For instance, to configure the titles of the symfony.com pages, you would do: .. configuration-block:: @@ -266,46 +221,102 @@ a configuration value: # app/config/config.yml cmf_seo: - translation_domain: AcmeDemoBundle + title: "%%content_title%% - Symfony" .. code-block:: xml - - - - + .. code-block:: php // app/config/config.php - $container->loadFromExtension( - 'cmf_seo' => array( - 'translation_domain' => 'AcmeDemoBundle', - ), - ); + $container->loadFromExtension('cmf_seo', array( + 'title' => '%%content_title%% - Symfony', + )); -Preface -------- +.. caution:: -Search engines punish you when you provide the same content under several -URLs. The CMF allows you to have several URLs for the same content if you -need that. There are two solutions to avoid penalties with search engines: + Be sure to escape the percentage characters by using a double percentage + character, otherwise the container will try to replace it with the value + of a container parameter. -* Create a canonical link that identifies the original URL: - ````; -* Redirect to THE original url. +This syntax might look familiair if you have used with the Translation +component before. And that's correct, under the hood the Translation component +is used to replace the placeholders with the correct values. This also means +you get Multi Language Support for free! + +For instance, you can do: + +.. configuration-block:: + + .. code-block:: yaml -Both take care on search engines, which does not like it to have same content -under different routes. + # app/config/config.yml + cmf_seo: + title: seo.title + description: seo.description + + .. code-block:: xml + + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension('cmf_seo', array( + 'title' => 'seo.title', + 'description' => 'seo.description', + )); + +And then configure the translation messages: + +.. configuration-block:: -The SeoBundle uses sonatas SeoBundle and its TwigHelper to render the the -`SeoMetadata` into your Pag. So you should have a look at the documentation at -`sonata seo documentation_` + .. code-block:: xml + + + + + + + + seo.title + %content_title% | Default title + + + seo.description + Default description. %content_description% + + + + + + .. code-block:: php + + // app/Resources/translations/messages.en.php + return array( + 'seo' => array( + 'title' => '%content_title% | Default title', + 'description' => 'Default description. %content_description', + ), + ); + + .. code-block:: yaml + + # app/Resources/translations/messages.en.yml + seo: + title: "%content_title% | Default title" + description: "Default description. %content_description%" -For redirects instead of canonical links (default) set the following option: +For changing the default translation domain (messages), you should use the +``cmf_seo.translation_domain`` setting: .. configuration-block:: @@ -313,16 +324,15 @@ For redirects instead of canonical links (default) set the following option: # app/config/config.yml cmf_seo: - original_route_pattern: redirect + translation_domain: AcmeDemoBundle .. code-block:: xml - - + .. code-block:: php @@ -330,27 +340,15 @@ For redirects instead of canonical links (default) set the following option: // app/config/config.php $container->loadFromExtension( 'cmf_seo' => array( - 'original_route_pattern' => 'redirect', + 'translation_domain' => 'AcmeDemoBundle', ), ); -This value will cause a redirect to the url persisted in the ``originalUrl`` -property of the ``SeoMetadata``. - -The SeoMetadata contains a form type for your Symfony Form. Just create you -form with the following key: - -.. code-block:: php - - $formBuilder - ... - ->add('seoMetadata', 'seo_metadata', array('label' => false)); - ... - ; - -For SonataAdminBundle user the SeoBundle provides an admin extension to add -that form to your form configuration. +Conclusion +---------- +That's it! You have now created a SEO optimized website using nothing more +than a couple of simple settings. .. _`SonataSeoBundle`: https://github.com/sonata-project/SonataSeoBundle .. _`with composer`: http://getcomposer.org From 3b16b818c9fa8433915ab4dbefe1f680ca56fdc5 Mon Sep 17 00:00:00 2001 From: WouterJ Date: Tue, 13 May 2014 20:44:38 +0200 Subject: [PATCH 13/14] Lots of fixes --- bundles/seo/index.rst | 1 + bundles/seo/introduction.rst | 93 ++++++++------------- bundles/seo/seo_aware.rst | 151 ++++++++++++++++++++++++----------- 3 files changed, 142 insertions(+), 103 deletions(-) diff --git a/bundles/seo/index.rst b/bundles/seo/index.rst index 22d54d0f..2c3866c1 100644 --- a/bundles/seo/index.rst +++ b/bundles/seo/index.rst @@ -6,3 +6,4 @@ SeoBundle introduction seo_aware + extractors diff --git a/bundles/seo/introduction.rst b/bundles/seo/introduction.rst index d4540fa4..e5bf2b1a 100644 --- a/bundles/seo/introduction.rst +++ b/bundles/seo/introduction.rst @@ -44,7 +44,7 @@ The simplest use of this bundle would be to just set some configuration to the page: title: Page's default title metas: - names: + name: description: The default description of the page keywords: default, sonata, seo @@ -55,7 +55,7 @@ The simplest use of this bundle would be to just set some configuration to the 'page' => array( 'title' => 'Page's default title', 'metas' => array( - 'names' => array( + 'name' => array( 'description' => 'default description', 'keywords' => 'default, key, other', ), @@ -110,12 +110,15 @@ This bundle provides two ways of using this metadata: #. Using the extractors, to extract the ``SeoMetadata`` from already existing values (e.g. the title of the page). -You can also use both ways at the same time for the document. In that case, -the persisted ``SeoMetadata`` can be changed by the extractors. +You can also combine both ways, even on the same document. In that case, the +persisted ``SeoMetadata`` can be changed by the extractors, to add or tweak +the current available SEO information. For instance, if you are writing a +``BlogPost`` class, you want the SEO keywords to be set to the tags/category +of the post and any additional tags set by the admin. Persisting the ``SeoMetadata`` with the document makes it easy to edit for the -admin, while using the extractors makes it perfect to use without doing -anything. +admin, while using the extractors are perfect to easily use values from the +displayed content. Both ways are documented in detail in seperate sections: @@ -130,8 +133,8 @@ URLs. The CMF allows you to have several URLs for the same content if you need that. There are two solutions to avoid penalties with search engines: * Create a canonical link that identifies the original URL: - ````; -* Define an "original url" and redirect the other to that one. + ```` +* Define an "original url" and redirect all duplicate URLs to it. The ``SeoMetadata`` can be configured with the original URL for the current page. By default, this bundle will create a canonical link for the page. If @@ -162,56 +165,25 @@ you want to change that to redirect instead, you can set the ), ); -Defining a Default ------------------- - -You've learned everything about extracting SEO information from objects. -However, in some cases the object doesn't provide any information or there is -no object (e.g. on a login page). For these cases, you have to configure a -default value. These default values can be configured for the SonataSeoBundle: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - sonata_seo: - page: - title: A Default Title - metas: - names: - keywords: default, sonata, seo - description: A default description - - .. code-block:: php - - // app/config/config.php - $container->loadFromExtension( - 'sonata_seo', array( - 'page' => array( - 'title' => 'A Default Title', - 'metas' => array( - 'names' => array( - 'keywords' => 'default, key, other', - 'description' => 'A default description', - ), - ), - ), - ), - ); - -The Standard Title and Description ----------------------------------- +Defining a Title and Description Template +----------------------------------------- Most of the times, the title of a site has a static and a dynamic part. For -instance, "The title of the Page - Symfony". Here "- Symfony" is static and +instance, "The title of the Page - Symfony". Here, "- Symfony" is static and "The title of the Page" will be replaced by the current title. It is of course -not nice if you need to add this static part to all your titles in documents. +not nice if you had to add this static part to all your titles in documents. + +That's why the CmfSeoBundle provides defining a title and description +template. When using these settings, there are 2 placeholders available: +``%content_title%`` and ``%content_description%``. These will be replaced with +the title extracted from the content object and the description extracted from +the content object. + +.. caution:: -That's why the CmfSeoBundle provides standard titles and descriptions. When -using these settings, there are 2 placeholders available: ``%content_title%`` -and ``%content_description%``. This will be replaced with the title extracted -from the content object and the description extracted from the content object. + The default title and description set by the SonataSeoBundle do override + this template. You should make sure that the defaults also follow the + template. For instance, to configure the titles of the symfony.com pages, you would do: @@ -243,10 +215,10 @@ For instance, to configure the titles of the symfony.com pages, you would do: character, otherwise the container will try to replace it with the value of a container parameter. -This syntax might look familiair if you have used with the Translation -component before. And that's correct, under the hood the Translation component -is used to replace the placeholders with the correct values. This also means -you get Multi Language Support for free! +This syntax might look familiar if you have used the Translation component +before. And that's correct, under the hood the Translation component is used +to replace the placeholders with the correct values. This also means you get +Multi Language Support for free! For instance, you can do: @@ -315,6 +287,11 @@ And then configure the translation messages: title: "%content_title% | Default title" description: "Default description. %content_description%" +.. tip:: + + You don't have to escape the percent characters here, since the + Translation loaders know how to deal with them. + For changing the default translation domain (messages), you should use the ``cmf_seo.translation_domain`` setting: diff --git a/bundles/seo/seo_aware.rst b/bundles/seo/seo_aware.rst index 04ae30f2..9c724c13 100644 --- a/bundles/seo/seo_aware.rst +++ b/bundles/seo/seo_aware.rst @@ -30,8 +30,16 @@ the ``SeoMetadata``:: } } -Now you can set some SEO data for this ``Page`` using the metadata. For -instance inside a data fixture:: +Now you can set some SEO data for this ``Page`` using the metadata:: + + $page = new Page(); + // ... set some page properties + + $pageMetadata = new SeoMetadata(); + $pageMetadata->setDescription('A special SEO description.'); + $pageMetadata->setTags('seo, cmf, symfony'); + + $page->setSeoMetadata($pageMetadata); // src/Acme/SiteBundle/DataFixture/PHPCR/LoadPageData.php namespace Acme\SiteBundle\DataFixtures\PHPCR; @@ -59,23 +67,14 @@ instance inside a data fixture:: } } -.. tip:: - - While this examples shows a Doctrine PHPCR ODM data fixture, the bundle - works fully storage agnostic. You can use it with every storage system you - like. - -Persisting the SeoMetadata with Doctrine ----------------------------------------- +Doctrine PHPCR-ODM Integration +------------------------------ -Since Doctrine doesn't allow you to persist an object as a database field, -there is a problem. The bundle provides a solution to solve this by providing -a Doctrine Listener. This listener will serialize the metadata object when -persisting it and it'll unserialize the metadata when the object is fetched -from the database. +In order to easily persist the SeoMetadata when using Doctrine PHPCR-ODM, the +SeoBundle provides a special ``SeoMetadata`` document with the correct +mappings. This document should be mapped as a child of the content document. -In order to use this listener, you should activate either ``orm`` or ``phpcr`` -as persisting layer for the SeoBundle: +To be able to use this document, you have to enable the PHPCR persistence: .. configuration-block:: @@ -85,8 +84,6 @@ as persisting layer for the SeoBundle: cmf_seo: persistence: phpcr: true - # when using the ORM: - # orm: true .. code-block:: xml @@ -94,9 +91,6 @@ as persisting layer for the SeoBundle: - @@ -106,45 +100,105 @@ as persisting layer for the SeoBundle: $container->loadFromExtension('cmf_seo', array( 'persistence' => array( 'phpcr' => true, - // when using the ORM: - // 'orm' => true, ), )); -This will automatically enable the listener. If you don't want to enable the -listener, but you want to enable a persistence layer, you can set the -``metadata_listener`` option to ``false``: +.. tip:: + + This is not needed if you already enabled PHPCR on the ``cmf_core`` + bundle. See :doc:`the CoreBundle docs <../core/persistence>` for more + information. + +After you've enabled PHPCR, map your seoMetadata as a child: .. configuration-block:: + .. code-block:: php-annotations + + // src/Acme/SiteBundle/Document/Page.php + namespace Acme\SiteBundle\Document; + + use Symfony\Cmf\Bundle\SeoBundle\Model\SeoAwareInterface; + use Doctrine\ODM\PHPCR\Mapping\Annotations as PHPCR; + + /** + * @PHPCR\Document() + */ + class Page implements SeoAwareInterface + { + /** + * @PHPCR\Child + */ + protected $seoMetadata; + + // ... + } + .. code-block:: yaml - # app/config/config.yml - cmf_seo: - persistence: + # src/Acme/SiteBundle/Resources/config/doctrine/Page.odm.yml + Acme\SiteBundle\Document\Page: + # ... + child: # ... - metadata_listener: false + seoMetadata: ~ .. code-block:: xml - - + + - + - - + + + - .. code-block:: php +And after that, you can use the +``Symfony\Cmf\Bundle\SeoBundle\Doctrine\Phpcr\SeoMetadata`` document:: - // app/config/config.php - $container->loadFromExtension('cmf_seo', array( - 'persistence' => array( - // ... - ), - 'metadata_listener' => false, - )); + // src/Acme/SiteBundle/DataFixture/PHPCR/LoadPageData.php + namespace Acme\SiteBundle\DataFixtures\PHPCR; + + use Acme\SiteBundle\Document\Page; + use Symfony\Cmf\Bundle\SeoBundle\Doctrine\Phpcr\SeoMetadata; + use Doctrine\Common\Persistence\ObjectManager; + use Doctrine\Common\DataFixtures\FixtureInterface; + + class LoadPageData implements FixtureInterface + { + public function load(ObjectManager $manager) + { + $page = new Page(); + // ... set some page properties + + $pageMetadata = new SeoMetadata(); + $pageMetadata->setDescription('A special SEO description.'); + $pageMetadata->setTags('seo, cmf, symfony'); + + $page->setSeoMetadata($pageMetadata); + + $manager->persist($page); + $manager->flush(); + } + } + +Doctrine ORM +------------ + +You can also use the Doctrine ORM with the CmfSeoBundle. You can just use the +``Symfony\Cmf\Bundle\SeoBundle\Model\SeoMetadata`` class and map it as an +object. + +You can also choose put the ``SeoMetadata`` class into a seperate table and +adding a relation between the ``SeoMetadata`` class and the content entity. To +do this, you have to enable ORM support just like you enabled PHPCR enabled +above. Form Type --------- @@ -159,3 +213,10 @@ Besides providing a form type, the bundle also provides a Sonata Admin Extension. This extension adds a field for the ``SeoMetadata`` when an admin edits an objec that implements the ``SeoAwareInterface`` in the Sonata Admin panel. + +.. note:: + + The bundles requires the `BurgovKeyValueFormBundle`_ when using the sonata + admin. Make sure you install and enable it. + +.. _`BurgovKeyValueFormBundle`: https://github.com/Burgov/KeyValueFormBundle From 2e0c0cdaf8d913a32fad38c8ceec2a1437022943 Mon Sep 17 00:00:00 2001 From: WouterJ Date: Wed, 14 May 2014 19:28:22 +0200 Subject: [PATCH 14/14] Final fixes and additions --- bundles/index.rst | 2 +- bundles/map.rst.inc | 6 ++ bundles/seo/extractors.rst | 63 ++++++++----- bundles/seo/introduction.rst | 26 ++++-- bundles/seo/seo_aware.rst | 102 +++++++++++++-------- reference/configuration/routing.rst | 1 - reference/configuration/seo.rst | 136 ++++++++++++++++++++++++++++ reference/index.rst | 23 ++--- reference/map.rst.inc | 1 + 9 files changed, 279 insertions(+), 81 deletions(-) create mode 100644 reference/configuration/seo.rst diff --git a/bundles/index.rst b/bundles/index.rst index 7d509868..bca08a8e 100644 --- a/bundles/index.rst +++ b/bundles/index.rst @@ -15,8 +15,8 @@ Bundles routing_auto/index routing/index search/index + seo/index simple_cms/index tree_browser/index - seo/index .. include:: map.rst.inc diff --git a/bundles/map.rst.inc b/bundles/map.rst.inc index 387d92fc..a8e67e34 100644 --- a/bundles/map.rst.inc +++ b/bundles/map.rst.inc @@ -59,6 +59,12 @@ library or they introduce a complete new concept. * :doc:`search/introduction` +* :doc:`seo/index` + + * :doc:`seo/introduction` + * :doc:`seo/seo_aware` + * :doc:`seo/extractors` + * :doc:`tree_browser/index` * :doc:`tree_browser/introduction` diff --git a/bundles/seo/extractors.rst b/bundles/seo/extractors.rst index 15f9511c..f6ba2155 100644 --- a/bundles/seo/extractors.rst +++ b/bundles/seo/extractors.rst @@ -2,34 +2,38 @@ Using Extractors to Retrieve the Seo Metadata ============================================= Instead of setting every value to the ``SeoMetadata`` manually, an extractor -can do the work for you. Extractors are executed when an object implements a -specific interface. The method required by that interface will return the -value for the specific SEO data. The extractor will then update the +can do the work for you. Extractors are executed when the content object +implements a specific interface. The method required by that interface will +return the value for the specific SEO data. The extractor will then update the ``SeoMetadata`` object for the current object with the returned value. Available Extractors -------------------- -+-----------------------------------+---------------------------+----------------------------------------------+ -| ExtractorInterface | Method | Type | -+===================================+===========================+==============================================+ -| ``SeoDescriptionReadInterface`` | ``getSeoDescription()`` | Returns the meta description | -+-----------------------------------+---------------------------+----------------------------------------------+ -| ``SeoTitleReadInterface`` | ``getSeoTitle()`` | Returns the page title | -+-----------------------------------+---------------------------+----------------------------------------------+ -| - | ``getTitle()`` | If the document has a ``getTitle()`` method, | -| | | it'll be used as the page title | -+-----------------------------------+---------------------------+----------------------------------------------+ -| ``SeoOriginalUrlReadInterface`` | ``getSeoOriginalUrl()`` | Returns a absolute url object to redirect to | -| | | or create a canonical link from | -+-----------------------------------+---------------------------+----------------------------------------------+ -| ``SeoOriginalRouteReadInterface`` | ``getSeoOriginalRoute()`` | Return a ``Route`` object to redirect to | -| | | or create a canonical link from | -+-----------------------------------+---------------------------+----------------------------------------------+ ++--------------------------------+---------------------------+----------------------------------------------+ +| ExtractorInterface | Method | Type | ++================================+===========================+==============================================+ +| ``DescriptionReadInterface`` | ``getSeoDescription()`` | Returns the meta description | ++--------------------------------+---------------------------+----------------------------------------------+ +| ``TitleReadInterface`` | ``getSeoTitle()`` | Returns the page title | ++--------------------------------+---------------------------+----------------------------------------------+ +| - | ``getTitle()`` | If the document has a ``getTitle()`` method, | +| | | it'll be used as the page title | ++--------------------------------+---------------------------+----------------------------------------------+ +| ``OriginalUrlReadInterface`` | ``getSeoOriginalUrl()`` | Returns a absolute url object to redirect to | +| | | or create a canonical link from | ++--------------------------------+---------------------------+----------------------------------------------+ +| ``OriginalRouteReadInterface`` | ``getSeoOriginalRoute()`` | Return a ``Route`` object to redirect to | +| | | or create a canonical link from | ++--------------------------------+---------------------------+----------------------------------------------+ +| ``ExtrasReadInterface`` | ``getSeoExtras()`` | Returns an associative array using | +| | | ``property``, ``http-equiv`` and ``name`` | +| | | as keys (see below from an example). | ++--------------------------------+---------------------------+----------------------------------------------+ .. note:: - The interfaces live in the ``Symfony\Cmf\Bundle\SeoBundle\Extractor`` + The interfaces life in the ``Symfony\Cmf\Bundle\SeoBundle\Extractor`` namespace. An Example @@ -42,10 +46,11 @@ description, you can implement both interfaces and your result will be:: // src/Acme/BlogBundle/Document/Article.php namespace Acme\BlogBundle\Document; - use Symfony\Cmf\Bundle\SeoBundle\Extractor\SeoTitleReadInterface; - use Symfony\Cmf\Bundle\SeoBundle\Extractor\SeoDescriptionReadInterface; + use Symfony\Cmf\Bundle\SeoBundle\Extractor\TitleReadInterface; + use Symfony\Cmf\Bundle\SeoBundle\Extractor\DescriptionReadInterface; + use Symfony\Cmf\Bundle\SeoBundle\Extractor\ExtrasReadInterface; - class Article implements SeoTitleReadInterface, SeoDescriptionReadInterface + class Article implements TitleReadInterface, DescriptionReadInterface, ExtraReadInterface { protected $title; protected $publishDate; @@ -59,7 +64,17 @@ description, you can implement both interfaces and your result will be:: public function getSeoDescription() { - return $this->title; + return $this->intro; + } + + public function getSeoExtras() + { + return array( + 'property' => array( + 'og:title' => $this->title, + 'og:description' => $this->description, + ), + ); } } diff --git a/bundles/seo/introduction.rst b/bundles/seo/introduction.rst index e5bf2b1a..3454a0c7 100644 --- a/bundles/seo/introduction.rst +++ b/bundles/seo/introduction.rst @@ -102,7 +102,14 @@ document. This metadata can hold: * The meta keywords; * The meta description; * The original URL (when more than one URL contains the same content). - +* Anything else that uses the ```` tag with the ``property``, ``name`` + or ``http-equiv`` type (e.g. Open Graph data). + +The content object is retrieved from the request attributes. By default, it +uses the ``DynamicRouter::CONTENT_KEY`` constant when the +:doc:`RoutingBundle <../routing/introduction>` is installed. To change this, +or if you don't use the RoutingBundle, you can configure it with +``cmf_seo.content_key``. This bundle provides two ways of using this metadata: #. Implementing the ``SeoAwareInterface`` and persisting the ``SeoMetadata`` @@ -165,25 +172,28 @@ you want to change that to redirect instead, you can set the ), ); +.. _bundles-seo-title-description-emplate: + Defining a Title and Description Template ----------------------------------------- Most of the times, the title of a site has a static and a dynamic part. For instance, "The title of the Page - Symfony". Here, "- Symfony" is static and -"The title of the Page" will be replaced by the current title. It is of course -not nice if you had to add this static part to all your titles in documents. +"The title of the Page" will be replaced by the current title. It would not be +nice if you had to add this static part to all your titles in documents. -That's why the CmfSeoBundle provides defining a title and description -template. When using these settings, there are 2 placeholders available: +The CmfSeoBundle allows you to define a title and description template for +this reason. When using these settings, there are 2 placeholders available: ``%content_title%`` and ``%content_description%``. These will be replaced with the title extracted from the content object and the description extracted from the content object. .. caution:: - The default title and description set by the SonataSeoBundle do override - this template. You should make sure that the defaults also follow the - template. + The title and description template is only used when the title is not set + on the content object or when the content object is not available, + otherwise it'll use the default set by the SonataSeoBundle. You should + make sure that the defaults also follow the template. For instance, to configure the titles of the symfony.com pages, you would do: diff --git a/bundles/seo/seo_aware.rst b/bundles/seo/seo_aware.rst index 9c724c13..ed81031c 100644 --- a/bundles/seo/seo_aware.rst +++ b/bundles/seo/seo_aware.rst @@ -12,7 +12,7 @@ the ``SeoMetadata``:: // src/Acme/SiteBundle/Document/Page.php namespace Acme\SiteBundle\Document; - use Symfony\Cmf\Bundle\SeoBundle\Model\SeoAwareInterface; + use Symfony\Cmf\Bundle\SeoBundle\SeoAwareInterface; class Page implements SeoAwareInterface { @@ -32,6 +32,9 @@ the ``SeoMetadata``:: Now you can set some SEO data for this ``Page`` using the metadata:: + use Acme\SiteBundle\Document\Page; + use Symfony\Cmf\Bundle\SeoBundle\SeoMetadata; + $page = new Page(); // ... set some page properties @@ -41,32 +44,6 @@ Now you can set some SEO data for this ``Page`` using the metadata:: $page->setSeoMetadata($pageMetadata); - // src/Acme/SiteBundle/DataFixture/PHPCR/LoadPageData.php - namespace Acme\SiteBundle\DataFixtures\PHPCR; - - use Acme\SiteBundle\Document\Page; - use Symfony\Cmf\Bundle\SeoBundle\Model\SeoMetadata; - use Doctrine\Common\Persistence\ObjectManager; - use Doctrine\Common\DataFixtures\FixtureInterface; - - class LoadPageData implements FixtureInterface - { - public function load(ObjectManager $manager) - { - $page = new Page(); - // ... set some page properties - - $pageMetadata = new SeoMetadata(); - $pageMetadata->setDescription('A special SEO description.'); - $pageMetadata->setTags('seo, cmf, symfony'); - - $page->setSeoMetadata($pageMetadata); - - $manager->persist($page); - $manager->flush(); - } - } - Doctrine PHPCR-ODM Integration ------------------------------ @@ -118,7 +95,7 @@ After you've enabled PHPCR, map your seoMetadata as a child: // src/Acme/SiteBundle/Document/Page.php namespace Acme\SiteBundle\Document; - use Symfony\Cmf\Bundle\SeoBundle\Model\SeoAwareInterface; + use Symfony\Cmf\Bundle\SeoBundle\SeoAwareInterface; use Doctrine\ODM\PHPCR\Mapping\Annotations as PHPCR; /** @@ -192,13 +169,61 @@ Doctrine ORM ------------ You can also use the Doctrine ORM with the CmfSeoBundle. You can just use the -``Symfony\Cmf\Bundle\SeoBundle\Model\SeoMetadata`` class and map it as an -object. +``Symfony\Cmf\Bundle\SeoBundle\SeoMetadata`` class and map it as an +object: -You can also choose put the ``SeoMetadata`` class into a seperate table and -adding a relation between the ``SeoMetadata`` class and the content entity. To +.. configuration-block:: + + .. code-block:: php-annotations + + // src/Acme/SiteBundle/Entity/Page.php + namespace Acme\SiteBundle\Entity; + + use Symfony\Cmf\Bundle\SeoBundle\SeoAwareInterface; + use Doctrine\ORM\Mapping as ORM; + + /** + * @ORM\Entity() + */ + class Page implements SeoAwareInterface + { + /** + * @ORM\Column(type="object") + */ + protected $seoMetadata; + + // ... + } + + .. code-block:: yaml + + # src/Acme/SiteBundle/Resources/config/doctrine/Page.orm.yml + Acme\SiteBundle\Entity\Page: + # ... + fields: + # ... + seoMetadata: + type: object + + .. code-block:: xml + + + + + + + + + + + +You can also choose to put the ``SeoMetadata`` class into a seperate table. To do this, you have to enable ORM support just like you enabled PHPCR enabled -above. +above and add a OneToOne or ManyToOne relation between the content entity and +the ``SeoMetadata`` entity. Form Type --------- @@ -206,6 +231,11 @@ Form Type The bundle also provides a special form type called ``seo_metadata``. This form type can be used in forms to edit the ``SeoMetadata`` object. +.. caution:: + + The bundles requires the `BurgovKeyValueFormBundle`_ when using the form + type. Make sure you install and enable it. + Sonata Admin Integration ------------------------ @@ -214,9 +244,9 @@ Extension. This extension adds a field for the ``SeoMetadata`` when an admin edits an objec that implements the ``SeoAwareInterface`` in the Sonata Admin panel. -.. note:: +.. caution:: - The bundles requires the `BurgovKeyValueFormBundle`_ when using the sonata - admin. Make sure you install and enable it. + The Sonata Admin uses the Form Type provided by the CmfSeoBundle, make + sure you have the `BurgovKeyValueFormBundle`_ installed. .. _`BurgovKeyValueFormBundle`: https://github.com/Burgov/KeyValueFormBundle diff --git a/reference/configuration/routing.rst b/reference/configuration/routing.rst index b19b2ccc..1bf69722 100644 --- a/reference/configuration/routing.rst +++ b/reference/configuration/routing.rst @@ -365,7 +365,6 @@ phpcr ), )); - enabled ******* diff --git a/reference/configuration/seo.rst b/reference/configuration/seo.rst new file mode 100644 index 00000000..fc22956e --- /dev/null +++ b/reference/configuration/seo.rst @@ -0,0 +1,136 @@ +SeoBundle Configuration +======================= + +The SeoBundle takes care of the SEO information of a page and can be +configured under the ``cmf_seo`` key in your application configuration. When +using XML, you can use the ``http://cmf.symfony.com/schema/dic/seo`` +namespace. + +Configuration +------------- + +persistence +~~~~~~~~~~~ + +phpcr +""""" + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + cmf_seo: + dynamic: + persistence: + phpcr: + enabled: false + manager_name: ~ + + .. code-block:: xml + + + + + + + + + + + + + + .. code-block:: php + + $container->loadFromExtension('cmf_seo', array( + 'dynamic' => array( + 'persistence' => array( + 'phpcr' => array( + 'enabled' => false, + 'manager_name' => null, + ), + ), + ), + )); + +enabled +******* + +.. include:: partials/persistence_phpcr_enabled.rst.inc + +manager_name +************ + +.. include:: partials/persistence_phpcr_manager_name.rst.inc + +translation_domain +~~~~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``messages`` + +The translation domain to use when translating the title and description +template. See :ref:`bundles-seo-title-description-emplate` for more +information. + + +title +~~~~~ + +**type**: ``string`` **default**: ``null`` + +The title template, read :ref:`here ` +about the usage. + +description +~~~~~~~~~~~ + +**type**: ``string`` **default**: ``null`` + +The description template, read :ref:`here ` +about the usage. + +original_route_pattern +~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``canonical`` + +The original route strategy to use when multiple routes have the same content. +Can be one of ``canonical`` or ``redirect``. + +content_key +~~~~~~~~~~~ + +**type**: ``string`` **default**: ``null`` (or ``DynamicRouter::CONTENT_KEY`` when RoutingBundle is enabled) + +The name of the Request attribute which contains the content object. This is +required when the RoutingBundle is not enabled, otherwise it defaults to +``DynamicRouter::CONTENT_KEY`` (which evaluates to ``contentDocument``). + +sonata_admin_extension +~~~~~~~~~~~~~~~~~~~~~~ + +If set to ``true``, the Sonata Admin Extension provided by the SeoBundle is +activated. + +enabled +""""""" + +**type**: ``enum`` **valid values** ``true|false|auto`` **default**: ``auto`` + +If ``true``, the Sonata Admin Extension will be activated. If set to ``auto``, +it is activated only if the SonataPhpcrAdminBundle is present. + +If the :doc:`CoreBundle <../../bundles/core/index>` is registered, this will default to the value +of ``cmf_core.persistence.phpcr.use_sonata_admin``. + +form_group +"""""""""" + +**type**: ``string`` **default**: ``form.group_seo`` + +The name of the form group of the group provided by the Sonata Admin +Extension. diff --git a/reference/index.rst b/reference/index.rst index 90393c53..78fbd819 100644 --- a/reference/index.rst +++ b/reference/index.rst @@ -4,16 +4,17 @@ Reference .. toctree:: :hidden: - configuration/block.rst - configuration/content.rst - configuration/core.rst - configuration/create.rst - configuration/media.rst - configuration/menu.rst - configuration/routing.rst - configuration/search.rst - configuration/simple_cms.rst - configuration/tree_browser.rst - configuration/phpcr_odm.rst + configuration/block + configuration/content + configuration/core + configuration/create + configuration/media + configuration/menu + configuration/routing + configuration/search + configuration/seo + configuration/simple_cms + configuration/tree_browser + configuration/phpcr_odm .. include:: map.rst.inc diff --git a/reference/map.rst.inc b/reference/map.rst.inc index 3e453923..463bc2f1 100644 --- a/reference/map.rst.inc +++ b/reference/map.rst.inc @@ -8,6 +8,7 @@ * :doc:`configuration/menu` * :doc:`configuration/routing` * :doc:`configuration/search` + * :doc:`configuration/seo` * :doc:`configuration/simple_cms` * :doc:`configuration/tree_browser` * :doc:`configuration/phpcr_odm`