Skip to content
This repository was archived by the owner on May 26, 2023. It is now read-only.
This repository was archived by the owner on May 26, 2023. It is now read-only.

Add URLManager for nice default for : posts/category/archive/pagination #11

@perruche

Description

@perruche

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:

  • /blog/ for the posts list page
  • /blog/page/%paged% for the posts list page with pagination
  • /blog/%category/ for an archive page
  • /blog/%category/page/%paged%+ for an archive page with pagination
  • /blog/%category%/%postname%/ for a single post

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

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

TODO

  • Find a way to get rid of flush_rewrite_rules(), rewrite_rules_array unset a rule, but does not save it to the database so the postpage is matching another rewrite rule.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions