Wordpress utveckling: Egna typer av inlägg och permalänkar

Har du, precis som vi, stött på problem med permalänkar och egna posttyper i WordPress? Har du spenderat otaliga timmar och svurit åt de där 404-felmeddelandena på grund av WordPress oförmåga att hantera taxonomiarkiv för egna posttyper? Vi har kanske lösningen för dig.

Vår idé om den optimala permalänkstrukturen för egna posttyper och tillhörande taxonomier är:

domain.se/egen-post-typ = arkiv för egen posttyp
domain.se/egen-post-typ/enskild-post= enskild post för den egna posttypen
domain.se/egen-post-typ/taxonomi/term = arkiv för egen taxonomi

Det här är dock inte hur egna posttyper är tänkta att fungera. En medlem från WordPress supportteam förklarade för oss att egna posttyper, trots namnet, inte alls är poster. Fokus borde snarare ligga på att de är en typ snarare än en post. För att uppnå en permalänkstruktur som vi vill ha, föreslår de att skapa egna posttyper inom egna posttyper på följande sätt:

domain.com/egen-post-typ = arkiv för egen posttyp
domain.com/egen-post-typ /sub-egen-post-typ = arkiv för sub-egen posttyp
domain.com/egen-post-typ /sub-egen-post-typ /enskild-post = enskild post för sub-egen posttyp

Även om vi erkänner att det här är ett sätt att göra det på, är det inte riktigt vad vi vill ha av två anledningar:

  • Vad om vi vill kategorisera posterna med mer än en taxonomi? En post kan aldrig tillhöra mer än en typ åt gången.
  • Hantering av egna posttyper görs idag enbart genom temakodning och/eller tredjeparts plugins. Det finns inga enkla sätt att hantera egna posttyper, åtminstone inte på ett användarvänligt sätt.

Så, istället för att använda egna posttyper inom egna posttyper vill vi kategorisera egna posttyper med taxonomier, precis som vi gör med vanliga inlägg och sidor. Men här stöter vi på problem. Medan registreringen av taxonomier för våra egna posttyper fungerar fint, ger permalänken domain.se/egen-post-typ/taxonomi/term en 404-sida. Återigen sa de till oss; det är inte en bugg, det är en funktion. Låt oss bara säga att vi har hittat ett sätt att förbättra den här funktionen. 🙂

Vad vi gör är att vi registrerar våra egna posttyper och taxonomier på vanligt sätt. Sedan lägger vi till följande kod i vårt temas functions.php:

function custom_init() {
    global $wp_rewrite;
     
    // Declare our permalink structure
    $post_type_structure = '/%post_type%/%taxonomy%/%term%';
 
    // Make wordpress aware of our custom querystring variables
    $wp_rewrite->add_rewrite_tag("%post_type%", '([^/]+)', "post_type=");
    $wp_rewrite->add_rewrite_tag("%taxonomy%", '([^/]+)', "taxonomy=");
    $wp_rewrite->add_rewrite_tag("%term%", '([^/]+)', "term=");
 
    // Only get custom and public post types
    $args=array(
        'public'   => true,
        '_builtin' => false
    );
    $output = 'names'; // names or objects, note names is the default
    $operator = 'and'; // 'and' or 'or'
    $post_types=get_post_types($args,$output,$operator);
    $post_types_string = implode("|", $post_types);
 
    $taxonomies=get_taxonomies($args,$output,$operator); // Note the use of same arguments as with get_post_types()
    $taxonomies_string = implode("|", $taxonomies);
 
    // Now add the rewrite rules, note that the order in which we declare them are important
    add_rewrite_rule('^('.$post_types_string.')/('.$taxonomies_string.')/([^/]*)/?','index.php?post_type=$matches[1]&$matches[2]=$matches[3]','top');
    add_rewrite_rule('^('.$post_types_string.')/([^/]*)/?','index.php?post_type=$matches[1]&name=$matches[2]','top');
    add_rewrite_rule('^('.$post_types_string.')/?','index.php?post_type=$matches[1]','top');
 
    // Finally, flush and recreate the rewrite rules
    flush_rewrite_rules();
}
 
function post_type_permalink($permalink, $post_id, $leavename){
    $post = get_post($post_id);
 
    // An array of our custom query variables
    $rewritecode = array(
        '%post_type%',
        '/%taxonomy%',
        '/%term%',
        $leavename? '' : '%postname%',
        $leavename? '' : '%pagename%',
    );
 
    // Avoid trying to rewrite permalinks when not applicable
    if ('' != $permalink && !in_array($post->post_status, array('draft', 'pending', 'auto-draft'))) {
        // Fetch the post type
        $post_type = get_post_type( $post->ID );
 
        // Setting these isn't necessary if the taxonomy has rewrite = true,
        // otherwise you need to fetch the relevant data from the current post
        $taxonomy = "";
        $term = "";
 
        // Now we do the permalink rewrite
        $rewritereplace = array(
            $post_type,
            $taxonomy,
            $term,
            $post->post_name,
            $post->post_name,
        );
        $permalink = str_replace($rewritecode, $rewritereplace, $permalink);
    }
 
    return $permalink;
}
 
// Create custom rewrite rules
add_action('init', 'custom_init');
 
// Translate the custom post type permalink tags
add_filter('post_type_link', 'post_type_permalink', 10, 3);

De ovanstående kodraderna är faktiskt allt som behövs. Vad den gör är att definiera /%post_type%/%taxonomy%/%term% som den nya permalänkstrukturen och skapar omskrivningsregler för permalänkarna med högsta prioritet. Omskrivningsreglerna skapas genom att helt enkelt kontrollera efter möjliga egna posttyper och taxonomier i databasen, vilket gör att vi kan skriva mycket enkla villkor i klartext med minimal overhead.

Det bör dock noteras att vi ännu inte har testat hur mycket overhead detta faktiskt orsakar. Därför delar vi denna lösning med den vanliga ansvarsfriskrivningen; använd på egen risk.

Loading