Skip to content

Custom Post Types

Horizon har stöd för klass-baserade custom post types. Detta innebär att man kan definiera post types och ha ett gränsnitt för att arbeta med dem på ett ställe istället för att sprida ut det på många ställen.

Skapa en custom post type

För att skapa en custom post type kan man köra följande Dusk kommando

shell
> wp dusk make:cpt <namn>

<namn> är namnet det önskade namnet på post typen. Namnet bör vara i engelskt singular och börja med stor bokstav. Det är inte ett krav men är starkt rekommenderat.

Exempel

Om man vill skapa en post type för kontaktpersoner skulle man rimligtvis kalla klassen Contact, då ett inlägg är en kontaktperson.

shell
> wp dusk make:cpt Contact

Detta exempel kommer användas i följande dokumentation.

Struktur

En custom post type ärver från klassen Nobox\Dusk\PostTypes\Post. Denna klass är en wrapper kring WP_Post. Man kommer åt det underliggande objektet med hjälp av $post fältet.

I metoden register sätter man upp post typen som en normal custom post type. Det går även bra att registrera tillhörande grejer här, som taxonomier och kategorier.

TIP

Man behöver inte anropa flush_rewrite_rules() i den här metoden, det kommer köras när samtliga post types är registrerade

I metoden fields kan man definiera ACF fält som tillhör post typen.

När man skapar en post type med hjälp av Dusk kommandot får man en liten boilerplate för att snabbare komma igång med register och fields metoderna.

Användning

Det finns flera sätt att arbeta med klassbaserade post types.

Ifall man är inuti en loop eller på en single sida för en post type kan man använda den statiska metoden get för att skapa en instans baserat på det nuvarande objektet.

php
$contact = Contact::get();

Ifall man vill hämta ett specifikt objekt kan man använda antingen ID:t genom get eller slug med getByName.

php
$contact = Contact::get(10);
// eller
$contact = Contact::getByName('benjamin');

Vill man hämta samtliga post type objekt kan man använda den statiska metoden all för att få en Collection av post type objekt.

php
$contacts = Contact::all();

Man kan också använda all metoden för att skicka med WP_Query parametrar och göra ett mer specifikt urval.

php
$contacts = Contact::all([
    's' => 'Benjamin',
]);

Funktionalitet

Enklare åtkomst till data

Genom att definiera ACF fält som klassfält underlättar man åtkomst till dem.

Som exempel kanske vi har lagt till telefonnummer för kontaktpersoner.

php
$fields->addText('phone');

Om man lägger till följande kod i klassen:

php
// app/PostTypes/Contact.php

class Contact extends Post
{
    // ...

    public string $phone = ''; 

    public function __construct(?WP_Post $post = null)
    {
        parent::__construct($post);

        if ($post !== null) {
            // Setup custom properties here.

            $fields = get_fields($post->ID);

            $this->phone = $fields['phone'] ?? ''; 
        }
    }
}

Kan man därefter hämta telefonnumret på följande vis:

php
echo $contact->phone;

Åtkomlig Post Type

Klassbaserade post types definierar sitt namn genom konstanten POST_TYPE. Det ger oss ett enkelt sätt att referera till en post type utan att behöva skriva in namnet.

Detta är användbart när man ska ex. sätta upp relationship fält i ACF.

php
$fields->addRelationship('contact', [
    'post_type' => Contact::POST_TYPE,
])

Ifall man skulle behöva byta namnet (dvs. det som lagras i wp_posts kolumnen post_type) på en post type behöver man bara ändra i klassen (utöver andra ställen, ex. databasen).

Ifall man skrivit in post type namnet manuellt måste man ändra det på samtliga andra ställen, genom att använda konstanten behöver man inte ändra något i koden.

Samling av relaterad funktionalitet

En fördel med klassbaserade post types är att man kan samla relaterad funktionalitet på ett och samma ställe.

Ett exempel på relaterad funktionalitet är metoden permalink som kommer med som standard. Som namnet antyder returnerar den objektets permalänk.

php
echo $contact->permalink();

Andra exempel på metoder man skulle kunna bygga in är att hämta relaterade objekt, ge resultat av uträkningar som berör objektet eller att skicka notiser om objektet till anhöriga personer.

Adminkolumner

INFO

Denna funktionalitet kräver Dusk 2.3+

