studiometa / create-wordpress-project

A generator to kickstart your WordPress project in a few seconds! ⚡
MIT License
6 stars 3 forks source link

Suggestion: Add URLManager #79

Open perruche opened 3 years ago

perruche commented 3 years ago

Add URLManager to implement some basic nice to have rewrite rules

Exemple for this common pattern: Permalinks are set to /%category%/%postname%/ and category_base is set to "blog"

We want the following URL:

Exemple file to achieve this result below

<?php
/**
 * Bootstraps URLs and rewrite rules.
 *
 * @package Studiometa
 */

namespace Studiometa\Managers;

use Studiometa\Managers\ManagerInterface;

/** Class */
class URLManager implements ManagerInterface {
    // phpcs:ignore Generic.Commenting.DocComment.MissingShort
    /**
     * @inheritDoc
     */
    public function run() {
        add_action( 'init', array( $this, 'add_rewrite_rules' ) );
        add_filter( 'pre_post_link', array( $this, 'meta_alter_pre_post_link' ), 10, 2 );
        add_filter( 'rewrite_rules_array', array( $this, 'meta_alter_rewrite_rules_array' ), 10, 1 );
    }

    /**
     * Add rewrite rules
     *
     * @return void
     */
    public function add_rewrite_rules() {
        $category_base = get_option( 'category_base' );

        // Add a rule for home.php, since url schema is /%category%/%postname% when querying $category_base/page/2 WordPress is looking for a category with the name "page".
        add_rewrite_rule(
            '(' . $category_base . '+)/page/?([0-9]{1,})/?$',
            'index.php?pagename=$matches[1]&paged=$matches[2]',
            'top'
        );

        // Add a rule to specify the $category_base prefix for posts permalink.
        add_rewrite_rule(
            $category_base . '/[a-z-]+/?([a-z-]+)/?$',
            'index.php?pagename=$matches[1]',
            'top'
        );
    }

    /**
     * Alter posts permalink structure before it is processed by WP.
     *
     * @param string  $permalink Current permalink.
     * @param WP_Post $post Current post.
     *
     * @return string
     */
    public function meta_alter_pre_post_link( $permalink, $post ) {
        $category_base = get_option( 'category_base' );

        if ( 'post' !== $post->post_type ) {
            return $permalink;
        }

        return '/' . $category_base . '/%category%/%postname%/';
    }

    /**
     * Add custom rewrite rules to global Rewrite Rules array.
     *
     * @param array $rules Current rewrite rules.
     *
     * @return array
     */
    public function meta_alter_rewrite_rules_array( $rules ) {
        $category_base = get_option( 'category_base' );
        $current_url   = trim( esc_url_raw( add_query_arg( array() ) ), '/' );
        $segments      = explode( '/', wp_parse_url( $current_url, PHP_URL_PATH ) );

        if ( empty( end( $segments ) ) ) {
            array_pop( $segments );
        }

        if (
            ( 3 === count( $segments ) && $category_base === $segments[0] ) ||
            ( 4 === count( $segments ) && ICL_LANGUAGE_CODE === $segments[0] && $category_base === $segments[1] ) // Manage i18n.
        ) {
            foreach ( $rules as $key => $rule ) {
                if ( $category_base . '/(.+?)/?$' === $key ) {
                    unset( $rules[ $key ] );
                }
            }
        }

        return $rules;
    }
}
perruche commented 3 years ago

@studiometa/wordpress any opinions on this subject ? Shall i provide more details ?