Le blog d’un développeur freelance passionné de web, qui partage ici diverses trouvailles et réflexions dans le domaine du web, du développement, du SEO, et des nouvelles technologies.


Prestashop : Corriger les incohérences (doublons) de positions dans la base de données

Si vous constatez des bugs lorsque vous modifiez les positions d’éléments tels que les catégories, produits, transporteurs, etc., ces changements de positions  ne fonctionnant pas toujours ou de manière un peu aléatoire, il est probable que vous ayez des incohérences dans votre base de données : plusieurs éléments qui sont dans le même élément parent on la même valeur dans le champ « position ».

J’ai développé un petit script pour corriger ce type d’incohérences.

Dans mon cas, il corrige ce problème pour les positions, redéfinissant correctement la valeur du champ « position » pour les sous catégories qui ont une position en doublon dans une même catégorie parent.
Etant dans un contexte multiboutique, il travaille sur la table ps_category_shop et non pas sur la table ps_category.

Il peut servir de modèle pour corriger d’autres tables (catégories dans un contexte non multiboutique, produits, transporteurs, etc.)
Ci dessous le script 🙂

$db = Db::getInstance();
$res = $db->executeS('SELECT DISTINCT id_category, id_shop FROM '._DB_PREFIX_.'category_shop');
foreach ($res as $row) {
    $res2 = $db->executeS('SELECT cs.* FROM '._DB_PREFIX_.'category_shop cs
        INNER JOIN '._DB_PREFIX_.'category c ON c.id_category = cs.id_category
        WHERE cs.id_shop = '.$row['id_shop'].'
        AND c.id_parent='.$row['id_category'].'
        ORDER BY cs.position');
    $i=1;
    foreach ($res2 as $row2) {
        if ($i != $row2['position']) {
            echo 'Position modifiée : '.$i.' catégorie '.$row2['id_category'].' shop '.$row['id_shop'].'
';
             $db->execute('UPDATE '._DB_PREFIX_.'category_shop SET position='.$i.'
                 WHERE id_shop = '.$row['id_shop'].'
                 AND id_category = '.$row2['id_category']);
        }
        $i++;
    }
}
9 juin 2016|Categories: Blog|Tags: |0 Commentaires

Images reponsive dans WordPress 4.4, problèmes de compatibilité et comment le désactiver

Depuis sa version 4.4 sortie le 8 décembre 2015, WordPress a introduit par défaut dans les images des attributs liés aux fonctionnalités responsive : « srcset » et « sizes ».

Le souci est que ces attributs posent des problèmes de compatibilité dans certains cas particuliers. J’ai été confronté à ce type de problèmes sur certaines versions de Safari, sur certaines images d’un site.

Si vous rencontrez ce type de problème, ou si vous voulez tout simplement désactiver ces nouvelles fonctionnalités, il suffit d’ajouter la ligne de code suivante dans votre thème :

add_filter( 'max_srcset_image_width', create_function( '', 'return 1;' ) );

Pour plus d’infos sur ces fonctionnalités :

Responsive Images in WordPress 4.4

15 décembre 2015|Categories: Blog|Tags: |0 Commentaires

Linux : Script bash pour une sauvegarde historisée

Le principe est simple : réaliser une sauvegarde historisée sur un certain nombre de jours d’un serveur Linux.
J’ai personnellement sélectionné :

  • Le répertoire etc pour avoir la conf du serveur et des services utilisés
  • Les bases de données, sous forme de dump MySQL
  • Les répertoires des différents sites web

Le principe est simple : une archive tar.gz par jour et par élément (etc, bases, répertoires web), enregistrés sous un dossier local qui sera ici /home/sauvegardes/
Il faudra en général prévoir un rsync distant de la dernière version de chaque élément au moins, pour avoir une sauvegarde distante. Ceci pourrait faire l’objet d’un autre article.

Ce script étant à appeler en tache « cron » bien entendu.

En attendant, voilà le script en question.

#!/bin/bash

# DECLARATIONS VARIABLES
mysqldbs=(db1 db2 db3)
wwwdirs=(dir1 dir2 dir3)
nbjours=30
jourtodelete=$((nbjours+1))

# ROTATION ANCIENNES VERSIONS
for ((  jour = ${nbjours[*]};  jour > 1;  jour--  ))
do
    jourprec=$((jour-1))
    # SYSTEME
    mv /home/sauvegardes/etc.$jourprec.tar.gz /home/sauvegardes/etc.$jour.tar.gz

    # MYSQL
    for db in ${mysqldbs[*]}
    do
        mv /home/sauvegardes/mysql_dump/$db.$jourprec.sql.tar.gz /home/sauvegardes/mysql_dump/$db.$jour.sql.tar.gz
    done
    # WWW
    for dir in ${wwwdirs[*]}
    do
        mv /home/sauvegardes/www/$dir.$jourprec.tar.gz /home/sauvegardes/www/$dir.$jour.tar.gz
    done
done

# SUPPRESSION VERSION LA PLUS VIEILLE
# SYSTEME
rm /home/sauvegardes/etc.$jourtodelete.sql.tar.gz
# MYSQL
for db in ${mysqldbs[*]}
do
    rm /home/sauvegardes/mysql_dump/$db.$jourtodelete.sql.tar.gz
done
# WWW
for dir in ${wwwdirs[*]}
do
    rm /home/sauvegardes/www/$dir.$jourtodelete.tar.gz
done

# GENERATION VERSION DU JOUR
# SYSTEME
tar czf /home/sauvegardes/etc.1.tar.gz /etc
# MYSQL
for db in ${mysqldbs[*]}
do
    mysqldump -u root --password=MYSQLROOTPASSWORD $db > /home/sauvegardes/mysql_dump/$db.sql
    tar czf /home/sauvegardes/mysql_dump/$db.1.sql.tar.gz /home/sauvegardes/mysql_dump/$db.sql
    rm /home/sauvegardes/mysql_dump/$db.sql
done
# WWW
for dir in ${wwwdirs[*]}
do
    tar czf /home/sauvegardes/www/$dir.1.tar.gz /var/www/$dir/
done

Pour l’adapter à votre environnement :

  • Remplacer « (db1 db2 db3) » par la liste des bases à sauvegarder
  • Remplacer « (dir1 dir2 dir3) » par la liste des répertoires web à sauvegarder
  • Variable « nbjours » : renseigner le nombre de jours d’historisation souhaités
  • Remplacer « MYSQLROOTPASSWORD » par le mot de passe root MySQL de votre serveur.
  • Remplacer « /home/sauvegardes/ » ainsi que « /home/sauvegardes/mysql_dump/ » et « /home/sauvegardes/www » par les chemins respectifs souhaités : racine des sauvegardes, répertoire des sauvegardes des bases, et répertoire des sauvegardes des répertoires web.

Et roulez jeunesse !

Cela reste artisanal, mais très pratique pour avoir une procédure de sauvegardes historisées suffisante pour pouvoir restaurer des versions antérieures de chaque site, ainsi que le paramétrage du serveur (en cas d’urgence, ce que je ne vous souhaite pas).

La grosse faille du script étant la présence du mot de passe root MySQL en dur, il mériterait de gérer les mots de passe de chaque base sous forme de liste pour éviter d’avoir le mot de passe root. Et dans l’idéal de trouver une solution pour ne pas faire apparaitre les mots de passe dans le script.
La première solution est relativement simple à implémenter, la deuxième beaucoup moins mais est sans doute possible également.
Je n’ai pas appronfondi ces aspects, le serveur concerné dans mon cas personnel étant un serveur de développement et de « gros bordel », les enjeux stratégiques sécuritaires n’en valaient pas la peine.

Si vous utilisez ce script comme base et le faites évoluer dans ce sens, n’hésitez pas à poster des modifications améliorant ces aspects de sécurité (et éventuellement d’autres que je n’aurais pas identifié) 🙂

14 octobre 2015|Categories: Blog|Tags: |0 Commentaires

Bootsrap : colonnes de même hauteur, par ligne, et responsive

Un problème récurrent avec bootsrap est d’avoir une présentation en « grille » avec des colonnes de même hauteur.

En effet, par défaut, les colonnes ont leur hauteur déterminée par leur contenu, et aucune solution CSS n’existe pour modifier ce comportement, car les différentes solutions proposées en cherchant sur le net ont d’autres incidences sur la présentation par défaut des colonnes.

La solution est donc de passer par du javascript pour gérer celà.

J’ai développé une petite fonction permettant de faire ça, et qui semble bien fonctionner, je vais donc vous la proposer ici, elle pourra vous faire gagner du temps !

Cette fonction nécessite que chaque colonne ait les classes de taille pour toutes les tailles de fenêtre possible, soit « col-xs-* », « col-sm-* », « col-md-* », « col-lg-* ».

Il faut également ajouter une classe « col-same-height » aux colonnes que l’on veut avoir de même hauteur.

Elle part également du principe que la taille de la grille est de 12 (valeur par défaut de bootstrap), et que les tailles de containers soient également celles par défaut de Bootsrap.
Si vous n’utilisez pas ces valeurs standard, vous pouvez les modifier facilement dans la fonction.

Code :

$(window).load(function() {
    $(window).resize(resizeColSameHeight);
    resizeColSameHeight();
});

/**
 * Redimensionnement hauteur des colonnes bootstrap "col-same-height" ligne par ligne selon la taille de la vue
 */
function resizeColSameHeight() {
    if ($('.col-same-height').length > 0) {
        var width = $('body').width();
        if (width < 768)
            var size = 'xs';
        else if (width < 992)
            var size = 'sm';
        else if (width < 1200) var size = 'md'; else var size = 'lg'; var classnames = $('.col-same-height').first().attr("class").toString().split(' '); for(var i in classnames) { var classname = classnames[i]; if (classname.indexOf('col-' + size + '-') != -1) var nbCols = 12 / classname.replace('col-' + size + '-', ''); } $('.col-same-height').css('height', 'auto'); if (nbCols > 1) {
            var i = 0;
            do {
                elems = $('.col-same-height').slice(i, i+nbCols);
                var maxHeight = 0;
                $(elems).each(function() {
                    if ($(this).height() > maxHeight)
                        maxHeight = $(this).height();
                });
                $(elems).each(function() {
                    $(this).css('height', maxHeight + 'px');
                });
                i += nbCols;
            } while (elems.length > 0);
        }
    }
}
25 août 2015|Categories: Blog|Tags: |0 Commentaires

La synthèse vocale minimaliste et efficace grâce à Google

C’est amusant et ça peut être utile.

Vous voulez intégrer de la synthèse vocale sur votre site ?

Une solution des plus simples : l’API Google Text To Speech !

Appeller l’URL http://translate.google.com/translate_tts?ie=utf-8&tl=fr&q= en rajoutant comme valeur au paramètre q le texte que l’on veut synthétiser.

Exemple : http://translate.google.com/translate_tts?ie=utf-8&tl=fr&q=salut%20%C3%A0%20toi

Ensuite vous n’avez plus qu’à récupérer le fichier audio et en faire ce que vous voulez 🙂

Vous pouvez même jouer sur le paramètre tl pour traduire votre texte !

Source et informations plus complètes : http://www.lycee-ledantec.ac-rennes.fr/ledan-tech/?p=794

13 janvier 2015|Categories: Blog|0 Commentaires

Deuxième contribution à wordpress.org : supprimer les metas boxes selon le rôle de l’utilisateur

Tout est dans le titre 🙂

La page du module est ici : https://wordpress.org/plugins/remove-meta-boxes-per-user-role/

 

25 novembre 2014|Categories: Blog|Tags: |0 Commentaires

Ma première contribution à wordpress.org

J’ai développé un module WordPress qui permet de gérer les permissions des utilisateurs selon les catégories, mots clés, et toutes les custom taxonomies.

Un module du genre « simple et efficace »qui peut être utile dans certains cas !

Téléchargeable sur wordpress.org : https://wordpress.org/plugins/admin-users-advances-permissions/

14 novembre 2014|Categories: Blog|Tags: |0 Commentaires

Restaurer les rôles et permissions par défaut sur WordPress

Dans le cadre de projets WordPress, il est courant de jouer avec les rôles utilisateurs et leurs permissions, pour customiser l’admin pour les différents types d’utilisateurs qui seront amenés à l’utiliser.

On joue avec les fonctions remove_role, add_role, et parfois on a de mauvaises surprises, comme un « Vous n’avez pas les droits suffisants pour accéder à cette page. » quand on veut accéder au wp-admin avec un des nouveaux rôles que l’on a créé.
On décide alors de recopier le nouveau rôle à partir d’un des rôles par défaut de WordPress, quand on se rend compte que l’on ne peut pas le faire car on a supprimé les rôles par défaut avec remove_role sans savoir que cette suppression était irrémédiable !

Heureusement, il est assez simple de réinitialiser tout ça pour repartir avec tous les roles par défaut et à nouveau pouvoir les utiliser comme modèle !

Pour cela, il faut agir directement en base de données, dans la table wp_options, en éditant la ligne qui a pour option_name : « wp_user_roles »

La option_value à assigner à cette ligne est la suivante :

a:5:{s:13:"administrator";a:2:{s:4:"name";s:13:"Administrator";s:12:"capabilities";a:62:{s:13:"switch_themes";b:1;s:11:"edit_themes";b:1;s:16:"activate_plugins";b:1;s:12:"edit_plugins";b:1;s:10:"edit_users";b:1;s:10:"edit_files";b:1;s:14:"manage_options";b:1;s:17:"moderate_comments";b:1;s:17:"manage_categories";b:1;s:12:"manage_links";b:1;s:12:"upload_files";b:1;s:6:"import";b:1;s:15:"unfiltered_html";b:1;s:10:"edit_posts";b:1;s:17:"edit_others_posts";b:1;s:20:"edit_published_posts";b:1;s:13:"publish_posts";b:1;s:10:"edit_pages";b:1;s:4:"read";b:1;s:8:"level_10";b:1;s:7:"level_9";b:1;s:7:"level_8";b:1;s:7:"level_7";b:1;s:7:"level_6";b:1;s:7:"level_5";b:1;s:7:"level_4";b:1;s:7:"level_3";b:1;s:7:"level_2";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:17:"edit_others_pages";b:1;s:20:"edit_published_pages";b:1;s:13:"publish_pages";b:1;s:12:"delete_pages";b:1;s:19:"delete_others_pages";b:1;s:22:"delete_published_pages";b:1;s:12:"delete_posts";b:1;s:19:"delete_others_posts";b:1;s:22:"delete_published_posts";b:1;s:20:"delete_private_posts";b:1;s:18:"edit_private_posts";b:1;s:18:"read_private_posts";b:1;s:20:"delete_private_pages";b:1;s:18:"edit_private_pages";b:1;s:18:"read_private_pages";b:1;s:12:"delete_users";b:1;s:12:"create_users";b:1;s:17:"unfiltered_upload";b:1;s:14:"edit_dashboard";b:1;s:14:"update_plugins";b:1;s:14:"delete_plugins";b:1;s:15:"install_plugins";b:1;s:13:"update_themes";b:1;s:14:"install_themes";b:1;s:11:"update_core";b:1;s:10:"list_users";b:1;s:12:"remove_users";b:1;s:9:"add_users";b:1;s:13:"promote_users";b:1;s:18:"edit_theme_options";b:1;s:13:"delete_themes";b:1;s:6:"export";b:1;}}s:6:"editor";a:2:{s:4:"name";s:6:"Editor";s:12:"capabilities";a:34:{s:17:"moderate_comments";b:1;s:17:"manage_categories";b:1;s:12:"manage_links";b:1;s:12:"upload_files";b:1;s:15:"unfiltered_html";b:1;s:10:"edit_posts";b:1;s:17:"edit_others_posts";b:1;s:20:"edit_published_posts";b:1;s:13:"publish_posts";b:1;s:10:"edit_pages";b:1;s:4:"read";b:1;s:7:"level_7";b:1;s:7:"level_6";b:1;s:7:"level_5";b:1;s:7:"level_4";b:1;s:7:"level_3";b:1;s:7:"level_2";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:17:"edit_others_pages";b:1;s:20:"edit_published_pages";b:1;s:13:"publish_pages";b:1;s:12:"delete_pages";b:1;s:19:"delete_others_pages";b:1;s:22:"delete_published_pages";b:1;s:12:"delete_posts";b:1;s:19:"delete_others_posts";b:1;s:22:"delete_published_posts";b:1;s:20:"delete_private_posts";b:1;s:18:"edit_private_posts";b:1;s:18:"read_private_posts";b:1;s:20:"delete_private_pages";b:1;s:18:"edit_private_pages";b:1;s:18:"read_private_pages";b:1;}}s:6:"author";a:2:{s:4:"name";s:6:"Author";s:12:"capabilities";a:10:{s:12:"upload_files";b:1;s:10:"edit_posts";b:1;s:20:"edit_published_posts";b:1;s:13:"publish_posts";b:1;s:4:"read";b:1;s:7:"level_2";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:12:"delete_posts";b:1;s:22:"delete_published_posts";b:1;}}s:11:"contributor";a:2:{s:4:"name";s:11:"Contributor";s:12:"capabilities";a:5:{s:10:"edit_posts";b:1;s:4:"read";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:12:"delete_posts";b:1;}}s:10:"subscriber";a:2:{s:4:"name";s:10:"Subscriber";s:12:"capabilities";a:2:{s:4:"read";b:1;s:7:"level_0";b:1;}}}

C’est tout bête mais c’est pratique d’avoir cela sous la main, ça peut éviter d’avoir à faire une nouvelle installation de WordPress juste pour pouvoir retrouver cette valeur 🙂

5 novembre 2014|Categories: Blog|Tags: |8 Commentaires

Prestashop 1.5.5.0, bug dans le cache

Prestashop est un outil formidable, mais quand il vient à présenter des problèmes de performances, il y a souvent de quoi s’arracher les cheveux.

J’ai récemment été confronté au problème, sur un prestashop 1.5.5.0, qui malgré tous les réglages dans l’admin optimisés (cache, compilation smarty, CCC, etc.) présentait des temps de réponse insatisfaisants.

Après avoir débuggé pendant quelques heures, j’ai pu trouver un bug dans les classes de prestashop, au niveau de la gestion du cache, qui faisait que les requêtes SQL mises en caches n’étaient jamais retrouvées, et étaient donc regénérées à chaque fois.

Le bug se situe au niveau de la gestion des clés du cache, dans le fichier classes/db/Db.php

Vous devez alors chercher la chaine

Cache::getInstance()->get(md5($sql))

Et la remplacer par la chaine

Cache::getInstance()->get(md5(_COOKIE_IV_.$sql))

Le gain de performances n’est pas miraculeux mais quitte à utiliser le système de cache, autant qu’il fonctionne à peu près correctement…

En espérant que cela puisse vous servir, et que Prestashop corrige rapidement dans les prochaines versions !

24 septembre 2013|Categories: Blog|Tags: |0 Commentaires

Validation des valeurs de radio boutons avec jquery.validate

La problématique est toute bête, on a un groupe de boutons radio, admettons « oui » et « non », et on veut imposer la valeur cochée avec jquery validate.

Exemple :

<input type='radio' name='truc' id='truc_oui' value='oui' /> Oui
<input type='radio' name='truc' id='truc_non' value='non' /> Non

Je n’ai pas trouvé de solution toute faire pour ça, et les recherches sur le net ont mené à une fonction buggée qui vérifie la valeur du champ, un truc du genre :

jQuery.validator.addMethod('correctAnswer', function(value, element, params) {
return this.optional(element) || value == params;
}, 'Select the correct answer to move on.');

Le problème étant que dans ce cas, le « value » passé à la fonction est systématiquement la première value du formulaire pour ce groupe de boutons radio, et non pas la valeur cochée.

J’ai donc créé une fonction équivalente mais non buggée, si ca peut vous servir 🙂

jQuery.validator.addMethod('correctAnswer', function(value, element, params) {
return $('input[type=radio][name='+element.name+']:checked').val()==params;
}, 'La réponse est incorrecte.');

 

7 septembre 2013|Categories: Blog|Tags: |0 Commentaires