it-swarm.com.de

Hinzufügen der Spalte "Zuletzt bearbeitet von" zur benutzerdefinierten Listentabelle für Beitragstypen

Derzeit verwende ich das Plugin "Admin Columns Pro" für Wordpress, um einige der Spalten im Backend zu ändern. Das Plugin enthält Funktionen zum Anzeigen des Autors des Posts (oder in meinem Fall des Produkts) als Spalte.

Ich bin jedoch in einer Position, in der ich sehen muss, wer der neueste Herausgeber des Produkts ist. Grundsätzlich haben wir jetzt eine Person, die einen Produktentwurf erstellt, und dann wird er von jemandem fertiggestellt. Ich muss beide Namen sehen (einen Ersteller und einen der_modifizierten_Autor).

Das Plugin enthält Dokumentation zum Erstellen von benutzerdefinierten Spalten , und ich habe versucht, ihm zu folgen, aber ich kann scheinbar nicht "the_modified_author" durchlassen.

Irgendwelche Gedanken?

5
itwasluck3

Das Ändern der Admin-Spalten gehört zu einem Plugin , nicht zu einer Themendatei, da Themen niemals etwas anderes als die Frontend-Ausgabe ändern sollten. Das komplette Plugin erhalten Sie hier:Plugin Product Editor Column.

Wenn ich mir die Dokumente ansehe, mit denen Sie verlinkt sind, sehe ich, dass der Plugin-Autor eine untergeordnete Klasse benötigt, die mehrere separate Aufgaben mischt. Das ist nicht gut. Wir werden gleich sehen, warum.

Auf der anderen Seite sind wir ohnehin nicht im Plugin-Support-Geschäft. Wir sind im Finden Sie Ihr eigenes Lösungsgeschäft. Ignorieren wir also dieses Plugin und schauen uns die Kernfunktionen an.

enter image description here

  • Spalte Überschriften für Beitragstypen sind im Filter "manage_{$post_type}_posts_columns" registriert. Für einen Beitragstyp product wäre dies "manage_product_posts_columns".
  • Die Spalte content kann auf die Aktion "manage_{$post_type}_posts_custom_column" gedruckt werden.

Dies sind sehr schlechte Namen: Sie sagen uns nicht wirklich, was hier passiert.

Beide Hooks werden aufgerufen, wenn die Datei wp-admin/edit.php geladen wird, also warten wir, bis die Aktion 'load-edit.php' ausgelöst wird.

Auf der Bearbeitungsseite sehen wir uns das von get_current_screen() zurückgegebene Objekt an: Wenn die Eigenschaft id mit "edit-$post_type" übereinstimmt, registrieren wir unsere Rückrufe.

Der "manage_{$post_type}_posts_columns"-Filter gibt uns ein Array der vorhandenen Spaltenüberschriften. Wir fügen einfach einen Eintrag hinzu und geben das Array zurück:

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

    return $columns;
}

Die Aktion "manage_{$post_type}_posts_custom_column" gibt uns den $column_name und den $post_id. Wir vergleichen den Spaltennamen mit unserem früheren registrierten Namen 'modified_author', da möglicherweise andere benutzerdefinierte Spalten vorhanden sind und wir sie nicht berühren möchten. Wenn der angegebene Spaltenname unserer ist, verwenden wir den $post_id, um die ID des letzten Autors zu erhalten, der den Beitrag geändert hat:

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

Die Kurzversion unseres Codes könnte folgendermaßen aussehen:

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
    );
});

Das funktioniert, aber es ist nicht gut.

  • Wir können diesen Code nicht wiederverwenden um die gleiche Spalte zu Posts oder Seiten oder etwas anderem hinzuzufügen.
  • Wir können den Code nicht testen , da alles in einem Aufruf geschieht.
  • Trennung von Bedenken passiert nicht. Wir mischen zu viele verschiedene Aufgaben:
    • Rückrufe registrieren
    • Überprüfen des Spaltennamens
    • Abrufen des Werts aus der Post-Meta-Tabelle
    • Drucken der maskierten Ausgabe der Spalte

Lasst uns unseren Code verbessern!

Das Registrieren der Rückrufe sollte durch einen Controller erfolgen. Es muss nicht bekannt sein, woher wir unsere Daten beziehen und wie wir sie auf dem Bildschirm des Benutzers drucken. Übergeben Sie diese also als abstrakte Abhängigkeiten :

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 und Column_View sind Schnittstellen , keine konkreten Klassen, daher können wir diesen Controller mit verschiedenen Datenprovidern oder Ausgabehandlern wiederverwenden. Erstellen wir diese Schnittstellen.

Die Schnittstelle für die Daten benötigt Methoden, um

  • fügen Sie die Spaltenüberschriften hinzu
  • inhalt abrufen (z. B. Anzeigename des Autors)
  • sagen Sie dem Controller, welchen Post-Typ er handhabt und
  • die Ansicht, ob es in der richtigen Spalte arbeitet, wenn es aufgerufen wird
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 );
}

Das Ausgabe-/Ansichtsobjekt benötigt nur eine Methode:

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

Die Ansicht muss einige Informationen aus dem Datenmodell abrufen. Übergeben Sie daher eine Instanz an den Konstruktor der konkreten Klasse:

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 );
    }
}

Das Datenmodell muss den Post-Typ kennen, daher übergeben wir das an den Konstruktor der konkreten Klasse:

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;
    }
}

Und jetzt können wir diese Klassen verwenden:

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();
});

Wir können den gleichen Code für Seiten mit nur einer kleinen Änderung verwenden:

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();
});

Warum ist dieser ziemlich lange Code besser?

Wir könnten die Datenschnittstelle in einer Klasse implementieren, die den Wert aus einer anderen Tabelle, einer Textdatei oder einer externen API abruft - ohne Änderungen an der Steuerung oder der Ansicht.

Wir könnten eine Ansicht verwenden, die den Namen des Autors fett macht oder einen anderen Fallback verwendet - ohne den Controller oder das Datenmodell zu ändern.

Wir können alle öffentlichen Methoden aller Klassen testen, indem wir Dummy-Objekte für die Abhängigkeiten (Stubs) bereitstellen.

Wir vermeiden das Problem der fragilen Basisklasse , da wir keine Vererbung wie den Autor des von Ihnen erwähnten Plugins verwenden.

14
fuxia