Vue normale

Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.
À partir d’avant-hierFlux principal

IA pour les développeurs : Amazon rend gratuit CodeWhisperer

Dans cette course à qui intègrerait plus d’Intelligence Artificielle dans ses offres, Amazon ne souhaite pas se laisser distancer. A défaut d’un partenariat avec OpenAI, comme c’est le cas de Microsoft, ce qui lui donne aujourd’hui une avance considérable sur le marché en particulier sur son rival Google, Amazon lui rend son produit d’aide au développeurs indépendants CodeWhisperer gratuit et cerise sur le gâteau, il fonctionnera y compris pour les personnes n’utilisant pas le cloud AWS.

Amazon a lancé CodeWhisperer en avant-première l’année dernière, que les développeurs peuvent utiliser dans divers environnements de développement intégrés (IDE), comme Visual Studio Code, pour générer des lignes de code sur la base d’une invite textuelle. Alors qu’il n’était à l’origine disponible que pour les clients d’Amazon Web Services, la nouvelle version gratuite devrait le rendre beaucoup plus accessible aux développeurs qui n’utilisent pas AWS.

Cet outil est un concurrent direct de GitHub Copilot, facturé de son coté 10$ par mois. Si le produit de Microsoft, basé sur OpenAI est tout bonnement bluffant, les avis sur celui d’Amazon ne sont pas aussi bons en moyenne, mais à 0€ qui va s’en plaindre ? Le grand perdant, une fois de plus dans cette course à l’IA est sans doute Google qui dispose également de son propre outil « AlphaCode », mais il est encore en phase de test privée…

Pour en revenir au produit d’Amazon, parmi les ponts mis en avant, il est doté de fonctions d’analyse de la sécurité qui permettent d’identifier les vulnérabilités dans le code d’un développeur, tout en proposant des suggestions pour aider à combler les lacunes de sécurité qu’il découvre. CodeWhisperer prend en charge plusieurs langages, dont Python, Java, JavaScript, TypeScript et C#, ainsi que Go, Rust, PHP, Ruby, Kotlin, C, C++, Shell scripting, SQL et Scala.

Une petite vidéo Amazon pour la mise en oeuvre avec Visual Studio Code :

stephanesabbague

IA pour les développeurs : Amazon rend gratuit CodeWhisperer

Dans cette course à qui intègrerait plus d’Intelligence Artificielle dans ses offres, Amazon ne souhaite pas se laisser distancer. A défaut d’un partenariat avec OpenAI, comme c’est le cas de Microsoft, ce qui lui donne aujourd’hui une avance considérable sur le marché en particulier sur son rival Google, Amazon lui rend son produit d’aide au développeurs indépendants CodeWhisperer gratuit et cerise sur le gâteau, il fonctionnera y compris pour les personnes n’utilisant pas le cloud AWS.

Amazon a lancé CodeWhisperer en avant-première l’année dernière, que les développeurs peuvent utiliser dans divers environnements de développement intégrés (IDE), comme Visual Studio Code, pour générer des lignes de code sur la base d’une invite textuelle. Alors qu’il n’était à l’origine disponible que pour les clients d’Amazon Web Services, la nouvelle version gratuite devrait le rendre beaucoup plus accessible aux développeurs qui n’utilisent pas AWS.

Cet outil est un concurrent direct de GitHub Copilot, facturé de son coté 10$ par mois. Si le produit de Microsoft, basé sur OpenAI est tout bonnement bluffant, les avis sur celui d’Amazon ne sont pas aussi bons en moyenne, mais à 0€ qui va s’en plaindre ? Le grand perdant, une fois de plus dans cette course à l’IA est sans doute Google qui dispose également de son propre outil « AlphaCode », mais il est encore en phase de test privée…

Pour en revenir au produit d’Amazon, parmi les ponts mis en avant, il est doté de fonctions d’analyse de la sécurité qui permettent d’identifier les vulnérabilités dans le code d’un développeur, tout en proposant des suggestions pour aider à combler les lacunes de sécurité qu’il découvre. CodeWhisperer prend en charge plusieurs langages, dont Python, Java, JavaScript, TypeScript et C#, ainsi que Go, Rust, PHP, Ruby, Kotlin, C, C++, Shell scripting, SQL et Scala.

Une petite vidéo Amazon pour la mise en oeuvre avec Visual Studio Code :

stephanesabbague

Un store de mods pour personnaliser Windows

Si vous êtes sous Windows et que vous voulez sortir des sentiers battus en le personnalisant un peu au-delà des paramètres prévus par Microsoft, vous êtes sur le bon site. Sur le site Windhawk, vous trouverez un utilitaire gratuit qui permet d’appliquer des mods à votre Windows.

Capture d'écran de l'interface utilisateur du store de mods pour personnaliser Windows

Un « mod », c’est une modification qui sera faite à Windows pour par exemple avoir un notepad avec un thème sombre, faire un clic avec le bouton du milieu de la souris pour fermer une application ouverte dans la barre des tâches, ou encore contrôler le volume sonore de votre PC en scrollant sur votre barre de menu.

Pack de mods pour personnaliser l'apparence de Windows disponible sur le store

La liste complète des mods proposés par Windhawk se trouve ici et évidemment, le code de chacun d’entre eux est disponible donc vous savez exactement ce que ça fait sur votre système.

Il n’y a pas encore énormément de mods en base, mais c’est un bon début et vous pouvez proposer les vôtres.

En tout cas, pour moi qui aime ce genre de petits hacks, je trouve que c’est une chouette idée à développer.

Python en toute sérénité avec Calmcode

Si vous voulez vous améliorer en Python, mais que vous manquez de temps et que vous ne voulez pas vous prendre la tête, alors Calmcode.io est la solution pour vous.

Avec plus de 600 vidéos assez courtes et simples à comprendre dans différents cours, vous pourrez facilement apprendre les bases de Python et découvrir de nouveaux outils open source.

Notez que le site propose également une newsletter pour être tenu informé des nouveaux contenus mis en ligne.

