MISE À JOUR 2022 : Le plugin BUSINESS DIRECTORY est maintenant 100% compatible avec le plugin NavXT Breadcrumb Vous n’avez donc plus besoin de la suite de cet article il vous suffit d’installer le plugin et vous aurez un fil d’Ariane sur votre site.

Le Fil D’Ariane ?

Le fil d’Ariane ou Breadcrumb en anglais est une méthode visuelle de navigation dont la représentation peut varier. Les symboles « > » sont répandus et fonctionnent alors comme des séparateurs et hiérarchisent le site Web. Cela aboutit généralement à un chemin de navigation construit de cette façon : 

Accueil > Catégorie > Position actuelle

En général ce système est placé en haut de la page du site internet et permet en clin d’œil de se situer. Le fil d’Ariane améliore aussi le SEO mais pour cela il doit respecter les standards de schema.org (https://schema.org) pour ne pas provoquer d’erreur dans la Search Console de Google.

Un fil d’Ariane avec Business Directory

Si comme moi vous souhaitez afficher sur votre site un fil d’Ariane ou Breadcrumb compatible avec le plugin Business Directory vous vous êtes sans doute confronté à des difficultés techniques dues au fait que le plugin BD utilise plusieurs sortes de pages différentes pour afficher les pages de son annuaire.

Il y’a déjà la page index de l’annuaire, les pages de recherche, de soumission et d’édition des annonces qui sont en fait des déclinaisons de la page principale. Les pages de catégories et de tags qui utilisent, elles, les « taxonomy » WordPress. Et enfin les pages d’annonces elles-mêmes qui sont en fait basées sur le système de « post » de WordPress.

NavXT Breadcrumb

Tout cela fait qu’adapter un fil d’Ariane standard pour les pages du Plugin Business Directory est particulièrement compliqué. Sur les forums de support du Plugin il est recommandé par l’équipe d’utiliser le plugin NavXT Breadcrumb qu’ils estiment compatible à 100%.

Malheureusement ce n’est pas vraiment le cas comme vous pouvez le constater dans cette conversation que j’ai eue avec l’équipe en charge du plugin le fichier qui sert à l’intégration de NavXT avec BD est obsolète et l’équipe n’a pas vraiment le temps de le mettre à jour car ils travaillent sur des erreurs critiques urgentes.

Le fichier en question se trouve là : 

wp-content/plugins/business-directory-plugin/includes/compatibility/ class-navxt-integration.php

Il pose 3 problèmes majeurs : le lien sur l’index de l’annuaire est absent lors des catégories, sous-catégorie et/ou annonces. De plus l’option « Place the home breadcrumb in the trail. » (Soit ajouter le lien vers la page d’accueil dans la hiérarchisation) ne fonctionne pas. Enfin les hiérarchies créées ne respectent pas les standards de schema.org.

Comment intégrer NavXT dans BD ?

Bien que cette intégration soit peu efficace, j’ai décidé de me servir du travail déjà effectué par l’équipe de developpement du Plugin Business Directory et de modifier la class d’intégration de NavXT pour qu’elle s’adapte au mieux.

Modifier ce fichier n’a pas posé de problème particulier, en utilisant la documentation conséquente du plugin NavXT il était facile de repérer les erreurs de construction du fichier d’intégration.

Voici le nouveau code php commenté.

<?php
/**
 * @since 3.6.5
 */

class WPBDP_NavXT_Integration{

    private $state = array();
    private $doing = '';

// les Hooks d'action de la class sur NavXT Plugin
    function __construct() {
        add_action( 'bcn_before_fill', array( &$this, 'prepare_state' ) );
        add_action( 'bcn_after_fill', array( &$this, 'restore_state' ) );
    }
    
// Détermine sur quelle vue ou page de l'annuaire on se trouve
// En fonction de la vue on met en route différentes fonctions
    function prepare_state( $trail ) {
        if ( $this->doing )
            return;

        global $wpbdp;
        $action = wpbdp_current_view();

        switch ( $action ) {
            case 'show_listing':
                $this->doing = 'listing';
                break;

            case 'show_category':
                $this->doing = 'category';
                break;

            case 'show_tag':
                $this->doing = 'tag';
                break;

            case 'edit_listing':
                $this->doing = 'edit';
                break;

            case 'submit_listing':
                $this->doing = 'submit';
                break;

            case 'search':
                $this->doing = 'search';
                break;

            default:
                $this->doing = '';
        }

        if ( ! $this->doing )
            return;

        if ( method_exists( $this, 'before_' . $this->doing ) )
            call_user_func( array( $this, 'before_' . $this->doing ), $trail );
    }

// sert à afficher en fonction de la page ou de la vue de l'annuaire la suite du fil
    function restore_state( $trail ) {
        if ( ! $this->doing )
            return;

        if ( method_exists( $this, 'after_' . $this->doing ) )
            call_user_func( array( $this, 'after_' . $this->doing ), $trail );

        $this->doing = '';
    }


// affiche dans le fil la page index de l'annuaire
    function main_page_breadcrumb( $trail ) {
        $last = $trail->trail[ count( $trail->trail ) - 1 ];

        if ( method_exists( $last, 'get_types' ) ) {
            $types = $last->get_types();
        } else if ( $last ) {
            $vars = get_object_vars( $last );
            $types = (array) ( isset( $vars['type'] ) ? $vars['type'] : array() );
        } else {
            $types = array();
        }

        if ( in_array( 'home', $types, true ) ) {
            array_pop( $trail->trail );
        }
        
// une premiere modification pour que le lien soit présent sur l'index j'ajoute true
        $trail->add( new bcn_breadcrumb( get_the_title( wpbdp_get_page_id() ),
                                         '',
                                         array('post post-page'),
                                         wpbdp_get_page_link(),
                                         wpbdp_get_page_id(),
                                         true ) );
// si l'option afficher la page d'accueil dans la hierarchie est cochée on l'affiche
// on utilise le template home grâce à $trail->opt['Hhome_template']                                  
        if ( $trail->opt['bhome_display'] ){
   		$site_name = get_option('blogname');
        $trail->add(new bcn_breadcrumb($site_name, $trail->opt['Hhome_template'], array('home'), get_home_url(), null, true)); 
        }
    }

// affiche l'annonce dans la hierrachie
    function before_listing( $trail ) {
        $listing_id = $this->get_current_listing_id();

        if ( ! $listing_id )
            return;

        $this->state['post'] = $GLOBALS['post'];
        $GLOBALS['post'] = get_post( $listing_id );
    }

// determine l'id ou le slug de l'annonce
    private function get_current_listing_id() {
        $id_or_slug = get_query_var( 'listing' );

        if ( ! $id_or_slug && isset( $_GET['listing'] ) ) {
            $id_or_slug = $_GET['listing'];
        }

        if ( ! $id_or_slug ) {
            $id_or_slug = get_query_var( 'id' );
        }

        if ( ! $id_or_slug && isset( $_GET['id'] ) ) {
            $id_or_slug = $_GET['id'];
        }

        if ( ! $id_or_slug ) {
            $id_or_slug = get_query_var( '_' . wpbdp_get_option( 'permalinks-directory-slug' ) );
        }

        if ( $id_or_slug ) {
            $listing_id = wpbdp_get_post_by_id_or_slug( $id_or_slug, 'id', 'id' );
        } else {
            $listing_id = get_queried_object_id();
        }

        return $listing_id;
    }

// affiche l'index de annuaire dans la hierarchie pour les pages annonce
    function after_listing( $trail ) {
        $GLOBALS['post'] = $this->state['post'];
        unset( $this->state['post'] );
   		$this->main_page_breadcrumb( $trail );
     }

// affiche la categorie ou sous categorie
    function before_category( $trail ) {
        $term = _wpbpd_current_category();

        if ( ! $term ) {
            return;
        }

        global $wp_query;

        $this->state['queried'] = $wp_query->get_queried_object();

        $wp_query->is_singular = false;
        $wp_query->queried_object = $term;
    }

// affiche l'index de annuaire dans la hierarchie pour les pages categorie
    function after_category( $trail ) {
        if ( ! $this->state['queried'] ) {
            return;
        }

        global $wp_query;
        $wp_query->queried_object = $this->state['queried'];
        $wp_query->is_singular = true;
        unset( $this->state['queried'] );
        $this->main_page_breadcrumb( $trail );
    }

// affiche les tags
    function before_tag( $trail ) {
        $tag = get_term_by( 'slug', get_query_var( 'tag' ), WPBDP_TAGS_TAX );

        if ( ! $tag )
            return;

        global $wp_query;
        $term = get_term( $category_id, WPBDP_CATEGORY_TAX );
        $this->state['queried'] = $wp_query->get_queried_object();

        $wp_query->is_singular = false;
        $wp_query->queried_object = $tag;
    }

// affiche l'index de annuaire dans la hierarchie pour les pages tag
    function after_tag( $trail ) {
        $this->after_category( $trail );
    }


// affiche la page de soumission d'annonce dans la hierarchie comme page en cours
// grâce à $trail->opt['bcurrent_item_linked'] on sait si on doit afficher le lien
    function before_submit( $trail ) {
		$trail->add( new bcn_breadcrumb( _x( 'Submit Listing', 'navxt', 'WPBDM' ), NULL, array('post post-page current-item'), '', NULL, $trail->opt['bcurrent_item_linked'] ) );
    }

// affiche la page d'édition d'annonce dans la hierarchie comme page en cours
// grâce à $trail->opt['bcurrent_item_linked'] on sait si on doit afficher le lien 
    function before_edit( $trail ) {
        $trail->add( new bcn_breadcrumb( _x( 'Edit Listing', 'navxt', 'WPBDM' ), NULL, array('post post-page current-item'), '', NULL, $trail->opt['bcurrent_item_linked']  ) );
    }


// affiche la page de recherche d'annonce dans la hierarchie comme page en cours
// grâce à $trail->opt['bcurrent_item_linked'] on sait si on doit afficher le lien
    function before_search( $trail) {
        $trail->add( new bcn_breadcrumb( _x( 'Search', 'navxt', 'WPBDM' ), NULL, array('post post-page current-item'), '', NULL, $trail->opt['bcurrent_item_linked'] ) );
    }

} 

Création d’un nouveau Plugin

Mais je ne pouvais pas me contenter de modifier le fichier directement dans le répertoire de BD. A chaque mise à jour du plugin ce fichier serait écrasé et il faudrait le téléverser à chaque fois à la main. Aussi je n’ai pas eu d’autre choix que de créer un nouveau plugin avec une nouvelle class PHP qui serait appelée à la place de la class WPBDP_NavXT_Integration. Et voilà la grande difficulté : comment remplacer l’ancienne class PHP par la nouvelle ?

Il a fallu d’abord comprendre que la class WPBDP_NavXT_Integration est mise en action directement dans sa construction :

    function __construct() {
        add_action( 'bcn_before_fill', array( &$this, 'prepare_state' ) );
        add_action( 'bcn_after_fill', array( &$this, 'restore_state' ) );
    }

add_action est ce qu’on appelle en langage WordPress un hook, c’est un mécanisme permettant aux développeurs d’effectuer une action précise à un moment précis.

Dans notre cas à chaque bcn_before_fill on ajoute la class WPBDP_NavXT_Integration qui met en action la fonction prepare_state puis ensuite à chaque bcn_after_fill on ajoute la class WPBDP_NavXT_Integration qui met action la fonction restore_state.

Il a fallu également comprendre que ces hooks sont mis en action lors du chargement du plugin BD grâce à cette partie de code dans la class principale class-wpbdp.php:

        $this->compat = new WPBDP_Compat();
        $this->rewrite = new WPBDP__Rewrite();


        do_action( 'wpbdp_loaded' );

J’ai trouvé ma solution après plusieurs jours de recherche en supprimant TOUTES les actions du plugin BD sur bcn_before_fill et bcn_after_fill  mais pas à n’importe quel moment : lors de wpbdp_loaded :

// supprime toutes les actions de BD sur le plugin NavXT
add_action( 'wpbdp_loaded', function(){
remove_all_actions('bcn_before_fill');
remove_all_actions('bcn_after_fill');
});

Ensuite il ne reste plus qu’à mettre en action ma nouvelle class WPBDP_NavXT_Integration_glink mais APRES grâce à l’indice de priorité 999 :

// ajoute la nouvelle class au plugin BD APRES la suppression grâce à la priorité 999
add_action('wpbdp_loaded', function(){new WPBDP_NavXT_Integration_glink();}, 999);

Le code du Plugin Complet

Pour résumé voici le code complet de mon nouveau plugin :

<?php
/*
 Plugin Name: wpbdp navxt integration
 Plugin URI: https://www.glink.fr
 Version: 1.0.0
 Author: L. Perderiset and Business Directory Team
 Description: Better integration of NavXT Breadcrumb Plugin with Business Directory Plugin
 Author URI: https://www.glink.fr
*/


// supprime toutes les actions de BD sur le plugin NavXT
add_action( 'wpbdp_loaded', function(){
remove_all_actions('bcn_before_fill');
remove_all_actions('bcn_after_fill');
});

// la nouvelle class
class WPBDP_NavXT_Integration_glink{

    private $state = array();
    private $doing = '';

// les Hooks d'action de la class sur NavXT Plugin
    function __construct() {
        add_action( 'bcn_before_fill', array( &$this, 'prepare_state' ) );
        add_action( 'bcn_after_fill', array( &$this, 'restore_state' ) );
    }
    
// Détermine sur quelle vue ou page de l'annuaire on se trouve
// En fonction de la vue on met en route différentes fonctions
    function prepare_state( $trail ) {
        if ( $this->doing )
            return;

        global $wpbdp;
        $action = wpbdp_current_view();

        switch ( $action ) {
            case 'show_listing':
                $this->doing = 'listing';
                break;

            case 'show_category':
                $this->doing = 'category';
                break;

            case 'show_tag':
                $this->doing = 'tag';
                break;

            case 'edit_listing':
                $this->doing = 'edit';
                break;

            case 'submit_listing':
                $this->doing = 'submit';
                break;

            case 'search':
                $this->doing = 'search';
                break;

            default:
                $this->doing = '';
        }

        if ( ! $this->doing )
            return;

        if ( method_exists( $this, 'before_' . $this->doing ) )
            call_user_func( array( $this, 'before_' . $this->doing ), $trail );
    }

// sert à afficher en fonction de la page ou de la vue de l'annuaire la suite du fil
    function restore_state( $trail ) {
        if ( ! $this->doing )
            return;

        if ( method_exists( $this, 'after_' . $this->doing ) )
            call_user_func( array( $this, 'after_' . $this->doing ), $trail );

        $this->doing = '';
    }


// affiche dans le fil la page index de l'annuaire
    function main_page_breadcrumb( $trail ) {
        $last = $trail->trail[ count( $trail->trail ) - 1 ];

        if ( method_exists( $last, 'get_types' ) ) {
            $types = $last->get_types();
        } else if ( $last ) {
            $vars = get_object_vars( $last );
            $types = (array) ( isset( $vars['type'] ) ? $vars['type'] : array() );
        } else {
            $types = array();
        }

        if ( in_array( 'home', $types, true ) ) {
            array_pop( $trail->trail );
        }
        
// une premiere modification pour que le lien soit présent sur l'index j'ajoute true
        $trail->add( new bcn_breadcrumb( get_the_title( wpbdp_get_page_id() ),
                                         '',
                                         array('post post-page'),
                                         wpbdp_get_page_link(),
                                         wpbdp_get_page_id(),
                                         true ) );
// si l'option afficher la page d'accueil dans la hierarchie est cochée on l'affiche
// on utilise le template home grâce à $trail->opt['Hhome_template']                                  
        if ( $trail->opt['bhome_display'] ){
   		$site_name = get_option('blogname');
        $trail->add(new bcn_breadcrumb($site_name, $trail->opt['Hhome_template'], array('home'), get_home_url(), null, true)); 
        }
    }

// affiche l'annonce dans la hierrachie
    function before_listing( $trail ) {
        $listing_id = $this->get_current_listing_id();

        if ( ! $listing_id )
            return;

        $this->state['post'] = $GLOBALS['post'];
        $GLOBALS['post'] = get_post( $listing_id );
    }

// determine l'id ou le slug de l'annonce
    private function get_current_listing_id() {
        $id_or_slug = get_query_var( 'listing' );

        if ( ! $id_or_slug && isset( $_GET['listing'] ) ) {
            $id_or_slug = $_GET['listing'];
        }

        if ( ! $id_or_slug ) {
            $id_or_slug = get_query_var( 'id' );
        }

        if ( ! $id_or_slug && isset( $_GET['id'] ) ) {
            $id_or_slug = $_GET['id'];
        }

        if ( ! $id_or_slug ) {
            $id_or_slug = get_query_var( '_' . wpbdp_get_option( 'permalinks-directory-slug' ) );
        }

        if ( $id_or_slug ) {
            $listing_id = wpbdp_get_post_by_id_or_slug( $id_or_slug, 'id', 'id' );
        } else {
            $listing_id = get_queried_object_id();
        }

        return $listing_id;
    }

// affiche l'index de annuaire dans la hierarchie pour les pages annonce
    function after_listing( $trail ) {
        $GLOBALS['post'] = $this->state['post'];
        unset( $this->state['post'] );
   		$this->main_page_breadcrumb( $trail );
     }

// affiche la categorie ou sous categorie
    function before_category( $trail ) {
        $term = _wpbpd_current_category();

        if ( ! $term ) {
            return;
        }

        global $wp_query;

        $this->state['queried'] = $wp_query->get_queried_object();

        $wp_query->is_singular = false;
        $wp_query->queried_object = $term;
    }

// affiche l'index de annuaire dans la hierarchie pour les pages categorie
    function after_category( $trail ) {
        if ( ! $this->state['queried'] ) {
            return;
        }

        global $wp_query;
        $wp_query->queried_object = $this->state['queried'];
        $wp_query->is_singular = true;
        unset( $this->state['queried'] );
        $this->main_page_breadcrumb( $trail );
    }

// affiche les tags
    function before_tag( $trail ) {
        $tag = get_term_by( 'slug', get_query_var( 'tag' ), WPBDP_TAGS_TAX );

        if ( ! $tag )
            return;

        global $wp_query;
        $term = get_term( $category_id, WPBDP_CATEGORY_TAX );
        $this->state['queried'] = $wp_query->get_queried_object();

        $wp_query->is_singular = false;
        $wp_query->queried_object = $tag;
    }

// affiche l'index de annuaire dans la hierarchie pour les pages tag
    function after_tag( $trail ) {
        $this->after_category( $trail );
    }


// affiche la page de soumission d'annonce dans la hierarchie comme page en cours
// grâce à $trail->opt['bcurrent_item_linked'] on sait si on doit afficher le lien
    function before_submit( $trail ) {
		$trail->add( new bcn_breadcrumb( _x( 'Submit Listing', 'navxt', 'WPBDM' ), NULL, array('post post-page current-item'), '', NULL, $trail->opt['bcurrent_item_linked'] ) );
    }

// affiche la page d'édition d'annonce dans la hierarchie comme page en cours
// grâce à $trail->opt['bcurrent_item_linked'] on sait si on doit afficher le lien 
    function before_edit( $trail ) {
        $trail->add( new bcn_breadcrumb( _x( 'Edit Listing', 'navxt', 'WPBDM' ), NULL, array('post post-page current-item'), '', NULL, $trail->opt['bcurrent_item_linked']  ) );
    }


// affiche la page de recherche d'annonce dans la hierarchie comme page en cours
// grâce à $trail->opt['bcurrent_item_linked'] on sait si on doit afficher le lien
    function before_search( $trail) {
        $trail->add( new bcn_breadcrumb( _x( 'Search', 'navxt', 'WPBDM' ), NULL, array('post post-page current-item'), '', NULL, $trail->opt['bcurrent_item_linked'] ) );
    }

} 

// ajoute la nouvelle class au plugin BD APRES la suppression grâce à la priorité 999
add_action('wpbdp_loaded', function(){new WPBDP_NavXT_Integration_glink();}, 999);

Soutenez Glink en téléchargeant le plugin dans la boutique

Si vous souhaitez télécharger le dossier zip complet du plugin WPBDP NavXT Integration d’intégration de NavXT Breadcrumb à Business Directory et en même temps soutenir Glink vous pouvez le faire dans la boutique.