Migrate https://www.carloscarrascal.com/ es Importando metatags con Drupal 8 y Migrate https://www.carloscarrascal.com/blog/importando-metatags-con-drupal-8-y-migrate <article data-history-node-id="41" class="node node--type-blog-post node--view-mode-rss group-one-column ds-2col-stacked-fluid clearfix"> <div class="group-header"> <div class="field field--name-node-title field--type-ds field--label-hidden field--item"><h1> Importando metatags con Drupal 8 y Migrate </h1> </div> <div class="field field--name-node-post-date field--type-ds field--label-hidden field--item">Viernes, Octubre 12, 2018 - 20:11</div> </div> <div class="group-left"> <div class="field field--name-field-tags field--type-entity-reference field--label-hidden field--items"> <div class="field--item"><a href="/tags/d8" hreflang="es">D8</a></div> <div class="field--item"><a href="/tags/migrate" hreflang="es">Migrate</a></div> <div class="field--item"><a href="/tags/drupal" hreflang="es">Drupal</a></div> </div> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><p>Estoy en mitad de un proyecto en el que estamos importando a Drupal 8 contenidos que vienen de un repositorio central, y se consumen usando una API REST en formato JSON.</p> <p>Hasta ahora esta funcionando bastante bien y sin muchos dolores de cabeza, pero tratando de importar los metadatos que vienen con nuestros contenidos a los campos que trae el módulo <a href="https://www.drupal.org/project/metatag">Metatag</a> he tenido que pegarme un poco hasta dar con la solución.</p> <p>Actualmente (octubre de 2017), el módulo Metatag no tiene soporte para Migrate en forma de plugins. Hay <a href="https://www.drupal.org/node/2563649">un ticket abierto</a> desde hace tiempo, con varios parches disponibles, pero aún no está completo. Lo bueno es que en ese mismo hilo hay un par de personas que cuentan como lo han hecho sin necesitar el parche, que era justo lo que yo intentaba, pero se me estaba escapando un detalle: serializar.</p> <p>Para esta importación estamos usando los siguientes módulos:</p> <ul><li><a href="https://www.drupal.org/project/migrate">migrate</a>: en el core de Drupal</li> <li><a href="https://www.drupal.org/project/migrate_tools">migrate_tools</a>: en contrib</li> <li><a href="https://www.drupal.org/project/migrate_plus">migrate_plus</a>: en contrib</li> </ul><p>Para importar contenido usando <em>migrate_plus</em> vamos a necesitar una serie de componentes:</p> <ul><li>Un archivo YML de control para la migración, donde especificaremos el tipo de proceso, los campos entrada y salida</li> <li>Un plugin de importación de contenido, que será una clase que extienda de <a href="https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21source%21SourcePluginBase.php/class/SourcePluginBase/8.6.x">SourcePluginBase</a>, y donde podremos hacer algunas transformaciones.</li> <li>Lo normal será que hayamos creado un módulo custom para controlar toda nuestra importación.</li> </ul><p>No me quiero meter mucho en detalle de cómo se hace la importación usando migrate_plus, porque quiero escribir un artículo entero para ello, así que me voy a centrar en importar los metadatos.</p> <p>Primero el archivo YML que controla la importación en mi módulo, migrate_plus.migration.json_page.yml:</p> <pre> id: json_page label: 'JSON migration for content type: Page' migration_group: my_group source: plugin: json_page cache_counts: true high_water_property: name: changed destination: plugin: entity:node bundle: page process: uuid: uuid langcode: language type: plugin: default_value default_value: page title: title created: changed changed: changed 'body/format': 'body/format' 'body/value': 'body/value' 'body/summary': 'body/summary' 'field_page_teaser/format': 'teaser/format' 'field_page_teaser/value': 'teaser/value' 'path/alias': alias 'promote/value': plugin: default_value default_value: 0 field_meta_tags: meta_tags # use forced module dependency so uninstall/reinstall works properly dependencies: enforced: module: - my_module_name</pre> <p>Lo pongo entero por si ayuda para ver como estoy importando otros campos, pero lo importante es esta línea para los metadatos:</p> <pre> field_meta_tags: meta_tags </pre> <p>Esta línea va a intentar importar los metadatos desde un campo 'meta_tags'  en el origen (el <em>source</em>), a un campo llamado <em>field_meta_tags</em>, que ya hemos creado en nuestro tipo de contenido, en este caso <em>page</em>, y que es de tipo Meta tags.</p> <p>En mi caso, los metadatos vienen en JSON que representa un nodo en este formato. Atención al detalle de que es '<em>metatags</em>', no '<em>meta_tags</em>':</p> <pre> "metatags":{ "title":"a simple node title | [site:name]", "og:title":"a simple node title", "twitter:title":"a simple node title", "description":"a simple description", "og:description":"a simple description", "og:updated_time":"2018-08-27T08:40:34-04:00", "article:published_time":"2017-04-13T04:26:00-04:00", "article:modified_time":"2018-08-27T08:40:34-04:00", "twitter:description":"a simple description", "canonical":"[site:url][current-page:url:path]", "og:site_name":"[site:name]", "og:type":"article", "og:url":"[site:url][current-page:url:path]", "twitter:card":"summary", "twitter:url":"[site:url][current-page:url:path]" },</pre> <p>Como veis ya vienen con tokens que Drupal va a entender, asi que genial. Lo que vamos a hacer es utilizar el plugin que hemos definido para esta importación (<em>json_page</em>) para coger estos datos que vienen en el source de la importación como '<em>metatags</em>', darles el formato adecuado, y colocarlos en '<em>meta_tags</em>', que es lo que espera el proceso de migración, definido en el archivo YML de antes.</p> <p>Este es el código de mi plugin:</p> <pre> class MyJsonPlugin extends SourcePluginBase { public function prepareRow(Row $row) { // Set URL alias. $alias = $row-&gt;getSourceProperty('alias'); if (!empty($alias)) { $row-&gt;setSourceProperty('alias', '/' . $alias); } // Set meta tags. $row-&gt;setSourceProperty('meta_tags', $row-&gt;getSourceProperty('metatags')); return parent::prepareRow($row); } protected function processMetaTags($data) { $metatags = []; if ($data) { foreach ($data as $key =&gt; $value) { $transforms = [ 'twitter:card' =&gt; 'twitter_cards_type', 'twitter:url' =&gt; 'twitter_cards_page_url', 'twitter:description' =&gt; 'twitter_cards_description', 'twitter:site' =&gt; 'twitter_cards_site', 'twitter:site:id' =&gt; 'twitter_cards_site_id', 'twitter:creator' =&gt; 'twitter_cards_creator', 'twitter:creator:id' =&gt; 'twitter_cards_creator_id', 'twitter:title' =&gt; 'twitter_cards_title', 'canonical' =&gt; 'canonical_url', 'og:url' =&gt; 'og_url', 'og:title' =&gt; 'og_title', 'og:site_name' =&gt; 'og_site_name', 'og:type' =&gt; 'og_type', 'og:description' =&gt; 'og_description', 'og:image' =&gt; 'og_image', 'og:image:url' =&gt; 'og_image_url', 'og:image:secure_url' =&gt; 'og_image_secure_url', 'og:image:type' =&gt; 'og_image_type', 'article:published_time' =&gt; 'article_published_time', 'article:modified_time' =&gt; 'article_modified_time', ]; if (array_key_exists($key, $transforms)) { $key = $transforms[$key]; } if ($value) { $metatags[$key] = $value; } } } if (!$metatags) { return NULL; } return serialize($metatags); } ... } </pre> <p>Básicamente hay dos funciones importantes: en <em>prepareRow</em>, cogemos los metadatos desde '<em>metatags</em>' que tiene el JSON, los formateamos y los volvemos a dejar bien bonitos en '<em>meta_tags</em>', y en la función <em>processMetaTags</em> los procesamos y serializamos.</p> <p>Aquí hay dos cosas a tener en cuenta:</p> <ul><li>Mis datos de origen en el JSON, vienen con los nombres de campo de Drupal 7, por ejemplo <em>twitter:card</em>, y los nombres de los campos de Drupal 8 son diferentes, por eso en la función <em>processMetaTags</em> revisamos las claves las cambiamos por las que corresponden. En esta lista no están todas las posibles pero sí las más importantes. Intentaré actualizarla en el futuro cuando la tenga completa.</li> <li>Una vez construido el array con los meta datos, tenemos que <strong>serializarlo</strong> (función <a href="http://php.net/manual/en/function.serialize.php">serialize</a> de PHP) antes de llamar a <em>setSourceProperty</em>, porque si no lo hacemos, los datos no se guardarán correctamente.</li> </ul><p>Y esto es todo amigos, si teneis alguna idea mejor o algún problema podéis dejar una nota en los comentarios.</p> <p> </p> <h3>Referencias</h3> <ul><li>El artículo original con el que empece a jugar con Migrate: <a href="https://www.metaltoad.com/blog/drupal-8-migrating-data-json-files">https://www.metaltoad.com/blog/drupal-8-migrating-data-json-files</a></li> <li>El ticket del modulo Metatags para incluir los plugins de Migrate: <a href="https://www.drupal.org/node/2563649">https://www.drupal.org/node/2563649</a></li> </ul></div> </div> <div class="group-footer"> <section> <h2>Comments</h2> <article data-comment-user-id="0" id="comment-38" about="/en/comment/38" typeof="schema:Comment" class="js-comment"> <mark class="hidden" data-comment-timestamp="1565734782"></mark> <footer> <article typeof="schema:Person" about="/user/0"> </article> <p><span rel="schema:author">Subido por <span lang="" typeof="schema:Person" property="schema:name" datatype="">Salvador B. (no verificado)</span> el Vie, 26/10/2018 - 14:49</span> <span property="schema:dateCreated" content="2018-10-26T12:49:17+00:00" class="hidden"></span> </p> <a href="/en/comment/38#comment-38" hreflang="en">Enlace permanente</a> </footer> <div> <h3 property="schema:name" datatype=""><a href="/en/comment/38#comment-38" class="permalink" rel="bookmark" hreflang="en">Migración Meta tags</a></h3> <div property="schema:text" class="field field--name-comment-body field--type-text-long field--label-hidden field--item"><p>Hola Carlos, te quería agradecer tu articulo. </p> <p>Te he encontrado a partir del ticket de Metatags (<a href="https://www.drupal.org/node/2563649">https://www.drupal.org/node/2563649</a>). Te has ganado un follower! :-D</p> <p>Saludos!</p> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=38&amp;1=default&amp;2=en&amp;3=" token="Kp71kBs1el410NhBpfenh3PMri37GPQSw9Csso9QNSI"></drupal-render-placeholder> </div> </article> <h2>Añadir nuevo comentario</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=41&amp;2=comment&amp;3=comment" token="gL6owGXCmF4P6iAHBLDYmzBZgqth1K2tPxIOuqJ0FrQ"></drupal-render-placeholder> </section> </div> </article> Fri, 12 Oct 2018 18:11:26 +0000 root 41 at https://www.carloscarrascal.com