Capture d'écran de la page d'accueil de Calmcode avec un fond bleu et le texte 'Calmcode'

L’objectif de Calmcode est de remédier à l’anxiété liée à vos perceptions de vos compétences en développement en proposant des leçons vidéo courtes et simples à capter qui partent de zéro.

Par exemple, vous y trouverez une bonne introduction à l’outil Bandit qui permet de renforcer la sécurité de votre code Python.

Capture d'écran de la page de documentation de Python avec un fond blanc et le logo Python en haut à gauche

Le contenu est axé sur des outils et des réflexions qui peuvent comme ça, rendre votre vie professionnelle plus agréable. Calmcode s’efforce ainsi de suivre des principes importants tels que fournir un contenu clair et concis, mettre l’accent sur la patience et l’itération plutôt que sur des délais à respecter, et surtout « montrer » comment on fait les choses plutôt que simplement les expliquer.

C’est vraiment cool et je suis certain que vous en retirerez des choses. Bref, à fouiller !

Low Code – No Code vs ERP : match en cours ?

Low Code – No Code vs ERP match en cours

L’ERP est-il en perte de vitesse ? Pour le moment, non. Mais se poser la question, c’est déjà donner une indication de réponse. S’il est suffisamment hégémonique pour ne pas être directement menacé par l’émergence des technologies Low Code et No Code, l’ERP est néanmoins obligé de s’adapter pour survivre. Quitte à embrasser son bourreau ? Pas si vite…

The post Low Code – No Code vs ERP : match en cours ? appeared first on iTPro.fr.

IA : Microsoft annonce le SDK Semantic Kernel

Microsoft vient d’annoncer la prévision du kit de développement « Semantic Kernel ». Logiquement ce dernier est dispo en Open Source sur GitHub. Le Semantic Kernel est donc un kit de développement logiciel (SDK) léger qui facilite l’utilisation d’éléments tels que ChatGPT d’OpenAI dans les applications, selon John Maeda, vice-président de Microsoft chargé de la conception et de l’intelligence artificielle, il fonctionne avec les langages de programmation conventionnels, avec une prise en charge actuelle en beta de « C# et Python ». Microsoft envisage d’ajouter la prise en charge de TypeScript et d’autres langages dans un futur proche.

Semantic Kernel, qui a débuté en tant que projet d’incubation interne à Microsoft, il prend actuellement en charge le modèle GPT-4 d’OpenAI et le service Azure OpenAI. Ses capacités peuvent être intégrées dans n’importe quel type d’application et peuvent se connecter à des sources de données et à des services externes. Semantic Kernel se distingue également par le fait qu’il permet aux développeurs d’utiliser des prompts complexes, ce qui peut s’avérer problématique lorsqu’on travaille avec de l’IA

« Ainsi, imaginez que vous puissiez facilement créer des invites complexes, des invites à multiples facettes, des invites qui font toutes sortes de choses comme se connecter à du code natif. Ce genre de choses est offert gratuitement avec Symantec Kernel » – John Maeda.

Ce SDK peut être en réalité considéré comme un ensemble de bonnes pour ajouter une IA riche en sémantique aux applications existantes. Ainsi la source GitHub comprend quelques exemples de codes modèles que les développeurs peuvent essayer. Il existe une capacité de « résumé de chat simple » pour les applications. Un exemple de code « Book creator » permet aux applications de créer des aperçus de livres. Il existe également un modèle de code de connecteur de base qui peut être utilisé pour « s’authentifier et se connecter à une API ».

Nous reviendrons lors du prochain Briefing sur les IA conversationnelles et leurs usages.

stephanesabbague

Afficher le prix HT dans la partie « Remise sur quantité » – Prestashop

Dans une boutique B2B on affiche les tarifs HT mais le panier est en TTC.

J’ai configuré un produit de la façon suivante :

prix-produit-presta-neuf

Mon groupe est configuré de la façon suivante :

groupe-visiteur-presta-neuf

Sauf que quand j’affiche mon produit je vois ceci :

fiche-produit-preprod

C’est surtout sur la partie remisée qu’il faut s ‘attarder.

Je devrais avoir pour 10 produit un tarif unitaire de 90€ soit une économie de 10€ HT par produit et donc un gain total de 100€ HT

Sauf que là je me retrouve pour 10 produit à un tarif unitaire à 108€, donc la apparemment prestashop applique la réduction sur le prix TTC.

MAIS POURQUOI ? je lui indiqué partout que je voulais les prix HT …..

Ce qui est le plus étrange c’est que sur les versions 1.5 nous n’avons jamais eu ce problème.

En grattant un peu je suis remonté à la méthode formatQuantityDiscounts() qui gère cette partie, et là qu’est-ce que l’on voit ?

$cur_price = (!$row['reduction_tax'] ? $row['price'] : $row['price'] * (1 + $tax_rate / 100)) + (float)$ecotax_amount;

Et oui dans tous les cas il multiplie par la taxe !

Bug (erreur) ou fonctionnement normal je ne sais pas.
Mais voici la solution que je vous propose.

Si l’utilisateur est dans un groupe ou on souhaite qu’il ait l’affichage des prix HT
Alors je retourne le prix du produit sans la multiplication
Sinon
Je retourne ce qui était a l’origine.

Ce qui donne :

if(Group::getPriceDisplayMethod($this->context->customer->id_default_group) == 1)
     $cur_price = (!$row['reduction_tax'] ? $row['price'] : $row['price']) + (float)$ecotax_amount;
else
     $cur_price = (!$row['reduction_tax'] ? $row['price'] : $row['price'] * (1 + $tax_rate / 100)) + (float)$ecotax_amount;

Pour faire ce correctif, vous devez créer un fichier ProductController.php dans le répertoire override/controllers/front/

Copier-coller le contenu suivant dans le fichier ProductController

<?php
class ProductController extends ProductControllerCore
{

