Cómo añadir los blogs de liferay al sitemap.xml

Ayudando al SEO de nuestra web

Liferay genera un sitemap.xml para cada sitio web, de forma automática, para que los motores de búsqueda puedan hacer un rastreo más efectivo de nuestros contenidos.

Por defecto, liferay añade al sitemap.xml tanto las páginas que hay en el sitio web público como los contenidos web visibles con su friendly url.

Una de las mejores cosas que trae liferay 7 es la modularidad y con ella la facilidad (ahora digo facilidad, pero reconozco que los primeros meses andaba bastante perdido) con la que podemos añadir nuevos componentes al sistema que enriquezcan la funcionalidad que se ofrece por defecto.

En este post vamos a ver algo que va a hacer las delicias de los expertos SEO en liferay, vamos a ver cómo añadir la friendly url de nuestros blogs al sitemap.xml generado por liferay, para facilitar la indexación de nuestros post en los motores de búsqueda.

Lo primero que tenemos que hacer es crear un modulo osgi con blade. Para ello, como siempre, ve al directorio modules de tu workspace (recuerda que en este mismo blog tienes un post donde se explica paso a paso cómo hacerlo) y ejecuta el siguiente comando.

blade create -t service -p com.miguelangeljulvez.sitemap -c BlogsEntrySitemapURLProvider -s com.liferay.layouts.admin.kernel. util.SitemapURLProvider blogs-sitemap

Lo que estamos diciendo con el comando anterior, es que vamos a crear un nuevo componente osgi que implementa el servicio SitemapURLProvider. Este servicio es el que se encarga en liferay de generar el sitemap.xml.

Una vez hecho esto, lo que hay que hacer es añadirle una serie de dependencias al fichero build.gradle el módulo generado

    dependencies {
      compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "2.6.0"
      compileOnly group: "org.osgi", name: "org.osgi.compendium", version: "5.0.0"

      //Estas 2 dependencias son las que tienes que añadir
      compileOnly 'javax.portlet:portlet-api:2.0'
      compileOnly 'javax.servlet:javax.servlet-api:3.0.1'
}

Lo que nos queda por hacer a continuación, es desarrollar el código para la clase que BlogsEntrySitemapURLProvider que Blade ha creado por nosotros.

El código debe quedarte así (abajo te explico un poco):

@Component(
   immediate = true,
   property = {
   },
   service = SitemapURLProvider.class
)
public class BlogsEntrySitemapURLProvider implements SitemapURLProvider {
   @Override
   public String getClassName() {
      return BlogsEntry.class.getName();
   }

