Un groupe dynamique de développeurs collabore à la 7ème édition du CloudFest Hackathon 2024, qui se déroulera du 16 au 18 mars 2024 à Europa Park,

CloudFest Hackathon 2024 : the recap

This year, I was lucky to be invited to the CloudFest Hackathon 2024, thanks to Carole Olinger, Alain Schlesser and Lucas Radke.

CloudFest Hackathon

11 projects competed this year and it was pretty hard to choose only one as there were loads of exciting challenges to overcome. We only have 2 full days (and nights) to code for the project we are part of and make history.

The projects were:

  1. Managing Multilingual Content with WP Multisite
  2. Public Sector Website Funding Transparency
  3. JSON Schema Field/Form Renderer
  4. CMS Health Checks
  5. Securing more infrastructure by easing OS upgrades
  6. Integrating MariaDB Catalogs with PHP Platforms
  7. Can everyone use _______?
  8. WordPress Tools for Hosting Providers
  9. Enable Mastodon Apps for WordPress and its Plugins
  10. Inclusive Language Checker for Open-Source Contributors
  11. Hack the Hackathon

I was on the fence for a while as I’m interested in Multilingual and Multisite, Inclusivity, JSON Schema, and MariaDB. Eventually, I took a chair at the JSON Schema table but quickly found it was too crowded already so I joined Integrating MariaDB Catalogs with PHP Platforms.

Integrating MariaDB Catalogs with PHP Platforms

The Team

We were very fortunate to work with Andrew Hutchings (aka Linux Jedi), who works for the MariaDB Foundation. The project this year revolves around the integration of a new feature called MariaDB Catalogs with PHP frameworks such as WordPress, Drupal, and others.

The team was therefore composed of:

Our hackathon team for the MariaDB catalogs!
Our hackathon team for the MariaDB catalogs!

The project: MariaDB catalogs

The general idea of catalogs is containerization inside MariaDB itself: you have one MariaDB instance running and every customer has their own catalog inside that instance. The memory is shared so you are saving a lot of RAM that way. You don’t have to have 50,000 different read DB instances running, each using a GB of RAM. You simply have one read DB instance running, but you still have each customer siloed.

The hackathon project is to make it easier to administer this, create and remove catalogs.

Lire la suite

wordpress rocketstack

WordPress Rocket Stack : envoyez WordPress sur orbite !

Sur Orion, j’ai installé ma WordPress Rocket Stack qui est configurée avec la stack suivante:

  • Ubuntu Server 22.04 LTS
  • MySQL 8+
  • NginX 1.25+
  • PHP 8.3
  • Redis
  • Nginx FastCGI Cache
  • Fail2ban
  • LetsEncrypt avec acme.sh

Hébergement

L’hébergement est la base de votre site, c’est tout simplement la fondation sur laquelle va reposer votre code.

Vous avez tout intérêt à avoir un très bon hébergeur : il doit être rapide dès le départ et offrir de bonnes garanties en termes de performance et de sécurité.

Si vous avez un site WordPress ou WooCommerce, je ne peux que vous recommander Kinsta, WPEngine ou Nexcess. Tous trois sont de très bons hébergeurs, particulièrement orientés vers la performance avec des ressources garanties et un support technique réactif et efficace en cas de besoin.

Personnellement, j’utilise un serveur dédié chez OVH parce que j’héberge pas mal de sites et j’ai besoin d’avoir un contrôle fin sur la configuration de chacun des services.

Ubuntu Server

J’étais auparavant sous Debian mais j’ai finalement opté pour Ubuntu Server 22.04 LTS pour ce nouveau serveur.

L’avantage d’Ubuntu est de pouvoir disposer des mises à jour plus rapidement que sous Debian.

Lire la suite

WordPress Using WP CLI

wp-cli : importer et exporter les utilisateurs WP

Voici une méthode simple pour exporter tous les utilisateurs d’une base de données WordPress, pour les réimporter sur un autre site, à l’aide de l’excellent wp-cli.