    protected function formatQuantityDiscounts($specific_prices, $price, $tax_rate, $ecotax_amount)
    {
        foreach ($specific_prices as $key => &$row) {
            $row['quantity'] = &$row['from_quantity'];
            if ($row['price'] >= 0) {
 
                if(Group::getPriceDisplayMethod($this->context->customer->id_default_group) == 1)
                    $cur_price = (!$row['reduction_tax'] ? $row['price'] : $row['price']) + (float)$ecotax_amount;
                else
                    $cur_price = (!$row['reduction_tax'] ? $row['price'] : $row['price'] * (1 + $tax_rate / 100)) + (float)$ecotax_amount;

                if ($row['reduction_type'] == 'amount') {
                    $cur_price -= ($row['reduction_tax'] ? $row['reduction'] : $row['reduction'] / (1 + $tax_rate / 100));
                    $row['reduction_with_tax'] = $row['reduction_tax'] ? $row['reduction'] : $row['reduction'] / (1 + $tax_rate / 100);
                } else {
                    $cur_price *= 1 - $row['reduction'];
                }

                $row['real_value'] = $price > 0 ? $price - $cur_price : $cur_price;
            } else {
                if ($row['reduction_type'] == 'amount') {
					if (Product::$_taxCalculationMethod == PS_TAX_INC) {
						$row['real_value'] = $row['reduction_tax'] == 1 ? $row['reduction'] : $row['reduction'] * (1 + $tax_rate / 100);
					} else {
						$row['real_value'] = $row['reduction_tax'] == 0 ? $row['reduction'] : $row['reduction'] / (1 + $tax_rate / 100);
					}
                    $row['reduction_with_tax'] = $row['reduction_tax'] ? $row['reduction'] : $row['reduction'] +  ($row['reduction'] *$tax_rate) / 100;
                } else {
                    $row['real_value'] = $row['reduction'] * 100;
                }
            }
            $row['nextQuantity'] = (isset($specific_prices[$key + 1]) ? (int)$specific_prices[$key + 1]['from_quantity'] : - 1);
        }
        return $specific_prices;
    }
}

La méthode formatQuantityDiscounts() du fichier ProductController.php viens écraser la méthode par défaut.

Il faut penser également :

  • Supprimer le cache
  • Supprimer ou modifier le fichier cache/class_index.php

Au final vous devez avoir le résultat voulu:

fiche-produit-finale

J’ai ouvert un topic sur le forum prestashop, mais je suis relativement déçu très peu de réponse de la part de la communauté bof bof 🙁

Classer par marque et référence les produits dans le BL et la facture Prestashop

Salut tout le monde, un petit snippet pour prestashop qui permet de mettre dans un ordre voulu les produits dans un bon de livraison et sur la facture.

Pourquoi faire ça ?

C’est une demande de mon boss, car nous venons de réorganiser les allées des stocks par Fabriquant (marque) puis par référence. Pour que ce soit plus pratique dans la constitution de la commande nous avons ordonné les produits du bon de livraison comme notre organisation physique.

Il suffit de créer un fichier OrderInvoice.php dans le répertoire override/classes/order et d’y ajouter ce petit bout de code.

L’intérêt de surcharger la méthode getProductsDetail() permet de ne pas embêter les mises à jour du core Prestashop.

Menu accessible sur WordPress : les bases d'un menu simple

Dans cette première partie nous allons voir comment mettre en place un menu accessible simple, sans sous-menu : récapitulatif des bases, explications des notions importantes et des moyens pour rendre notre menu à un niveau accessible. C’est parti !

Créer un menu dans WordPress : les bases

Tout d’abord voyons en quelques étapes comment mettre en place un menu sur WordPress.

1) Enregistrer un emplacement de menu

Dans le fichier de configuration du thème (souvent functions.php ou un sous-fichier si vous prônez l’organisation comme chez Alsacréations) enregistrons un menu "Menu principal" avec la fonction register_nav_menu(). Il a pour slug main-menu qui nous sera utile pour afficher le menu :

function register_my_menu() {
    register_nav_menu( 'main-menu' => __( 'Menu principal', 'text-domain' ) );
}
add_action( 'after_setup_theme', 'register_my_menu' );

Dans l’administration WordPress, l’emplacement apparait dans les réglages du menu :

Dans les réglages du menu, l'emplacement “Menu principal“ est sélectionnable.

2) Afficher le menu

Il n’y a plus qu’à appeler le menu là où nous souhaitons l’afficher, dans l’en-tête header.php par exemple. Pour cela il faut utiliser la fonction wp_nav_menu() et préciser le slug précédemment enregistré :

/**
 * Affiche le menu "Menu principal" enregistré au préalable.
 */
wp_nav_menu([
    'theme_location' => 'main-menu',
]);

Cette fonction propose des options de configuration très avancées. Vous retrouverez la liste des paramètres disponibles sur la documentation officielle de wp_nav_menu.

3) Administrer le menu

Pour le moment nous souhaitons créer un menu simple. Pour cela créer un nouveau menu dans l'interface d'administration de WordPress, le nommer, et cocher l’emplacement enregistré à l’étape 1.

Dans l’administration WordPress, le menu principal est composé de 3 éléments “Accueil”, “Actualités” et “Contact”. L’emplacement coché est “Menu principal”.

Si vous avez bien suivi les étapes, vous devriez avoir un menu qui fonctionne à minima. Et voici le code généré par WordPress :

<div class="menu-menu-principal-container">
  <ul id="menu-menu-principal" class="menu">
    <li id="menu-item-256" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-home current-menu-item page_item page-item-251 current_page_item menu-item-256">
      <a href="">Accueil</a>
    </li>
    <li id="menu-item-290" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-290">
      <a href="">Actualités</a>
    </li>
    <li id="menu-item-253" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-253">
      <a href="">Contact</a>
    </li>
  </ul>
</div>

Rendre notre menu accessible

Côté accessibilité, le code généré possède quelques points à améliorer :

  • le conteneur du menu n’a pas de sémantique. C’est une simple <div>.
  • La page courante n’est pas restituée aux lecteurs d’écran.

Mais comment corriger cela ? La fonction wp_nav_menu() possède des paramètres qui pourront nous aider, mais cela ne nous permettra pas de tout corriger. Dans ce cas, il faudra modifier le code généré par WordPress.