Om man vill ändra på kolumnerna för en post type använder man vissa hooks för att modifiera vilka kolumner som ska visas samt vad som ska skrivas ut per rad.

Istället för att manuellt registrera hooks kan man använda metoder i post type klassen.

Exempel

I detta exempel ska vi lägga till en "Roll" kolumn för kontaktspersonens roll.

Fältdata

Först registrerar vi fältet.

php
public static function fields()
{
    // ...

    $fields->addText('role');

    // ...
}

Kolumndefinition

Sen registrerar vi vår egna kolumn i metoden columns. Denna metod ska returnera en array som innehåller varje kolumn. För att definiera en kolumn gör man en array som innehåller name och label.

php
protected static function columns(): array
{
    return [
        [
            'name' => 'role',
            'label' => __('Roll'),
        ],
    ];
}

Kolumner

För att bestämma vad vilka kolumner som ska skrivas ut använder vi metoden adminColumns. Denna metod körs genom filtret manage_{$post_type}_posts_columns.

Vi vill att kolumnerna titel och roll ska skrivas ut, med ändringen att titeln på ett kontaktspersonsinlägg är namnet på personen.

För att hämta en kolumn som definierats i columns metoden används metoden column. Den metoden returnerar en array, så vi behöver göra en spread för att det ska skrivas ut ordentligt i kolumnarrayen.

php
public static function adminColumns(array $columns): array
{
    return [
        'cb' => $columns['cb'],
        'title' => __('Namn'),
        ...static::column('role'),
    ];
}

Kolumndata

Det har nu skapats en tom kolumn som heter "Roll". För att fylla kolumnen med data implementerar vi metoden adminColumnData.

Denna metod körs genom filtret manage_{$post_type}_posts_custom_column.

Denna metod kommer köras för varje egen kolumn, ovan har vi definierat två kolumner som redan finns (cb och title), så den kommer köras en gång för role kolumnen.

Datan för kolumnen ska skrivas ut (ex. echo), inte returneras.

Notera

Vi har inte tillgång till objektets resurser här, så använd $post_id parametern för att hämta värden.

php
public static function adminColumnData(string $column_name, int $post_id): void
{
    if ($column_name === 'role') {
        the_field('role', $post_id);
    }
}

Nu kommer vi ha tre kolumner i tabellen, första kolumnen är kryssrutan för massoperationer, sedan "Namn" (som är omdöpt från "Titel") och till sist "Roll".

Sortering

Om man vill kunna sortera på sina egna kolumner kan man implementera metoden adminSortableColumns, som returnerar en array av kolumner som är sorteringsbara. I denna metod kan man använda sig av columnSortable för att hämta en kolumn från columns i det format som förväntas.

Denna metod körs av filtret manage_{$this->screen->id}_sortable_columns.

php
public static function adminSortableColumns(array $columns): array
{
    return [
        'title' => $columns['title'],
        ...static::columnSortable('role'),
    ];
}

Samtliga kolumner som definieras i columns metoden kommer kunna sorteras utan extra query filtreringar.

Primärkolumn

Om man vill ändra vilken kolumn som är den primära kolumnen man kan implementera metoden adminPrimaryColumn. Denna metod returnerar namnet på den kolumn som ska vara primär. Som standard är det title.

Denna metod körs av filtret list_table_primary_column.

Om man skulle vilja att "Roll" kolumnen ska vara primärkolumnen kan man implementera det på följande vis.

php
public static function adminPrimaryColumn(string $default, string $context): string
{
    return 'role';
}

Hookprioritet

Standardprioritet på samtliga hooks är 10. Ifall man vill ändra prioritet kan man lägga till en eller flera av dessa i klassen.

php
/**
 * Priority for the `manage_{$post_type}_posts_columns` filter.
 *
 * Default value is `10`.
 */
protected static int $adminColumnsPriority = 10;

/**
 * Priority for the `manage_{$post_type}_posts_custom_column` filter.
 *
 * Default value is `10`.
 */
protected static int $adminColumnDataPriority = 10;

/**
 * Priority for the `manage_edit-{$post_type}_sortable_columns` filter.
 *
 * Default value is `10`.
 */
protected static int $adminSortableColumnsPriority = 10;

/**
 * Priority for the `list_table_primary_column` filter.
 *
 * Default value is `10`.
 */
protected static int $adminPrimaryColumnPriority = 10;