From 3e2bdb622a4faa47b2555f9d083e6ddca9570438 Mon Sep 17 00:00:00 2001 From: Shady Sharaf Date: Tue, 20 Sep 2016 17:30:57 +0200 Subject: [PATCH 01/17] Allow filtering the selected term of post terms for a taxonomy replacement, imitating core --- wp-permastructure.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index 30e891e..83b336f 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -294,8 +294,18 @@ public function parse_permalinks( $post_link, WP_Post $post, $leavename, $sample $terms = get_the_terms( $post->ID, $taxonomy ); if ( $terms ) { usort($terms, '_usort_terms_by_ID'); // order by ID - $term = $terms[0]->slug; - if ( $taxonomy_object->hierarchical && $parent = $terms[0]->parent ) + + /** + * Filter the term that gets used in the `$tax` permalink token. + * + * @param WP_Term $term The `$tax` term to use in the permalink. + * @param array $terms Array of all `$tax` terms associated with the post. + * @param WP_Post $post The post in question. + */ + $term_object = apply_filters( "post_link_{$taxonomy}", reset( $terms ), $terms, $post ); + + $term = $term_object->slug; + if ( $taxonomy_object->hierarchical && $parent = $term_object->parent ) $term = get_term_parents($parent, $taxonomy, false, '/', true) . $term; } // show default category in permalinks, without From 5ddc629d9852de5e168cd9e92f4ad607bfaed447 Mon Sep 17 00:00:00 2001 From: Max Maton Date: Mon, 22 May 2017 14:25:11 +0100 Subject: [PATCH 02/17] _usort_terms_by_ID is deprecated in WP 4.7 --- wp-permastructure.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index 83b336f..79151dc 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -293,7 +293,11 @@ public function parse_permalinks( $post_link, WP_Post $post, $leavename, $sample if ( strpos($permalink, '%'. $taxonomy .'%') !== false ) { $terms = get_the_terms( $post->ID, $taxonomy ); if ( $terms ) { - usort($terms, '_usort_terms_by_ID'); // order by ID + if( function_exists( 'wp_list_sort' ) ) { + $terms = wp_list_sort( $terms, 'term_id', 'ASC' ); // order by term_id ASC + } else { + usort( $terms, '_usort_terms_by_ID' ); // order by term_id ASC + } /** * Filter the term that gets used in the `$tax` permalink token. From d999de2dbfd4303523238c4fceb2fa5e40ad80aa Mon Sep 17 00:00:00 2001 From: Max Maton Date: Mon, 22 May 2017 14:45:11 +0100 Subject: [PATCH 03/17] Updated indentation --- wp-permastructure.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index ac7f3c7..daabb9a 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -297,11 +297,11 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false if ( strpos($permalink, '%'. $taxonomy .'%') !== false ) { $terms = get_the_terms( $post->ID, $taxonomy ); if ( $terms ) { - if( function_exists( 'wp_list_sort' ) ) { - $terms = wp_list_sort( $terms, 'term_id', 'ASC' ); // order by term_id ASC - } else { - usort( $terms, '_usort_terms_by_ID' ); // order by term_id ASC - } + if( function_exists( 'wp_list_sort' ) ) { + $terms = wp_list_sort( $terms, 'term_id', 'ASC' ); // order by term_id ASC + } else { + usort( $terms, '_usort_terms_by_ID' ); // order by term_id ASC + } /** * Filter the term that gets used in the `$tax` permalink token. From 4a5ed59c4f9b90c240fd42d06dd4e282139e9d15 Mon Sep 17 00:00:00 2001 From: Robert O'Rourke Date: Wed, 24 May 2017 15:16:16 +0100 Subject: [PATCH 04/17] code style --- wp-permastructure.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index daabb9a..038dd0c 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -242,10 +242,10 @@ public function add_permastructs( $rules ) { * @return string The parsed permalink */ public function parse_permalinks( $post_link, $post, $leavename, $sample = false ) { - // Yoast Sitemap plug-in doesn't pass a WP_Post object causing a fatal, so we'll check for it and return. - if ( !is_a( $post, 'WP_Post' ) ) { - return $post_link; - } + // Yoast Sitemap plug-in doesn't pass a WP_Post object causing a fatal, so we'll check for it and return. + if ( !is_a( $post, 'WP_Post' ) ) { + return $post_link; + } // Make a stupid request and we'll do nothing. if ( !post_type_exists( $post->post_type ) ) From 5f9268a94026a17e16008d5c111ed4b2da489d3f Mon Sep 17 00:00:00 2001 From: Robert O'Rourke Date: Fri, 26 May 2017 09:03:09 +0100 Subject: [PATCH 05/17] better checking to mke sure we have a WP_Post object --- wp-permastructure.php | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index 038dd0c..70ece4c 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -234,16 +234,19 @@ public function add_permastructs( $rules ) { * Generic version of standard permalink parsing function. Adds support for * custom taxonomies as well as the standard %author% etc... * - * @param string $post_link The post URL - * @param WP_Post $post The post object - * @param bool $leavename Passed to pre_post_link filter - * @param bool $sample Used in admin if generating an example permalink + * @param string $post_link The post URL + * @param WP_Post|object|int|null $post The post object + * @param bool $leavename Passed to pre_post_link filter + * @param bool $sample Used in admin if generating an example permalink * - * @return string The parsed permalink + * @return string The parsed permalink */ public function parse_permalinks( $post_link, $post, $leavename, $sample = false ) { - // Yoast Sitemap plug-in doesn't pass a WP_Post object causing a fatal, so we'll check for it and return. - if ( !is_a( $post, 'WP_Post' ) ) { + // Ensure WP_Post object. Some plugins pass arbitrary objects or other data. + $post = get_post( $post ); + + // Only bail if the above get_post() didn't work. + if ( ! $post instanceof WP_Post ) { return $post_link; } From 76508717db156d7c1b7f9ed5b0af9acb5fb09e79 Mon Sep 17 00:00:00 2001 From: Robert O'Rourke Date: Fri, 26 May 2017 09:07:52 +0100 Subject: [PATCH 06/17] code style --- wp-permastructure.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index 70ece4c..1ed5549 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -300,10 +300,10 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false if ( strpos($permalink, '%'. $taxonomy .'%') !== false ) { $terms = get_the_terms( $post->ID, $taxonomy ); if ( $terms ) { - if( function_exists( 'wp_list_sort' ) ) { - $terms = wp_list_sort( $terms, 'term_id', 'ASC' ); // order by term_id ASC + if ( function_exists( 'wp_list_sort' ) ) { + $terms = wp_list_sort( $terms, 'term_id', 'ASC' ); // order by term_id ASC } else { - usort( $terms, '_usort_terms_by_ID' ); // order by term_id ASC + usort( $terms, '_usort_terms_by_ID' ); // order by term_id ASC } /** From 5f3a1f107802cdfe98e9c1253e28e206a8cd98ad Mon Sep 17 00:00:00 2001 From: Robert O'Rourke Date: Fri, 26 May 2017 09:10:18 +0100 Subject: [PATCH 07/17] further code style --- wp-permastructure.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index 1ed5549..6c0a737 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -316,8 +316,9 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false $term_object = apply_filters( "post_link_{$taxonomy}", reset( $terms ), $terms, $post ); $term = $term_object->slug; - if ( $taxonomy_object->hierarchical && $parent = $term_object->parent ) - $term = get_term_parents($parent, $taxonomy, false, '/', true) . $term; + if ( $taxonomy_object->hierarchical && $parent = $term_object->parent ) { + $term = get_term_parents( $parent, $taxonomy, false, '/', true ) . $term; + } } // show default category in permalinks, without // having to assign it explicitly @@ -331,14 +332,13 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false } $author = ''; - if ( strpos($permalink, '%author%') !== false ) { - $authordata = get_userdata($post->post_author); + if ( strpos( $permalink, '%author%' ) !== false ) { + $authordata = get_userdata( $post->post_author ); $author = $authordata->user_nicename; } - $date = explode(" ",date('Y m d H i s', $unixtime)); - $rewritereplace = - array( + $date = explode( " ", date( 'Y m d H i s', $unixtime ) ); + $rewritereplace = array( $date[0], $date[1], $date[2], @@ -352,10 +352,10 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false ); foreach( $taxonomies as $taxonomy ) $rewritereplace[] = $replace_terms[ $taxonomy ]; - $permalink = home_url( str_replace($rewritecode, $rewritereplace, $permalink) ); - $permalink = user_trailingslashit($permalink, 'single'); + $permalink = home_url( str_replace( $rewritecode, $rewritereplace, $permalink ) ); + $permalink = user_trailingslashit( $permalink, 'single' ); } else { // if they're not using the fancy permalink option - $permalink = home_url('?p=' . $post->ID); + $permalink = home_url( '?p=' . $post->ID ); } return $permalink; From d4065e24357b63fd270f6999bac367cc44638321 Mon Sep 17 00:00:00 2001 From: Robert O'Rourke Date: Tue, 23 Jan 2024 16:01:37 +0000 Subject: [PATCH 08/17] Update to 1.4.4 --- wp-permastructure.php | 783 ++++++++++++++++++++++-------------------- 1 file changed, 411 insertions(+), 372 deletions(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index 6c0a737..2305959 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -3,7 +3,7 @@ Plugin Name: WP Permastructure Plugin URI: https://github.com/interconnectit/wp-permastructure Description: Adds the ability to define permalink structures for any custom post type using rewrite tags. -Version: 1.4.3 +Version: 1.4.4 Author: Robert O'Rourke Author URI: http://interconnectit.com License: GPLv2 or later @@ -19,9 +19,9 @@ * eg: * * register_post_type( 'my_type', array( - * ... - * 'rewrite' => array( 'permastruct' => '/%custom_taxonomy%/%author%/%postname%/' ), - * ... + * ... + * 'rewrite' => array( 'permastruct' => '/%custom_taxonomy%/%author%/%postname%/' ), + * ... * ) ); * * Alternatively you can set the permalink structure from the permalinks settings page @@ -38,368 +38,404 @@ * 1.0: Initial import */ -if ( ! class_exists( 'wp_permastructure' ) ) { +if ( !class_exists( 'wp_permastructure' ) ) { -add_action( 'init', array( 'wp_permastructure', 'instance' ), 0 ); + add_action( 'init', array( 'wp_permastructure', 'instance' ), 0 ); -class wp_permastructure { + class wp_permastructure { - public $settings_section = 'wp_permastructure'; + public $settings_section = 'wp_permastructure'; - /** - * @var protect endpoints from being vaped if a category/tag slug is set - */ - protected $endpoints; + /** + * @var protect endpoints from being vaped if a category/tag slug is set + */ + protected $endpoints; - /** - * Reusable object instance. - * - * @type object - */ - protected static $instance = null; + /** + * Reusable object instance. + * + * @type object + */ + protected static $instance = null; - /** - * Creates a new instance. Called on 'init'. - * May be used to access class methods from outside. - * - * @see __construct() - * @return void - */ - public static function instance() { - null === self :: $instance AND self :: $instance = new self; - return self :: $instance; - } + /** + * Creates a new instance. Called on 'init'. + * May be used to access class methods from outside. + * + * @see __construct() + * @return void + */ + public static function instance() { + null === self:: $instance AND self:: $instance = new self; + return self:: $instance; + } - public function __construct() { - // Late init to protect endpoints - add_action( 'init', array( $this, 'late_init' ), 999 ); + public function __construct() { - // Settings fields on permalinks page - add_action( 'admin_init', array( $this, 'admin_init' ) ); + // Late init to protect endpoints + add_action( 'init', array( $this, 'late_init' ), 999 ); - // add our new peramstructs to the rewrite rules - add_filter( 'post_rewrite_rules', array( $this, 'add_permastructs' ) ); + // Settings fields on permalinks page + add_action( 'admin_init', array( $this, 'admin_init' ) ); - // parse the generated links - enable custom taxonomies for built in post links - add_filter( 'post_link', array( $this, 'parse_permalinks' ), 10, 3 ); - add_filter( 'post_type_link', array( $this, 'parse_permalinks' ), 10, 4 ); + // add our new peramstructs to the rewrite rules + add_filter( 'post_rewrite_rules', array( $this, 'add_permastructs' ) ); - // that's it! + // parse the generated links - enable custom taxonomies for built in post links + add_filter( 'post_link', array( $this, 'parse_permalinks' ), 10, 3 ); + add_filter( 'post_type_link', array( $this, 'parse_permalinks' ), 10, 4 ); - } + // that's it! + } - public function late_init() { - global $wp_rewrite; - $this->endpoints = $wp_rewrite->endpoints; - } + public function late_init() { + global $wp_rewrite; + $this->endpoints = $wp_rewrite->endpoints; + } - /** - * Add the settings UI - */ - public function admin_init() { - add_settings_section( - $this->settings_section, - __( 'Custom post type permalink settings' ), - array( $this, 'settings_section' ), - 'permalink' - ); + /** + * Add the settings UI + */ + public function admin_init() { - foreach( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects' ) as $type ) { - $id = $type->name . '_permalink_structure'; + add_settings_section( + $this->settings_section, + __( 'Custom post type permalink settings' ), + array( $this, 'settings_section' ), + 'permalink' + ); - register_setting( 'permalink', $id, array( $this, 'sanitize_permalink' ) ); - add_settings_field( - $id, - __( $type->label . ' permalink structure' ), - array( $this, 'permalink_field' ), - 'permalink', - $this->settings_section, - array( 'id' => $id ) - ); - } + foreach ( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects' ) as $type ) { + $id = $type->name . '_permalink_structure'; - } + register_setting( 'permalink', $id, array( $this, 'sanitize_permalink' ) ); + add_settings_field( + $id, + __( $type->label . ' permalink structure' ), + array( $this, 'permalink_field' ), + 'permalink', + $this->settings_section, + array( 'id' => $id ) + ); + } + } - public function settings_section() { - } + public function settings_section() { + } - public function permalink_field( $args ) { - echo ''; - } - - /** - * Runs a simple sanitisation of the custom post type permalink structures - * and adds an error if no post ID or post name present - * - * @param string $permalink The permalink structure - * - * @return string Sanitised permalink structure - */ - public function sanitize_permalink( $permalink ) { - if ( ! empty( $permalink ) && ! preg_match( '/%(post_id|postname)%/', $permalink ) ) - add_settings_error( 'permalink_structure', 10, __( 'Permalink structures must contain at least the %post_id% or %postname%.' ) ); - - $filtered = wp_check_invalid_utf8( $permalink ); - - if ( strpos($filtered, '<') !== false ) { - $filtered = wp_pre_kses_less_than( $filtered ); - // This will strip extra whitespace for us. - $filtered = wp_strip_all_tags( $filtered, true ); - } else { - $filtered = trim( preg_replace('/[\r\n\t ]+/', ' ', $filtered) ); - } - - return preg_replace( '/[^a-zA-Z0-9\/\%_-]*/', '', $filtered ); - } - - - /** - * This function removes unnecessary rules and adds in the new rules - * - * @param array $rules The rewrite rules array for post permalinks - * - * @return array The modified rules array - */ - public function add_permastructs( $rules ) { - global $wp_rewrite; - - // restore endpoints - if ( empty( $wp_rewrite->endpoints ) && ! empty( $this->endpoints ) ) - $wp_rewrite->endpoints = $this->endpoints; - - $permastruct = $wp_rewrite->permalink_structure; - $permastructs = array( $permastruct => array( 'post' ) ); - - // force page rewrite to bottom - $wp_rewrite->use_verbose_page_rules = false; - - // get permastructs foreach custom post type and group any that use the same struct - foreach( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects' ) as $type ) { - // add/override the custom permalink structure if set in options - $post_type_permastruct = get_option( $type->name . '_permalink_structure' ); - if ( $post_type_permastruct && ! empty( $post_type_permastruct ) ) { - if ( ! is_array( $type->rewrite ) ) - $type->rewrite = array(); - $type->rewrite[ 'permastruct' ] = $post_type_permastruct; - } - - // check we have a custom permalink structure - if ( ! is_array( $type->rewrite ) || ! isset( $type->rewrite[ 'permastruct' ] ) ) - continue; - - // remove default struct rules - add_filter( $type->name . '_rewrite_rules', create_function( '$rules', 'return array();' ), 11 ); - - if ( ! isset( $permastructs[ $type->rewrite[ 'permastruct' ] ] ) ) - $permastructs[ $type->rewrite[ 'permastruct' ] ] = array(); - - $permastructs[ $type->rewrite[ 'permastruct' ] ][] = $type->name; - } - - $rules = array(); - - // add our permastructs scoped to the post types - overwriting any keys that already exist - foreach( $permastructs as $struct => $post_types ) { - - // if a struct is %postname% only then we need page rules first - if not found wp tries again with later rules - if ( preg_match( '/^\/?%postname%\/?$/', $struct ) ) - $wp_rewrite->use_verbose_page_rules = true; - - // get rewrite rules without walking dirs - $post_type_rules_temp = $wp_rewrite->generate_rewrite_rules( $struct, EP_PERMALINK, false, true, false, false, true ); - foreach( $post_type_rules_temp as $regex => $query ) { - if ( preg_match( '/(&|\?)(cpage|attachment|p|name|pagename)=/', $query ) ) { - $post_type_query = ( count( $post_types ) < 2 ? '&post_type=' . $post_types[ 0 ] : '&post_type[]=' . join( '&post_type[]=', array_unique( $post_types ) ) ); - $rules[ $regex ] = $query . ( preg_match( '/(&|\?)(attachment|pagename)=/', $query ) ? '' : $post_type_query ); - } else - unset( $rules[ $regex ] ); - } - - } - - return $rules; - } - - - /** - * Generic version of standard permalink parsing function. Adds support for - * custom taxonomies as well as the standard %author% etc... - * - * @param string $post_link The post URL - * @param WP_Post|object|int|null $post The post object - * @param bool $leavename Passed to pre_post_link filter - * @param bool $sample Used in admin if generating an example permalink - * - * @return string The parsed permalink - */ - public function parse_permalinks( $post_link, $post, $leavename, $sample = false ) { - // Ensure WP_Post object. Some plugins pass arbitrary objects or other data. - $post = get_post( $post ); - - // Only bail if the above get_post() didn't work. - if ( ! $post instanceof WP_Post ) { - return $post_link; - } - - // Make a stupid request and we'll do nothing. - if ( !post_type_exists( $post->post_type ) ) - return $post_link; - - $rewritecode = array( - '%year%', - '%monthnum%', - '%day%', - '%hour%', - '%minute%', - '%second%', - $leavename? '' : '%postname%', - '%post_id%', - '%author%', - $leavename? '' : '%pagename%', - ); - - $taxonomies = get_object_taxonomies( $post->post_type ); - - foreach( $taxonomies as $taxonomy ) - $rewritecode[] = '%' . $taxonomy . '%'; - - if ( is_object($post) && isset($post->filter) && 'sample' == $post->filter ) - $sample = true; - - $post_type = get_post_type_object( $post->post_type ); - $permastruct = get_option( $post_type->name . '_permalink_structure' ); - - // prefer option over default - if ( $permastruct && ! empty( $permastruct ) ) { - $permalink = $permastruct; - } elseif ( isset( $post_type->rewrite[ 'permastruct' ] ) && ! empty( $post_type->rewrite[ 'permastruct' ] ) ) { - $permalink = $post_type->rewrite[ 'permastruct' ]; - } else { - return $post_link; - } - - $permalink = apply_filters('pre_post_link', $permalink, $post, $leavename); - - if ( '' != $permalink && !in_array($post->post_status, array('draft', 'pending', 'auto-draft')) ) { - $unixtime = strtotime($post->post_date); - - // add ability to use any taxonomies in post type permastruct - $replace_terms = array(); - foreach( $taxonomies as $taxonomy ) { - $term = ''; - $taxonomy_object = get_taxonomy( $taxonomy ); - if ( strpos($permalink, '%'. $taxonomy .'%') !== false ) { - $terms = get_the_terms( $post->ID, $taxonomy ); - if ( $terms ) { - if ( function_exists( 'wp_list_sort' ) ) { - $terms = wp_list_sort( $terms, 'term_id', 'ASC' ); // order by term_id ASC - } else { - usort( $terms, '_usort_terms_by_ID' ); // order by term_id ASC + public function permalink_field( $args ) { + echo ''; + } + + + /** + * Runs a simple sanitisation of the custom post type permalink structures + * and adds an error if no post ID or post name present + * + * @param string $permalink The permalink structure + * + * @return string Sanitised permalink structure + */ + public function sanitize_permalink( $permalink ) { + if ( !empty( $permalink ) && !preg_match( '/%(post_id|postname)%/', $permalink ) ) { + add_settings_error( 'permalink_structure', 10, __( 'Permalink structures must contain at least the %post_id% or %postname%.' ) ); + } + + $filtered = wp_check_invalid_utf8( $permalink ); + + if ( strpos( $filtered, '<' ) !== false ) { + $filtered = wp_pre_kses_less_than( $filtered ); + // This will strip extra whitespace for us. + $filtered = wp_strip_all_tags( $filtered, true ); + } + else { + $filtered = trim( preg_replace( '/[\r\n\t ]+/', ' ', $filtered ) ); + } + + return preg_replace( '/[^a-zA-Z0-9\/\%\._-]*/', '', $filtered ); + } + + + /** + * This function removes unnecessary rules and adds in the new rules + * + * @param array $rules The rewrite rules array for post permalinks + * + * @return array The modified rules array + */ + public function add_permastructs( $rules ) { + global $wp_rewrite; + + // restore endpoints + if ( empty( $wp_rewrite->endpoints ) && !empty( $this->endpoints ) ) { + $wp_rewrite->endpoints = $this->endpoints; + } + + $permastruct = $wp_rewrite->permalink_structure; + $permastructs = array( $permastruct => array( 'post' ) ); + + // force page rewrite to bottom + $wp_rewrite->use_verbose_page_rules = false; + + // get permastructs foreach custom post type and group any that use the same struct + foreach ( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects' ) as $type ) { + // add/override the custom permalink structure if set in options + $post_type_permastruct = get_option( $type->name . '_permalink_structure' ); + if ( $post_type_permastruct && !empty( $post_type_permastruct ) ) { + if ( !is_array( $type->rewrite ) ) { + $type->rewrite = array(); + } + $type->rewrite[ 'permastruct' ] = $post_type_permastruct; + } + + // check we have a custom permalink structure + if ( !is_array( $type->rewrite ) || !isset( $type->rewrite[ 'permastruct' ] ) ) { + continue; + } + + // remove default struct rules + add_filter( $type->name . '_rewrite_rules', function( $rules ) { + return array(); + }, 11 ); + + if ( !isset( $permastructs[ $type->rewrite[ 'permastruct' ] ] ) ) { + $permastructs[ $type->rewrite[ 'permastruct' ] ] = array(); + } + + $permastructs[ $type->rewrite[ 'permastruct' ] ][] = $type->name; + } + + $rules = array(); + + // add our permastructs scoped to the post types - overwriting any keys that already exist + foreach ( $permastructs as $struct => $post_types ) { + + // if a struct is %postname% only then we need page rules first - if not found wp tries again with later rules + if ( preg_match( '/^\/?%postname%\/?$/', $struct ) ) { + $wp_rewrite->use_verbose_page_rules = true; + } + + // get rewrite rules without walking dirs + $post_type_rules_temp = $wp_rewrite->generate_rewrite_rules( $struct, EP_PERMALINK, false, true, false, false, true ); + foreach ( $post_type_rules_temp as $regex => $query ) { + if ( preg_match( '/(&|\?)(cpage|attachment|p|name|pagename)=/', $query ) ) { + $post_type_query = ( count( $post_types ) < 2 ? '&post_type=' . $post_types[ 0 ] : '&post_type[]=' . join( '&post_type[]=', array_unique( $post_types ) ) ); + $rules[ $regex ] = $query . ( preg_match( '/(&|\?)(attachment|pagename)=/', $query ) ? '' : $post_type_query ); + // Ensure permalinks that match a custom taxonomy path don't get swallowed. + $wp_rewrite->extra_rules_top[ $regex ] = $rules[ $regex ]; + } + else { + unset( $rules[ $regex ] ); + } + } + + } + + return $rules; + } + + + /** + * Generic version of standard permalink parsing function. Adds support for + * custom taxonomies as well as the standard %author% etc... + * + * @param string $post_link The post URL + * @param WP_Post $post The post object + * @param bool $leavename Passed to pre_post_link filter + * @param bool $sample Used in admin if generating an example permalink + * + * @return string The parsed permalink + */ + public function parse_permalinks( $post_link, $post, $leavename, $sample = false ) { + // Yoast Sitemap plug-in doesn't pass a WP_Post object causing a fatal, so we'll check for it and return. + if ( !is_a( $post, 'WP_Post' ) ) { + return $post_link; + } + + // Make a stupid request and we'll do nothing. + if ( !post_type_exists( $post->post_type ) ) { + return $post_link; + } + + $rewritecode = array( + '%year%', + '%monthnum%', + '%day%', + '%hour%', + '%minute%', + '%second%', + $leavename ? '' : '%postname%', + '%post_id%', + '%author%', + $leavename ? '' : '%pagename%', + ); + + $taxonomies = get_object_taxonomies( $post->post_type ); + + foreach ( $taxonomies as $taxonomy ) { + $rewritecode[] = '%' . $taxonomy . '%'; + } + + if ( is_object( $post ) && isset( $post->filter ) && 'sample' == $post->filter ) { + $sample = true; + } + + $post_type = get_post_type_object( $post->post_type ); + $permastruct = get_option( $post_type->name . '_permalink_structure' ); + + if ( empty( $permastruct ) && $post->post_type === 'post' ) { + $permastruct = get_option( 'permalink_structure' ); + } + + // prefer option over default + if ( !empty( $permastruct ) ) { + $permalink = $permastruct; + } + elseif ( isset( $post_type->rewrite[ 'permastruct' ] ) && !empty( $post_type->rewrite[ 'permastruct' ] ) ) { + $permalink = $post_type->rewrite[ 'permastruct' ]; + } + else { + return $post_link; + } + + $permalink = apply_filters( 'pre_post_link', $permalink, $post, $leavename ); + + if ( '' != $permalink && !in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ) ) ) { + $unixtime = strtotime( $post->post_date ); + + // add ability to use any taxonomies in post type permastruct + $replace_terms = array(); + foreach ( $taxonomies as $taxonomy ) { + $term = ''; + $taxonomy_object = get_taxonomy( $taxonomy ); + if ( strpos( $permalink, '%' . $taxonomy . '%' ) !== false ) { + $terms = get_the_terms( $post->ID, $taxonomy ); + if ( $terms && ! is_wp_error( $terms ) ) { + if ( function_exists( 'wp_list_sort' ) ) { + $terms = wp_list_sort( $terms, 'term_id', 'ASC' ); // order by term_id ASC + } else { + usort( $terms, '_usort_terms_by_ID' ); // order by term_id ASC + } + + /** + * Filter the term that gets used in the `$tax` permalink token. + * + * @param WP_Term $term The `$tax` term to use in the permalink. + * @param array $terms Array of all `$tax` terms associated with the post. + * @param WP_Post $post The post in question. + */ + $term_object = apply_filters( "post_link_{$taxonomy}", reset( $terms ), $terms, $post ); + + $term = $term_object->slug; + if ( $taxonomy_object->hierarchical && $parent = $term_object->parent ) { + $term = get_term_parents( $parent, $taxonomy, false, '/', true ) . $term; + } } - - /** - * Filter the term that gets used in the `$tax` permalink token. - * - * @param WP_Term $term The `$tax` term to use in the permalink. - * @param array $terms Array of all `$tax` terms associated with the post. - * @param WP_Post $post The post in question. - */ - $term_object = apply_filters( "post_link_{$taxonomy}", reset( $terms ), $terms, $post ); - - $term = $term_object->slug; - if ( $taxonomy_object->hierarchical && $parent = $term_object->parent ) { - $term = get_term_parents( $parent, $taxonomy, false, '/', true ) . $term; + // show default category in permalinks, without + // having to assign it explicitly + if ( empty( $term ) && $taxonomy == 'category' ) { + $default_category = get_category( get_option( 'default_category' ) ); + $term = is_wp_error( $default_category ) ? '' : $default_category->slug; } - } - // show default category in permalinks, without - // having to assign it explicitly - if ( empty( $term ) && $taxonomy == 'category' ) { - $default_category = get_category( get_option( 'default_category' ) ); - $term = is_wp_error( $default_category ) ? '' : $default_category->slug; - } - - } - $replace_terms[ $taxonomy ] = $term; - } - - $author = ''; - if ( strpos( $permalink, '%author%' ) !== false ) { - $authordata = get_userdata( $post->post_author ); - $author = $authordata->user_nicename; - } - - $date = explode( " ", date( 'Y m d H i s', $unixtime ) ); - $rewritereplace = array( - $date[0], - $date[1], - $date[2], - $date[3], - $date[4], - $date[5], - $post->post_name, - $post->ID, - $author, - $post->post_name, - ); - foreach( $taxonomies as $taxonomy ) - $rewritereplace[] = $replace_terms[ $taxonomy ]; - $permalink = home_url( str_replace( $rewritecode, $rewritereplace, $permalink ) ); - $permalink = user_trailingslashit( $permalink, 'single' ); - } else { // if they're not using the fancy permalink option - $permalink = home_url( '?p=' . $post->ID ); - } - - return $permalink; - } - -} + } + $replace_terms[ $taxonomy ] = $term; + } + + $author = ''; + if ( strpos( $permalink, '%author%' ) !== false ) { + $authordata = get_userdata( $post->post_author ); + $author = $authordata->user_nicename; + } + + $date = explode( " ", date( 'Y m d H i s', $unixtime ) ); + $rewritereplace = + array( + $date[ 0 ], + $date[ 1 ], + $date[ 2 ], + $date[ 3 ], + $date[ 4 ], + $date[ 5 ], + $post->post_name, + $post->ID, + $author, + $post->post_name, + ); + foreach ( $taxonomies as $taxonomy ) { + $rewritereplace[] = $replace_terms[ $taxonomy ]; + } + $permalink = home_url( str_replace( $rewritecode, $rewritereplace, $permalink ) ); + $permalink = user_trailingslashit( $permalink, 'single' ); + } + else { // if they're not using the fancy permalink option + $permalink = home_url( '?p=' . $post->ID ); + } + + return $permalink; + } + + } } if ( ! function_exists( 'get_term_parents' ) ) { - /** - * Retrieve term parents with separator. - * - * @param int $id Term ID. - * @param string $taxonomy The taxonomy the term belongs to. - * @param bool $link Optional, default is false. Whether to format with link. - * @param string $separator Optional, default is '/'. How to separate categories. - * @param bool $nicename Optional, default is false. Whether to use nice name for display. - * @param array $visited Optional. Already linked to categories to prevent duplicates. - * @return string - */ - function get_term_parents( $id, $taxonomy, $link = false, $separator = '/', $nicename = false, $visited = array() ) { - $chain = ''; - $parent = get_term( $id, $taxonomy ); - if ( is_wp_error( $parent ) ) - return $parent; - - if ( $nicename ) - $name = $parent->slug; - else - $name = $parent->cat_name; - - if ( $parent->parent && ( $parent->parent != $parent->term_id ) && !in_array( $parent->parent, $visited ) ) { - $visited[] = $parent->parent; - $chain .= get_term_parents( $parent->parent, $taxonomy, $link, $separator, $nicename, $visited ); - } - - if ( $link ) - $chain .= 'name ) ) . '">'.$name.'' . $separator; - else - $chain .= $name.$separator; - return $chain; - } + /** + * Retrieve term parents with separator. + * + * @param int $id Term ID. + * @param string $taxonomy The taxonomy the term belongs to. + * @param bool $link Optional, default is false. Whether to format with link. + * @param string $separator Optional, default is '/'. How to separate categories. + * @param bool $nicename Optional, default is false. Whether to use nice name for display. + * @param array $visited Optional. Already linked to categories to prevent duplicates. + * + * @return string + */ + function get_term_parents( + $id, + $taxonomy, + $link = false, + $separator = '/', + $nicename = false, + $visited = array() + ) { + $chain = ''; + $parent = get_term( $id, $taxonomy ); + if ( is_wp_error( $parent ) ) { + return $parent; + } + + if ( $nicename ) { + $name = $parent->slug; + } + else { + $name = $parent->cat_name; + } + + if ( $parent->parent && ( $parent->parent != $parent->term_id ) && ! in_array( $parent->parent, $visited ) ) { + $visited[] = $parent->parent; + $chain .= get_term_parents( $parent->parent, $taxonomy, $link, $separator, $nicename, $visited ); + } + + if ( $link ) { + $chain .= '' . $name . '' . $separator; + } + else { + $chain .= $name . $separator; + } + + return $chain; + } } @@ -409,45 +445,48 @@ function get_term_parents( $id, $taxonomy, $link = false, $separator = '/', $nic */ if ( ! function_exists( 'enable_permalinks_settings' ) ) { - // process the $_POST variable after all settings have been - // registered so they are whitelisted - add_action( 'admin_init', 'enable_permalinks_settings', 300 ); - - function enable_permalinks_settings() { - global $new_whitelist_options; - - // save hook for permalinks page - if ( isset( $_POST['permalink_structure'] ) || isset( $_POST['category_base'] ) ) { - check_admin_referer('update-permalink'); - - $option_page = 'permalink'; - - $capability = 'manage_options'; - $capability = apply_filters( "option_page_capability_{$option_page}", $capability ); - - if ( !current_user_can( $capability ) ) - wp_die(__('Cheatin’ uh?')); - - // get extra permalink options - $options = $new_whitelist_options[ $option_page ]; - - if ( $options ) { - foreach ( $options as $option ) { - $option = trim($option); - $value = null; - if ( isset($_POST[$option]) ) - $value = $_POST[$option]; - if ( !is_array($value) ) - $value = trim($value); - $value = stripslashes_deep($value); - update_option( $option, $value ); - } - } - - /** - * Handle settings errors - */ - set_transient('settings_errors', get_settings_errors(), 30); - } - } + // process the $_POST variable after all settings have been + // registered so they are whitelisted + add_action( 'admin_init', 'enable_permalinks_settings', 300 ); + + function enable_permalinks_settings() { + global $new_whitelist_options; + + // save hook for permalinks page + if ( isset( $_POST['permalink_structure'] ) || isset( $_POST['category_base'] ) ) { + check_admin_referer( 'update-permalink' ); + + $option_page = 'permalink'; + + $capability = 'manage_options'; + $capability = apply_filters( "option_page_capability_{$option_page}", $capability ); + + if ( ! current_user_can( $capability ) ) { + wp_die( __( 'Cheatin’ uh?' ) ); + } + + // get extra permalink options + $options = $new_whitelist_options[ $option_page ]; + + if ( $options ) { + foreach ( $options as $option ) { + $option = trim( $option ); + $value = null; + if ( isset( $_POST[ $option ] ) ) { + $value = $_POST[ $option ]; + } + if ( ! is_array( $value ) ) { + $value = trim( $value ); + } + $value = stripslashes_deep( $value ); + update_option( $option, $value ); + } + } + + /** + * Handle settings errors + */ + set_transient( 'settings_errors', get_settings_errors(), 30 ); + } + } } From 4c9dfb2686b78e145b94b500ca4ca0201bce93f9 Mon Sep 17 00:00:00 2001 From: Robert O'Rourke Date: Tue, 23 Jan 2024 16:02:36 +0000 Subject: [PATCH 09/17] Tabs --- wp-permastructure.php | 772 +++++++++++++++++++++--------------------- 1 file changed, 386 insertions(+), 386 deletions(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index 2305959..c00af86 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -40,285 +40,285 @@ if ( !class_exists( 'wp_permastructure' ) ) { - add_action( 'init', array( 'wp_permastructure', 'instance' ), 0 ); + add_action( 'init', array( 'wp_permastructure', 'instance' ), 0 ); - class wp_permastructure { + class wp_permastructure { - public $settings_section = 'wp_permastructure'; + public $settings_section = 'wp_permastructure'; - /** - * @var protect endpoints from being vaped if a category/tag slug is set - */ - protected $endpoints; + /** + * @var protect endpoints from being vaped if a category/tag slug is set + */ + protected $endpoints; - /** - * Reusable object instance. - * - * @type object - */ - protected static $instance = null; + /** + * Reusable object instance. + * + * @type object + */ + protected static $instance = null; - /** - * Creates a new instance. Called on 'init'. - * May be used to access class methods from outside. - * - * @see __construct() - * @return void - */ - public static function instance() { - null === self:: $instance AND self:: $instance = new self; + /** + * Creates a new instance. Called on 'init'. + * May be used to access class methods from outside. + * + * @see __construct() + * @return void + */ + public static function instance() { + null === self:: $instance AND self:: $instance = new self; - return self:: $instance; - } + return self:: $instance; + } - public function __construct() { + public function __construct() { - // Late init to protect endpoints - add_action( 'init', array( $this, 'late_init' ), 999 ); + // Late init to protect endpoints + add_action( 'init', array( $this, 'late_init' ), 999 ); - // Settings fields on permalinks page - add_action( 'admin_init', array( $this, 'admin_init' ) ); + // Settings fields on permalinks page + add_action( 'admin_init', array( $this, 'admin_init' ) ); - // add our new peramstructs to the rewrite rules - add_filter( 'post_rewrite_rules', array( $this, 'add_permastructs' ) ); + // add our new peramstructs to the rewrite rules + add_filter( 'post_rewrite_rules', array( $this, 'add_permastructs' ) ); - // parse the generated links - enable custom taxonomies for built in post links - add_filter( 'post_link', array( $this, 'parse_permalinks' ), 10, 3 ); - add_filter( 'post_type_link', array( $this, 'parse_permalinks' ), 10, 4 ); + // parse the generated links - enable custom taxonomies for built in post links + add_filter( 'post_link', array( $this, 'parse_permalinks' ), 10, 3 ); + add_filter( 'post_type_link', array( $this, 'parse_permalinks' ), 10, 4 ); - // that's it! + // that's it! - } + } - public function late_init() { - global $wp_rewrite; - $this->endpoints = $wp_rewrite->endpoints; - } + public function late_init() { + global $wp_rewrite; + $this->endpoints = $wp_rewrite->endpoints; + } - /** - * Add the settings UI - */ - public function admin_init() { + /** + * Add the settings UI + */ + public function admin_init() { - add_settings_section( - $this->settings_section, - __( 'Custom post type permalink settings' ), - array( $this, 'settings_section' ), - 'permalink' - ); - - foreach ( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects' ) as $type ) { - $id = $type->name . '_permalink_structure'; - - register_setting( 'permalink', $id, array( $this, 'sanitize_permalink' ) ); - add_settings_field( - $id, - __( $type->label . ' permalink structure' ), - array( $this, 'permalink_field' ), - 'permalink', - $this->settings_section, - array( 'id' => $id ) - ); - } + add_settings_section( + $this->settings_section, + __( 'Custom post type permalink settings' ), + array( $this, 'settings_section' ), + 'permalink' + ); + + foreach ( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects' ) as $type ) { + $id = $type->name . '_permalink_structure'; + + register_setting( 'permalink', $id, array( $this, 'sanitize_permalink' ) ); + add_settings_field( + $id, + __( $type->label . ' permalink structure' ), + array( $this, 'permalink_field' ), + 'permalink', + $this->settings_section, + array( 'id' => $id ) + ); + } - } + } - public function settings_section() { - - } - - - public function permalink_field( $args ) { - echo ''; - } - - - /** - * Runs a simple sanitisation of the custom post type permalink structures - * and adds an error if no post ID or post name present - * - * @param string $permalink The permalink structure - * - * @return string Sanitised permalink structure - */ - public function sanitize_permalink( $permalink ) { - if ( !empty( $permalink ) && !preg_match( '/%(post_id|postname)%/', $permalink ) ) { - add_settings_error( 'permalink_structure', 10, __( 'Permalink structures must contain at least the %post_id% or %postname%.' ) ); - } - - $filtered = wp_check_invalid_utf8( $permalink ); - - if ( strpos( $filtered, '<' ) !== false ) { - $filtered = wp_pre_kses_less_than( $filtered ); - // This will strip extra whitespace for us. - $filtered = wp_strip_all_tags( $filtered, true ); - } - else { - $filtered = trim( preg_replace( '/[\r\n\t ]+/', ' ', $filtered ) ); - } - - return preg_replace( '/[^a-zA-Z0-9\/\%\._-]*/', '', $filtered ); - } - - - /** - * This function removes unnecessary rules and adds in the new rules - * - * @param array $rules The rewrite rules array for post permalinks - * - * @return array The modified rules array - */ - public function add_permastructs( $rules ) { - global $wp_rewrite; - - // restore endpoints - if ( empty( $wp_rewrite->endpoints ) && !empty( $this->endpoints ) ) { - $wp_rewrite->endpoints = $this->endpoints; - } - - $permastruct = $wp_rewrite->permalink_structure; - $permastructs = array( $permastruct => array( 'post' ) ); - - // force page rewrite to bottom - $wp_rewrite->use_verbose_page_rules = false; - - // get permastructs foreach custom post type and group any that use the same struct - foreach ( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects' ) as $type ) { - // add/override the custom permalink structure if set in options - $post_type_permastruct = get_option( $type->name . '_permalink_structure' ); - if ( $post_type_permastruct && !empty( $post_type_permastruct ) ) { - if ( !is_array( $type->rewrite ) ) { - $type->rewrite = array(); - } - $type->rewrite[ 'permastruct' ] = $post_type_permastruct; - } - - // check we have a custom permalink structure - if ( !is_array( $type->rewrite ) || !isset( $type->rewrite[ 'permastruct' ] ) ) { - continue; - } - - // remove default struct rules - add_filter( $type->name . '_rewrite_rules', function( $rules ) { - return array(); - }, 11 ); - - if ( !isset( $permastructs[ $type->rewrite[ 'permastruct' ] ] ) ) { - $permastructs[ $type->rewrite[ 'permastruct' ] ] = array(); - } - - $permastructs[ $type->rewrite[ 'permastruct' ] ][] = $type->name; - } - - $rules = array(); - - // add our permastructs scoped to the post types - overwriting any keys that already exist - foreach ( $permastructs as $struct => $post_types ) { - - // if a struct is %postname% only then we need page rules first - if not found wp tries again with later rules - if ( preg_match( '/^\/?%postname%\/?$/', $struct ) ) { - $wp_rewrite->use_verbose_page_rules = true; - } - - // get rewrite rules without walking dirs - $post_type_rules_temp = $wp_rewrite->generate_rewrite_rules( $struct, EP_PERMALINK, false, true, false, false, true ); - foreach ( $post_type_rules_temp as $regex => $query ) { - if ( preg_match( '/(&|\?)(cpage|attachment|p|name|pagename)=/', $query ) ) { - $post_type_query = ( count( $post_types ) < 2 ? '&post_type=' . $post_types[ 0 ] : '&post_type[]=' . join( '&post_type[]=', array_unique( $post_types ) ) ); - $rules[ $regex ] = $query . ( preg_match( '/(&|\?)(attachment|pagename)=/', $query ) ? '' : $post_type_query ); - // Ensure permalinks that match a custom taxonomy path don't get swallowed. - $wp_rewrite->extra_rules_top[ $regex ] = $rules[ $regex ]; - } - else { - unset( $rules[ $regex ] ); - } - } - - } - - return $rules; - } - - - /** - * Generic version of standard permalink parsing function. Adds support for - * custom taxonomies as well as the standard %author% etc... - * - * @param string $post_link The post URL - * @param WP_Post $post The post object - * @param bool $leavename Passed to pre_post_link filter - * @param bool $sample Used in admin if generating an example permalink - * - * @return string The parsed permalink - */ - public function parse_permalinks( $post_link, $post, $leavename, $sample = false ) { - // Yoast Sitemap plug-in doesn't pass a WP_Post object causing a fatal, so we'll check for it and return. - if ( !is_a( $post, 'WP_Post' ) ) { - return $post_link; - } - - // Make a stupid request and we'll do nothing. - if ( !post_type_exists( $post->post_type ) ) { - return $post_link; - } - - $rewritecode = array( - '%year%', - '%monthnum%', - '%day%', - '%hour%', - '%minute%', - '%second%', - $leavename ? '' : '%postname%', - '%post_id%', - '%author%', - $leavename ? '' : '%pagename%', - ); - - $taxonomies = get_object_taxonomies( $post->post_type ); - - foreach ( $taxonomies as $taxonomy ) { - $rewritecode[] = '%' . $taxonomy . '%'; - } - - if ( is_object( $post ) && isset( $post->filter ) && 'sample' == $post->filter ) { - $sample = true; - } - - $post_type = get_post_type_object( $post->post_type ); - $permastruct = get_option( $post_type->name . '_permalink_structure' ); - - if ( empty( $permastruct ) && $post->post_type === 'post' ) { - $permastruct = get_option( 'permalink_structure' ); - } - - // prefer option over default - if ( !empty( $permastruct ) ) { - $permalink = $permastruct; - } - elseif ( isset( $post_type->rewrite[ 'permastruct' ] ) && !empty( $post_type->rewrite[ 'permastruct' ] ) ) { - $permalink = $post_type->rewrite[ 'permastruct' ]; - } - else { - return $post_link; - } - - $permalink = apply_filters( 'pre_post_link', $permalink, $post, $leavename ); - - if ( '' != $permalink && !in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ) ) ) { - $unixtime = strtotime( $post->post_date ); - - // add ability to use any taxonomies in post type permastruct - $replace_terms = array(); - foreach ( $taxonomies as $taxonomy ) { - $term = ''; - $taxonomy_object = get_taxonomy( $taxonomy ); - if ( strpos( $permalink, '%' . $taxonomy . '%' ) !== false ) { - $terms = get_the_terms( $post->ID, $taxonomy ); + public function settings_section() { + + } + + + public function permalink_field( $args ) { + echo ''; + } + + + /** + * Runs a simple sanitisation of the custom post type permalink structures + * and adds an error if no post ID or post name present + * + * @param string $permalink The permalink structure + * + * @return string Sanitised permalink structure + */ + public function sanitize_permalink( $permalink ) { + if ( !empty( $permalink ) && !preg_match( '/%(post_id|postname)%/', $permalink ) ) { + add_settings_error( 'permalink_structure', 10, __( 'Permalink structures must contain at least the %post_id% or %postname%.' ) ); + } + + $filtered = wp_check_invalid_utf8( $permalink ); + + if ( strpos( $filtered, '<' ) !== false ) { + $filtered = wp_pre_kses_less_than( $filtered ); + // This will strip extra whitespace for us. + $filtered = wp_strip_all_tags( $filtered, true ); + } + else { + $filtered = trim( preg_replace( '/[\r\n\t ]+/', ' ', $filtered ) ); + } + + return preg_replace( '/[^a-zA-Z0-9\/\%\._-]*/', '', $filtered ); + } + + + /** + * This function removes unnecessary rules and adds in the new rules + * + * @param array $rules The rewrite rules array for post permalinks + * + * @return array The modified rules array + */ + public function add_permastructs( $rules ) { + global $wp_rewrite; + + // restore endpoints + if ( empty( $wp_rewrite->endpoints ) && !empty( $this->endpoints ) ) { + $wp_rewrite->endpoints = $this->endpoints; + } + + $permastruct = $wp_rewrite->permalink_structure; + $permastructs = array( $permastruct => array( 'post' ) ); + + // force page rewrite to bottom + $wp_rewrite->use_verbose_page_rules = false; + + // get permastructs foreach custom post type and group any that use the same struct + foreach ( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects' ) as $type ) { + // add/override the custom permalink structure if set in options + $post_type_permastruct = get_option( $type->name . '_permalink_structure' ); + if ( $post_type_permastruct && !empty( $post_type_permastruct ) ) { + if ( !is_array( $type->rewrite ) ) { + $type->rewrite = array(); + } + $type->rewrite[ 'permastruct' ] = $post_type_permastruct; + } + + // check we have a custom permalink structure + if ( !is_array( $type->rewrite ) || !isset( $type->rewrite[ 'permastruct' ] ) ) { + continue; + } + + // remove default struct rules + add_filter( $type->name . '_rewrite_rules', function( $rules ) { + return array(); + }, 11 ); + + if ( !isset( $permastructs[ $type->rewrite[ 'permastruct' ] ] ) ) { + $permastructs[ $type->rewrite[ 'permastruct' ] ] = array(); + } + + $permastructs[ $type->rewrite[ 'permastruct' ] ][] = $type->name; + } + + $rules = array(); + + // add our permastructs scoped to the post types - overwriting any keys that already exist + foreach ( $permastructs as $struct => $post_types ) { + + // if a struct is %postname% only then we need page rules first - if not found wp tries again with later rules + if ( preg_match( '/^\/?%postname%\/?$/', $struct ) ) { + $wp_rewrite->use_verbose_page_rules = true; + } + + // get rewrite rules without walking dirs + $post_type_rules_temp = $wp_rewrite->generate_rewrite_rules( $struct, EP_PERMALINK, false, true, false, false, true ); + foreach ( $post_type_rules_temp as $regex => $query ) { + if ( preg_match( '/(&|\?)(cpage|attachment|p|name|pagename)=/', $query ) ) { + $post_type_query = ( count( $post_types ) < 2 ? '&post_type=' . $post_types[ 0 ] : '&post_type[]=' . join( '&post_type[]=', array_unique( $post_types ) ) ); + $rules[ $regex ] = $query . ( preg_match( '/(&|\?)(attachment|pagename)=/', $query ) ? '' : $post_type_query ); + // Ensure permalinks that match a custom taxonomy path don't get swallowed. + $wp_rewrite->extra_rules_top[ $regex ] = $rules[ $regex ]; + } + else { + unset( $rules[ $regex ] ); + } + } + + } + + return $rules; + } + + + /** + * Generic version of standard permalink parsing function. Adds support for + * custom taxonomies as well as the standard %author% etc... + * + * @param string $post_link The post URL + * @param WP_Post $post The post object + * @param bool $leavename Passed to pre_post_link filter + * @param bool $sample Used in admin if generating an example permalink + * + * @return string The parsed permalink + */ + public function parse_permalinks( $post_link, $post, $leavename, $sample = false ) { + // Yoast Sitemap plug-in doesn't pass a WP_Post object causing a fatal, so we'll check for it and return. + if ( !is_a( $post, 'WP_Post' ) ) { + return $post_link; + } + + // Make a stupid request and we'll do nothing. + if ( !post_type_exists( $post->post_type ) ) { + return $post_link; + } + + $rewritecode = array( + '%year%', + '%monthnum%', + '%day%', + '%hour%', + '%minute%', + '%second%', + $leavename ? '' : '%postname%', + '%post_id%', + '%author%', + $leavename ? '' : '%pagename%', + ); + + $taxonomies = get_object_taxonomies( $post->post_type ); + + foreach ( $taxonomies as $taxonomy ) { + $rewritecode[] = '%' . $taxonomy . '%'; + } + + if ( is_object( $post ) && isset( $post->filter ) && 'sample' == $post->filter ) { + $sample = true; + } + + $post_type = get_post_type_object( $post->post_type ); + $permastruct = get_option( $post_type->name . '_permalink_structure' ); + + if ( empty( $permastruct ) && $post->post_type === 'post' ) { + $permastruct = get_option( 'permalink_structure' ); + } + + // prefer option over default + if ( !empty( $permastruct ) ) { + $permalink = $permastruct; + } + elseif ( isset( $post_type->rewrite[ 'permastruct' ] ) && !empty( $post_type->rewrite[ 'permastruct' ] ) ) { + $permalink = $post_type->rewrite[ 'permastruct' ]; + } + else { + return $post_link; + } + + $permalink = apply_filters( 'pre_post_link', $permalink, $post, $leavename ); + + if ( '' != $permalink && !in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ) ) ) { + $unixtime = strtotime( $post->post_date ); + + // add ability to use any taxonomies in post type permastruct + $replace_terms = array(); + foreach ( $taxonomies as $taxonomy ) { + $term = ''; + $taxonomy_object = get_taxonomy( $taxonomy ); + if ( strpos( $permalink, '%' . $taxonomy . '%' ) !== false ) { + $terms = get_the_terms( $post->ID, $taxonomy ); if ( $terms && ! is_wp_error( $terms ) ) { if ( function_exists( 'wp_list_sort' ) ) { $terms = wp_list_sort( $terms, 'term_id', 'ASC' ); // order by term_id ASC @@ -346,96 +346,96 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false $default_category = get_category( get_option( 'default_category' ) ); $term = is_wp_error( $default_category ) ? '' : $default_category->slug; } - } - $replace_terms[ $taxonomy ] = $term; - } - - $author = ''; - if ( strpos( $permalink, '%author%' ) !== false ) { - $authordata = get_userdata( $post->post_author ); - $author = $authordata->user_nicename; - } - - $date = explode( " ", date( 'Y m d H i s', $unixtime ) ); - $rewritereplace = - array( - $date[ 0 ], - $date[ 1 ], - $date[ 2 ], - $date[ 3 ], - $date[ 4 ], - $date[ 5 ], - $post->post_name, - $post->ID, - $author, - $post->post_name, - ); - foreach ( $taxonomies as $taxonomy ) { - $rewritereplace[] = $replace_terms[ $taxonomy ]; - } - $permalink = home_url( str_replace( $rewritecode, $rewritereplace, $permalink ) ); - $permalink = user_trailingslashit( $permalink, 'single' ); - } - else { // if they're not using the fancy permalink option - $permalink = home_url( '?p=' . $post->ID ); - } - - return $permalink; - } - - } + } + $replace_terms[ $taxonomy ] = $term; + } + + $author = ''; + if ( strpos( $permalink, '%author%' ) !== false ) { + $authordata = get_userdata( $post->post_author ); + $author = $authordata->user_nicename; + } + + $date = explode( " ", date( 'Y m d H i s', $unixtime ) ); + $rewritereplace = + array( + $date[ 0 ], + $date[ 1 ], + $date[ 2 ], + $date[ 3 ], + $date[ 4 ], + $date[ 5 ], + $post->post_name, + $post->ID, + $author, + $post->post_name, + ); + foreach ( $taxonomies as $taxonomy ) { + $rewritereplace[] = $replace_terms[ $taxonomy ]; + } + $permalink = home_url( str_replace( $rewritecode, $rewritereplace, $permalink ) ); + $permalink = user_trailingslashit( $permalink, 'single' ); + } + else { // if they're not using the fancy permalink option + $permalink = home_url( '?p=' . $post->ID ); + } + + return $permalink; + } + + } } if ( ! function_exists( 'get_term_parents' ) ) { - /** - * Retrieve term parents with separator. - * - * @param int $id Term ID. - * @param string $taxonomy The taxonomy the term belongs to. - * @param bool $link Optional, default is false. Whether to format with link. - * @param string $separator Optional, default is '/'. How to separate categories. - * @param bool $nicename Optional, default is false. Whether to use nice name for display. - * @param array $visited Optional. Already linked to categories to prevent duplicates. - * - * @return string - */ - function get_term_parents( - $id, - $taxonomy, - $link = false, - $separator = '/', - $nicename = false, - $visited = array() - ) { - $chain = ''; - $parent = get_term( $id, $taxonomy ); - if ( is_wp_error( $parent ) ) { - return $parent; - } - - if ( $nicename ) { - $name = $parent->slug; - } - else { - $name = $parent->cat_name; - } - - if ( $parent->parent && ( $parent->parent != $parent->term_id ) && ! in_array( $parent->parent, $visited ) ) { - $visited[] = $parent->parent; - $chain .= get_term_parents( $parent->parent, $taxonomy, $link, $separator, $nicename, $visited ); - } - - if ( $link ) { - $chain .= '' . $name . '' . $separator; - } - else { - $chain .= $name . $separator; - } - - return $chain; - } + /** + * Retrieve term parents with separator. + * + * @param int $id Term ID. + * @param string $taxonomy The taxonomy the term belongs to. + * @param bool $link Optional, default is false. Whether to format with link. + * @param string $separator Optional, default is '/'. How to separate categories. + * @param bool $nicename Optional, default is false. Whether to use nice name for display. + * @param array $visited Optional. Already linked to categories to prevent duplicates. + * + * @return string + */ + function get_term_parents( + $id, + $taxonomy, + $link = false, + $separator = '/', + $nicename = false, + $visited = array() + ) { + $chain = ''; + $parent = get_term( $id, $taxonomy ); + if ( is_wp_error( $parent ) ) { + return $parent; + } + + if ( $nicename ) { + $name = $parent->slug; + } + else { + $name = $parent->cat_name; + } + + if ( $parent->parent && ( $parent->parent != $parent->term_id ) && ! in_array( $parent->parent, $visited ) ) { + $visited[] = $parent->parent; + $chain .= get_term_parents( $parent->parent, $taxonomy, $link, $separator, $nicename, $visited ); + } + + if ( $link ) { + $chain .= '' . $name . '' . $separator; + } + else { + $chain .= $name . $separator; + } + + return $chain; + } } @@ -445,48 +445,48 @@ function get_term_parents( */ if ( ! function_exists( 'enable_permalinks_settings' ) ) { - // process the $_POST variable after all settings have been - // registered so they are whitelisted - add_action( 'admin_init', 'enable_permalinks_settings', 300 ); - - function enable_permalinks_settings() { - global $new_whitelist_options; - - // save hook for permalinks page - if ( isset( $_POST['permalink_structure'] ) || isset( $_POST['category_base'] ) ) { - check_admin_referer( 'update-permalink' ); - - $option_page = 'permalink'; - - $capability = 'manage_options'; - $capability = apply_filters( "option_page_capability_{$option_page}", $capability ); - - if ( ! current_user_can( $capability ) ) { - wp_die( __( 'Cheatin’ uh?' ) ); - } - - // get extra permalink options - $options = $new_whitelist_options[ $option_page ]; - - if ( $options ) { - foreach ( $options as $option ) { - $option = trim( $option ); - $value = null; - if ( isset( $_POST[ $option ] ) ) { - $value = $_POST[ $option ]; - } - if ( ! is_array( $value ) ) { - $value = trim( $value ); - } - $value = stripslashes_deep( $value ); - update_option( $option, $value ); - } - } - - /** - * Handle settings errors - */ - set_transient( 'settings_errors', get_settings_errors(), 30 ); - } - } + // process the $_POST variable after all settings have been + // registered so they are whitelisted + add_action( 'admin_init', 'enable_permalinks_settings', 300 ); + + function enable_permalinks_settings() { + global $new_whitelist_options; + + // save hook for permalinks page + if ( isset( $_POST['permalink_structure'] ) || isset( $_POST['category_base'] ) ) { + check_admin_referer( 'update-permalink' ); + + $option_page = 'permalink'; + + $capability = 'manage_options'; + $capability = apply_filters( "option_page_capability_{$option_page}", $capability ); + + if ( ! current_user_can( $capability ) ) { + wp_die( __( 'Cheatin’ uh?' ) ); + } + + // get extra permalink options + $options = $new_whitelist_options[ $option_page ]; + + if ( $options ) { + foreach ( $options as $option ) { + $option = trim( $option ); + $value = null; + if ( isset( $_POST[ $option ] ) ) { + $value = $_POST[ $option ]; + } + if ( ! is_array( $value ) ) { + $value = trim( $value ); + } + $value = stripslashes_deep( $value ); + update_option( $option, $value ); + } + } + + /** + * Handle settings errors + */ + set_transient( 'settings_errors', get_settings_errors(), 30 ); + } + } } From f75df245ccf687beccafd05cae8aa1165a174d64 Mon Sep 17 00:00:00 2001 From: Robert O'Rourke Date: Tue, 23 Jan 2024 16:06:59 +0000 Subject: [PATCH 10/17] Tabs --- wp-permastructure.php | 697 +++++++++++++++++++++--------------------- 1 file changed, 349 insertions(+), 348 deletions(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index c00af86..7df38ec 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -38,404 +38,406 @@ * 1.0: Initial import */ -if ( !class_exists( 'wp_permastructure' ) ) { +if ( class_exists( 'wp_permastructure' ) ) { + return; +} - add_action( 'init', array( 'wp_permastructure', 'instance' ), 0 ); +add_action( 'init', array( 'wp_permastructure', 'instance' ), 0 ); - class wp_permastructure { +class wp_permastructure { - public $settings_section = 'wp_permastructure'; + public $settings_section = 'wp_permastructure'; - /** - * @var protect endpoints from being vaped if a category/tag slug is set - */ - protected $endpoints; - - /** - * Reusable object instance. - * - * @type object - */ - protected static $instance = null; + /** + * @var protect endpoints from being vaped if a category/tag slug is set + */ + protected $endpoints; - /** - * Creates a new instance. Called on 'init'. - * May be used to access class methods from outside. - * - * @see __construct() - * @return void - */ - public static function instance() { - null === self:: $instance AND self:: $instance = new self; + /** + * Reusable object instance. + * + * @type object + */ + protected static $instance = null; - return self:: $instance; - } + /** + * Creates a new instance. Called on 'init'. + * May be used to access class methods from outside. + * + * @see __construct() + * @return void + */ + public static function instance() { + null === self:: $instance AND self:: $instance = new self; + return self:: $instance; + } - public function __construct() { - // Late init to protect endpoints - add_action( 'init', array( $this, 'late_init' ), 999 ); + public function __construct() { - // Settings fields on permalinks page - add_action( 'admin_init', array( $this, 'admin_init' ) ); + // Late init to protect endpoints + add_action( 'init', array( $this, 'late_init' ), 999 ); - // add our new peramstructs to the rewrite rules - add_filter( 'post_rewrite_rules', array( $this, 'add_permastructs' ) ); + // Settings fields on permalinks page + add_action( 'admin_init', array( $this, 'admin_init' ) ); - // parse the generated links - enable custom taxonomies for built in post links - add_filter( 'post_link', array( $this, 'parse_permalinks' ), 10, 3 ); - add_filter( 'post_type_link', array( $this, 'parse_permalinks' ), 10, 4 ); + // add our new peramstructs to the rewrite rules + add_filter( 'post_rewrite_rules', array( $this, 'add_permastructs' ) ); - // that's it! + // parse the generated links - enable custom taxonomies for built in post links + add_filter( 'post_link', array( $this, 'parse_permalinks' ), 10, 3 ); + add_filter( 'post_type_link', array( $this, 'parse_permalinks' ), 10, 4 ); - } + // that's it! + } - public function late_init() { - global $wp_rewrite; - $this->endpoints = $wp_rewrite->endpoints; - } + public function late_init() { + global $wp_rewrite; + $this->endpoints = $wp_rewrite->endpoints; + } - /** - * Add the settings UI - */ - public function admin_init() { - add_settings_section( + /** + * Add the settings UI + */ + public function admin_init() { + + add_settings_section( + $this->settings_section, + __( 'Custom post type permalink settings' ), + array( $this, 'settings_section' ), + 'permalink' + ); + + foreach ( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects' ) as $type ) { + $id = $type->name . '_permalink_structure'; + + register_setting( 'permalink', $id, array( $this, 'sanitize_permalink' ) ); + add_settings_field( + $id, + __( $type->label . ' permalink structure' ), + array( $this, 'permalink_field' ), + 'permalink', $this->settings_section, - __( 'Custom post type permalink settings' ), - array( $this, 'settings_section' ), - 'permalink' + array( 'id' => $id ) ); - - foreach ( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects' ) as $type ) { - $id = $type->name . '_permalink_structure'; - - register_setting( 'permalink', $id, array( $this, 'sanitize_permalink' ) ); - add_settings_field( - $id, - __( $type->label . ' permalink structure' ), - array( $this, 'permalink_field' ), - 'permalink', - $this->settings_section, - array( 'id' => $id ) - ); - } - } + } - public function settings_section() { - } + public function settings_section() { + } - public function permalink_field( $args ) { - echo ''; - } + public function permalink_field( $args ) { + echo ''; + } - /** - * Runs a simple sanitisation of the custom post type permalink structures - * and adds an error if no post ID or post name present - * - * @param string $permalink The permalink structure - * - * @return string Sanitised permalink structure - */ - public function sanitize_permalink( $permalink ) { - if ( !empty( $permalink ) && !preg_match( '/%(post_id|postname)%/', $permalink ) ) { - add_settings_error( 'permalink_structure', 10, __( 'Permalink structures must contain at least the %post_id% or %postname%.' ) ); - } - $filtered = wp_check_invalid_utf8( $permalink ); + /** + * Runs a simple sanitisation of the custom post type permalink structures + * and adds an error if no post ID or post name present + * + * @param string $permalink The permalink structure + * + * @return string Sanitised permalink structure + */ + public function sanitize_permalink( $permalink ) { + if ( !empty( $permalink ) && !preg_match( '/%(post_id|postname)%/', $permalink ) ) { + add_settings_error( 'permalink_structure', 10, __( 'Permalink structures must contain at least the %post_id% or %postname%.' ) ); + } - if ( strpos( $filtered, '<' ) !== false ) { - $filtered = wp_pre_kses_less_than( $filtered ); - // This will strip extra whitespace for us. - $filtered = wp_strip_all_tags( $filtered, true ); - } - else { - $filtered = trim( preg_replace( '/[\r\n\t ]+/', ' ', $filtered ) ); - } + $filtered = wp_check_invalid_utf8( $permalink ); - return preg_replace( '/[^a-zA-Z0-9\/\%\._-]*/', '', $filtered ); + if ( strpos( $filtered, '<' ) !== false ) { + $filtered = wp_pre_kses_less_than( $filtered ); + // This will strip extra whitespace for us. + $filtered = wp_strip_all_tags( $filtered, true ); + } + else { + $filtered = trim( preg_replace( '/[\r\n\t ]+/', ' ', $filtered ) ); } + return preg_replace( '/[^a-zA-Z0-9\/\%\._-]*/', '', $filtered ); + } - /** - * This function removes unnecessary rules and adds in the new rules - * - * @param array $rules The rewrite rules array for post permalinks - * - * @return array The modified rules array - */ - public function add_permastructs( $rules ) { - global $wp_rewrite; - // restore endpoints - if ( empty( $wp_rewrite->endpoints ) && !empty( $this->endpoints ) ) { - $wp_rewrite->endpoints = $this->endpoints; - } + /** + * This function removes unnecessary rules and adds in the new rules + * + * @param array $rules The rewrite rules array for post permalinks + * + * @return array The modified rules array + */ + public function add_permastructs( $rules ) { + global $wp_rewrite; - $permastruct = $wp_rewrite->permalink_structure; - $permastructs = array( $permastruct => array( 'post' ) ); + // restore endpoints + if ( empty( $wp_rewrite->endpoints ) && !empty( $this->endpoints ) ) { + $wp_rewrite->endpoints = $this->endpoints; + } - // force page rewrite to bottom - $wp_rewrite->use_verbose_page_rules = false; + $permastruct = $wp_rewrite->permalink_structure; + $permastructs = array( $permastruct => array( 'post' ) ); - // get permastructs foreach custom post type and group any that use the same struct - foreach ( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects' ) as $type ) { - // add/override the custom permalink structure if set in options - $post_type_permastruct = get_option( $type->name . '_permalink_structure' ); - if ( $post_type_permastruct && !empty( $post_type_permastruct ) ) { - if ( !is_array( $type->rewrite ) ) { - $type->rewrite = array(); - } - $type->rewrite[ 'permastruct' ] = $post_type_permastruct; - } + // force page rewrite to bottom + $wp_rewrite->use_verbose_page_rules = false; - // check we have a custom permalink structure - if ( !is_array( $type->rewrite ) || !isset( $type->rewrite[ 'permastruct' ] ) ) { - continue; + // get permastructs foreach custom post type and group any that use the same struct + foreach ( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects' ) as $type ) { + // add/override the custom permalink structure if set in options + $post_type_permastruct = get_option( $type->name . '_permalink_structure' ); + if ( $post_type_permastruct && !empty( $post_type_permastruct ) ) { + if ( !is_array( $type->rewrite ) ) { + $type->rewrite = array(); } + $type->rewrite[ 'permastruct' ] = $post_type_permastruct; + } - // remove default struct rules - add_filter( $type->name . '_rewrite_rules', function( $rules ) { - return array(); - }, 11 ); + // check we have a custom permalink structure + if ( !is_array( $type->rewrite ) || !isset( $type->rewrite[ 'permastruct' ] ) ) { + continue; + } - if ( !isset( $permastructs[ $type->rewrite[ 'permastruct' ] ] ) ) { - $permastructs[ $type->rewrite[ 'permastruct' ] ] = array(); - } + // remove default struct rules + add_filter( $type->name . '_rewrite_rules', function( $rules ) { + return array(); + }, 11 ); - $permastructs[ $type->rewrite[ 'permastruct' ] ][] = $type->name; + if ( !isset( $permastructs[ $type->rewrite[ 'permastruct' ] ] ) ) { + $permastructs[ $type->rewrite[ 'permastruct' ] ] = array(); } - $rules = array(); + $permastructs[ $type->rewrite[ 'permastruct' ] ][] = $type->name; + } - // add our permastructs scoped to the post types - overwriting any keys that already exist - foreach ( $permastructs as $struct => $post_types ) { + $rules = array(); - // if a struct is %postname% only then we need page rules first - if not found wp tries again with later rules - if ( preg_match( '/^\/?%postname%\/?$/', $struct ) ) { - $wp_rewrite->use_verbose_page_rules = true; - } + // add our permastructs scoped to the post types - overwriting any keys that already exist + foreach ( $permastructs as $struct => $post_types ) { - // get rewrite rules without walking dirs - $post_type_rules_temp = $wp_rewrite->generate_rewrite_rules( $struct, EP_PERMALINK, false, true, false, false, true ); - foreach ( $post_type_rules_temp as $regex => $query ) { - if ( preg_match( '/(&|\?)(cpage|attachment|p|name|pagename)=/', $query ) ) { - $post_type_query = ( count( $post_types ) < 2 ? '&post_type=' . $post_types[ 0 ] : '&post_type[]=' . join( '&post_type[]=', array_unique( $post_types ) ) ); - $rules[ $regex ] = $query . ( preg_match( '/(&|\?)(attachment|pagename)=/', $query ) ? '' : $post_type_query ); - // Ensure permalinks that match a custom taxonomy path don't get swallowed. - $wp_rewrite->extra_rules_top[ $regex ] = $rules[ $regex ]; - } - else { - unset( $rules[ $regex ] ); - } - } + // if a struct is %postname% only then we need page rules first - if not found wp tries again with later rules + if ( preg_match( '/^\/?%postname%\/?$/', $struct ) ) { + $wp_rewrite->use_verbose_page_rules = true; + } + // get rewrite rules without walking dirs + $post_type_rules_temp = $wp_rewrite->generate_rewrite_rules( $struct, EP_PERMALINK, false, true, false, false, true ); + foreach ( $post_type_rules_temp as $regex => $query ) { + if ( preg_match( '/(&|\?)(cpage|attachment|p|name|pagename)=/', $query ) ) { + $post_type_query = ( count( $post_types ) < 2 ? '&post_type=' . $post_types[ 0 ] : '&post_type[]=' . join( '&post_type[]=', array_unique( $post_types ) ) ); + $rules[ $regex ] = $query . ( preg_match( '/(&|\?)(attachment|pagename)=/', $query ) ? '' : $post_type_query ); + // Ensure permalinks that match a custom taxonomy path don't get swallowed. + $wp_rewrite->extra_rules_top[ $regex ] = $rules[ $regex ]; + } + else { + unset( $rules[ $regex ] ); + } } - return $rules; } + return $rules; + } - /** - * Generic version of standard permalink parsing function. Adds support for - * custom taxonomies as well as the standard %author% etc... - * - * @param string $post_link The post URL - * @param WP_Post $post The post object - * @param bool $leavename Passed to pre_post_link filter - * @param bool $sample Used in admin if generating an example permalink - * - * @return string The parsed permalink - */ - public function parse_permalinks( $post_link, $post, $leavename, $sample = false ) { - // Yoast Sitemap plug-in doesn't pass a WP_Post object causing a fatal, so we'll check for it and return. - if ( !is_a( $post, 'WP_Post' ) ) { - return $post_link; - } - // Make a stupid request and we'll do nothing. - if ( !post_type_exists( $post->post_type ) ) { - return $post_link; - } + /** + * Generic version of standard permalink parsing function. Adds support for + * custom taxonomies as well as the standard %author% etc... + * + * @param string $post_link The post URL + * @param WP_Post $post The post object + * @param bool $leavename Passed to pre_post_link filter + * @param bool $sample Used in admin if generating an example permalink + * + * @return string The parsed permalink + */ + public function parse_permalinks( $post_link, $post, $leavename, $sample = false ) { + // Yoast Sitemap plug-in doesn't pass a WP_Post object causing a fatal, so we'll check for it and return. + if ( !is_a( $post, 'WP_Post' ) ) { + return $post_link; + } - $rewritecode = array( - '%year%', - '%monthnum%', - '%day%', - '%hour%', - '%minute%', - '%second%', - $leavename ? '' : '%postname%', - '%post_id%', - '%author%', - $leavename ? '' : '%pagename%', - ); + // Make a stupid request and we'll do nothing. + if ( !post_type_exists( $post->post_type ) ) { + return $post_link; + } - $taxonomies = get_object_taxonomies( $post->post_type ); + $rewritecode = array( + '%year%', + '%monthnum%', + '%day%', + '%hour%', + '%minute%', + '%second%', + $leavename ? '' : '%postname%', + '%post_id%', + '%author%', + $leavename ? '' : '%pagename%', + ); + + $taxonomies = get_object_taxonomies( $post->post_type ); + + foreach ( $taxonomies as $taxonomy ) { + $rewritecode[] = '%' . $taxonomy . '%'; + } - foreach ( $taxonomies as $taxonomy ) { - $rewritecode[] = '%' . $taxonomy . '%'; - } + if ( is_object( $post ) && isset( $post->filter ) && 'sample' == $post->filter ) { + $sample = true; + } - if ( is_object( $post ) && isset( $post->filter ) && 'sample' == $post->filter ) { - $sample = true; - } + $post_type = get_post_type_object( $post->post_type ); + $permastruct = get_option( $post_type->name . '_permalink_structure' ); - $post_type = get_post_type_object( $post->post_type ); - $permastruct = get_option( $post_type->name . '_permalink_structure' ); + if ( empty( $permastruct ) && $post->post_type === 'post' ) { + $permastruct = get_option( 'permalink_structure' ); + } - if ( empty( $permastruct ) && $post->post_type === 'post' ) { - $permastruct = get_option( 'permalink_structure' ); - } + // prefer option over default + if ( !empty( $permastruct ) ) { + $permalink = $permastruct; + } + elseif ( isset( $post_type->rewrite[ 'permastruct' ] ) && !empty( $post_type->rewrite[ 'permastruct' ] ) ) { + $permalink = $post_type->rewrite[ 'permastruct' ]; + } + else { + return $post_link; + } - // prefer option over default - if ( !empty( $permastruct ) ) { - $permalink = $permastruct; - } - elseif ( isset( $post_type->rewrite[ 'permastruct' ] ) && !empty( $post_type->rewrite[ 'permastruct' ] ) ) { - $permalink = $post_type->rewrite[ 'permastruct' ]; - } - else { - return $post_link; - } + $permalink = apply_filters( 'pre_post_link', $permalink, $post, $leavename ); - $permalink = apply_filters( 'pre_post_link', $permalink, $post, $leavename ); - - if ( '' != $permalink && !in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ) ) ) { - $unixtime = strtotime( $post->post_date ); - - // add ability to use any taxonomies in post type permastruct - $replace_terms = array(); - foreach ( $taxonomies as $taxonomy ) { - $term = ''; - $taxonomy_object = get_taxonomy( $taxonomy ); - if ( strpos( $permalink, '%' . $taxonomy . '%' ) !== false ) { - $terms = get_the_terms( $post->ID, $taxonomy ); - if ( $terms && ! is_wp_error( $terms ) ) { - if ( function_exists( 'wp_list_sort' ) ) { - $terms = wp_list_sort( $terms, 'term_id', 'ASC' ); // order by term_id ASC - } else { - usort( $terms, '_usort_terms_by_ID' ); // order by term_id ASC - } - - /** - * Filter the term that gets used in the `$tax` permalink token. - * - * @param WP_Term $term The `$tax` term to use in the permalink. - * @param array $terms Array of all `$tax` terms associated with the post. - * @param WP_Post $post The post in question. - */ - $term_object = apply_filters( "post_link_{$taxonomy}", reset( $terms ), $terms, $post ); - - $term = $term_object->slug; - if ( $taxonomy_object->hierarchical && $parent = $term_object->parent ) { - $term = get_term_parents( $parent, $taxonomy, false, '/', true ) . $term; - } + if ( '' != $permalink && !in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ) ) ) { + $unixtime = strtotime( $post->post_date ); + + // add ability to use any taxonomies in post type permastruct + $replace_terms = array(); + foreach ( $taxonomies as $taxonomy ) { + $term = ''; + $taxonomy_object = get_taxonomy( $taxonomy ); + if ( strpos( $permalink, '%' . $taxonomy . '%' ) !== false ) { + $terms = get_the_terms( $post->ID, $taxonomy ); + if ( $terms && ! is_wp_error( $terms ) ) { + if ( function_exists( 'wp_list_sort' ) ) { + $terms = wp_list_sort( $terms, 'term_id', 'ASC' ); // order by term_id ASC + } else { + usort( $terms, '_usort_terms_by_ID' ); // order by term_id ASC } - // show default category in permalinks, without - // having to assign it explicitly - if ( empty( $term ) && $taxonomy == 'category' ) { - $default_category = get_category( get_option( 'default_category' ) ); - $term = is_wp_error( $default_category ) ? '' : $default_category->slug; + + /** + * Filter the term that gets used in the `$tax` permalink token. + * + * @param WP_Term $term The `$tax` term to use in the permalink. + * @param array $terms Array of all `$tax` terms associated with the post. + * @param WP_Post $post The post in question. + */ + $term_object = apply_filters( "post_link_{$taxonomy}", reset( $terms ), $terms, $post ); + + $term = $term_object->slug; + if ( $taxonomy_object->hierarchical && $parent = $term_object->parent ) { + $term = get_term_parents( $parent, $taxonomy, false, '/', true ) . $term; } } - $replace_terms[ $taxonomy ] = $term; - } - - $author = ''; - if ( strpos( $permalink, '%author%' ) !== false ) { - $authordata = get_userdata( $post->post_author ); - $author = $authordata->user_nicename; - } - - $date = explode( " ", date( 'Y m d H i s', $unixtime ) ); - $rewritereplace = - array( - $date[ 0 ], - $date[ 1 ], - $date[ 2 ], - $date[ 3 ], - $date[ 4 ], - $date[ 5 ], - $post->post_name, - $post->ID, - $author, - $post->post_name, - ); - foreach ( $taxonomies as $taxonomy ) { - $rewritereplace[] = $replace_terms[ $taxonomy ]; + // show default category in permalinks, without + // having to assign it explicitly + if ( empty( $term ) && $taxonomy == 'category' ) { + $default_category = get_category( get_option( 'default_category' ) ); + $term = is_wp_error( $default_category ) ? '' : $default_category->slug; + } } - $permalink = home_url( str_replace( $rewritecode, $rewritereplace, $permalink ) ); - $permalink = user_trailingslashit( $permalink, 'single' ); + $replace_terms[ $taxonomy ] = $term; } - else { // if they're not using the fancy permalink option - $permalink = home_url( '?p=' . $post->ID ); + + $author = ''; + if ( strpos( $permalink, '%author%' ) !== false ) { + $authordata = get_userdata( $post->post_author ); + $author = $authordata->user_nicename; } - return $permalink; + $date = explode( " ", date( 'Y m d H i s', $unixtime ) ); + $rewritereplace = + array( + $date[ 0 ], + $date[ 1 ], + $date[ 2 ], + $date[ 3 ], + $date[ 4 ], + $date[ 5 ], + $post->post_name, + $post->ID, + $author, + $post->post_name, + ); + foreach ( $taxonomies as $taxonomy ) { + $rewritereplace[] = $replace_terms[ $taxonomy ]; + } + $permalink = home_url( str_replace( $rewritecode, $rewritereplace, $permalink ) ); + $permalink = user_trailingslashit( $permalink, 'single' ); + } + else { // if they're not using the fancy permalink option + $permalink = home_url( '?p=' . $post->ID ); } + return $permalink; } } -if ( ! function_exists( 'get_term_parents' ) ) { +} - /** - * Retrieve term parents with separator. - * - * @param int $id Term ID. - * @param string $taxonomy The taxonomy the term belongs to. - * @param bool $link Optional, default is false. Whether to format with link. - * @param string $separator Optional, default is '/'. How to separate categories. - * @param bool $nicename Optional, default is false. Whether to use nice name for display. - * @param array $visited Optional. Already linked to categories to prevent duplicates. - * - * @return string - */ - function get_term_parents( - $id, - $taxonomy, - $link = false, - $separator = '/', - $nicename = false, - $visited = array() - ) { - $chain = ''; - $parent = get_term( $id, $taxonomy ); - if ( is_wp_error( $parent ) ) { - return $parent; - } +if ( ! function_exists( 'get_term_parents' ) ) { - if ( $nicename ) { - $name = $parent->slug; - } - else { - $name = $parent->cat_name; - } +/** + * Retrieve term parents with separator. + * + * @param int $id Term ID. + * @param string $taxonomy The taxonomy the term belongs to. + * @param bool $link Optional, default is false. Whether to format with link. + * @param string $separator Optional, default is '/'. How to separate categories. + * @param bool $nicename Optional, default is false. Whether to use nice name for display. + * @param array $visited Optional. Already linked to categories to prevent duplicates. + * + * @return string + */ +function get_term_parents( + $id, + $taxonomy, + $link = false, + $separator = '/', + $nicename = false, + $visited = array() +) { + $chain = ''; + $parent = get_term( $id, $taxonomy ); + if ( is_wp_error( $parent ) ) { + return $parent; + } - if ( $parent->parent && ( $parent->parent != $parent->term_id ) && ! in_array( $parent->parent, $visited ) ) { - $visited[] = $parent->parent; - $chain .= get_term_parents( $parent->parent, $taxonomy, $link, $separator, $nicename, $visited ); - } + if ( $nicename ) { + $name = $parent->slug; + } + else { + $name = $parent->cat_name; + } - if ( $link ) { - $chain .= '' . $name . '' . $separator; - } - else { - $chain .= $name . $separator; - } + if ( $parent->parent && ( $parent->parent != $parent->term_id ) && ! in_array( $parent->parent, $visited ) ) { + $visited[] = $parent->parent; + $chain .= get_term_parents( $parent->parent, $taxonomy, $link, $separator, $nicename, $visited ); + } - return $chain; + if ( $link ) { + $chain .= '' . $name . '' . $separator; } + else { + $chain .= $name . $separator; + } + + return $chain; +} } @@ -445,48 +447,47 @@ function get_term_parents( */ if ( ! function_exists( 'enable_permalinks_settings' ) ) { - // process the $_POST variable after all settings have been - // registered so they are whitelisted - add_action( 'admin_init', 'enable_permalinks_settings', 300 ); +// process the $_POST variable after all settings have been +// registered so they are whitelisted +add_action( 'admin_init', 'enable_permalinks_settings', 300 ); - function enable_permalinks_settings() { - global $new_whitelist_options; +function enable_permalinks_settings() { + global $new_whitelist_options; - // save hook for permalinks page - if ( isset( $_POST['permalink_structure'] ) || isset( $_POST['category_base'] ) ) { - check_admin_referer( 'update-permalink' ); + // save hook for permalinks page + if ( isset( $_POST['permalink_structure'] ) || isset( $_POST['category_base'] ) ) { + check_admin_referer( 'update-permalink' ); - $option_page = 'permalink'; + $option_page = 'permalink'; - $capability = 'manage_options'; - $capability = apply_filters( "option_page_capability_{$option_page}", $capability ); + $capability = 'manage_options'; + $capability = apply_filters( "option_page_capability_{$option_page}", $capability ); - if ( ! current_user_can( $capability ) ) { - wp_die( __( 'Cheatin’ uh?' ) ); - } + if ( ! current_user_can( $capability ) ) { + wp_die( __( 'Cheatin’ uh?' ) ); + } - // get extra permalink options - $options = $new_whitelist_options[ $option_page ]; + // get extra permalink options + $options = $new_whitelist_options[ $option_page ]; - if ( $options ) { - foreach ( $options as $option ) { - $option = trim( $option ); - $value = null; - if ( isset( $_POST[ $option ] ) ) { - $value = $_POST[ $option ]; - } - if ( ! is_array( $value ) ) { - $value = trim( $value ); - } - $value = stripslashes_deep( $value ); - update_option( $option, $value ); + if ( $options ) { + foreach ( $options as $option ) { + $option = trim( $option ); + $value = null; + if ( isset( $_POST[ $option ] ) ) { + $value = $_POST[ $option ]; + } + if ( ! is_array( $value ) ) { + $value = trim( $value ); } + $value = stripslashes_deep( $value ); + update_option( $option, $value ); } - - /** - * Handle settings errors - */ - set_transient( 'settings_errors', get_settings_errors(), 30 ); } + + /** + * Handle settings errors + */ + set_transient( 'settings_errors', get_settings_errors(), 30 ); } } From 92522815a21d13e99bc6432c5193b6c185f14baf Mon Sep 17 00:00:00 2001 From: Robert O'Rourke Date: Tue, 23 Jan 2024 16:13:11 +0000 Subject: [PATCH 11/17] Fix indents for functions --- wp-permastructure.php | 178 +++++++++++++++++++++--------------------- 1 file changed, 89 insertions(+), 89 deletions(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index 7df38ec..6b98c5c 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -68,9 +68,9 @@ class wp_permastructure { * @return void */ public static function instance() { - null === self:: $instance AND self:: $instance = new self; + null === self::$instance AND self::$instance = new self; - return self:: $instance; + return self::$instance; } @@ -148,7 +148,7 @@ public function permalink_field( $args ) { * @return string Sanitised permalink structure */ public function sanitize_permalink( $permalink ) { - if ( !empty( $permalink ) && !preg_match( '/%(post_id|postname)%/', $permalink ) ) { + if ( ! empty( $permalink ) && ! preg_match( '/%(post_id|postname)%/', $permalink ) ) { add_settings_error( 'permalink_structure', 10, __( 'Permalink structures must contain at least the %post_id% or %postname%.' ) ); } @@ -178,7 +178,7 @@ public function add_permastructs( $rules ) { global $wp_rewrite; // restore endpoints - if ( empty( $wp_rewrite->endpoints ) && !empty( $this->endpoints ) ) { + if ( empty( $wp_rewrite->endpoints ) && ! empty( $this->endpoints ) ) { $wp_rewrite->endpoints = $this->endpoints; } @@ -192,15 +192,15 @@ public function add_permastructs( $rules ) { foreach ( get_post_types( array( '_builtin' => false, 'public' => true ), 'objects' ) as $type ) { // add/override the custom permalink structure if set in options $post_type_permastruct = get_option( $type->name . '_permalink_structure' ); - if ( $post_type_permastruct && !empty( $post_type_permastruct ) ) { - if ( !is_array( $type->rewrite ) ) { + if ( $post_type_permastruct && ! empty( $post_type_permastruct ) ) { + if ( ! is_array( $type->rewrite ) ) { $type->rewrite = array(); } $type->rewrite[ 'permastruct' ] = $post_type_permastruct; } // check we have a custom permalink structure - if ( !is_array( $type->rewrite ) || !isset( $type->rewrite[ 'permastruct' ] ) ) { + if ( ! is_array( $type->rewrite ) || ! isset( $type->rewrite[ 'permastruct' ] ) ) { continue; } @@ -209,7 +209,7 @@ public function add_permastructs( $rules ) { return array(); }, 11 ); - if ( !isset( $permastructs[ $type->rewrite[ 'permastruct' ] ] ) ) { + if ( ! isset( $permastructs[ $type->rewrite[ 'permastruct' ] ] ) ) { $permastructs[ $type->rewrite[ 'permastruct' ] ] = array(); } @@ -259,12 +259,12 @@ public function add_permastructs( $rules ) { */ public function parse_permalinks( $post_link, $post, $leavename, $sample = false ) { // Yoast Sitemap plug-in doesn't pass a WP_Post object causing a fatal, so we'll check for it and return. - if ( !is_a( $post, 'WP_Post' ) ) { + if ( ! is_a( $post, 'WP_Post' ) ) { return $post_link; } // Make a stupid request and we'll do nothing. - if ( !post_type_exists( $post->post_type ) ) { + if ( ! post_type_exists( $post->post_type ) ) { return $post_link; } @@ -302,7 +302,7 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false if ( !empty( $permastruct ) ) { $permalink = $permastruct; } - elseif ( isset( $post_type->rewrite[ 'permastruct' ] ) && !empty( $post_type->rewrite[ 'permastruct' ] ) ) { + elseif ( isset( $post_type->rewrite[ 'permastruct' ] ) && ! empty( $post_type->rewrite[ 'permastruct' ] ) ) { $permalink = $post_type->rewrite[ 'permastruct' ]; } else { @@ -344,7 +344,7 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false } // show default category in permalinks, without // having to assign it explicitly - if ( empty( $term ) && $taxonomy == 'category' ) { + if ( empty( $term ) && $taxonomy === 'category' ) { $default_category = get_category( get_option( 'default_category' ) ); $term = is_wp_error( $default_category ) ? '' : $default_category->slug; } @@ -387,57 +387,55 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false } -} - if ( ! function_exists( 'get_term_parents' ) ) { -/** - * Retrieve term parents with separator. - * - * @param int $id Term ID. - * @param string $taxonomy The taxonomy the term belongs to. - * @param bool $link Optional, default is false. Whether to format with link. - * @param string $separator Optional, default is '/'. How to separate categories. - * @param bool $nicename Optional, default is false. Whether to use nice name for display. - * @param array $visited Optional. Already linked to categories to prevent duplicates. - * - * @return string - */ -function get_term_parents( - $id, - $taxonomy, - $link = false, - $separator = '/', - $nicename = false, - $visited = array() -) { - $chain = ''; - $parent = get_term( $id, $taxonomy ); - if ( is_wp_error( $parent ) ) { - return $parent; - } + /** + * Retrieve term parents with separator. + * + * @param int $id Term ID. + * @param string $taxonomy The taxonomy the term belongs to. + * @param bool $link Optional, default is false. Whether to format with link. + * @param string $separator Optional, default is '/'. How to separate categories. + * @param bool $nicename Optional, default is false. Whether to use nice name for display. + * @param array $visited Optional. Already linked to categories to prevent duplicates. + * + * @return string + */ + function get_term_parents( + $id, + $taxonomy, + $link = false, + $separator = '/', + $nicename = false, + $visited = array() + ) { + $chain = ''; + $parent = get_term( $id, $taxonomy ); + if ( is_wp_error( $parent ) ) { + return $parent; + } - if ( $nicename ) { - $name = $parent->slug; - } - else { - $name = $parent->cat_name; - } + if ( $nicename ) { + $name = $parent->slug; + } + else { + $name = $parent->cat_name; + } - if ( $parent->parent && ( $parent->parent != $parent->term_id ) && ! in_array( $parent->parent, $visited ) ) { - $visited[] = $parent->parent; - $chain .= get_term_parents( $parent->parent, $taxonomy, $link, $separator, $nicename, $visited ); - } + if ( $parent->parent && ( $parent->parent != $parent->term_id ) && ! in_array( $parent->parent, $visited ) ) { + $visited[] = $parent->parent; + $chain .= get_term_parents( $parent->parent, $taxonomy, $link, $separator, $nicename, $visited ); + } - if ( $link ) { - $chain .= '' . $name . '' . $separator; - } - else { - $chain .= $name . $separator; - } + if ( $link ) { + $chain .= '' . $name . '' . $separator; + } + else { + $chain .= $name . $separator; + } - return $chain; -} + return $chain; + } } @@ -447,47 +445,49 @@ function get_term_parents( */ if ( ! function_exists( 'enable_permalinks_settings' ) ) { -// process the $_POST variable after all settings have been -// registered so they are whitelisted -add_action( 'admin_init', 'enable_permalinks_settings', 300 ); + // process the $_POST variable after all settings have been + // registered so they are whitelisted + add_action( 'admin_init', 'enable_permalinks_settings', 300 ); -function enable_permalinks_settings() { - global $new_whitelist_options; + function enable_permalinks_settings() { + global $new_whitelist_options; - // save hook for permalinks page - if ( isset( $_POST['permalink_structure'] ) || isset( $_POST['category_base'] ) ) { - check_admin_referer( 'update-permalink' ); + // save hook for permalinks page + if ( isset( $_POST['permalink_structure'] ) || isset( $_POST['category_base'] ) ) { + check_admin_referer( 'update-permalink' ); - $option_page = 'permalink'; + $option_page = 'permalink'; - $capability = 'manage_options'; - $capability = apply_filters( "option_page_capability_{$option_page}", $capability ); + $capability = 'manage_options'; + $capability = apply_filters( "option_page_capability_{$option_page}", $capability ); - if ( ! current_user_can( $capability ) ) { - wp_die( __( 'Cheatin’ uh?' ) ); - } + if ( ! current_user_can( $capability ) ) { + wp_die( __( 'Cheatin’ uh?' ) ); + } - // get extra permalink options - $options = $new_whitelist_options[ $option_page ]; + // get extra permalink options + $options = $new_whitelist_options[ $option_page ]; - if ( $options ) { - foreach ( $options as $option ) { - $option = trim( $option ); - $value = null; - if ( isset( $_POST[ $option ] ) ) { - $value = $_POST[ $option ]; - } - if ( ! is_array( $value ) ) { - $value = trim( $value ); + if ( $options ) { + foreach ( $options as $option ) { + $option = trim( $option ); + $value = null; + if ( isset( $_POST[ $option ] ) ) { + $value = $_POST[ $option ]; + } + if ( ! is_array( $value ) ) { + $value = trim( $value ); + } + $value = stripslashes_deep( $value ); + update_option( $option, $value ); } - $value = stripslashes_deep( $value ); - update_option( $option, $value ); } - } - /** - * Handle settings errors - */ - set_transient( 'settings_errors', get_settings_errors(), 30 ); + /** + * Handle settings errors + */ + set_transient( 'settings_errors', get_settings_errors(), 30 ); + } } + } From 5fc8d69ab4a855e5dbc1504bc5591c9fb5d62253 Mon Sep 17 00:00:00 2001 From: Robert O'Rourke Date: Tue, 23 Jan 2024 16:15:55 +0000 Subject: [PATCH 12/17] no new line for if/else control struct --- wp-permastructure.php | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index 6b98c5c..6dc7f94 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -19,9 +19,9 @@ * eg: * * register_post_type( 'my_type', array( - * ... - * 'rewrite' => array( 'permastruct' => '/%custom_taxonomy%/%author%/%postname%/' ), - * ... + * ... + * 'rewrite' => array( 'permastruct' => '/%custom_taxonomy%/%author%/%postname%/' ), + * ... * ) ); * * Alternatively you can set the permalink structure from the permalinks settings page @@ -158,8 +158,7 @@ public function sanitize_permalink( $permalink ) { $filtered = wp_pre_kses_less_than( $filtered ); // This will strip extra whitespace for us. $filtered = wp_strip_all_tags( $filtered, true ); - } - else { + } else { $filtered = trim( preg_replace( '/[\r\n\t ]+/', ' ', $filtered ) ); } @@ -234,8 +233,7 @@ public function add_permastructs( $rules ) { $rules[ $regex ] = $query . ( preg_match( '/(&|\?)(attachment|pagename)=/', $query ) ? '' : $post_type_query ); // Ensure permalinks that match a custom taxonomy path don't get swallowed. $wp_rewrite->extra_rules_top[ $regex ] = $rules[ $regex ]; - } - else { + } else { unset( $rules[ $regex ] ); } } @@ -301,11 +299,9 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false // prefer option over default if ( !empty( $permastruct ) ) { $permalink = $permastruct; - } - elseif ( isset( $post_type->rewrite[ 'permastruct' ] ) && ! empty( $post_type->rewrite[ 'permastruct' ] ) ) { + } elseif ( isset( $post_type->rewrite[ 'permastruct' ] ) && ! empty( $post_type->rewrite[ 'permastruct' ] ) ) { $permalink = $post_type->rewrite[ 'permastruct' ]; - } - else { + } else { return $post_link; } @@ -377,8 +373,7 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false } $permalink = home_url( str_replace( $rewritecode, $rewritereplace, $permalink ) ); $permalink = user_trailingslashit( $permalink, 'single' ); - } - else { // if they're not using the fancy permalink option + } else { // if they're not using the fancy permalink option $permalink = home_url( '?p=' . $post->ID ); } @@ -417,8 +412,7 @@ function get_term_parents( if ( $nicename ) { $name = $parent->slug; - } - else { + } else { $name = $parent->cat_name; } @@ -429,8 +423,7 @@ function get_term_parents( if ( $link ) { $chain .= '' . $name . '' . $separator; - } - else { + } else { $chain .= $name . $separator; } From e5c871b4e174ada16e997b81e725ef66b7f4bc04 Mon Sep 17 00:00:00 2001 From: Robert O'Rourke Date: Tue, 23 Jan 2024 16:18:42 +0000 Subject: [PATCH 13/17] bump version --- wp-permastructure.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index 6dc7f94..9ef5403 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -3,7 +3,7 @@ Plugin Name: WP Permastructure Plugin URI: https://github.com/interconnectit/wp-permastructure Description: Adds the ability to define permalink structures for any custom post type using rewrite tags. -Version: 1.4.4 +Version: 1.5.0 Author: Robert O'Rourke Author URI: http://interconnectit.com License: GPLv2 or later @@ -297,7 +297,7 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false } // prefer option over default - if ( !empty( $permastruct ) ) { + if ( ! empty( $permastruct ) ) { $permalink = $permastruct; } elseif ( isset( $post_type->rewrite[ 'permastruct' ] ) && ! empty( $post_type->rewrite[ 'permastruct' ] ) ) { $permalink = $post_type->rewrite[ 'permastruct' ]; @@ -307,7 +307,7 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false $permalink = apply_filters( 'pre_post_link', $permalink, $post, $leavename ); - if ( '' != $permalink && !in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ) ) ) { + if ( '' !== $permalink && ! in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ) ) ) { $unixtime = strtotime( $post->post_date ); // add ability to use any taxonomies in post type permastruct From 6dfcf95cae11f07cebc9245b7cc2989d29ab0182 Mon Sep 17 00:00:00 2001 From: Robert O'Rourke Date: Tue, 23 Jan 2024 16:29:42 +0000 Subject: [PATCH 14/17] Add composer file --- composer.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 composer.json diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..f1d68ac --- /dev/null +++ b/composer.json @@ -0,0 +1,13 @@ +{ + "name": "humanmade/wp-permastructure", + "description": "Post type rewrite features for WordPress", + "type": "wordpress-plugin", + "license": "GPL-2.0-or-later", + "authors": [ + { + "name": "Robert O'Rourke", + "email": "rob@humanmade.com" + } + ], + "require": {} +} From 16baa176e0f7715e5ce7a87b60cb0aca9b54e25e Mon Sep 17 00:00:00 2001 From: Robert O'Rourke <23417+roborourke@users.noreply.github.com> Date: Tue, 23 Jan 2024 16:41:48 +0000 Subject: [PATCH 15/17] Remove class exists check, as it'll be true regardless --- wp-permastructure.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index 9ef5403..75c7d4b 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -3,7 +3,7 @@ Plugin Name: WP Permastructure Plugin URI: https://github.com/interconnectit/wp-permastructure Description: Adds the ability to define permalink structures for any custom post type using rewrite tags. -Version: 1.5.0 +Version: 1.5.1 Author: Robert O'Rourke Author URI: http://interconnectit.com License: GPLv2 or later @@ -38,10 +38,6 @@ * 1.0: Initial import */ -if ( class_exists( 'wp_permastructure' ) ) { - return; -} - add_action( 'init', array( 'wp_permastructure', 'instance' ), 0 ); class wp_permastructure { From 9dc26703bb8be64bbef606e6fb6d74291670a0a0 Mon Sep 17 00:00:00 2001 From: Robert O'Rourke <23417+roborourke@users.noreply.github.com> Date: Wed, 24 Jan 2024 12:54:53 +0000 Subject: [PATCH 16/17] Specificity support and term hierarchy control --- wp-permastructure.php | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index 75c7d4b..1066a91 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -3,7 +3,7 @@ Plugin Name: WP Permastructure Plugin URI: https://github.com/interconnectit/wp-permastructure Description: Adds the ability to define permalink structures for any custom post type using rewrite tags. -Version: 1.5.1 +Version: 1.6.0 Author: Robert O'Rourke Author URI: http://interconnectit.com License: GPLv2 or later @@ -31,6 +31,8 @@ /** * Changelog * + * 1.6: Sort permastructs by length for specifity, allow filtering whether to expand hierarchical terms + * 1.5: Ensure rewrites prefixed with taxonomies are checked before the taxonomies themselves * 1.4: Handles sample filters without the need for the get post call * 1.3: Fixed permalink sanitisation, was truncating the third placeholder for some reason * 1.2: Fixed attachment URL rewrites, fixed edge case where permastruct is %postname% only @@ -211,6 +213,11 @@ public function add_permastructs( $rules ) { $permastructs[ $type->rewrite[ 'permastruct' ] ][] = $type->name; } + // Sort permastructs by longest to shortest, e.g. higher specificity to lower. + uksort( $permastructs, function ( $a, $b ) { + return mb_strlen( $b ) <=> mb_strlen( $a ); + } ); + $rules = array(); // add our permastructs scoped to the post types - overwriting any keys that already exist @@ -225,7 +232,7 @@ public function add_permastructs( $rules ) { $post_type_rules_temp = $wp_rewrite->generate_rewrite_rules( $struct, EP_PERMALINK, false, true, false, false, true ); foreach ( $post_type_rules_temp as $regex => $query ) { if ( preg_match( '/(&|\?)(cpage|attachment|p|name|pagename)=/', $query ) ) { - $post_type_query = ( count( $post_types ) < 2 ? '&post_type=' . $post_types[ 0 ] : '&post_type[]=' . join( '&post_type[]=', array_unique( $post_types ) ) ); + $post_type_query = ( count( $post_types ) < 2 ? '&post_type=' . $post_types[0] : '&post_type[]=' . join( '&post_type[]=', array_unique( $post_types ) ) ); $rules[ $regex ] = $query . ( preg_match( '/(&|\?)(attachment|pagename)=/', $query ) ? '' : $post_type_query ); // Ensure permalinks that match a custom taxonomy path don't get swallowed. $wp_rewrite->extra_rules_top[ $regex ] = $rules[ $regex ]; @@ -314,11 +321,8 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false if ( strpos( $permalink, '%' . $taxonomy . '%' ) !== false ) { $terms = get_the_terms( $post->ID, $taxonomy ); if ( $terms && ! is_wp_error( $terms ) ) { - if ( function_exists( 'wp_list_sort' ) ) { - $terms = wp_list_sort( $terms, 'term_id', 'ASC' ); // order by term_id ASC - } else { - usort( $terms, '_usort_terms_by_ID' ); // order by term_id ASC - } + // order by term_id ASC. + $terms = wp_list_sort( $terms, 'term_id', 'ASC' ); /** * Filter the term that gets used in the `$tax` permalink token. @@ -329,8 +333,17 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false */ $term_object = apply_filters( "post_link_{$taxonomy}", reset( $terms ), $terms, $post ); + /** + * Filter whether to expand child term paths. + * + * @param bool $allow_hierarchy Whether to expand child terms to include term parents. + * @param WP_Term $term Current term object selected. + * @param WP_Post $post The post in question. + */ + $allow_hierarchy = apply_filters( "post_link_{$taxonomy}_allow_hierarchy", $taxonomy_object->hierarchical, $term_object, $post ); + $term = $term_object->slug; - if ( $taxonomy_object->hierarchical && $parent = $term_object->parent ) { + if ( $allow_hierarchy && $parent = $term_object->parent ) { $term = get_term_parents( $parent, $taxonomy, false, '/', true ) . $term; } } From 1f7d68bac4c11807aa0097f5e1b83a88715bd85c Mon Sep 17 00:00:00 2001 From: Robert O'Rourke <23417+roborourke@users.noreply.github.com> Date: Thu, 8 Feb 2024 13:21:27 +0000 Subject: [PATCH 17/17] Fix custom post type previews --- wp-permastructure.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/wp-permastructure.php b/wp-permastructure.php index 1066a91..5c0eaf2 100644 --- a/wp-permastructure.php +++ b/wp-permastructure.php @@ -3,7 +3,7 @@ Plugin Name: WP Permastructure Plugin URI: https://github.com/interconnectit/wp-permastructure Description: Adds the ability to define permalink structures for any custom post type using rewrite tags. -Version: 1.6.0 +Version: 1.6.1 Author: Robert O'Rourke Author URI: http://interconnectit.com License: GPLv2 or later @@ -310,7 +310,10 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false $permalink = apply_filters( 'pre_post_link', $permalink, $post, $leavename ); - if ( '' !== $permalink && ! in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ) ) ) { + if ( + '' !== $permalink + && ! wp_force_plain_post_permalink( $post, $sample ) + ) { $unixtime = strtotime( $post->post_date ); // add ability to use any taxonomies in post type permastruct @@ -382,8 +385,9 @@ public function parse_permalinks( $post_link, $post, $leavename, $sample = false } $permalink = home_url( str_replace( $rewritecode, $rewritereplace, $permalink ) ); $permalink = user_trailingslashit( $permalink, 'single' ); - } else { // if they're not using the fancy permalink option - $permalink = home_url( '?p=' . $post->ID ); + } else { + // If they're not using the fancy permalink option or it's forced to be plain. + $permalink = $post_link; } return $permalink;