   @Override
   public void visitLayoutSet(
         Element element, LayoutSet layoutSet, ThemeDisplay themeDisplay)
         throws PortalException {

      QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(WorkflowConstants.STATUS_APPROVED);

      List<BlogsEntry> blogsEntries = _blogsEntryLocalService.getGroupEntries(layoutSet.getGroupId(), Date.from(Instant.now()), queryDefinition);

      if (blogsEntries.isEmpty()) {
         _log.info("No hay ninguna entrada de blog para añadir al sitemap para el groupId " + layoutSet.getGroupId());

         return;
      }

      //Obtenemos la primera página pública donde está añadido nuestro portlet
      long plid = PortalUtil.getPlidFromPortletId(layoutSet.getGroupId(), false, "com_liferay_blogs_web_portlet_BlogsPortlet");

      if (plid == LayoutConstants.DEFAULT_PLID) {
         _log.warn("No hay ningún visor de blogs configurado en ninguna página pública para el groupId " + layoutSet.getGroupId());

         return;
      }

      Layout layout = _layoutLocalService.getLayout(plid);

      String portalURL = PortalUtil.getPortalURL(layoutSet, themeDisplay);
      String friendlyURL = layout.getFriendlyURL(themeDisplay.getLocale());

      for (BlogsEntry blogsEntry: blogsEntries) {

         if (_log.isDebugEnabled())
            _log.debug("Tratando entrada de blog: '" + blogsEntry.getTitle() + "' (" + blogsEntry.getUrlTitle() + ")");

         StringBundler sb = new StringBundler(4);

         String groupFriendlyURL = PortalUtil.getGroupFriendlyURL(
               _layoutSetLocalService.getLayoutSet(blogsEntry.getGroupId(), false), themeDisplay);

         if (!groupFriendlyURL.startsWith(portalURL)) {
            sb.append(portalURL);
         }

         sb.append(groupFriendlyURL);
         sb.append(friendlyURL);
         sb.append("/-/blogs/");
         sb.append(blogsEntry.getUrlTitle());
         sb.append("/maximized");

         Map<Locale, String> alternateURLs = SitemapUtil.getAlternateURLs(
               sb.toString(), themeDisplay, layout);

         SitemapUtil.addURLElement(
               element, sb.toString(), null, blogsEntry.getModifiedDate(),
               sb.toString(), alternateURLs);

         if (alternateURLs.size() > 1) {
            Locale defaultLocale = LocaleUtil.getSiteDefault();

            for (Map.Entry<Locale, String> entry :
                  alternateURLs.entrySet()) {

               Locale availableLocale = entry.getKey();
               String alternateURL = entry.getValue();

               if (!availableLocale.equals(defaultLocale)) {
                  SitemapUtil.addURLElement(
                        element, alternateURL, null,
                        blogsEntry.getModifiedDate(), sb.toString(),
                        alternateURLs);
               }
            }
         }

         if (_log.isDebugEnabled())
            _log.debug("Url añadida al sitemap.xml: '" + sb.toString() + "'");
      }

      _log.info("Todos los post de blog añadidos al sitemap.xml para el groupId " + layoutSet.getGroupId());
   }

   @Reference(unbind = "-")
   protected void setBlogsEntryLocalService(
         BlogsEntryLocalService blogsEntryLocalService) {

      _blogsEntryLocalService = blogsEntryLocalService;
   }

   @Reference(unbind = "-")
   protected void setLayoutLocalService(
         LayoutLocalService layoutLocalService) {

      _layoutLocalService = layoutLocalService;
   }

   @Reference(unbind = "-")
   protected void setLayoutSetLocalService(
         LayoutSetLocalService layoutSetLocalService) {

      _layoutSetLocalService = layoutSetLocalService;
   }

   private BlogsEntryLocalService _blogsEntryLocalService;
   private LayoutLocalService _layoutLocalService;
   private LayoutSetLocalService _layoutSetLocalService;

   private static Log _log = LogFactoryUtil.getLog(BlogsEntrySitemapURLProvider.class);
}

Yo creo que se entiende bastante bien, aunque voy a intentar explicarlo con palabras:

  • Dame todas las entradas de blog del sitio web para el que se está generando el sitemap, pero solo los blogs ya aprobados y con fecha de publicación previa a la fecha actual
  • Dame la primera página pública donde está instalado el portlet blogs.

  • Para cada entrada de blog, genera la friendly url para todos los idiomas configurados en el portal de la página en la que está el portlet de blogs.
Por los códigos complicados que he visto en diferentes proyectos, no mucha gente lo sabe pero PortalUtil.getPlidFromPortletId() devuelve la primera página donde está instalada el portlet que se le indica.

Al final Liferay siempre es más fácil de lo que se pinta.

Y finalmente, como siempre, ejecutamos

blade gw deploy

Por último, puedes acceder al sitemap.xml de tu web para comprobarlo. O puedes cotillear el sitemap.xml esta web (https://www.miguelangeljulvez.com/sitemap.xml) mientras tanto.

Esperemos que con este post, Liferay sea un poco mas friendly SEO.

Stay tuned! Para el siguiente post: cómo añadir datos estructurados de schema.org a nuestro blog. ¡A por el SEO!