Nous ferons référence à la base de données source en tant que source-db et à la base de données cible en tant que target-db et je supposerai que vous avez accès aux deux instances WordPress via wp-cli.

Étape 1 : exporter les utilisateurs WordPress

Cette étape fonctionnera avec la base de données source-db:

wp db export --tables = $(wp db tables 'wp_*_users') users.sqlCode language: JavaScript (javascript)
  • notez l’astérisque dans le nom de la table – utilisez-le pour éviter de taper le nom exact de la table pour votre base de données WordPress spécifique
  • notez le nom du fichier exporté, users.sql – cela permet d’identifier clairement le contenu de ce fichier.

Étape 2 : exporter la méta utilisateur WordPress

Cette étape fonctionnera avec la base source-db. Comme ci-dessus, notez le caractère générique et le nom de fichier:

wp db export --tables = $(wp db tables 'wp_*_usermeta') usermeta.sqlCode language: JavaScript (javascript)

Étape 3 : sauvegarde facultative des utilisateurs et usermeta

Cette étape fonctionnera avec la base target-db. Il s’agit d’une sauvegarde facultative des utilisateurs et des tables usermeta avant d’importer les nouvelles données:

  • répétez l’étape 1 (mais en travaillant avec target-db)
  • nommez le fichier backup-users.sql
  • répétez l’étape 2 (mais en travaillant avec target-db)
  • nommez le fichier backup-usermeta.sql

Cela nous donne donc:

wp db export --tables = $(wp db tables 'wp_*_users') backup-users.sql
wp db export --tables = $(wp db tables 'wp_*_usermeta') backup-usermeta.sqlCode language: JavaScript (javascript)

Lire la suite

Group photo of all devs at Cloudfest Hackathon 2022

Le Hackathon du CloudFest 2022

Cette année, j’ai eu la chance et le grand honneur d’être invité au CloudFest 2022 pour le hackathon: 3 jours de code sur un projet web en mode open-source pour faire avancer les choses.

Le Cloudfest

Le Cloudfest est une convention de développeurs et d’acteurs du web qui peuvent être extrêmement variés: cela va des hébergeurs web aux plateformes comme Codeable mais aussi avec de gros acteurs comme Airbus, Intel, Automattic, HP, Cpanel, Plesk…

Les conférences sont très variées: intelligence artificielle, business… et il est très facile de rencontrer des gens très connus sur le web pour se faire un réseau.

Le Cloudfest se tient à Rust, en Allemagne, à l’Europa Park.

Le Hackathon

Cette année le hackathon proposait plusieurs projets mais j’ai opté pour travailler sur wp-cli pour ajouter une nouvelle commande qui permettre de sécuriser 80% des attaques contre les instances WordPress, en appliquant simplement les meilleures pratiques de sécurité courantes.

Les devs du Hackathon 2022
Les devs du Hackathon 2022

Concrètement, nous avons identifié les problèmes de sécurité courants et nous avons développé une extension de l’interface de ligne de commande WordPress (wp-cli) pour offrir une alternative sécurisée et facile à utiliser aux plugins de sécurité WordPress généralement non sécurisés.

Avec la simple commande wp secure all, les meilleures pratiques courantes sont appliquées automatiquement à votre instance WordPress, et en moins de 60 secondes, vous attenuez la grande majorité des vecteurs d’attaque WordPress actuels : permissions de fichiers et de dossiers, entêtes de sécurité, bloquer l’accès aux fichiers sensibles…

Lire la suite

Créer un site staging pour WordPress sur un sous-domaine photo

Créer un site staging pour WordPress sur un sous-domaine

Le Centre de Kriya Yoga France n’avait pas de site staging, ce site de développement et de test qui permet de tester, développer ou mettre à jour de nouvelles extensions, sans affecter le site principal.

Une des extensions a eu besoin d’être débugguée par ses concepteurs mais pour des raisons de confidentialité, il nous est apparu intéressant et plus sécurisé de donner accès à un site de développement, fraîche copie du site original, pour le débuggage.