Comment WordPress gère ce code ? Comment modifier ce code ?

Nous allons utiliser le walker Walker_Nav_Menu qui nous sera utile pour personnaliser le code généré. Mais avant, explications !

Qu’est ce qu’un Walker ?

Un walker est une classe abstraite PHP qui permet de parcourir une arborescence de données (objets ou tableaux) afin de générer du code HTML.

Par rapport à notre menu ➡️ le walker va parcourir le menu, et exécuter à chaque noeud une fonction.

Quand nous observons la classe dans le codex, le walker possède 4 fonctions :

  • start_lvl : correspond au début d’un sous-menu <ul> et son contenu.
  • end_lvl : Fin d’un sous-menu </ul>.
  • start_el : Début d’un élément du menu. Équivalent du <li> et son contenu.
  • end_el : Fin d’un élément </li>.
Visualisation des fonctions du walker Walker_Nav_Menu à travers un menu à deux niveaux.

Et l’avantage d’un walker, c’est qu’il est possible de l’étendre afin de customiser ces fonctions. Spoiler : c’est ce que nous allons faire 🤠.

Rendre notre menu sémantiquement parlant

Actuellement, notre menu est perçu simplement comme une liste, avec un conteneur ne donnant aucun contexte.

Nous allons donc ajouter un peu de sémantique pour restituer, à l’utilisateur et aux lecteurs d’écran, que c’est un menu de navigation. Pour cela, faisons appel aux landmarks ARIA.

Rappel : les landmarks permettent de déclarer des régions (header, main, footer, nav, aside, etc.) afin de structurer une page et de restituer le contexte aux lecteurs d’écran.

Ici, nous allons englober notre menu d’une balise <nav> avec un attribut ARIA role="navigation". Si plusieurs menus de navigation existent dans le site, une bonne pratique est de l’identifier via un attribut aria-label ou la combinaison aria-labelledby/id.

Si vous avez regardé en détail le codex de wp_nav_menu(), vous vous demanderez sûrement pourquoi ne pas utiliser les paramètres container et container_aria_label. Comme ils sont de type string, il n’aurait donc pas été possible de passer l’attribut role="navigation".

Nous privilégions donc de ne pas utiliser le conteneur généré par WP :

<nav role="navigation" aria-label="<?php _e('Menu principal', 'text-domain'); ?>">
    <?php
        wp_nav_menu([
            'theme_location' => 'main-menu',
            'container'      => false // On retire le conteneur généré par WP
        ]);
    ?>
</nav>

Préciser la page courante

Visuellement la page courante d’un menu peut-être indiquée par la couleur, la forme (bordure basse), une icône, etc. :

Exemple d’affichage pour indiquer la position courante (site Smashing Magazine)

Mais qu’en-est-il des personnes malvoyantes utilisant un lecteur d’écran ? Il faut une alternative HTML en plus de l’indication visuelle.

L’attribut aria-current rentre en piste ! Il permet d’indiquer aux lecteurs d’écran l’élément actif parmi un ensemble. Dans notre cas, il aura pour valeur :

  • page sur la page courante;
  • true sur la page parente, si existante.

Exemples :

<a href="#" aria-current="page">Accueil</a>
<a href="#" aria-current="true">Actualités</a>
<ul class="sub-menu">
  <li>
    <a href="#" aria-current="page">Sous-actualité</a>
  </li>
  <li>
    <a href="#">Sous-actualité</a>
  </li>
</ul>

Mais.. comment faire sur WordPress ? Si vous avez bien suivi c’est le moment d’étendre le walker 🚀

Étendre le walker par défaut

Pour cela, nous allons dans un premier temps créer un nouveau fichier menus.php et l’appeler dans le fichier functions.php.

Dans ce fichier nous allons simplement copier/coller le walker existant de WordPress Walker_Nav_Menu.

Quel est l’intérêt me direz-vous ? Simplement pour éviter de faire des erreurs. Nous aurons juste à customiser la/les fonction(s) souhaitée(s).

La seconde étape est de renommer le walker pour le distinguer d’autres potentiels walkers :

