web-dev-qa-db-fra.com

Ajouter la colonne "Dernière modification par" à la table de liste de types d'articles personnalisée

Actuellement, j'utilise le plug-in "Admin Columns Pro" pour Wordpress pour modifier certaines des colonnes du backend. Le plugin contient des fonctionnalités permettant d'afficher l'auteur de l'article (ou dans mon cas, le produit) sous forme de colonne.

Cependant, je suis dans une position où j'ai besoin de voir qui est l'éditeur le plus récent du produit. Fondamentalement, ce que nous avons maintenant, c'est qu'un individu crée un brouillon de produit, puis quelqu'un le termine, et j'ai besoin de voir ces deux noms (un créateur et un the_modified_author).

Le plugin contient la documentation pour créer des colonnes personnalisées , et j'ai essayé de la suivre, mais je n'arrive pas à obtenir le passage "the_modified_author" .

Des pensées?

5
itwasluck3

Changer de colonne admin appartient à un plugin , pas à un fichier de thème, car les thèmes ne devraient jamais changer autre chose que la sortie frontale. Vous pouvez obtenir le plugin complet ici:Editeur de produit de plugin Column.

En regardant les documents que vous avez liés, je vois que l'auteur du plug-in a besoin d'une classe enfant qui mélange plusieurs tâches distinctes. Ce n'est pas bon. Nous verrons dans une minute pourquoi.

Par contre, nous ne sommes pas dans le support de plugin de toute façon. Nous sommes dans le Trouvez votre propre entreprise de solutions. Ignorons donc ce plugin et examinons les fonctions principales.

enter image description here

  • Les colonnes en-têtes pour les types d'article sont enregistrées sur le filtre "manage_{$post_type}_posts_columns". Pour une publication, tapez product, ce serait "manage_product_posts_columns".
  • La colonne content peut être imprimée sur l’action "manage_{$post_type}_posts_custom_column".

Ce sont des noms très pauvres: ils ne nous disent pas vraiment ce qui se passe ici.

Les deux points d'ancrage sont appelés lorsque le fichier wp-admin/edit.php est chargé. Nous attendons donc que l'action 'load-edit.php' se déclenche.

Sur la page d'édition, nous examinons l'objet renvoyé par get_current_screen(): si sa propriété id correspond à "edit-$post_type", nous enregistrons nos rappels.

Le filtre "manage_{$post_type}_posts_columns" nous donne un tableau des en-têtes de colonnes existants. Nous ajoutons simplement une entrée et retournons le tableau:

function add_column( Array $columns )
{
    $columns[ 'modified_author' ] = 'Last modified by';

    return $columns;
}

L'action "manage_{$post_type}_posts_custom_column" nous donne le $column_name et le $post_id. Nous comparons le nom de la colonne avec notre nom enregistré antérieur, 'modified_author', car il peut y avoir d’autres colonnes personnalisées et nous ne souhaitons pas les toucher. Si le nom de colonne indiqué est le nôtre, nous utilisons le $post_id pour obtenir l'ID du dernier auteur ayant modifié le message:

$last_id   = get_post_meta( $post_id, '_edit_last', TRUE );
$last_user = get_userdata( $last_id );
print esc_html( $last_user->display_name );

La version courte de notre code pourrait ressembler à ceci:

add_action( 'load-edit.php', function() {

    $post_type   = 'product';
    $col_name    = 'modified_author';

    $screen = get_current_screen();

    if ( ! isset ( $screen->id ) )
        return;

    if ( "edit-$post_type" !== $screen->id )
        return;

    add_filter(
        "manage_{$post_type}_posts_columns",
        function( $posts_columns ) use ( $col_name ) {
            $posts_columns[ $col_name ] = 'Last modified by';

            return $posts_columns;
        }
    );

    add_action(
        "manage_{$post_type}_posts_custom_column",
        function( $column_name, $post_id ) use ( $col_name ) {

            if ( $col_name !== $column_name )
                return;

            $last_id = get_post_meta( $post_id, '_edit_last', TRUE );

            if ( ! $last_id ) {
                print '<i>Unknown</i>';
                return;
            }

            $last_user = get_userdata( $last_id );

            print esc_html( $last_user->display_name );
        },
        10, 2
    );
});

Cela fonctionne, mais ce n’est pas bon.

  • Nous ne pouvons pas réutiliser ce code pour ajouter la même colonne à des publications, des pages ou autre chose.
  • Nous ne pouvons pas tester le code, car tout se passe en un seul appel.
  • Séparation des préoccupations ne se produit pas. Nous mélangeons trop de tâches différentes:
    • Enregistrement des rappels
    • Valider le nom de la colonne
    • Récupérer la valeur de la table meta
    • Imprimer la sortie échappée de la colonne

Améliorons notre code!

L'enregistrement des rappels doit être effectué par un contrôleur. Il n’est pas nécessaire de savoir où nous obtenons nos données et comment nous les imprimons à l’écran de l’utilisateur; transmettez-les donc comme - dépendances abstraites :

class Controller
{
    /**
     * @var Column_Data
     */
    private $data;