Si vous avez besoin de créer un site staging pour votre site WordPress et que votre hébergeur ne le propose pas, voici comment faire.

Étape 1 : créer un sous-domaine au niveau DNS

Nous choisissons la solution la plus simple: servir le site STAGING depuis un sous-domaine. Il suffit de créer un nouvel enregistrement DNS sous la forme:

staging IN A xxx.xxx.xxx.xxxCode language: CSS (css)

staging represente le sous-domaine et xxx.xxx.xxx.xxx représente l’adresse IPv4 du serveur.

Étape 2 : créer le server block sous NginX

Le domaine étant déjà actif, j’ai uniquement rajouté ce server block:

### STAGING ###
 server {
 listen              443 ssl http2;
 listen              [::]:443 ssl http2;
 server_name staging.kriyayoga.fr;
 root /home/www/kriyayoga/staging/public_html;
 set $root /home/www/kriyayoga/staging/public_html;
 index index.php index.htm index.html;
 error_log /var/log/nginx/kriyayoga_staging_error.log;
 #SSL
 ssl_certificate        /etc/nginx/ssl/kriyayoga.fr/fullchain.pem;
 ssl_certificate_key    /etc/nginx/ssl/kriyayoga.fr/privkey.pem;
 include snippets/mime-types.conf;
 #Exclusions
 include snippets/exclusions.conf;
 #Security
 include snippets/security.conf;
 #Static Content
 include snippets/static-files.conf;
 #Fastcgi cache rules
 include snippets/fastcgi-cache.conf;
 include snippets/limits.conf;
 include snippets/nginx-cloudflare.conf;
 #Gzip
 include snippets/gzip.conf;
 location / {
 try_files $uri $uri/ /index.php?$args;
 }
 location ~ .php$ {
 try_files $uri =404;
 include snippets/fastcgi-params.conf;
 fastcgi_pass unix:/run/php/php7.4-fpm.sock;
 #Skip cache based on rules in snippets/fastcgi-cache.conf.
 fastcgi_cache_bypass $skip_cache;
 fastcgi_no_cache $skip_cache;
 #Define memory zone for caching. Should match key_zone in fastcgi_cache_path above.
 fastcgi_cache kriyayoga;
 #Define caching time.
 fastcgi_cache_valid 60m;
 #increase timeouts
 fastcgi_read_timeout 6000;
 fastcgi_connect_timeout 6000;
 fastcgi_send_timeout 6000;
 proxy_read_timeout 6000;
 proxy_connect_timeout 6000;
 proxy_send_timeout 6000;
 send_timeout 6000;
 #these lines should be the ones to allow Cloudflare Flexible SSL 
 #to be used so the server does not need to decrypt SSL if you wish
 proxy_set_header X-Forwarded-Host $host;
 proxy_set_header X-Forwarded-Server $host;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header X-Forwarded-Proto https;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-NginX-Proxy true;
 }
 #Protect WooCommerce upload folder from being accessed directly.
 #You may want to delete this config if you are using "Redirect Only" method for downloadable products.
 #Place this config towards the end of "server" block in NginX configuration.
 location ~* /wp-content/uploads/woocommerce_uploads/ {
   if ( $upstream_http_x_accel_redirect = "" ) {
     return 403;
     }
     internal;
 }
 }Code language: PHP (php)

Testez la nouvelle configuration:

nginx -t

Puis redémarrez NginX:

service nginx reload

Note: il est important de noter que je n’ai pas besoin de créer de certificat SSL puisque mes certificats sont wildcard par défaut. Si ce n’est pas le cas chez vous, pensez à en générer pour votre sous-domaine.

Lire la suite

Redémarrer la machine virtuelle de Local by Flywheel photo

Local : résoudre les problèmes d’importation de la base de données

Aujourd’hui, on importe la base de données d’un site existant dans la nouvelle version de Local Lightning, estampillée 5.4.1.