class A11y_Walker_Nav_Menu extends Walker {

Ensuite, nous allons appeler ce walker dans la fonction wp_nav_menu() en ajoutant un paramètre walker pour créer une instance de notre classe A11y_Walker_Nav_Menu :

<nav role="navigation" aria-label="<?php _e('Menu principal', 'text-domain'); ?>">
  <?php
    wp_nav_menu([
        'theme_location' => 'main-menu',
        'container'      => false,
        'walker'         => new A11y_Walker_Nav_Menu()
    ]);
  ?>
</nav>

Personnaliser notre nouveau walker

Notre objectif est d’ajouter un attribut aria-current sur un élément du menu lorsqu’il correspond à la page courante.

Comme précisé plus haut, c’est la fonction start_el() qui va permettre de modifier le contenu d’un élément du menu.

Avant tout, regardons plus en détail cette fonction :

/**
 * Starts the element output.
 *
 * @since 3.0.0
 * @since 4.4.0 The {@see 'nav_menu_item_args'} filter was added.
 * @since 5.9.0 Renamed `$item` to `$data_object` and `$id` to `$current_object_id`
 *              to match parent class for PHP 8 named parameter support.
 *
 * @see Walker::start_el()
 *
 * @param string   $output            Used to append additional content (passed by reference).
 * @param WP_Post  $data_object       Menu item data object.
 * @param int      $depth             Depth of menu item. Used for padding.
 * @param stdClass $args              An object of wp_nav_menu() arguments.
 * @param int      $current_object_id Optional. ID of the current menu item. Default 0.
 */
public function start_el( &$output, $data_object, $depth = 0, $args = null, $current_object_id = 0 ) {
    // Restores the more descriptive, specific name for use within this method.
    $menu_item = $data_object;

    // Suite de la fonction...

Les commentaires nous précisent que :

  • le paramètre $output est le résultat de la fonction sous forme de contenu HTML.
  • Le paramètre $data_object est un objet qui nous permet de récupérer toutes les informations de l’élément. À noter que la première ligne de la fonction nous précise d’utiliser $menu_item. Cette variable regroupe plusieurs clés (n’hésitez pas à explorer son contenu en utilisant var_dump($menu_item) ).

Arrêtons-nous sur la clé current. C’est un booléen qui a pour valeur true lorsque l’élément correspond à la page courante. Parfait, c’est ce que nous voulons !

Mais comment ajouter un attribut à l’élément ? Et bien WordPress ne fait pas les choses à moitié : si vous regardez bien la fonction, un paramètre $atts est mis à disposition. Il utilise le filtre nav_menu_link_attributes :

$atts = apply_filters( 'nav_menu_link_attributes', $atts, $menu_item, $args, $depth );

Ce filtre permet d’ajouter/modifier des attributs à l’élément actuel. Il faut donc ajouter, avant la ligne ci-dessus, le code suivant :

$atts['aria-current'] = $menu_item->current ? 'page' : '';

Et voilà, l’attribut est ajouté dans le code lorsque $menu_item possède la clé current. Plutôt simple, hein ?

Ajouter un attribut title si le lien s’ouvre dans un nouvel onglet

L’utilisation d’un attribut title permet d’ajouter un complément d’information. Attention à l’utiliser correctement : il faut reprendre l’intitulé du lien, puis ajouter le texte complémentaire (notes du glossaire RGAA).

Dans notre cas nous allons préciser qu’un lien s’ouvre dans un nouvel onglet lorsque son target vaut _blank:

Exemple :

<a href="#" target="_blank" title="Intitulé du lien (s'ouvre dans un nouvel onglet)">Intitulé du lien</a>

Préciser cette action permet de prévenir les utilisateurs d’un changement brusque et éviter de perturber leur navigation.

Comment le faire sur WordPress ?

Nous allons donc modifier la fonction start_el() pour ajouter un title lorsque le target est _blank. Si vous regardez bien, cette condition existe déjà :

if ( '_blank' === $menu_item->target && empty( $menu_item->xfn ) )

Il n’y a plus qu’à ajouter l’attribut title et lui donner pour valeur le titre de l’élément title suivi de notre texte :

if ( '_blank' === $menu_item->target && empty( $menu_item->xfn ) ) {

 // Attribut title : on précise que le lien s'ouvre dans un nouvel onglet
 $atts['title'] = $menu_item->title . __( ' (s\'ouvre dans un nouvel onglet)', 'text-domain' );

}

Voilà ce qu’il en est pour la mise en place d’un menu accessible simple. Cette première partie était assez longue car nous trouvions important de revenir sur les bases de la création d’un menu WordPress. La prochaine entrera directement dans le vif du sujet et concernera la gestion des sous-éléments d’un menu.

Retrouvez l'intégralité de ce tutoriel en ligne sur Alsacreations.com

Menu accessible sur WordPress : les bases d'un menu simple

Dans cette première partie nous allons voir comment mettre en place un menu accessible simple, sans sous-menu : récapitulatif des bases, explications des notions importantes et des moyens pour rendre notre menu à un niveau accessible. C’est parti !

Créer un menu dans WordPress : les bases

Tout d’abord voyons en quelques étapes comment mettre en place un menu sur WordPress.

1) Enregistrer un emplacement de menu

Dans le fichier de configuration du thème (souvent functions.php ou un sous-fichier si vous prônez l’organisation comme chez Alsacréations) enregistrons un menu "Menu principal" avec la fonction register_nav_menu(). Il a pour slug main-menu qui nous sera utile pour afficher le menu :

function register_my_menu() {
    register_nav_menu( 'main-menu' => __( 'Menu principal', 'text-domain' ) );
}
add_action( 'after_setup_theme', 'register_my_menu' );

Dans l’administration WordPress, l’emplacement apparait dans les réglages du menu :

Dans les réglages du menu, l'emplacement “Menu principal“ est sélectionnable.

2) Afficher le menu

Il n’y a plus qu’à appeler le menu là où nous souhaitons l’afficher, dans l’en-tête header.php par exemple. Pour cela il faut utiliser la fonction wp_nav_menu() et préciser le slug précédemment enregistré :

/**
 * Affiche le menu "Menu principal" enregistré au préalable.
 */
wp_nav_menu([
    'theme_location' => 'main-menu',
]);

Cette fonction propose des options de configuration très avancées. Vous retrouverez la liste des paramètres disponibles sur la documentation officielle de wp_nav_menu.

3) Administrer le menu

Pour le moment nous souhaitons créer un menu simple. Pour cela créer un nouveau menu dans l'interface d'administration de WordPress, le nommer, et cocher l’emplacement enregistré à l’étape 1.

Dans l’administration WordPress, le menu principal est composé de 3 éléments “Accueil”, “Actualités” et “Contact”. L’emplacement coché est “Menu principal”.

Si vous avez bien suivi les étapes, vous devriez avoir un menu qui fonctionne à minima. Et voici le code généré par WordPress :

<div class="menu-menu-principal-container">
  <ul id="menu-menu-principal" class="menu">
    <li id="menu-item-256" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-home current-menu-item page_item page-item-251 current_page_item menu-item-256">
      <a href="">Accueil</a>
    </li>
    <li id="menu-item-290" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-290">
      <a href="">Actualités</a>
    </li>
    <li id="menu-item-253" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-253">
      <a href="">Contact</a>
    </li>
  </ul>
</div>

Rendre notre menu accessible

Côté accessibilité, le code généré possède quelques points à améliorer :

  • le conteneur du menu n’a pas de sémantique. C’est une simple <div>.
  • La page courante n’est pas restituée aux lecteurs d’écran.

Mais comment corriger cela ? La fonction wp_nav_menu() possède des paramètres qui pourront nous aider, mais cela ne nous permettra pas de tout corriger. Dans ce cas, il faudra modifier le code généré par WordPress.

Comment WordPress gère ce code ? Comment modifier ce code ?