    /**
     * @var Column_View
     */
    private $view;

    /**
     * @param Column_Data $data
     * @param Column_View $view
     */
    public function __construct( Column_Data $data, Column_View $view ) {

        $this->data = $data;
        $this->view = $view;
    }

    /**
     * @return void
     */
    public function setup()
    {
        $screen    = get_current_screen();
        $post_type = $this->data->get_post_type();

        if ( ! isset ( $screen->id ) )
            return;

        if ( "edit-$post_type" !== $screen->id )
            return;

        add_filter(
            "manage_{$post_type}_posts_columns",
            [ $this->data, 'add_column' ]
        );

        add_action(
            "manage_{$post_type}_posts_custom_column",
            [ $this->view, 'render_column' ],
            10, 2
        );
    }
}

Column_Data et Column_View sont interfaces , pas des classes concrètes, nous pouvons donc réutiliser ce contrôleur avec différents fournisseurs de données ou gestionnaires de sortie. Construisons ces interfaces.

L’interface pour les données a besoin de méthodes pour

  • ajouter les en-têtes de colonne
  • obtenir le contenu (nom d'affichage de l'auteur par exemple)
  • dire au contrôleur quel type de poste il gère et
  • la vue si elle fonctionne dans la bonne colonne quand on l'appelle
interface Column_Data
{
    /**
     * @param array $columns
     * @return array
     */
    public function add_column( Array $columns );

    /**
     * @param  int    $post_id
     * @return string
     */
    public function get_column_content( $post_id );

    /**
     * @return string
     */
    public function get_post_type();

    /**
     * @param $column_name
     * @return bool
     */
    public function is_valid_column( $column_name );
}

L'objet de sortie/vue n'a besoin que d'une méthode:

interface Column_View
{
    /**
     * @param  string $column_name
     * @param  int    $post_id
     * @return void
     */
    public function render_column( $column_name, $post_id );
}

La vue doit extraire des informations du modèle de données, passez donc une instance au constructeur de la classe concrète:

class Last_Mod_Author_Column_Output implements Column_View
{
    /**
     * @var Column_Data
     */
    private $data;

    /**
     * @param Column_Data $data
     */
    public function __construct( Column_Data $data )
    {
        $this->data = $data;
    }

    /**
     * @param  string $column_name
     * @param  int    $post_id
     * @return void
     */
    public function render_column( $column_name, $post_id )
    {
        if ( ! $this->data->is_valid_column( $column_name ) )
            return;

        $content = $this->data->get_column_content( $post_id );

        if ( '' === $content )
            print '<i>Unknown</i>';
        else
            print esc_html( $content );
    }
}

Le modèle de données doit connaître le type de publication. Nous le transmettons donc au constructeur de la classe Concrete:

class Last_Mod_Author_Column_Data implements Column_Data
{
    /**
     * @var string
     */
    private $post_type;

    /**
     * @var string
     */
    private $column_name = 'modified_author';

    /**
     * @param string $post_type
     */
    public function __construct( $post_type )
    {
        $this->post_type = $post_type;
    }

    /**
     * @param array $columns
     * @return array
     */
    public function add_column( Array $columns )
    {
        $columns[ $this->column_name ] = 'Last modified by';

        return $columns;
    }

    /**
     * @param  int    $post_id
     * @return string
     */
    public function get_column_content( $post_id )
    {
        $last_id = get_post_meta( $post_id, '_edit_last', TRUE );

        if ( ! $last_id ) {
            return '';
        }

        $last_user = get_userdata( $last_id );

        return $last_user->display_name;
    }

    /**
     * @return string
     */
    public function get_post_type()
    {
        return $this->post_type;
    }

    /**
     * @param $column_name
     * @return bool
     */
    public function is_valid_column( $column_name )
    {
        return $this->column_name === $column_name;
    }
}

Et maintenant, nous pouvons utiliser ces classes:

add_action( 'load-edit.php', function() {

    $model      = new Last_Mod_Author_Column_Data( 'product' );
    $view       = new Last_Mod_Author_Column_Output( $model );
    $controller = new Controller( $model, $view );

    $controller->setup();
});

Nous pouvons utiliser le même code pour les pages avec juste un changement minime:

add_action( 'load-edit.php', function() {

    $model      = new Last_Mod_Author_Column_Data( 'page' );
    $view       = new Last_Mod_Author_Column_Output( $model );
    $controller = new Controller( $model, $view );

    $controller->setup();
});

Pourquoi ce code plutôt long est-il meilleur?

Nous pourrions implémenter l'interface de données dans une classe qui extrait la valeur d'une autre table, d'un fichier texte ou d'une API externe, sans modifier le contrôleur ni la vue.

Nous pourrions utiliser une vue qui met le nom de l'auteur en gras ou utilise un repli différent, sans changer le contrôleur ou le modèle de données.

Nous pouvons tester toutes les méthodes publiques de toutes les classes en fournissant des objets factices pour les dépendances (stubs).

Nous évitons le problème de classe de base fragile , car nous n’utilisons pas l’héritage comme celui du plugin que vous avez mentionné.

14
fuxia