D’habitude, je lance Adminer > Import, je sélectionne mon fichier de base de données et boom, la base est importée. Mais aujourd’hui, rien ne se passe comme prévu: Adminer mouline, mouline, perd la moitié du design de sa page et n’importe pas la base.

SSH à la rescousse

Je me dis qu’on aura peut-être plus de chance depuis la console SSH. Dans Local, faites un clic droit sur le site > Open Site Shell. Une fenêtre de terminal apparaît alors.

Utilisation de WP-CLI

On commence d’abord par la méthode wp-cli. On copie notre fichier adminer.sql sous /app/public et on lance la commande suivante:

wp db import ./adminer.sqlCode language: JavaScript (javascript)

Résultat:

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)Code language: JavaScript (javascript)

Cela commence bien. La version 5 de Local utilise MySQL 8 donc certaines choses ne sont peut-être pas tout à fait au point. Comme il n’y a pas de socket mysql dans /tmp/mysql.sock, nous allons manuellement spécifier notre socket MySQL dans notre commande. Local nous donne l’adresse du socket dans l’onglet Database:

wp db import ./adminer.sql --socket="/Users/matt/Library/Application Support/Local/run/rvrb6Ce-Z/mysql/mysqld.sock"

Résultat:
ERROR 1067 (42000) at line 23841 in file: './adminer.sql': Invalid default value for 'comment_date'
Code language: JavaScript (javascript)

La bonne nouvelle, c’est que l’on peut se connecter à la base de données MySQL. Mais tiens donc, nous sommes déjà tombés sur cette erreur Invalid default value for comment_date !

Configuration de MySQL

Pour régler le problème sous Local, la marche à suivre diffère un peu de ce que nous avions lancé sur notre serveur puisqu’il n’y a pas une mais deux variables de configuration de mysqld à modifier.

On se connecte au serveur mysql:

mysql -u root -proot

Commençons par voir ce que les variables sql_mode contiennent:

SELECT @@GLOBAL.sql_mode; SELECT @@SESSION.sql_mode; Code language: CSS (css)

Résultat:

+------------------------------------------------------------------------------------------+
| @@GLOBAL.sql_mode                                                                        |
+------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+------------------------------------------------------------------------------------------+
1 row in set (0,00 sec)

+------------------------------------------------------------------------------------------+
| @@SESSION.sql_mode                                                                       |
+------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+------------------------------------------------------------------------------------------+Code language: JavaScript (javascript)

Le problème est, comme la dernière fois, la présence de ces deux instructions: NO_ZERO_IN_DATE,NO_ZERO_DATE.

On enlève donc ces deux instructions de nos deux directives:

SET @@GLOBAL.sql_mode="ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION";
SET @@SESSION.sql_mode="ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION";Code language: CSS (css)

Voilà ce que nous obtenons au final:

+------------------------------------------------------------------------------------------+
| @@GLOBAL.sql_mode                                                                        |
+------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+------------------------------------------------------------------------------------------+
1 row in set (0,00 sec)

+------------------------------------------------------------------------------------------+
| @@SESSION.sql_mode                                                                       |
+------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+------------------------------------------------------------------------------------------+
1 row in set (0,00 sec)Code language: JavaScript (javascript)

On peut désormais importer notre fichier SQL:

mysql -u root -proot local < ./adminer.sql 

Hop l’import de la base de données se passe maintenant sans aucun problème.

WordPress : résoudre l'erreur "ftp_nlist() expects parameter 1 to be resource" photo

Lister tous les articles publiés sur un blog WordPress avec wp-cli

wordpress banner 1280x512

Lister les URLs de tous les articles publiés

J’ai récemment eu besoin de lister toutes les URLs des articles du site, pour les promouvoir sur les réseaux sociaux. L’un des services que j’utilise, SocialBee, permet de soumettre une liste de 100 URLs à chaque soumission du formulaire.

Il nous faut donc une liste d’adresse de 100 articles publiés, ce qui est très facile à obtenir grâce à wp-cli. Voici la commande que j’ai écrite:

wp post list --field=url --post_status=publish --allow-root --posts_per_page=100 --paged=1Code language: PHP (php)

Explications:

  • wp est un alias de wp-cli, installé sur le serveur
  • post indique l’on va interroger les articles
  • list: on va lister!
  • --field=url : on veut le champ URL
  • --post_status=publish : les articles publiés uniquement
  • --allow-root : parce que je suis en root
  • --posts_per_page=100: le nombre d’article à récupérer
  • --paged=1 : le numéro de la pagination de la requête

Il vous suffit ensuite d’incrémenter la valeur de --paged pour passer en revue toutes les pages de la requête.

Ou alors retirer totalement les arguments --posts_per_page=100 --paged=1 pour obtenir la liste complète des URLs de tous les articles publiés.

WordPress : résoudre l'erreur "ftp_nlist() expects parameter 1 to be resource" photo

WordPress : résoudre l’erreur “ftp_nlist() expects parameter 1 to be resource, null given”

Sous WordPress 5.3.x et en utilisant wp-cli, on peut obtenir cette erreur lors de la mise à jour de plugins et thèmes:

Warning: ftp_nlist() expects parameter 1 to be resource, null given in /var/www/html/wp-admin/includes/class-wp-filesystem-ftpext.php on line 402

PHP Warning:  ftp_pwd() expects parameter 1 to be resource, null given in /var/www/html/wp-admin/includes/class-wp-filesystem-ftpext.php on line 226Code language: HTTP (http)

Le tout répété cinq à six fois pour la mise à jour d’un plugin. En regardant le ticket trac qui rapporte ce problème, il s’agit d’une erreur qui était auparavant cachée (avec un @ devant la fonction) et qui est maintenant affichée.

Au -delà du fait de cacher ou ne plus cacher l’erreur, il semble qu’il manque une routine qui vérifie que le lien wp_filesystem est bien actif avant de pouvoir l’utiliser.

En attendant que cela soit réglé dans une prochaine version de WordPress, voici ce que l’on peut ajouter au fichier wp-config.php pour se débarrasser de l’erreur proprement:

if ( !defined( 'FS_METHOD' ) ):
    define( 'FS_METHOD', 'direct' );
endif;Code language: PHP (php)

Enregistrez le fichier, problème réglé !

WordPress : résoudre le problème de la table wp_options à qui manquent une colonne Unique et une Primary Key photo

WordPress : résoudre le problème de la table wp_options à qui manquent une colonne Unique et une Primary Key

Chez Codeable, j’ai travaillé sur l’optimisation d’un site e-commerce propulsé par WooCommerce récemment, qui connaissait quelques problèmes de lenteur.

Sous phpMyAdmin, on trouvait également cette erreur:

Current selection does not contain a unique column

Si vous obtenez cette erreur, c’est que la structure de la table wp_options n’est pas à jour donc nous la vérifions avec wp-cli:

wp db query "DESCRIBE $(wp db prefix --allow-root)options" --allow-rootCode language: JavaScript (javascript)

Le résultat obtenu nous montre qu’il n’y a pas de clé primaire (primary key) qui est normalement option_id et qu’il n’y a pas de restriction unique imposée sur la colonne option_name:

+--------------+---------------------+------+-----+---------+-------+
| Field        | Type                | Null | Key | Default | Extra |
+--------------+---------------------+------+-----+---------+-------+
| option_id    | bigint(20) unsigned | NO   |     | NULL    |       |
| option_name  | varchar(191)        | YES  |     | NULL    |       |
| option_value | longtext            | NO   |     | NULL    |       |
| autoload     | varchar(20)         | NO   |     | yes     |       |
+--------------+---------------------+------+-----+---------+-------+Code language: PHP (php)

Et c’est là que le bât blesse – voici à quoi ressemble la structure standard de la table wp-options:

+--------------+---------------------+------+-----+---------+----------------+
| Field        | Type                | Null | Key | Default | Extra          |
+--------------+---------------------+------+-----+---------+----------------+
| option_id    | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| option_name  | varchar(191)        | NO   | UNI | NULL    |                |
| option_value | longtext            | NO   |     | NULL    |                |
| autoload     | varchar(20)         | NO   | MUL | yes     |                |
+--------------+---------------------+------+-----+---------+----------------+Code language: PHP (php)

Ajouter la Primary Key manquante à wp_options

On ajoute à la colonne option_id la clé primaire qui lui manque:

wp db query "ALTER TABLE $(wp db prefix --allow-root)options MODIFY option_id INT AUTO_INCREMENT PRIMARY KEY;" --allow-rootCode language: JavaScript (javascript)

Et on vérifie le résultat:

wp db query "DESCRIBE $(wp db prefix --allow-root)options" --allow-rootCode language: JavaScript (javascript)

Ajouter la contrainte Unique qui manque à wp_options

Pour ajouter la contrainte UNIQUE à la colonne option_name, on lance:

wp db query "ALTER TABLE $(wp db prefix --allow-root)options ADD UNIQUE (option_name);" --allow-rootCode language: JavaScript (javascript)

Là, il est possible que cela bloque, suivant ce qui se trouve dans votre table wp_options.

Résoudre le problème des doublons

Si vous obtenez une erreur comme :

ERROR 1062 (23000) at line 1: Duplicate entry 'jetpack_available_modules' for key 'option_name'Code language: JavaScript (javascript)

alors cela signifie qu’il existe des enregistrements option_name dupliqués, des doublons qui portent le même nom alors que chaque nom option_name devrait être unique.

On peut obtenir la liste des enregistrements option_name doublons avec cette requête:

wp db query "SELECT option_name, COUNT(*) optioncount FROM $(wp db prefix --allow-root)options GROUP BY option_name HAVING optioncount > 1 ORDER BY optioncount DESC;" --allow-rootCode language: JavaScript (javascript)

Par ordre ascendant, voici la liste des doublons:

+---------------------------------------------+-------------+
| option_name                                 | optioncount |
+---------------------------------------------+-------------+
| jetpack_callables_sync_checksum             |       47123 |
| jetpack_sync_full_config                    |          50 |
| jetpack_sync_full_enqueue_status            |          43 |
| jpsq_sync_checkout                          |          10 |
| jetpack_sync_full__params                   |           5 |
| jetpack_sync_settings_sync_via_cron         |           4 |
| jetpack_sync_full__started                  |           4 |
+---------------------------------------------+-------------+

On peut supprimer automatiquement tous les doublons option_name de deux manières différentes, soit en utilisant la plus vieille valeuroption_id(donc la plus petite valeur d’ID), soit en utilisant la valeuroption_id la plus récente (plus grande valeur d’ID).

Garder le doublon option_name le plus ancien

Voici la requête SQL qui montre uniquement le plus ancien enregistrement (MIN) option_id pour chaque doublon de valeur option_name:

SELECT *
FROM wp options
WHERE option_id NOT IN
    (SELECT *
     FROM
       (SELECT MIN(n.option_id)
        FROM wp_options
        GROUP BY n.option_name) x)Code language: CSS (css)

Une fois que vous avez vérifié le résultat, on peut passer à la suppression.

Cette requête SQL garde l’enregistrement (MIN) option_id le plus ancien de tous les doublonsoption_name et supprime tous les enregistrements plus récents que la valeur trouvée:

DELETE
FROM wp options
WHERE option_id NOT IN
    (SELECT *
     FROM
       (SELECT MIN(n.option_id)
        FROM wp_options n
        GROUP BY n.option_name) x)Code language: CSS (css)

Voici l’équivalent wp-cli:

wp db query "DELETE FROM $(wp db prefix --allow-root)options WHERE option_id NOT IN (SELECT * FROM (SELECT MIN(n.option_id) FROM $(wp db prefix --allow-root)options n GROUP BY n.option_name) x)" --allow-rootCode language: JavaScript (javascript)