Nous allons utiliser le walker Walker_Nav_Menu qui nous sera utile pour personnaliser le code généré. Mais avant, explications !

Qu’est ce qu’un Walker ?

Un walker est une classe abstraite PHP qui permet de parcourir une arborescence de données (objets ou tableaux) afin de générer du code HTML.

Par rapport à notre menu ➡️ le walker va parcourir le menu, et exécuter à chaque noeud une fonction.

Quand nous observons la classe dans le codex, le walker possède 4 fonctions :

  • start_lvl : correspond au début d’un sous-menu <ul> et son contenu.
  • end_lvl : Fin d’un sous-menu </ul>.
  • start_el : Début d’un élément du menu. Équivalent du <li> et son contenu.
  • end_el : Fin d’un élément </li>.
Visualisation des fonctions du walker Walker_Nav_Menu à travers un menu à deux niveaux.

Et l’avantage d’un walker, c’est qu’il est possible de l’étendre afin de customiser ces fonctions. Spoiler : c’est ce que nous allons faire 🤠.

Rendre notre menu sémantiquement parlant

Actuellement, notre menu est perçu simplement comme une liste, avec un conteneur ne donnant aucun contexte.

Nous allons donc ajouter un peu de sémantique pour restituer, à l’utilisateur et aux lecteurs d’écran, que c’est un menu de navigation. Pour cela, faisons appel aux landmarks ARIA.

Rappel : les landmarks permettent de déclarer des régions (header, main, footer, nav, aside, etc.) afin de structurer une page et de restituer le contexte aux lecteurs d’écran.

Ici, nous allons englober notre menu d’une balise <nav> avec un attribut ARIA role="navigation". Si plusieurs menus de navigation existent dans le site, une bonne pratique est de l’identifier via un attribut aria-label ou la combinaison aria-labelledby/id.

Si vous avez regardé en détail le codex de wp_nav_menu(), vous vous demanderez sûrement pourquoi ne pas utiliser les paramètres container et container_aria_label. Comme ils sont de type string, il n’aurait donc pas été possible de passer l’attribut role="navigation".

Nous privilégions donc de ne pas utiliser le conteneur généré par WP :

<nav role="navigation" aria-label="<?php _e('Menu principal', 'text-domain'); ?>">
    <?php
        wp_nav_menu([
            'theme_location' => 'main-menu',
            'container'      => false // On retire le conteneur généré par WP
        ]);
    ?>
</nav>

Préciser la page courante

Visuellement la page courante d’un menu peut-être indiquée par la couleur, la forme (bordure basse), une icône, etc. :

Exemple d’affichage pour indiquer la position courante (site Smashing Magazine)

Mais qu’en-est-il des personnes malvoyantes utilisant un lecteur d’écran ? Il faut une alternative HTML en plus de l’indication visuelle.

L’attribut aria-current rentre en piste ! Il permet d’indiquer aux lecteurs d’écran l’élément actif parmi un ensemble. Dans notre cas, il aura pour valeur :

  • page sur la page courante;
  • true sur la page parente, si existante.

Exemples :

<a href="#" aria-current="page">Accueil</a>
<a href="#" aria-current="true">Actualités</a>
<ul class="sub-menu">
  <li>
    <a href="#" aria-current="page">Sous-actualité</a>
  </li>
  <li>
    <a href="#">Sous-actualité</a>
  </li>
</ul>

Mais.. comment faire sur WordPress ? Si vous avez bien suivi c’est le moment d’étendre le walker 🚀

Étendre le walker par défaut

Pour cela, nous allons dans un premier temps créer un nouveau fichier menus.php et l’appeler dans le fichier functions.php.

Dans ce fichier nous allons simplement copier/coller le walker existant de WordPress Walker_Nav_Menu.

Quel est l’intérêt me direz-vous ? Simplement pour éviter de faire des erreurs. Nous aurons juste à customiser la/les fonction(s) souhaitée(s).

La seconde étape est de renommer le walker pour le distinguer d’autres potentiels walkers :