Garder le doublon option_name le plus récent

Cette requête SQL ne montre que les enregistrements option_id les plus récents (MAX) pour tous les doublons option_name :

SELECT *
FROM wp_options
WHERE option_id NOT IN
    (SELECT *
     FROM
       (SELECT MAX(n.option_id)
        FROM wp_options n
        GROUP BY n.option_name) x)Code language: CSS (css)

Et voici la requête qui permet de garder les enregistrements option_id les plus récents (MAX) pour tous les doublons option_name en supprimant tous les doublons les plus anciens:

DELETE
FROM wp_options
WHERE option_id NOT IN
    (SELECT *
     FROM
       (SELECT MAX(n.option_id)
        FROM wp_options n
        GROUP BY n.option_name) x)Code language: CSS (css)

Voici l’équivalent wp-cli pour garder l’enregistrement option_name le plus récent:

wp db query "DELETE FROM $(wp db prefix --allow-root)options WHERE option_id NOT IN (SELECT * FROM (SELECT MAX(n.option_id) FROM $(wp db prefix --allow-root)options n GROUP BY n.option_name) x)" --allow-rootCode language: JavaScript (javascript)

Vérifier les clés et contraintes de la table wp_options

Ajoutons de nouveau la contrainte UNIQUE sur la colonne option_name :

wp db query "ALTER TABLE $(wp db prefix --allow-root)options ADD UNIQUE (option_name);" --allow-rootCode language: JavaScript (javascript)

Si vous n’obtenez pas d’erreur, vérifiez la table une nouvelle fois pour constater les changements:

wp db query "DESCRIBE $(wp db prefix --allow-root)options;" --allow-rootCode language: JavaScript (javascript)

Kaboom! Votre table wp_options possède maintenant une PRIMARY KEY sur la colonne option_id et la contrainte UNIQUE sur la colonne option_name:

+--------------+---------------------+------+-----+---------+----------------+
| Field        | Type                | Null | Key | Default | Extra          |
+--------------+---------------------+------+-----+---------+----------------+
| option_id    | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| option_name  | varchar(191)        | NO   | UNI |         |                |
| option_value | longtext            | NO   |     | NULL    |                |
| autoload     | varchar(20)         | NO   |     | yes     |                |
+--------------+---------------------+------+-----+---------+----------------+Code language: PHP (php)

Je vous conseille de vérifier la structure de la table de temps à autre, notamment si vous constatez une prise de poids anormale en très peu de temps

Ajouter un lien avec le nombre d'articles et le total du panier WooCommerce photo

Mettre à jour la base de données de WooCommerce avec wp-cli

Il existe certaines situations dans lesquelles le plugin WooCommerce est mis à jour mais la mise à jour de la base de données du plugin échoue.

Cet échec de la mise à jour de la base de données est généralement causé par le délai d’attente de PHP, en particulier sur l’environnement d’hébergement partagé, puisque PHP ne dispose que de 60 secondes pour s’exécuter via une requête Web.

La non-concordance de version entre la version de la base de données WooCommerce et celle du plugin WooCommerce peut être à l’origine de problèmes.

Mise à jour de la base WooCommerce en ligne de commande

Pour résoudre ces problèmes, nous pouvons mettre à jour la base de données WooCommerce via la ligne de commande, en utilisant wp-cli.

1. Connectez-vous au serveur en SSH.

2. Naviguez jusqu’à la racine du site via SSH et exécutez la commande de mise à jour de WooCommerce:

wp wc update

Pour une grosse base de données, cela peut prendre un certain temps. Voici le résultat que vous devriez obtenir une fois le processus de mise à jour de la base de données terminé :

wp wc update

Calling update function: wc_update_350_db_version
Success: 2 updates complete. Database version is 3.5.0Code language: CSS (css)

3. Vérifiez dans WooCommerce > Status que la version de la base de données correspond bien à la version du plugin WooCommerce.

Et voilà votre base de données WooCommerce à jour!