class A11y_Walker_Nav_Menu extends Walker {

Ensuite, nous allons appeler ce walker dans la fonction wp_nav_menu() en ajoutant un paramètre walker pour créer une instance de notre classe A11y_Walker_Nav_Menu :

<nav role="navigation" aria-label="<?php _e('Menu principal', 'text-domain'); ?>">
  <?php
    wp_nav_menu([
        'theme_location' => 'main-menu',
        'container'      => false,
        'walker'         => new A11y_Walker_Nav_Menu()
    ]);
  ?>
</nav>

Personnaliser notre nouveau walker

Notre objectif est d’ajouter un attribut aria-current sur un élément du menu lorsqu’il correspond à la page courante.

Comme précisé plus haut, c’est la fonction start_el() qui va permettre de modifier le contenu d’un élément du menu.

Avant tout, regardons plus en détail cette fonction :

/**
 * Starts the element output.
 *
 * @since 3.0.0
 * @since 4.4.0 The {@see 'nav_menu_item_args'} filter was added.
 * @since 5.9.0 Renamed `$item` to `$data_object` and `$id` to `$current_object_id`
 *              to match parent class for PHP 8 named parameter support.
 *
 * @see Walker::start_el()
 *
 * @param string   $output            Used to append additional content (passed by reference).
 * @param WP_Post  $data_object       Menu item data object.
 * @param int      $depth             Depth of menu item. Used for padding.
 * @param stdClass $args              An object of wp_nav_menu() arguments.
 * @param int      $current_object_id Optional. ID of the current menu item. Default 0.
 */
public function start_el( &$output, $data_object, $depth = 0, $args = null, $current_object_id = 0 ) {
    // Restores the more descriptive, specific name for use within this method.
    $menu_item = $data_object;

    // Suite de la fonction...

Les commentaires nous précisent que :

  • le paramètre $output est le résultat de la fonction sous forme de contenu HTML.
  • Le paramètre $data_object est un objet qui nous permet de récupérer toutes les informations de l’élément. À noter que la première ligne de la fonction nous précise d’utiliser $menu_item. Cette variable regroupe plusieurs clés (n’hésitez pas à explorer son contenu en utilisant var_dump($menu_item) ).

Arrêtons-nous sur la clé current. C’est un booléen qui a pour valeur true lorsque l’élément correspond à la page courante. Parfait, c’est ce que nous voulons !

Mais comment ajouter un attribut à l’élément ? Et bien WordPress ne fait pas les choses à moitié : si vous regardez bien la fonction, un paramètre $atts est mis à disposition. Il utilise le filtre nav_menu_link_attributes :

$atts = apply_filters( 'nav_menu_link_attributes', $atts, $menu_item, $args, $depth );

Ce filtre permet d’ajouter/modifier des attributs à l’élément actuel. Il faut donc ajouter, avant la ligne ci-dessus, le code suivant :

$atts['aria-current'] = $menu_item->current ? 'page' : '';

Et voilà, l’attribut est ajouté dans le code lorsque $menu_item possède la clé current. Plutôt simple, hein ?

Ajouter un attribut title si le lien s’ouvre dans un nouvel onglet

L’utilisation d’un attribut title permet d’ajouter un complément d’information. Attention à l’utiliser correctement : il faut reprendre l’intitulé du lien, puis ajouter le texte complémentaire (notes du glossaire RGAA).

Dans notre cas nous allons préciser qu’un lien s’ouvre dans un nouvel onglet lorsque son target vaut _blank:

Exemple :

<a href="#" target="_blank" title="Intitulé du lien (s'ouvre dans un nouvel onglet)">Intitulé du lien</a>

Préciser cette action permet de prévenir les utilisateurs d’un changement brusque et éviter de perturber leur navigation.

Comment le faire sur WordPress ?

Nous allons donc modifier la fonction start_el() pour ajouter un title lorsque le target est _blank. Si vous regardez bien, cette condition existe déjà :

if ( '_blank' === $menu_item->target && empty( $menu_item->xfn ) )

Il n’y a plus qu’à ajouter l’attribut title et lui donner pour valeur le titre de l’élément title suivi de notre texte :

if ( '_blank' === $menu_item->target && empty( $menu_item->xfn ) ) {

 // Attribut title : on précise que le lien s'ouvre dans un nouvel onglet
 $atts['title'] = $menu_item->title . __( ' (s\'ouvre dans un nouvel onglet)', 'text-domain' );

}

Voilà ce qu’il en est pour la mise en place d’un menu accessible simple. Cette première partie était assez longue car nous trouvions important de revenir sur les bases de la création d’un menu WordPress. La prochaine entrera directement dans le vif du sujet et concernera la gestion des sous-éléments d’un menu.

Retrouvez l'intégralité de ce tutoriel en ligne sur Alsacreations.com

Traductions multilingues avec Timber

On l'a vu dans l'article "Pourquoi écrire du Twig dans WordPress ?", Timber est une excellente dépendance pour WordPress faite pour les développeurs.

J'aimerais faire le lien avec l'article "Préparer un thème WordPress pour l'internationalisation", car la syntaxe n'est pas forcément évidente si vous êtes habitués à l'écriture standard de WordPress.

Les bases

Dans l'ensemble, rien de bien plus compliqué qu’avec PHP hormis la syntaxe. On utilise toujours la même fonction WordPress qui est aussi disponible dans Timber.

Voilà un exemple simple avec PHP :

<?php echo __( "Voir toutes les actualités", "textdomain" ); ?>

Et voilà son équivalent avec Timber :

{{ __( "Voir toutes les actualités", "textdomain" ) }}

Jusqu’ici tout va bien, si vous avez l’habitude d’écrire en Twig c’est la même chose.

Abordons maintenant un cas plus spécifique.

Gérer les singuliers et les pluriels

Dans cette partie, on utilisera l'exemple de la barre de recherche, qui est un composant que l'on retrouve fréquemment sur beaucoup de sites et qui est naturellement accompagnée d'une page de résultats, sur laquelle on retrouve une phrase récapitulant le nombre de résultats trouvés et la requête faite par l'utilisateur.

Le formulaire de recherche d'alsacreations.com

Cette dernière est souvent sous la forme : "X résultat(s) trouvé(s) pour le mot Y."

Ce qui induit qu'en fonction du nombre de résultats trouvés, cette phrase peut être au pluriel. Comme toujours, il y a plusieurs méthodes pour réaliser cela et je divulgâche, mais certaines de ces méthodes sont meilleures que d'autres sur plusieurs points.

Première méthode

En tant que développeur, on peut être tenté de gérer l'affichage avec une condition.

Par exemple :

  • Si le résultat de ma recherche est supérieur à 1, j'affiche le pluriel, sinon j'affiche le singulier.
  • J’utilise la fonction sprintf avec les spécificateurs adéquats respectivement pour le nombre de résultats et le terme de recherche.

En PHP, cela donnerait :

<?php if( $search_result > 1 ) : ?>

  <?php
    sprintf(
      __( "%d résultats trouvés pour le mot \"%s\".", "textdomain" ),
        $search_result,
        get_search_query()
    );
  ?>

<?php else : ?>

  <?php
    sprintf(
      __( "%d résultat trouvé pour le mot \"%s\".", "textdomain" ),
        $search_result,
        get_search_query()
      );
  ?>

<?php endif; ?>

Et avec Timber :

{% if search_result|length > 1 %}

  {{
    __( "%d résultats trouvés pour le mot \"%s\".", "textdomain")|format(
      search_result|length,
      fn('get_search_query')
    )
  }}

{% else %}
  {{
    __( "%d résultat trouvé pour le mot \"%s\".", "textdomain" )|format(
      search_result|length,
      fn('get_search_query')
    )
  }}

{% endif %}

C’est la même chose, excepté que l’on remplace un appel de fonction par un filtre.

On y retrouve :

  • Le filtre length sur la variable search_result renvoie le nombre d'éléments.
  • La fonction __() pour les traductions avec le bon textdomain
  • Le filtre format qui est l’équivalent de la fonction sprintf en PHP
  • fn() ou function() qui permet d’utiliser une fonction WordPress ou PHP

Avec cette méthode, si search_result est supérieur à 1, on obtiendra :

2 résultats trouvés pour le mot Burger.

Sinon :

1 résultat trouvé pour le mot Burger.

Parfait, le résultat est comme attendu. Ça fonctionne !

Dans notre outil de traduction (Poedit), on retrouve bien les chaînes de caractères à traduire. Cependant, il y a une chaîne pour gérer le singulier et une pour gérer le pluriel.

Les chaines de traduction dans Poedit

Pourquoi ça ne va pas ?!

  • On se retrouve avec deux traductions à produire, alors que c’est potentiellement la même phrase.
  • S'il y a des cas similaires à traiter sur le site, on aura un fichier de traduction long comme le bras, qui contient pleins de doublons de phrases.
  • Si le fichier doit être fourni à une tierce personne pour la traduction, cela manquera de contexte pour traduire correctement.

Il existe des fonctions faites pour ce genre de cas !

La bonne méthode

Pour avoir des traductions singulier/pluriel propres et optimisées, on utilise la fonction WordPress _n(), qui est un tout-en-un.

Il suffit de lui passer la valeur qui sert de référence et elle s'occupera de choisir d'afficher le singulier ou le pluriel.

Toujours dans l'exemple de page de résultats de recherche, voici comment l'utiliser avec PHP :

<?php
  sprintf(
    _n(
      "%d résultat trouvé pour le mot \"%s\".",
      "%d résultats trouvés pour le mot \"%s\".",
      $search_result,
      "textdomain"
    ),
    $search_result,
    get_search_query()
  );
?>

Et son équivalence avec Timber :

{{
  __(
    _n(
      "%d résultat trouvé pour le mot \"%s\".",
      "%d résultats trouvés pour le mot \"%s\".",
      search_result|length,
      "textdomain"
    )|format(
      search_result|length,
      fn('get_search_query')
    )
  )
}}

Mais c’est plus imbriqué, plus dur à lire/écrire et la finalité est la même ! Alors ça change quoi ? 🤔

Le résultat dans l'outil de traduction est complètement différent !

Un exemple de gestion correcte des pluriels dans Poedit

Pourquoi c’est mieux ? Pourquoi privilégier cette méthode ?

  • Le singulier et le pluriel se retrouvent dans le même champ pour la traduction
  • On apporte plus de contexte et de compréhension
  • On obtient un fichier de traduction optimisé et propre

Et voilà ! Vous avez une bonne pratique supplémentaire à intégrer dès le début du développement de votre thème WordPress avec Timber !

À bientôt pour un prochain article. 🙂

Retrouvez l'intégralité de ce tutoriel en ligne sur Alsacreations.com

API RESTful du plugin ZWave

Le tutoriel d’aujourd’hui m’a été demandé à maintes reprises depuis plus d’une année. Je vous propose aujourd’hui : d’exploiter l’API RESTful du plugin ZWave. Le plugin ZWave met à disposition des web services via un serveur REST. Je vais vous apprendre...

L’article API RESTful du plugin ZWave est apparu en premier sur La domotique de Nechry.

Domotiser une toile de store extérieur

Bonjour aujourd’hui je vais vous présenter une de mes dernières réalisations. Je possède un store banne à caisson Opal Design de la marque Griesser. Le toile est commandée via une télécommande dans un protocole BiLine de Griesser. Je vais vous...

L’article Domotiser une toile de store extérieur est apparu en premier sur La domotique de Nechry.

Programmatically remove every Teams except some by PowerShell Script

Why such script ?

My customer was a school, each year they need to recreate the Teams classroom, to reset the content and canal

The solution was to remove every Teams except the permanent one (workgroup Teams)

Below is the PowerShell Script. I use an xml file to connect easily to the Microsoft 365, avoiding re entering login / password

#By Jeff ANGAMA
#02.09.2020

#************GOAL************#
#This script remove every TEAMS except the one specified in variable $keepThoseTeams
#Write the list of TEAMS without ACCENT !!!

#************PRE REQUISITE - Run those commands to save your creds************#
#$pathToCred = "C:\credTenant.xml"
# $credential = Get-Credential
# $credential | Export-CliXml -Path $pathToCred

#************CONFIG************#
$keepThoseTeams = (
    'IT Team',
    'Support Informatique',
    'Training',
    'Administration',
    'College',
    'Coordinateurs lycee',
    'Documents de suivi lycee',
    'Budget',
    'Demande de creation de classe'
    )

#LOGS
$currentFolder = Get-Location
$timeStamp = $(((get-date).ToUniversalTime()).ToString("yyyyMMddThhmmssZ"))
$logFileName = "$currentFolder\logs\logDeleteTeams_" + $timeStamp + ".txt"
Start-Transcript -path $logFileName -append

#Connect
$pathToCred = "C:\credTenant.xml"
$credential = Import-CliXml -Path $pathToCred
Connect-MicrosoftTeams -Credential $credential

#remove accent from text, to avoid issue with contains or eq function containing accents
function get-sanitizedUTF8Input{   
    Param(
        [String]$inputString
    )
    #replace diacritics
    $sb = [Text.Encoding]::ASCII.GetString([Text.Encoding]::GetEncoding("Cyrillic").GetBytes($inputString))
    
    #remove spaces and anything the above function may have missed
    return $sb
}

Get-Team | ForEach-Object { 
    $valueToCheck = get-sanitizedUTF8Input -inputString $_.DisplayName

    if($keepThoseTeams -contains $valueToCheck){
        Write-Host -ForeGroundColor Green "Do not delete this Team " $_.DisplayName $_.GroupId
    }else {
        Write-Host "Deleting Team " $_.DisplayName $_.GroupId
        #Remove-Team -GroupId $_.GroupId
    }
}

Stop-Transcript

Write-Host -ForeGroundColor Green "END OF SCRIPT"

The post Programmatically remove every Teams except some by PowerShell Script appeared first on Collabmania.

❌
❌