initial
This commit is contained in:
@@ -0,0 +1,775 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) exit;
|
||||
|
||||
/**
|
||||
* Additional hooks for "Permalink Manager Pro"
|
||||
*/
|
||||
class Permalink_Manager_Actions {
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'admin_init', array( $this, 'trigger_action' ), 9 );
|
||||
add_action( 'admin_init', array( $this, 'extra_actions' ) );
|
||||
|
||||
// Ajax-based functions
|
||||
if ( is_admin() ) {
|
||||
add_action( 'wp_ajax_pm_bulk_tools', array( $this, 'ajax_bulk_tools' ) );
|
||||
add_action( 'wp_ajax_pm_save_permalink', array( $this, 'ajax_save_permalink' ) );
|
||||
add_action( 'wp_ajax_pm_detect_duplicates', array( $this, 'ajax_detect_duplicates' ) );
|
||||
add_action( 'wp_ajax_pm_dismissed_notice_handler', array( $this, 'ajax_hide_global_notice' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Route the requests to functions that save datasets with associated callbacks
|
||||
*/
|
||||
public function trigger_action() {
|
||||
global $permalink_manager_after_sections_html;
|
||||
|
||||
// 1. Check if the form was submitted
|
||||
if ( empty( $_POST ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Do nothing if search query is not empty
|
||||
if ( isset( $_POST['uri_editor_nonce'] ) && ( isset( $_REQUEST['search-submit'] ) || isset( $_REQUEST['filter-button'] ) ) ) {
|
||||
$this->trigger_filter_action();
|
||||
}
|
||||
|
||||
$actions_map = array(
|
||||
'uri_editor_nonce' => array( 'function' => 'update_all_permalinks', 'display_uri_table' => true ),
|
||||
'permalink_manager_options' => array( 'function' => 'save_settings' ),
|
||||
'permalink_manager_permastructs' => array( 'function' => 'save_permastructures' ),
|
||||
'import' => array( 'function' => 'import_custom_permalinks_uris' ),
|
||||
);
|
||||
|
||||
// 3. Find the action
|
||||
foreach ( $actions_map as $action => $map ) {
|
||||
$nonce = ( isset( $_POST[ $action ] ) ) ? sanitize_key( $_POST[ $action ] ) : '';
|
||||
|
||||
if ( ! empty( $nonce ) && wp_verify_nonce( $nonce, 'permalink-manager' ) ) {
|
||||
// Execute the function
|
||||
$output = call_user_func( array( $this, $map['function'] ) );
|
||||
|
||||
// Get list of updated URIs
|
||||
if ( ! empty( $map['display_uri_table'] ) ) {
|
||||
$updated_slugs_count = ( isset( $output['updated_count'] ) && $output['updated_count'] > 0 ) ? $output['updated_count'] : false;
|
||||
$updated_slugs_array = ( $updated_slugs_count ) ? $output['updated'] : '';
|
||||
}
|
||||
|
||||
// Trigger only one function
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Display the slugs table (and append the globals)
|
||||
if ( isset( $updated_slugs_count ) && isset( $updated_slugs_array ) ) {
|
||||
$permalink_manager_after_sections_html .= Permalink_Manager_UI_Elements::display_updated_slugs( $updated_slugs_array );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the Bulk URI Editor filter URL
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function trigger_filter_action() {
|
||||
if ( empty( $_POST['uri_editor_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['uri_editor_nonce'] ), 'permalink-manager' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$query_args = array(
|
||||
'langcode' => ! empty( $_REQUEST['langcode'] ) ? sanitize_key( $_REQUEST['langcode'] ) : null,
|
||||
'month' => ! empty( $_REQUEST['month'] ) ? sanitize_key( $_REQUEST['month'] ) : null,
|
||||
's' => ! empty( $_REQUEST['s'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ) : null,
|
||||
);
|
||||
|
||||
if ( ! empty( $query_args ) ) {
|
||||
$sendback = remove_query_arg( array_keys( $query_args ), wp_get_referer() );
|
||||
$sendback = add_query_arg( array_filter( $query_args ), $sendback );
|
||||
|
||||
wp_safe_redirect( $sendback );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Route the requests to the additional tools-related functions with the relevant callbacks
|
||||
*/
|
||||
public static function extra_actions() {
|
||||
global $permalink_manager_before_sections_html;
|
||||
|
||||
if ( current_user_can( 'manage_options' ) && ! empty( $_GET['permalink-manager-nonce'] ) ) {
|
||||
// Check if the nonce field is correct
|
||||
$nonce = sanitize_key( $_GET['permalink-manager-nonce'] );
|
||||
|
||||
if ( ! wp_verify_nonce( $nonce, 'permalink-manager' ) ) {
|
||||
$permalink_manager_before_sections_html = Permalink_Manager_UI_Elements::get_alert_message( __( 'You are not allowed to remove Permalink Manager data!', 'permalink-manager' ), 'error updated_slugs' );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( isset( $_GET['clear-permalink-manager-uris'] ) ) {
|
||||
self::clear_all_uris();
|
||||
} else if ( isset( $_GET['remove-permalink-manager-settings'] ) ) {
|
||||
$option_name = sanitize_key( $_GET['remove-permalink-manager-settings'] );
|
||||
self::remove_plugin_data( $option_name );
|
||||
} else if ( ! empty( $_REQUEST['remove-uri'] ) ) {
|
||||
$uri_key = sanitize_key( $_REQUEST['remove-uri'] );
|
||||
self::force_clear_single_element_uris_and_redirects( $uri_key );
|
||||
} else if ( ! empty( $_REQUEST['remove-redirect'] ) ) {
|
||||
$redirect_key = sanitize_key( $_REQUEST['remove-redirect'] );
|
||||
self::force_clear_single_redirect( $redirect_key );
|
||||
}
|
||||
} else if ( ! empty( $_POST['screen-options-apply'] ) ) {
|
||||
self::save_screen_options();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk remove obsolete custom permalinks and redirects
|
||||
*/
|
||||
public static function clear_all_uris() {
|
||||
global $permalink_manager_redirects, $permalink_manager_before_sections_html;
|
||||
|
||||
// Get all custom permalinks & redirects
|
||||
$custom_permalinks = Permalink_Manager_URI_Functions::get_all_uris();
|
||||
$custom_redirects = (array) $permalink_manager_redirects;
|
||||
|
||||
// Check if array with custom URIs exists
|
||||
if ( empty( $custom_permalinks ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Count removed URIs & redirects
|
||||
$removed_uris = 0;
|
||||
$removed_redirects = 0;
|
||||
|
||||
// Get all element IDs
|
||||
$element_ids = array_merge( array_keys( $custom_permalinks ), array_keys( $custom_redirects ) );
|
||||
|
||||
// 1. Remove unused custom URI & redirects for deleted post or term
|
||||
foreach ( $element_ids as $element_id ) {
|
||||
$count = self::clear_single_element_uris_and_redirects( $element_id, true );
|
||||
|
||||
$removed_uris = ( ! empty( $count[0] ) ) ? $count[0] + $removed_uris : $removed_uris;
|
||||
$removed_redirects = ( ! empty( $count[1] ) ) ? $count[1] + $removed_redirects : $removed_redirects;
|
||||
}
|
||||
|
||||
// 2. Keep only a single redirect
|
||||
$removed_redirects += self::clear_redirects_array();
|
||||
|
||||
// 3. Save cleared URIs & Redirects
|
||||
if ( $removed_uris > 0 || $removed_redirects > 0 ) {
|
||||
Permalink_Manager_URI_Functions::save_all_uris();
|
||||
update_option( 'permalink-manager-redirects', array_filter( $permalink_manager_redirects ) );
|
||||
|
||||
// Translators: 1: Number of custom URIs, 2: Number of custom redirects.
|
||||
$permalink_manager_before_sections_html .= Permalink_Manager_UI_Elements::get_alert_message( sprintf( __( '%1$d Custom URIs and %2$d Custom Redirects were removed!', 'permalink-manager' ), $removed_uris, $removed_redirects ), 'updated updated_slugs' );
|
||||
} else {
|
||||
$permalink_manager_before_sections_html .= Permalink_Manager_UI_Elements::get_alert_message( __( 'No Custom URIs or Custom Redirects were removed!', 'permalink-manager' ), 'error updated_slugs' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove obsolete custom permalink & redirects for specific post or term
|
||||
*
|
||||
* @param string|int $element_id
|
||||
* @param bool $count_removed
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function clear_single_element_uris_and_redirects( $element_id, $count_removed = false ) {
|
||||
global $wpdb, $permalink_manager_redirects, $permalink_manager_options;
|
||||
|
||||
// Count removed URIs & redirects
|
||||
$removed_uris = 0;
|
||||
$removed_redirects = 0;
|
||||
|
||||
// Only admin users can remove the broken URIs for removed post types & taxonomies
|
||||
$check_if_admin = is_admin();
|
||||
|
||||
// Check if the advanced mode is turned on
|
||||
$advanced_mode = Permalink_Manager_Helper_Functions::is_advanced_mode_on();
|
||||
|
||||
// If "Disable URI Editor to disallow Permalink changes" is set globally, the pages that follow the global settings should also be removed
|
||||
if ( $advanced_mode && ! empty( $permalink_manager_options["general"]["auto_update_uris"] ) && $permalink_manager_options["general"]["auto_update_uris"] == 2 ) {
|
||||
$strict_mode = true;
|
||||
} else {
|
||||
$strict_mode = false;
|
||||
}
|
||||
|
||||
// 1. Check if element exists
|
||||
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Direct SQL query is needed to join multiple tables
|
||||
if ( strpos( $element_id, 'tax-' ) !== false ) {
|
||||
$term_id = preg_replace( "/[^0-9]/", "", $element_id );
|
||||
$term_info = $wpdb->get_row( $wpdb->prepare( "SELECT taxonomy, meta_value FROM {$wpdb->term_taxonomy} AS t LEFT JOIN {$wpdb->termmeta} AS tm ON tm.term_id = t.term_id AND tm.meta_key = 'auto_update_uri' WHERE t.term_id = %d", $term_id ) );
|
||||
|
||||
// Custom URIs for disabled taxonomies may only be deleted via the admin dashboard, although they will always be removed if the term no longer exists in the database
|
||||
$remove = ( ! empty( $term_info->taxonomy ) ) ? Permalink_Manager_Helper_Functions::is_taxonomy_disabled( $term_info->taxonomy, $check_if_admin ) : true;
|
||||
|
||||
// Remove custom URIs for URIs disabled in URI Editor
|
||||
if ( $strict_mode ) {
|
||||
$remove = ( empty( $term_info->meta_value ) || $term_info->meta_value == 2 ) ? true : $remove;
|
||||
} else {
|
||||
$remove = ( ! empty( $term_info->meta_value ) && $term_info->meta_value == 2 ) ? true : $remove;
|
||||
}
|
||||
} else if ( is_numeric( $element_id ) ) {
|
||||
$post_info = $wpdb->get_row( $wpdb->prepare( "SELECT post_type, meta_value FROM {$wpdb->posts} AS p LEFT JOIN {$wpdb->postmeta} AS pm ON pm.post_ID = p.ID AND pm.meta_key = 'auto_update_uri' WHERE ID = %d AND post_status NOT IN ('auto-draft', 'trash') AND post_type != 'nav_menu_item'", $element_id ) );
|
||||
|
||||
// Custom URIs for disabled post types may only be deleted via the admin dashboard, although they will always be removed if the post no longer exists in the database
|
||||
$remove = ( ! empty( $post_info->post_type ) ) ? Permalink_Manager_Helper_Functions::is_post_type_disabled( $post_info->post_type, $check_if_admin ) : true;
|
||||
|
||||
// Remove custom URIs for URIs disabled in URI Editor
|
||||
if ( $strict_mode ) {
|
||||
$remove = ( empty( $post_info->meta_value ) || $post_info->meta_value == 2 ) ? true : $remove;
|
||||
} else {
|
||||
$remove = ( ! empty( $post_info->meta_value ) && $post_info->meta_value == 2 ) ? true : $remove;
|
||||
}
|
||||
|
||||
// Remove custom URIs for attachments redirected with Yoast's SEO Premium
|
||||
$yoast_permalink_options = ( class_exists( 'WPSEO_Premium' ) ) ? get_option( 'wpseo_permalinks' ) : array();
|
||||
|
||||
if ( ! empty( $yoast_permalink_options['redirectattachment'] ) && $post_info->post_type == 'attachment' ) {
|
||||
$attachment_parent = $wpdb->get_var( $wpdb->prepare( "SELECT post_parent FROM {$wpdb->prefix}posts WHERE ID = %d AND post_type = %s", $element_id, 'attachment' ) );
|
||||
if ( ! empty( $attachment_parent ) ) {
|
||||
$remove = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
||||
|
||||
// 2A. Remove ALL unused custom permalinks & redirects
|
||||
if ( ! empty( $remove ) ) {
|
||||
$current_uri = Permalink_Manager_URI_Functions::get_single_uri( $element_id, false, true, null );
|
||||
|
||||
// Remove URI
|
||||
if ( ! empty( $current_uri ) ) {
|
||||
$removed_uris = 1;
|
||||
Permalink_Manager_URI_Functions::remove_single_uri( $element_id, null, false );
|
||||
}
|
||||
|
||||
// Remove all custom redirects
|
||||
if ( ! empty( $permalink_manager_redirects[ $element_id ] ) && is_array( $permalink_manager_redirects[ $element_id ] ) ) {
|
||||
$removed_redirects = count( $permalink_manager_redirects[ $element_id ] );
|
||||
unset( $permalink_manager_redirects[ $element_id ] );
|
||||
}
|
||||
} // 2B. Check if the post/term uses the same URI for both permalink & custom redirects
|
||||
else {
|
||||
$removed_redirect = self::clear_single_element_duplicated_redirect( $element_id, false );
|
||||
$removed_redirects = ( ! empty( $removed_redirect ) ) ? 1 : 0;
|
||||
}
|
||||
|
||||
// Check if function should only return the counts or update
|
||||
if ( $count_removed ) {
|
||||
return array( $removed_uris, $removed_redirects );
|
||||
} else if ( ! empty( $removed_uris ) || ! empty( $removed_redirects ) ) {
|
||||
Permalink_Manager_URI_Functions::save_all_uris();
|
||||
update_option( 'permalink-manager-redirects', array_filter( $permalink_manager_redirects ) );
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the duplicated custom redirect if the post/term has the same URI for both custom permalink and custom redirect
|
||||
*
|
||||
* @param string|int $element_id
|
||||
* @param bool $save_redirects
|
||||
* @param string $uri
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function clear_single_element_duplicated_redirect( $element_id, $save_redirects = true, $uri = null ) {
|
||||
global $permalink_manager_redirects;
|
||||
|
||||
// If the custom permalink is not changed ($uri) use the one that is currently used
|
||||
if ( ! empty( $uri ) ) {
|
||||
$current_uri = $uri;
|
||||
} else {
|
||||
$current_uri = Permalink_Manager_URI_Functions::get_single_uri( $element_id, false, true, null );
|
||||
}
|
||||
|
||||
if ( ! empty( $current_uri ) && ! empty( $permalink_manager_redirects[ $element_id ] ) && in_array( $current_uri, $permalink_manager_redirects[ $element_id ] ) ) {
|
||||
$duplicated_redirect_id = array_search( $current_uri, $permalink_manager_redirects[ $element_id ] );
|
||||
unset( $permalink_manager_redirects[ $element_id ][ $duplicated_redirect_id ] );
|
||||
}
|
||||
|
||||
// Update the redirects array in the database if the duplicated redirect was unset
|
||||
if ( isset( $duplicated_redirect_id ) && $save_redirects ) {
|
||||
update_option( 'permalink-manager-redirects', array_filter( $permalink_manager_redirects ) );
|
||||
}
|
||||
|
||||
return ( isset( $duplicated_redirect_id ) ) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the duplicated if the same URI is used for multiple custom redirects and return the removed redirects count
|
||||
*
|
||||
* @param bool $save_redirects
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function clear_redirects_array( $save_redirects = false ) {
|
||||
global $permalink_manager_redirects;
|
||||
|
||||
$removed_redirects = 0;
|
||||
|
||||
$all_redirect_duplicates = Permalink_Manager_Admin_Functions::get_all_duplicates();
|
||||
|
||||
foreach ( $all_redirect_duplicates as $single_redirect_duplicate ) {
|
||||
$last_element = reset( $single_redirect_duplicate );
|
||||
|
||||
foreach ( $single_redirect_duplicate as $redirect_key ) {
|
||||
// Keep a single redirect
|
||||
if ( $last_element == $redirect_key ) {
|
||||
continue;
|
||||
}
|
||||
preg_match( "/redirect-(\d+)_(tax-\d+|\d+)/", $redirect_key, $ids );
|
||||
|
||||
if ( ! empty( $ids[2] ) && ! empty( $permalink_manager_redirects[ $ids[2] ][ $ids[1] ] ) ) {
|
||||
$removed_redirects ++;
|
||||
unset( $permalink_manager_redirects[ $ids[2] ][ $ids[1] ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the redirects array in the database if the duplicated redirect was unset
|
||||
if ( isset( $duplicated_redirect_id ) && $save_redirects ) {
|
||||
update_option( 'permalink-manager-redirects', array_filter( $permalink_manager_redirects ) );
|
||||
}
|
||||
|
||||
return $removed_redirects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove custom permalinks & custom redirects for requested post or term
|
||||
*
|
||||
* @param $uri_key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function force_clear_single_element_uris_and_redirects( $uri_key ) {
|
||||
global $permalink_manager_redirects, $permalink_manager_before_sections_html;
|
||||
|
||||
$custom_uri = Permalink_Manager_URI_Functions::get_single_uri( $uri_key, false, true, null );
|
||||
|
||||
// Check if custom URI is set
|
||||
if ( ! empty( $custom_uri ) ) {
|
||||
Permalink_Manager_URI_Functions::remove_single_uri( $uri_key, null, true );
|
||||
// translators: %s is the custom URI that was removed.
|
||||
$updated = Permalink_Manager_UI_Elements::get_alert_message( sprintf( __( 'URI "%s" was removed successfully!', 'permalink-manager' ), $custom_uri ), 'updated' );
|
||||
}
|
||||
|
||||
// Check if custom redirects are set
|
||||
if ( isset( $permalink_manager_redirects[ $uri_key ] ) ) {
|
||||
unset( $permalink_manager_redirects[ $uri_key ] );
|
||||
update_option( 'permalink-manager-redirects', $permalink_manager_redirects );
|
||||
}
|
||||
|
||||
if ( empty( $updated ) ) {
|
||||
$permalink_manager_before_sections_html .= Permalink_Manager_UI_Elements::get_alert_message( __( 'URI and/or custom redirects does not exist or were already removed!', 'permalink-manager' ), 'error' );
|
||||
} else {
|
||||
// Display the alert in admin panel
|
||||
if ( isset( $permalink_manager_before_sections_html ) && is_admin() ) {
|
||||
$permalink_manager_before_sections_html .= $updated;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove only custom redirects for requested post or term
|
||||
*
|
||||
* @param string $redirect_key
|
||||
*/
|
||||
public static function force_clear_single_redirect( $redirect_key ) {
|
||||
global $permalink_manager_redirects, $permalink_manager_before_sections_html;
|
||||
|
||||
preg_match( "/redirect-(\d+)_(tax-\d+|\d+)/", $redirect_key, $ids );
|
||||
|
||||
if ( ! empty( $permalink_manager_redirects[ $ids[2] ][ $ids[1] ] ) ) {
|
||||
unset( $permalink_manager_redirects[ $ids[2] ][ $ids[1] ] );
|
||||
|
||||
update_option( 'permalink-manager-redirects', array_filter( $permalink_manager_redirects ) );
|
||||
|
||||
$permalink_manager_before_sections_html = Permalink_Manager_UI_Elements::get_alert_message( __( 'The redirect was removed successfully!', 'permalink-manager' ), 'updated' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save "Screen Options"
|
||||
*/
|
||||
public static function save_screen_options() {
|
||||
check_admin_referer( 'screen-options-nonce', 'screenoptionnonce' );
|
||||
|
||||
$screen_options = ( isset( $_POST['screen-options'] ) ) ? map_deep( wp_unslash( $_POST['screen-options'] ), 'sanitize_text_field' ) : array();
|
||||
|
||||
if ( ! empty( $screen_options ) ) {
|
||||
self::save_settings( 'screen-options', $screen_options );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the plugin settings
|
||||
*
|
||||
* @param bool $field
|
||||
* @param bool $value
|
||||
* @param bool $display_alert
|
||||
*/
|
||||
public static function save_settings( $field = false, $value = false, $display_alert = true ) {
|
||||
global $permalink_manager_options, $permalink_manager_before_sections_html;
|
||||
|
||||
// Info: The settings array is used also by "Screen Options"
|
||||
$new_options = $permalink_manager_options;
|
||||
|
||||
// Save only selected field/sections
|
||||
if ( $field && $value ) {
|
||||
$new_options[ $field ] = $value;
|
||||
} else {
|
||||
$post_fields = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- The nonce is already validated in enclosing function
|
||||
|
||||
foreach ( $post_fields as $option_name => $option_value ) {
|
||||
$new_options[ $option_name ] = $option_value;
|
||||
}
|
||||
}
|
||||
|
||||
// Allow only white-listed option groups
|
||||
foreach ( $new_options as $group => $group_options ) {
|
||||
if ( ! in_array( $group, array( 'licence', 'screen-options', 'general', 'permastructure-settings', 'stop-words' ) ) ) {
|
||||
unset( $new_options[ $group ] );
|
||||
}
|
||||
}
|
||||
|
||||
// Sanitize & override the global with new settings
|
||||
$new_options = Permalink_Manager_Helper_Functions::sanitize_array( $new_options );
|
||||
$permalink_manager_options = $new_options = array_filter( $new_options );
|
||||
|
||||
// Save the settings in database
|
||||
update_option( 'permalink-manager', $new_options );
|
||||
|
||||
// Display the message
|
||||
$permalink_manager_before_sections_html .= ( $display_alert ) ? Permalink_Manager_UI_Elements::get_alert_message( __( 'The settings are saved!', 'permalink-manager' ), 'updated' ) : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the permastructures
|
||||
*/
|
||||
public static function save_permastructures() {
|
||||
global $permalink_manager_permastructs;
|
||||
|
||||
$permastructure_options = $permastructures = array();
|
||||
$permastructure_types = array( 'post_types', 'taxonomies' );
|
||||
|
||||
// Split permastructures & sanitize them
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- The nonce is already validated in enclosing function
|
||||
foreach ( $permastructure_types as $type ) {
|
||||
if ( empty( $_POST[ $type ] ) || ! is_array( $_POST[ $type ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$permastructures[ $type ] = $_POST[ $type ];
|
||||
|
||||
foreach ( $permastructures[ $type ] as &$single_permastructure ) {
|
||||
$single_permastructure = Permalink_Manager_Helper_Functions::sanitize_title( $single_permastructure, true, false, false );
|
||||
$single_permastructure = trim( $single_permastructure, '\/ ' );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $_POST['permastructure-settings'] ) ) {
|
||||
$permastructure_options = $_POST['permastructure-settings'];
|
||||
}
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
|
||||
// A. Permastructures
|
||||
if ( ! empty( $permastructures['post_types'] ) || ! empty( $permastructures['taxonomies'] ) ) {
|
||||
// Override the global with settings
|
||||
$permalink_manager_permastructs = $permastructures;
|
||||
|
||||
// Save the settings in database
|
||||
update_option( 'permalink-manager-permastructs', $permastructures );
|
||||
}
|
||||
|
||||
// B. Permastructure settings
|
||||
if ( ! empty( $permastructure_options ) ) {
|
||||
self::save_settings( 'permastructure-settings', $permastructure_options );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all permalinks in "Bulk URI Editor"
|
||||
*/
|
||||
function update_all_permalinks() {
|
||||
// Check if posts or terms should be updated
|
||||
if ( ! empty( $_POST['content_type'] ) && $_POST['content_type'] == 'taxonomies' ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- The nonce is already validated in enclosing function
|
||||
return Permalink_Manager_URI_Functions_Tax::update_all_permalinks();
|
||||
} else {
|
||||
return Permalink_Manager_URI_Functions_Post::update_all_permalinks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a specific section of the plugin data stored in the database
|
||||
*
|
||||
* @param $field_name
|
||||
*/
|
||||
public static function remove_plugin_data( $field_name ) {
|
||||
global $permalink_manager, $permalink_manager_before_sections_html;
|
||||
|
||||
// Make sure that the user is allowed to remove the plugin data
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
$permalink_manager_before_sections_html .= Permalink_Manager_UI_Elements::get_alert_message( __( 'You are not allowed to remove Permalink Manager data!', 'permalink-manager' ), 'error updated_slugs' );
|
||||
}
|
||||
|
||||
switch ( $field_name ) {
|
||||
case 'uris' :
|
||||
$option_name = 'permalink-manager-uris';
|
||||
$alert = __( 'Custom permalinks', 'permalink-manager' );
|
||||
break;
|
||||
case 'redirects' :
|
||||
$option_name = 'permalink-manager-redirects';
|
||||
$alert = __( 'Custom redirects', 'permalink-manager' );
|
||||
break;
|
||||
case 'external-redirects' :
|
||||
$option_name = 'permalink-manager-external-redirects';
|
||||
$alert = __( 'External redirects', 'permalink-manager' );
|
||||
break;
|
||||
case 'permastructs' :
|
||||
$option_name = 'permalink-manager-permastructs';
|
||||
$alert = __( 'Permastructure settings', 'permalink-manager' );
|
||||
break;
|
||||
case 'settings' :
|
||||
$option_name = 'permalink-manager';
|
||||
$alert = __( 'Permastructure settings', 'permalink-manager' );
|
||||
break;
|
||||
default :
|
||||
$alert = '';
|
||||
}
|
||||
|
||||
if ( ! empty( $option_name ) ) {
|
||||
// Remove the option from DB
|
||||
delete_option( $option_name );
|
||||
|
||||
// Reload globals
|
||||
$permalink_manager->get_options_and_globals();
|
||||
|
||||
// Translators: %s is the name of the data field that was removed
|
||||
$alert_message = sprintf( __( '%s were removed!', 'permalink-manager' ), $alert );
|
||||
$permalink_manager_before_sections_html .= Permalink_Manager_UI_Elements::get_alert_message( $alert_message, 'updated updated_slugs' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger bulk tools ("Regenerate & reset", "Find & replace") via AJAX
|
||||
*/
|
||||
function ajax_bulk_tools() {
|
||||
global $sitepress, $wpdb;
|
||||
|
||||
// Define variables
|
||||
$return = array( 'alert' => Permalink_Manager_UI_Elements::get_alert_message( __( '<strong>No items</strong> were processed!', 'permalink-manager' ), 'error updated_slugs' ) );
|
||||
|
||||
// Get the name of the function
|
||||
if ( isset( $_POST['regenerate'] ) ) {
|
||||
$nonce_name = sanitize_key( $_POST['regenerate'] );
|
||||
$operation = 'regenerate';
|
||||
} else if ( isset( $_POST['find_and_replace'] ) ) {
|
||||
$nonce_name = sanitize_key( $_POST['find_and_replace'] );
|
||||
$operation = ( ! empty( $_POST['old_string'] ) && ! empty( $_POST['new_string'] ) ) ? 'find_and_replace' : '';
|
||||
}
|
||||
|
||||
// Validate the nonce
|
||||
if ( empty( $nonce_name ) || ! wp_verify_nonce( $nonce_name, 'permalink-manager' ) ) {
|
||||
$error = true;
|
||||
$return = array( 'alert' => Permalink_Manager_UI_Elements::get_alert_message( __( 'Nonce is invalid!', 'permalink-manager' ), 'error updated_slugs' ) );
|
||||
}
|
||||
|
||||
// Get the session ID
|
||||
$uniq_id = ( ! empty( $_POST['pm_session_id'] ) ) ? sanitize_key( $_POST['pm_session_id'] ) : '';
|
||||
|
||||
// Get content type & post statuses
|
||||
if ( ! empty( $_POST['content_type'] ) && $_POST['content_type'] == 'taxonomies' ) {
|
||||
$content_type = 'taxonomies';
|
||||
|
||||
if ( empty( $_POST['taxonomies'] ) ) {
|
||||
$error = true;
|
||||
$return = array( 'alert' => Permalink_Manager_UI_Elements::get_alert_message( __( '<strong>No taxonomy</strong> selected!', 'permalink-manager' ), 'error updated_slugs' ) );
|
||||
}
|
||||
} else {
|
||||
$content_type = 'post_types';
|
||||
|
||||
// Check if any post type was selected
|
||||
if ( empty( $_POST['post_types'] ) ) {
|
||||
$error = true;
|
||||
$return = array( 'alert' => Permalink_Manager_UI_Elements::get_alert_message( __( '<strong>No post type</strong> selected!', 'permalink-manager' ), 'error updated_slugs' ) );
|
||||
}
|
||||
|
||||
// Check post status
|
||||
if ( empty( $_POST['post_statuses'] ) ) {
|
||||
$error = true;
|
||||
$return = array( 'alert' => Permalink_Manager_UI_Elements::get_alert_message( __( '<strong>No post status</strong> selected!', 'permalink-manager' ), 'error updated_slugs' ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $operation ) && empty( $error ) ) {
|
||||
// Hotfix for WPML (start)
|
||||
if ( $sitepress ) {
|
||||
remove_filter( 'get_terms_args', array( $sitepress, 'get_terms_args_filter' ), 10 );
|
||||
remove_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ), 1 );
|
||||
remove_filter( 'terms_clauses', array( $sitepress, 'terms_clauses' ), 10 );
|
||||
remove_filter( 'get_pages', array( $sitepress, 'get_pages_adjust_ids' ), 1 );
|
||||
}
|
||||
|
||||
// Get the mode
|
||||
$mode = ( isset( $_POST['mode'] ) ) ? sanitize_key( $_POST['mode'] ) : 'custom_uris';
|
||||
$preview_mode = ( ! empty( $_POST['preview_mode'] ) ) ? true : false;
|
||||
|
||||
// Get items (try to get them from transient)
|
||||
$items = get_transient( "pm_{$uniq_id}" );
|
||||
|
||||
// Get the iteration count and chunk size
|
||||
$iteration = isset( $_POST['iteration'] ) ? intval( $_POST['iteration'] ) : 1;
|
||||
$chunk_size = apply_filters( 'permalink_manager_chunk_size', 50 );
|
||||
|
||||
if ( empty( $items ) && ! empty ( $chunk_size ) ) {
|
||||
if ( $content_type == 'taxonomies' ) {
|
||||
$items = Permalink_Manager_URI_Functions_Tax::get_items();
|
||||
} else {
|
||||
$items = Permalink_Manager_URI_Functions_Post::get_items();
|
||||
}
|
||||
|
||||
if ( ! empty( $items ) ) {
|
||||
// Count how many items need to be processed
|
||||
$total = count( $items );
|
||||
|
||||
// Split items array into chunks and save them to transient
|
||||
$items = array_chunk( $items, $chunk_size );
|
||||
|
||||
set_transient( "pm_{$uniq_id}", $items, 600 );
|
||||
|
||||
// Check for MySQL errors
|
||||
if ( ! empty( $wpdb->last_error ) ) {
|
||||
printf( '%s (%sMB)', esc_html( $wpdb->last_error ), esc_html( number_format( strlen( serialize( $items ) ) / 1000000, 2 ) ) );
|
||||
http_response_code( 500 );
|
||||
die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get homepage URL and ensure that it ends with slash
|
||||
$home_url = Permalink_Manager_Permastructure_Functions::get_permalink_base() . "/";
|
||||
|
||||
// Process the variables from $_POST object
|
||||
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- The escaped slashes can be a part of REGEX formula
|
||||
$old_string = ( ! empty( $_POST['old_string'] ) ) ? str_replace( $home_url, '', esc_sql( sanitize_text_field( $_POST['old_string'] ) ) ) : '';
|
||||
$new_string = ( ! empty( $_POST['new_string'] ) ) ? str_replace( $home_url, '', esc_sql( sanitize_text_field( $_POST['new_string'] ) ) ) : '';
|
||||
// phpcs:enable WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
||||
|
||||
// Process only one subarray
|
||||
if ( ! empty( $items[ $iteration - 1 ] ) ) {
|
||||
$chunk = $items[ $iteration - 1 ];
|
||||
|
||||
// Check how many iterations are needed
|
||||
$total_iterations = count( $items );
|
||||
|
||||
if ( $content_type == 'taxonomies' ) {
|
||||
$output = Permalink_Manager_URI_Functions_Tax::bulk_process_items( $chunk, $mode, $operation, $old_string, $new_string, $preview_mode );
|
||||
} else {
|
||||
$output = Permalink_Manager_URI_Functions_Post::bulk_process_items( $chunk, $mode, $operation, $old_string, $new_string, $preview_mode );
|
||||
}
|
||||
|
||||
if ( ! empty( $output['updated_count'] ) ) {
|
||||
$return = array_merge( $return, (array) Permalink_Manager_UI_Elements::display_updated_slugs( $output['updated'], true, true, $preview_mode ) );
|
||||
$return['updated_count'] = $output['updated_count'];
|
||||
}
|
||||
|
||||
// Send total number of processed items with a first chunk
|
||||
if ( ! empty( $total ) && ! empty( $total_iterations ) && $iteration == 1 ) {
|
||||
$return['total'] = $total;
|
||||
$return['items'] = $items;
|
||||
}
|
||||
|
||||
$return['iteration'] = $iteration;
|
||||
$return['total_iterations'] = $total_iterations;
|
||||
$return['progress'] = $chunk_size * $iteration;
|
||||
$return['chunk'] = $chunk;
|
||||
|
||||
// After all chunks are processed remove the transient
|
||||
if ( $iteration == $total_iterations ) {
|
||||
delete_transient( "pm_{$uniq_id}" );
|
||||
}
|
||||
}
|
||||
|
||||
// Hotfix for WPML (end)
|
||||
if ( $sitepress ) {
|
||||
add_filter( 'terms_clauses', array( $sitepress, 'terms_clauses' ), 10, 4 );
|
||||
add_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ), 1, 1 );
|
||||
add_filter( 'get_terms_args', array( $sitepress, 'get_terms_args_filter' ), 10, 2 );
|
||||
add_filter( 'get_pages', array( $sitepress, 'get_pages_adjust_ids' ), 1, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
wp_send_json( $return );
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save permalink via AJAX
|
||||
*/
|
||||
public function ajax_save_permalink() {
|
||||
$element_id = ( ! empty( $_POST['permalink-manager-edit-uri-element-id'] ) ) ? sanitize_key( $_POST['permalink-manager-edit-uri-element-id'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is validated inside update_post_hook
|
||||
|
||||
if ( ! empty( $element_id ) && is_numeric( $element_id ) && current_user_can( 'edit_post', $element_id ) ) {
|
||||
Permalink_Manager_URI_Functions_Post::update_post_hook( $element_id );
|
||||
|
||||
// Reload URI Editor & clean post cache
|
||||
clean_post_cache( $element_id );
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if URI was used before
|
||||
*/
|
||||
function ajax_detect_duplicates() {
|
||||
$duplicate_alert = __( "Permalink is already in use, please select another one!", "permalink-manager" );
|
||||
$duplicates_data = array();
|
||||
$custom_uris = ( ! empty( $_REQUEST['custom_uris'] ) ) ? Permalink_Manager_Helper_Functions::sanitize_array( $_REQUEST['custom_uris'] ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended -- No data is saved here
|
||||
|
||||
if ( ! empty( $custom_uris ) ) {
|
||||
// Check each URI
|
||||
foreach ( $custom_uris as $raw_element_id => $element_uri ) {
|
||||
$element_id = sanitize_key( $raw_element_id );
|
||||
$duplicates_data[ $element_id ] = Permalink_Manager_URI_Functions::is_uri_duplicated( $element_uri, $element_id ) ? $duplicate_alert : 0;
|
||||
}
|
||||
} else if ( ! empty( $_REQUEST['custom_uri'] ) && ! empty( $_REQUEST['element_id'] ) ) {
|
||||
$duplicates_data = Permalink_Manager_URI_Functions::is_uri_duplicated( $_REQUEST['custom_uri'], sanitize_key( $_REQUEST['element_id'] ) );
|
||||
}
|
||||
|
||||
wp_send_json( $duplicates_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide global notices (AJAX)
|
||||
*/
|
||||
function ajax_hide_global_notice() {
|
||||
global $permalink_manager_alerts;
|
||||
|
||||
// Get the ID of the alert
|
||||
$alert_id = ( ! empty( $_REQUEST['alert_id'] ) ) ? sanitize_title( $_REQUEST['alert_id'] ) : "";
|
||||
if ( ! empty( $permalink_manager_alerts[ $alert_id ] ) ) {
|
||||
$dismissed_transient_name = sprintf( 'permalink-manager-notice_%s', $alert_id );
|
||||
$dismissed_time = ( ! empty( $permalink_manager_alerts[ $alert_id ]['dismissed_time'] ) ) ? (int) $permalink_manager_alerts[ $alert_id ]['dismissed_time'] : DAY_IN_SECONDS;
|
||||
|
||||
set_transient( $dismissed_transient_name, 1, $dismissed_time );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Import old URIs from "Custom Permalinks" (Pro)
|
||||
*/
|
||||
function import_custom_permalinks_uris() {
|
||||
Permalink_Manager_Third_Parties::import_custom_permalinks_uris();
|
||||
}
|
||||
|
||||
}
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional functions related to WordPress Admin Dashboard UI
|
||||
*/
|
||||
class Permalink_Manager_Admin_Functions {
|
||||
|
||||
public $sections, $active_section, $active_subsection;
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'admin_menu', array( $this, 'add_menu_page' ) );
|
||||
add_action( 'admin_init', array( $this, 'init' ) );
|
||||
add_action( 'admin_bar_menu', array( $this, 'fix_customize_url' ), 41 );
|
||||
|
||||
add_action( 'admin_notices', array( $this, 'display_plugin_notices' ) );
|
||||
add_action( 'admin_notices', array( $this, 'display_global_notices' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks that should be triggered with "admin_init"
|
||||
*/
|
||||
public function init() {
|
||||
// Additional links in "Plugins" page
|
||||
add_filter( "plugin_action_links_" . PERMALINK_MANAGER_BASENAME, array( $this, "plugins_page_links" ) );
|
||||
add_filter( "plugin_row_meta", array( $this, "plugins_page_meta" ), 10, 2 );
|
||||
|
||||
// Detect current section
|
||||
$this->sections = apply_filters( 'permalink_manager_sections', array() );
|
||||
$this->get_current_section();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the native URL for "Customize" button in the admin bar
|
||||
*
|
||||
* @param WP_Admin_Bar $wp_admin_bar
|
||||
*/
|
||||
public function fix_customize_url( $wp_admin_bar ) {
|
||||
global $permalink_manager_ignore_permalink_filters;
|
||||
|
||||
$object = get_queried_object();
|
||||
$customize = $wp_admin_bar->get_node( 'customize' );
|
||||
|
||||
if ( empty( $customize->href ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$permalink_manager_ignore_permalink_filters = true;
|
||||
if ( ! empty( $object->ID ) && is_a( $object, 'WP_Post' ) ) {
|
||||
$new_url = get_permalink( $object->ID );
|
||||
} else if ( ! empty( $object->taxonomy ) && is_a( $object, 'WP_Term' ) ) {
|
||||
$new_url = get_term_link( $object, $object->taxonomy );
|
||||
}
|
||||
$permalink_manager_ignore_permalink_filters = false;
|
||||
|
||||
if ( ! empty( $new_url ) ) {
|
||||
// The original permalink should be already encoded via "utf8_uri_encode()" in "sanitize_title_with_dashes()" function, so there is no need to encode them once again
|
||||
$new_url = filter_var( $new_url, FILTER_SANITIZE_URL );
|
||||
$customize_url = preg_replace( '/url=([^&]+)/', "url={$new_url}", $customize->href );
|
||||
|
||||
$wp_admin_bar->add_node( array(
|
||||
'id' => 'customize',
|
||||
'href' => $customize_url,
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current section of Permalink Manager admin panel
|
||||
*/
|
||||
public function get_current_section() {
|
||||
global $active_section, $active_subsection, $current_admin_tax;
|
||||
|
||||
// 1. Get current section
|
||||
if ( isset( $_GET['page'] ) && $_GET['page'] == PERMALINK_MANAGER_PLUGIN_SLUG ) {
|
||||
if ( isset( $_POST['section'] ) ) {
|
||||
$this->active_section = sanitize_title_with_dashes( $_POST['section'] );
|
||||
} else if ( isset( $_GET['section'] ) ) {
|
||||
$this->active_section = sanitize_title_with_dashes( $_GET['section'] );
|
||||
} else {
|
||||
$sections_names = array_keys( $this->sections );
|
||||
$this->active_section = $sections_names[0];
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Get current subsection
|
||||
if ( $this->active_section && isset( $this->sections[ $this->active_section ]['subsections'] ) ) {
|
||||
if ( isset( $_POST['subsection'] ) ) {
|
||||
$this->active_subsection = sanitize_title_with_dashes( $_POST['subsection'] );
|
||||
} else if ( isset( $_GET['subsection'] ) ) {
|
||||
$this->active_subsection = sanitize_title_with_dashes( $_GET['subsection'] );
|
||||
} else {
|
||||
$subsections_names = array_keys( $this->sections[ $this->active_section ]['subsections'] );
|
||||
$this->active_subsection = $subsections_names[0];
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Check if current admin page is related to taxonomies
|
||||
if ( ! empty( $this->active_subsection ) && substr( $this->active_subsection, 0, 4 ) == 'tax_' ) {
|
||||
$current_admin_tax = substr( $this->active_subsection, 4, strlen( $this->active_subsection ) );
|
||||
} else {
|
||||
$current_admin_tax = false;
|
||||
}
|
||||
|
||||
// Set globals
|
||||
$active_section = $this->active_section;
|
||||
$active_subsection = $this->active_subsection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "Tools -> Permalink Manager" to the admin sidebar menu
|
||||
*/
|
||||
public function add_menu_page() {
|
||||
add_management_page( __( 'Permalink Manager', 'permalink-manager' ), __( 'Permalink Manager', 'permalink-manager' ), 'manage_options', PERMALINK_MANAGER_PLUGIN_SLUG, array( $this, 'display_section' ) );
|
||||
|
||||
add_action( 'admin_init', array( $this, 'enqueue_cssjs' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the plugin sections
|
||||
*/
|
||||
public function display_section() {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo Permalink_Manager_UI_Elements::get_plugin_sections_html( $this->sections, $this->active_section, $this->active_subsection );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the CSS & JS files for the plugin's dashboard
|
||||
*/
|
||||
public function enqueue_cssjs() {
|
||||
wp_enqueue_style( 'permalink-manager-plugins', PERMALINK_MANAGER_URL . '/out/permalink-manager-plugins.css', array(), PERMALINK_MANAGER_VERSION );
|
||||
wp_enqueue_style( 'permalink-manager', PERMALINK_MANAGER_URL . '/out/permalink-manager-admin.css', array( 'permalink-manager-plugins' ), PERMALINK_MANAGER_VERSION );
|
||||
|
||||
wp_enqueue_script( 'permalink-manager-plugins', PERMALINK_MANAGER_URL . '/out/permalink-manager-plugins.js', array( 'jquery', ), PERMALINK_MANAGER_VERSION, array( 'in_footer' => false ) );
|
||||
wp_enqueue_script( 'permalink-manager', PERMALINK_MANAGER_URL . '/out/permalink-manager-admin.js', array( 'jquery', 'permalink-manager-plugins' ), PERMALINK_MANAGER_VERSION, array( 'in_footer' => false ) );
|
||||
|
||||
if ( isset( $_GET['section'] ) && $_GET['section'] === 'permastructs' ) {
|
||||
wp_enqueue_script( 'thickbox' );
|
||||
wp_enqueue_style( 'thickbox' );
|
||||
}
|
||||
|
||||
wp_localize_script( 'permalink-manager', 'permalink_manager', array(
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
'url' => PERMALINK_MANAGER_URL,
|
||||
'confirm' => __( 'Are you sure? This action cannot be undone!', 'permalink-manager' ),
|
||||
'spinners' => admin_url( 'images' )
|
||||
) );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL of the plugin's dashboard
|
||||
*
|
||||
* @param string $append
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_admin_url( $append = '' ) {
|
||||
//return menu_page_url(PERMALINK_MANAGER_PLUGIN_SLUG, false) . $append;
|
||||
$admin_page = sprintf( "tools.php?page=%s", PERMALINK_MANAGER_PLUGIN_SLUG . $append );
|
||||
|
||||
return admin_url( $admin_page );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add shortcut links for Permalink Manager on "Plugins" page
|
||||
*
|
||||
* @param array $links
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function plugins_page_links( $links ) {
|
||||
$new_links = array(
|
||||
sprintf( '<a href="%s">%s</a>', $this->get_admin_url(), __( 'URI Editor', 'permalink-manager' ) ),
|
||||
sprintf( '<a href="%s">%s</a>', $this->get_admin_url( '§ion=settings' ), __( 'Settings', 'permalink-manager' ) ),
|
||||
);
|
||||
|
||||
return array_merge( $links, $new_links );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add shortcut meta links for Permalink Manager on "Plugins" page
|
||||
*
|
||||
* @param array $links
|
||||
* @param string $file
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function plugins_page_meta( $links, $file ) {
|
||||
if ( $file == PERMALINK_MANAGER_BASENAME ) {
|
||||
$new_links = array(
|
||||
'doc' => sprintf( '<a href="%s?utm_source=plugin_admin_page" target="_blank">%s</a>', 'https://permalinkmanager.pro/docs/', __( 'Documentation', 'permalink-manager' ) )
|
||||
);
|
||||
|
||||
if ( ! defined( 'PERMALINK_MANAGER_PRO' ) ) {
|
||||
$new_links['upgrade'] = sprintf( '<a href="%s" target="_blank"><strong>%s</strong></a>', PERMALINK_MANAGER_PROMO, __( 'Buy Permalink Manager Pro', 'permalink-manager' ) );
|
||||
}
|
||||
|
||||
$links = array_merge( $links, $new_links );
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if URI Editor should be displayed for current user
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function current_user_can_edit_uris() {
|
||||
global $permalink_manager_options;
|
||||
|
||||
$edit_uris_cap = ( ! empty( $permalink_manager_options['general']['edit_uris_cap'] ) ) ? $permalink_manager_options['general']['edit_uris_cap'] : 'publish_posts';
|
||||
|
||||
return current_user_can( $edit_uris_cap );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display global notices (throughout wp-admin dashboard)
|
||||
*/
|
||||
function display_global_notices() {
|
||||
global $permalink_manager_alerts, $active_section;
|
||||
|
||||
$html = "";
|
||||
if ( ! empty( $permalink_manager_alerts ) && is_array( $permalink_manager_alerts ) ) {
|
||||
foreach ( $permalink_manager_alerts as $alert_id => $alert ) {
|
||||
$dismissed_transient_name = sprintf( 'permalink-manager-notice_%s', sanitize_title( $alert_id ) );
|
||||
$dismissed = get_transient( $dismissed_transient_name );
|
||||
|
||||
// Check if alert was dismissed
|
||||
if ( empty( $dismissed ) ) {
|
||||
// Hide notice in Permalink Manager Pro
|
||||
if ( defined( 'PERMALINK_MANAGER_PRO' ) && $alert['show'] == 'pro_hide' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Display the notice only on the plugin pages
|
||||
if ( empty( $active_section ) && ! empty( $alert['plugin_only'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the notice did not expire
|
||||
if ( isset( $alert['until'] ) && ( time() > strtotime( $alert['until'] ) ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$html .= Permalink_Manager_UI_Elements::get_alert_message( $alert['txt'], $alert['type'], true, $alert_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo wp_kses_post( $html );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display notices generated by Permalink Manager tools
|
||||
*/
|
||||
function display_plugin_notices() {
|
||||
global $permalink_manager_before_sections_html;
|
||||
|
||||
echo wp_kses_post( $permalink_manager_before_sections_html );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of all duplicated redirects and custom permalinks
|
||||
*
|
||||
* @param bool $include_custom_uris
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_all_duplicates( $include_custom_uris = true ) {
|
||||
global $permalink_manager_redirects;
|
||||
|
||||
// Make sure that both variables are arrays
|
||||
$all_uris = ( $include_custom_uris ) ? Permalink_Manager_URI_Functions::get_all_uris() : array();
|
||||
$permalink_manager_redirects = ( is_array( $permalink_manager_redirects ) ) ? $permalink_manager_redirects : array();
|
||||
|
||||
// Convert redirects list, so it can be merged with custom permalinks array
|
||||
foreach ( $permalink_manager_redirects as $element_id => $redirects ) {
|
||||
if ( is_array( $redirects ) ) {
|
||||
foreach ( $redirects as $index => $uri ) {
|
||||
$all_uris["redirect-{$index}_{$element_id}"] = $uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Count duplicates
|
||||
$duplicates_groups = array();
|
||||
$duplicates_list = array_count_values( $all_uris );
|
||||
$duplicates_list = array_filter( $duplicates_list, function ( $x ) {
|
||||
return $x >= 2;
|
||||
} );
|
||||
|
||||
// Assign keys to duplicates (group them)
|
||||
if ( count( $duplicates_list ) > 0 ) {
|
||||
foreach ( $duplicates_list as $duplicated_uri => $count ) {
|
||||
$duplicated_ids = array_keys( $all_uris, $duplicated_uri );
|
||||
|
||||
// Ignore duplicates in different langauges
|
||||
if ( Permalink_Manager_URI_Functions::is_uri_duplicated( $duplicated_uri, $duplicated_ids[0], $duplicated_ids ) ) {
|
||||
$duplicates_groups[ $duplicated_uri ] = $duplicated_ids;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $duplicates_groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Permalink Manager Pro is active
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_pro_active() {
|
||||
if ( defined( 'PERMALINK_MANAGER_PRO' ) && class_exists( 'Permalink_Manager_Pro_License' ) ) {
|
||||
// Check if license is active
|
||||
$exp_date = Permalink_Manager_Pro_License::get_expiration_date( true );
|
||||
|
||||
$is_pro = ( $exp_date > 2 ) ? false : true;
|
||||
} else {
|
||||
$is_pro = false;
|
||||
}
|
||||
|
||||
return $is_pro;
|
||||
}
|
||||
}
|
||||
+980
@@ -0,0 +1,980 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) exit;
|
||||
|
||||
/**
|
||||
* Core functions
|
||||
*/
|
||||
class Permalink_Manager_Core_Functions {
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'init_hooks' ), 99 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add hooks used by plugin to change the way the permalinks are detected
|
||||
*
|
||||
* @return false|void
|
||||
*/
|
||||
function init_hooks() {
|
||||
global $permalink_manager_options;
|
||||
|
||||
// Trailing slashes
|
||||
add_filter( 'permalink_manager_filter_final_term_permalink', array( $this, 'control_trailing_slashes' ), 9 );
|
||||
add_filter( 'permalink_manager_filter_final_post_permalink', array( $this, 'control_trailing_slashes' ), 9 );
|
||||
add_filter( 'permalink_manager_filter_post_sample_uri', array( $this, 'control_trailing_slashes' ), 9 );
|
||||
add_filter( 'wpseo_canonical', array( $this, 'control_trailing_slashes' ), 9 );
|
||||
add_filter( 'wpseo_opengraph_url', array( $this, 'control_trailing_slashes' ), 9 );
|
||||
add_filter( 'paginate_links', array( $this, 'control_trailing_slashes' ), 9 );
|
||||
|
||||
/**
|
||||
* Detect & canonical URL/redirect functions
|
||||
*/
|
||||
// Do not trigger in back-end
|
||||
if ( is_admin() && ! wp_doing_ajax() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do not trigger if Customizer is loaded
|
||||
if ( function_exists( 'is_customize_preview' ) && is_customize_preview() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use the URIs set in this plugin
|
||||
add_filter( 'request', array( $this, 'detect_post' ), 0, 1 );
|
||||
|
||||
if ( ! is_admin() ) {
|
||||
// Redirect from old URIs to new URIs + adjust canonical redirect settings
|
||||
add_action( 'template_redirect', array( $this, 'new_uri_redirect_and_404' ), 1 );
|
||||
add_action( 'wp', array( $this, 'adjust_canonical_redirect' ), 1 );
|
||||
|
||||
// Case-insensitive permalinks
|
||||
if ( ! empty( $permalink_manager_options['general']['case_insensitive_permalinks'] ) ) {
|
||||
add_action( 'parse_request', array( $this, 'case_insensitive_permalinks' ), 0 );
|
||||
}
|
||||
// Force 404 on non-existing pagination pages
|
||||
if ( ! empty( $permalink_manager_options['general']['pagination_redirect'] ) ) {
|
||||
add_action( 'wp', array( $this, 'fix_pagination_pages' ), 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the request array used by WordPress to load specific content item (post, term, archive, etc.)
|
||||
*
|
||||
* @param array $query
|
||||
* @param bool $request_url
|
||||
* @param bool $return_object
|
||||
*
|
||||
* @return array|WP_Post|WP_Term
|
||||
*/
|
||||
public static function detect_post( $query, $request_url = false, $return_object = false ) {
|
||||
global $wp, $wp_rewrite, $permalink_manager_uris, $permalink_manager_options, $pm_query;
|
||||
|
||||
// Check if the array with custom URIs is set
|
||||
if ( ! ( is_array( $permalink_manager_uris ) ) ) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
// Used in debug mode & endpoints
|
||||
$old_query = ( ! empty( $request_url ) && empty( $query ) ) ? false : $query;
|
||||
|
||||
/**
|
||||
* 1. Prepare URL and check if it is correct (make sure that both requested URL & home_url share the same protocol and get rid of www prefix)
|
||||
*/
|
||||
$request_url = ( ! empty( $request_url ) ) ? parse_url( $request_url, PHP_URL_PATH ) : $_SERVER['REQUEST_URI'];
|
||||
$request_url = ( ! empty( $request_url ) ) ? strtok( $request_url, "?" ) : $request_url;
|
||||
|
||||
// Make sure that either $_SERVER['SERVER_NAME'] or $_SERVER['HTTP_HOST'] are set
|
||||
if ( empty( $_SERVER['HTTP_HOST'] ) && empty( $_SERVER['SERVER_NAME'] ) ) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
$http_host = ( ! empty( $_SERVER['HTTP_HOST'] ) ) ? $_SERVER['HTTP_HOST'] : preg_replace( '/www\./i', '', $_SERVER['SERVER_NAME'] );
|
||||
$request_url = sprintf( "http://%s%s", str_replace( "www.", "", $http_host ), $request_url );
|
||||
$raw_home_url = trim( get_option( 'home' ) );
|
||||
$home_url = preg_replace( "/http(s)?:\/\/(www\.)?(.+?)\/?$/", "http://$3", $raw_home_url );
|
||||
|
||||
if ( parse_url( $request_url, PHP_URL_HOST ) ) {
|
||||
// Check if "Deep Detect" is enabled
|
||||
$deep_detect_enabled = apply_filters( 'permalink_manager_deep_uri_detect', true );
|
||||
|
||||
// Sanitize the URL
|
||||
// $request_url = filter_var($request_url, FILTER_SANITIZE_URL);
|
||||
|
||||
// Keep only the URI
|
||||
$request_url = str_replace( $home_url, "", $request_url );
|
||||
|
||||
// Hotfix for language plugins
|
||||
if ( filter_var( $request_url, FILTER_VALIDATE_URL ) ) {
|
||||
$request_url = parse_url( $request_url, PHP_URL_PATH );
|
||||
}
|
||||
|
||||
$request_url = trim( $request_url, "/" );
|
||||
|
||||
// Get all the endpoints & pattern
|
||||
$endpoints = Permalink_Manager_Helper_Functions::get_endpoints();
|
||||
$pattern = "/^(.+?)(?|\/({$endpoints})(?|\/(.*)|$)|\/()([\d]+)\/?)?$/i";
|
||||
|
||||
// Use default REGEX to detect post
|
||||
preg_match( $pattern, $request_url, $regex_parts );
|
||||
$uri_parts['lang'] = false;
|
||||
$uri_parts['uri'] = ( ! empty( $regex_parts[1] ) ) ? $regex_parts[1] : "";
|
||||
$uri_parts['endpoint'] = ( ! empty( $regex_parts[2] ) ) ? $regex_parts[2] : "";
|
||||
$uri_parts['endpoint_value'] = ( ! empty( $regex_parts[3] ) ) ? $regex_parts[3] : "";
|
||||
|
||||
// Allow to filter the results by third-parties + store the URI parts with $pm_query global
|
||||
$uri_parts = apply_filters( 'permalink_manager_detect_uri', $uri_parts, $request_url, $endpoints );
|
||||
|
||||
// Support comment pages
|
||||
preg_match( "/(.*)\/{$wp_rewrite->comments_pagination_base}-([\d]+)/", $uri_parts['uri'], $regex_parts );
|
||||
if ( ! empty( $regex_parts[2] ) ) {
|
||||
$uri_parts['uri'] = $regex_parts[1];
|
||||
$uri_parts['endpoint'] = 'cpage';
|
||||
$uri_parts['endpoint_value'] = $regex_parts[2];
|
||||
}
|
||||
|
||||
// Support pagination endpoint
|
||||
if ( ! empty( $wp_rewrite->pagination_base ) && $uri_parts['endpoint'] == $wp_rewrite->pagination_base ) {
|
||||
$uri_parts['endpoint'] = 'page';
|
||||
}
|
||||
|
||||
// Stop the function if $uri_parts is empty
|
||||
if ( empty( $uri_parts ) ) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
// Store the URI parts in a separate global variable
|
||||
$pm_query = $uri_parts;
|
||||
|
||||
// Get the URI parts from REGEX parts
|
||||
// $lang = $uri_parts['lang'];
|
||||
$uri = $uri_parts['uri'];
|
||||
$endpoint = $uri_parts['endpoint'];
|
||||
$endpoint_value = $uri_parts['endpoint_value'];
|
||||
|
||||
// Trim slashes
|
||||
$uri = trim( $uri, "/" );
|
||||
|
||||
// Ignore URLs with no URI grabbed
|
||||
if ( empty( $uri ) ) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
// Check what content type should be loaded in case of duplicate ("posts" or "terms")
|
||||
$duplicates_priority = apply_filters( 'permalink_manager_duplicates_priority', false );
|
||||
|
||||
/**
|
||||
* 2. Check if the requested URI matches any custom permalink assigned to a post or term
|
||||
*/
|
||||
$uri_query_iteration = 1;
|
||||
$element_object = '';
|
||||
$excluded_ids = array();
|
||||
|
||||
do {
|
||||
// Store an array with custom permalinks in a separate variable
|
||||
$all_uris = $permalink_manager_uris;
|
||||
|
||||
// Remove empty rows
|
||||
$all_uris = array_filter( $all_uris );
|
||||
|
||||
// In case of multiple elements using the same URI, the function will follow the "permalink_manager_duplicates_priority" filter value to determine whether terms or posts should be ignored
|
||||
if ( $duplicates_priority ) {
|
||||
$duplicated_uris = array_keys( $all_uris, $uri );
|
||||
$duplicates_removed = 0;
|
||||
$duplicates_count = count( $duplicated_uris );
|
||||
|
||||
if ( $duplicates_count > 1 ) {
|
||||
foreach ( $duplicated_uris as $duplicated_uri_id ) {
|
||||
if ( ( $duplicates_priority == 'posts' && ! is_numeric( $duplicated_uri_id ) ) || ( $duplicates_priority !== 'posts' && is_numeric( $duplicated_uri_id ) ) ) {
|
||||
$duplicates_removed ++;
|
||||
|
||||
if ( $duplicates_removed < $duplicates_count ) {
|
||||
$excluded_ids[] = $duplicated_uri_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the element was excluded in the previous iteration add it to the array
|
||||
if ( ! empty( $excluded ) ) {
|
||||
$excluded_ids[] = $excluded;
|
||||
}
|
||||
$excluded = '';
|
||||
|
||||
// Exclude all the element detected in the previous iterations
|
||||
if ( ! empty( $excluded_ids ) ) {
|
||||
$excluded_ids = array_unique( $excluded_ids );
|
||||
foreach ( $excluded_ids as $excluded_element ) {
|
||||
unset( $all_uris[ $excluded_element ] );
|
||||
}
|
||||
}
|
||||
|
||||
// Flip array for better performance
|
||||
$all_uris = array_flip( $all_uris );
|
||||
|
||||
// Attempt 1.
|
||||
// Find the element ID
|
||||
$element_id = isset( $all_uris[ $uri ] ) ? $all_uris[ $uri ] : false;
|
||||
|
||||
// Attempt 2.
|
||||
// Decode both request URI & URIs array & make them lowercase (and save in a separate variable)
|
||||
if ( empty( $element_id ) ) {
|
||||
$uri = strtolower( urldecode( $uri ) );
|
||||
|
||||
foreach ( $all_uris as $raw_uri => $uri_id ) {
|
||||
$raw_uri = strtolower( urldecode( $raw_uri ) );
|
||||
$all_uris[ $raw_uri ] = $uri_id;
|
||||
}
|
||||
|
||||
$element_id = isset( $all_uris[ $uri ] ) ? $all_uris[ $uri ] : $element_id;
|
||||
}
|
||||
|
||||
// Attempt 3.
|
||||
// Check custom permalinks with endpoints included
|
||||
if ( $deep_detect_enabled && ! empty( $uri_parts['endpoint_value'] ) ) {
|
||||
// Check again in case someone used post/tax IDs instead of slugs
|
||||
if ( empty( $uri_parts['endpoint'] ) && is_numeric( $uri_parts['endpoint_value'] ) ) {
|
||||
$uri_alt = sprintf( '%s/%s', $uri, $uri_parts['endpoint_value'] );
|
||||
} // Check again for attachments' custom permalinks
|
||||
else if ( ! empty( $uri_parts['endpoint'] ) && $uri_parts['endpoint'] == 'attachment' ) {
|
||||
$uri_alt = sprintf( '%s/%s/%s', $uri, $uri_parts['endpoint'], $uri_parts['endpoint_value'] );
|
||||
}
|
||||
|
||||
if ( ! empty( $uri_alt ) && isset( $all_uris[ $uri_alt ] ) ) {
|
||||
$element_id = $all_uris[ $uri_alt ];
|
||||
$endpoint_value = $endpoint = "";
|
||||
}
|
||||
}
|
||||
|
||||
// Allow to filter the item_id by third-parties after initial detection
|
||||
$element_id = apply_filters( 'permalink_manager_detected_element_id', $element_id, $uri_parts, $request_url );
|
||||
|
||||
// Clear the original query before it is filtered
|
||||
$query = ( $element_id ) ? array() : $query;
|
||||
|
||||
/**
|
||||
* 2A. Custom URI assigned to taxonomy
|
||||
*/
|
||||
if ( strpos( $element_id, 'tax-' ) !== false ) {
|
||||
// Remove the "tax-" prefix
|
||||
$term_element_id = intval( preg_replace( "/[^0-9]/", "", $element_id ) );
|
||||
|
||||
// Filter detected post ID
|
||||
$term_element_id = apply_filters( 'permalink_manager_detected_term_id', $term_element_id, $uri_parts, true, $old_query );
|
||||
|
||||
// Get the variables to filter wp_query and double-check if taxonomy exists
|
||||
$term = $element_object = ( ! empty( $term_element_id ) && is_numeric( $term_element_id ) ) ? get_term( $term_element_id ) : false;
|
||||
$term_taxonomy = ( ! empty( $term->taxonomy ) ) ? $term->taxonomy : false;
|
||||
$term_taxonomy_object = ( ! empty( $term_taxonomy ) ) ? get_taxonomy( $term_taxonomy ) : '';
|
||||
|
||||
// Check if term is allowed
|
||||
$disabled = ( $term_taxonomy_object && Permalink_Manager_Helper_Functions::is_term_excluded( $term ) ) ? true : false;
|
||||
|
||||
// Proceed only if the term is not removed and its taxonomy is not disabled
|
||||
if ( ! $disabled && $term_taxonomy_object ) {
|
||||
$term_ancestors = get_ancestors( $element_id, $term_taxonomy );
|
||||
$final_uri = $term->slug;
|
||||
|
||||
// Fix for hierarchical terms
|
||||
if ( ! empty( $term_ancestors ) ) {
|
||||
foreach ( $term_ancestors as $parent_id ) {
|
||||
$parent = get_term( $parent_id, $term_taxonomy );
|
||||
if ( ! empty( $parent->slug ) ) {
|
||||
$final_uri = $parent->slug . '/' . $final_uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $term_taxonomy_object->query_var ) ) {
|
||||
$query["taxonomy"] = $term_taxonomy;
|
||||
$query["term"] = $term->slug;
|
||||
} else {
|
||||
$query[ $term_taxonomy_object->query_var ] = $term->slug;
|
||||
}
|
||||
} else if ( $disabled ) {
|
||||
$broken_uri = true;
|
||||
$query = $old_query;
|
||||
$excluded = $element_id;
|
||||
} else {
|
||||
$query = $old_query;
|
||||
$excluded = $element_id;
|
||||
}
|
||||
} /**
|
||||
* 2B. Custom URI assigned to post/page/CPT item
|
||||
*/ else if ( isset( $element_id ) && is_numeric( $element_id ) ) {
|
||||
// Fix for revisions
|
||||
$is_revision = wp_is_post_revision( $element_id );
|
||||
if ( $is_revision ) {
|
||||
$revision_id = $element_id;
|
||||
$element_id = $is_revision;
|
||||
}
|
||||
|
||||
// Filter detected post ID
|
||||
$post_element_id = apply_filters( 'permalink_manager_detected_post_id', $element_id, $uri_parts, false, $old_query );
|
||||
|
||||
$post_to_load = $element_object = ( ! empty( $post_element_id ) && is_numeric( $post_element_id ) ) ? get_post( $post_element_id ) : false;
|
||||
$final_uri = ( ! empty( $post_to_load->post_name ) ) ? $post_to_load->post_name : false;
|
||||
$post_type = ( ! empty( $post_to_load->post_type ) ) ? $post_to_load->post_type : false;
|
||||
|
||||
// Check if post is allowed
|
||||
$disabled = ( $post_type && Permalink_Manager_Helper_Functions::is_post_excluded( $post_to_load, true ) ) ? true : false;
|
||||
|
||||
// Proceed only if the term is not removed and its taxonomy is not disabled
|
||||
if ( ! $disabled && $post_type ) {
|
||||
$post_type_object = get_post_type_object( $post_type );
|
||||
|
||||
// Fix for hierarchical CPT & pages
|
||||
if ( ! ( empty( $post_to_load->ancestors ) ) && ! empty( $post_type_object->hierarchical ) ) {
|
||||
foreach ( $post_to_load->ancestors as $parent ) {
|
||||
$parent = get_post( $parent );
|
||||
if ( $parent && $parent->post_name ) {
|
||||
$final_uri = $parent->post_name . '/' . $final_uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Alter the final query array
|
||||
if ( $post_to_load->post_status == 'private' && ( ! is_user_logged_in() || current_user_can( 'read_private_posts', $element_id ) !== true ) ) {
|
||||
$element_id = 0;
|
||||
$query = $old_query;
|
||||
} else if ( $post_to_load->post_status == 'draft' || empty( $final_uri ) ) {
|
||||
// A. The draft permalinks should be allowed for logged-in users
|
||||
if ( is_user_logged_in() ) {
|
||||
if ( $post_type == 'page' ) {
|
||||
$query['page_id'] = $element_id;
|
||||
} else {
|
||||
$query['p'] = $element_id;
|
||||
}
|
||||
|
||||
$query['preview'] = true;
|
||||
$query['post_type'] = $post_type;
|
||||
} // B. The draft permalinks should be disabled for non-logged-in visitors
|
||||
else if ( $post_to_load->post_status == 'draft' ) {
|
||||
$query['pagename'] = '-';
|
||||
$query['error'] = '404';
|
||||
|
||||
$element_id = 0;
|
||||
} else {
|
||||
$query = $old_query;
|
||||
$excluded = $element_id;
|
||||
}
|
||||
} else if ( $post_type == 'page' ) {
|
||||
$query['pagename'] = $final_uri;
|
||||
// $query['post_type'] = $post_type;
|
||||
} else if ( $post_type == 'post' ) {
|
||||
$query['name'] = $final_uri;
|
||||
} else if ( $post_type == 'attachment' ) {
|
||||
$query['attachment'] = $final_uri;
|
||||
} else {
|
||||
// Get the query var
|
||||
$query_var = ( ! empty( $post_type_object->query_var ) ) ? $post_type_object->query_var : $post_type;
|
||||
|
||||
$query['name'] = $final_uri;
|
||||
$query['post_type'] = $post_type;
|
||||
$query[ $query_var ] = $final_uri;
|
||||
}
|
||||
} else if ( $disabled ) {
|
||||
$broken_uri = true;
|
||||
$query = $old_query;
|
||||
$excluded = $element_id;
|
||||
} else {
|
||||
$query = $old_query;
|
||||
$excluded = $element_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-remove removed term custom URI & redirects (works if enabled in plugin settings)
|
||||
if ( ! empty( $broken_uri ) && ( ! empty( $permalink_manager_options['general']['auto_fix_duplicates'] ) ) && $permalink_manager_options['general']['auto_fix_duplicates'] == 1 ) {
|
||||
// Do not trigger if WP Rocket cache plugin is turned on
|
||||
if ( ! defined( 'WP_ROCKET_VERSION' ) && is_array( $permalink_manager_uris ) ) {
|
||||
$broken_element_id = ( ! empty( $revision_id ) ) ? $revision_id : $element_id;
|
||||
$remove_broken_uri = ( ! empty( $broken_element_id ) ) ? Permalink_Manager_Actions::force_clear_single_element_uris_and_redirects( $broken_element_id ) : '';
|
||||
|
||||
// Reload page if success
|
||||
if ( $remove_broken_uri && ! headers_sent() ) {
|
||||
header( "Refresh:0" );
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Overwrite the detect function and decide whether to exclude the detected item
|
||||
$excluded = apply_filters( 'permalink_manager_excluded_element_id', $excluded, $element_object, $old_query, $pm_query );
|
||||
|
||||
// Make sure the loop does not execute infinitely (limit it to 20 iterations)
|
||||
$uri_query_iteration ++;
|
||||
if ( $uri_query_iteration === 25 ) {
|
||||
break;
|
||||
}
|
||||
} // If the detected element was excluded repeat the URI query and try to find a new one
|
||||
while ( ! empty( $excluded ) );
|
||||
|
||||
/**
|
||||
* 3A. Endpoints
|
||||
*/
|
||||
if ( ! empty( $element_id ) && empty( $disabled ) && ( ! empty( $endpoint ) || ! empty( $endpoint_value ) ) ) {
|
||||
if ( is_array( $endpoint ) ) {
|
||||
foreach ( $endpoint as $endpoint_name => $endpoint_value ) {
|
||||
$query[ $endpoint_name ] = $endpoint_value;
|
||||
}
|
||||
} else if ( $endpoint == 'feed' ) {
|
||||
$feed_rewrite = true;
|
||||
|
||||
// Check if /feed/ endpoint is allowed for selected post type or taxonomy
|
||||
if ( ! empty( $post_type_object ) && is_array( $post_type_object->rewrite ) && empty( $post_type_object->rewrite['feeds'] ) ) {
|
||||
$feed_rewrite = false;
|
||||
}
|
||||
|
||||
if ( $feed_rewrite ) {
|
||||
$query[ $endpoint ] = 'feed';
|
||||
} else {
|
||||
$element_id = '';
|
||||
$query = array(
|
||||
'error' => 404
|
||||
);
|
||||
}
|
||||
} else if ( $endpoint == 'embed' ) {
|
||||
$query[ $endpoint ] = true;
|
||||
} else if ( $endpoint == 'page' ) {
|
||||
$endpoint = 'paged';
|
||||
if ( is_numeric( $endpoint_value ) ) {
|
||||
$query[ $endpoint ] = $endpoint_value;
|
||||
} else {
|
||||
$query = $old_query;
|
||||
}
|
||||
} else if ( $endpoint == 'trackback' ) {
|
||||
$endpoint = 'tb';
|
||||
$query[ $endpoint ] = 1;
|
||||
} else if ( empty( $endpoint ) && is_numeric( $endpoint_value ) ) {
|
||||
$query['page'] = $endpoint_value;
|
||||
} else {
|
||||
$query[ $endpoint ] = $endpoint_value;
|
||||
}
|
||||
|
||||
// Fix for attachments
|
||||
if ( ! empty( $query['attachment'] ) ) {
|
||||
$query = array( 'attachment' => $query['attachment'], 'do_not_redirect' => 1 );
|
||||
} else if ( isset( $query['attachment'] ) ) {
|
||||
$query = $old_query;
|
||||
$element_id = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 3B. Endpoints - check if any endpoint is set with $_GET parameter
|
||||
*/
|
||||
if ( ! empty( $element_id ) && $deep_detect_enabled && ! empty( $_GET ) ) {
|
||||
$get_endpoints = array_intersect( $wp->public_query_vars, array_keys( $_GET ) );
|
||||
|
||||
if ( ! empty( $get_endpoints ) ) {
|
||||
// Append query vars from $_GET parameters
|
||||
foreach ( $get_endpoints as $endpoint ) {
|
||||
// Numeric endpoints
|
||||
$endpoint_value = ( in_array( $endpoint, array( 'page', 'paged', 'attachment_id' ) ) ) ? filter_var( $_GET[ $endpoint ], FILTER_SANITIZE_NUMBER_INT ) : $_GET[ $endpoint ];
|
||||
|
||||
// Ignore page endpoint if its value is empty or equal to 1
|
||||
if ( in_array( $endpoint, array( 'page', 'paged' ) ) && ( empty( $endpoint_value ) || $endpoint_value == 1 ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Replace whitespaces with '+' (for YITH WooCommerce Ajax Product Filter URLs only) and sanitize the value
|
||||
$endpoint_value = ( isset( $_GET['yith_wcan'] ) ) ? preg_replace( '/\s+/', '+', $endpoint_value ) : $endpoint_value;
|
||||
$query[ $endpoint ] = sanitize_text_field( $endpoint_value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 4. Set global with detected item id
|
||||
*/
|
||||
if ( ! empty( $element_id ) && empty( $disabled ) && empty( $excluded ) ) {
|
||||
if ( ! empty( $element_object->taxonomy ) ) {
|
||||
$pm_query['id'] = $element_object->term_id;
|
||||
$content_type = "Taxonomy: {$element_object->taxonomy}";
|
||||
} else if ( ! empty( $element_object->post_type ) ) {
|
||||
$pm_query['id'] = $element_object->ID;
|
||||
$content_type = "Post type: {$element_object->post_type}";
|
||||
}
|
||||
|
||||
// If language mismatch is detected do not set 'do_not_redirect' to allow canonical redirect
|
||||
if ( is_array( $query ) && ( empty( $pm_query['flag'] ) || $pm_query['flag'] !== 'language_mismatch' ) ) {
|
||||
$query['do_not_redirect'] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 5. Debug data
|
||||
*/
|
||||
if ( empty ( $element_object ) || empty ( $content_type ) ) {
|
||||
$content_type = $element_object = '';
|
||||
}
|
||||
|
||||
$uri_parts = ( ! empty( $uri_parts ) ) ? $uri_parts : '';
|
||||
$query = apply_filters( 'permalink_manager_filter_query', $query, $old_query, $uri_parts, $pm_query, $content_type, $element_object );
|
||||
|
||||
if ( $return_object && ! empty( $element_object ) ) {
|
||||
return $element_object;
|
||||
} else {
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trailing slash & remove BOM and double slashes
|
||||
*
|
||||
* @param string $permalink
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static function control_trailing_slashes( $permalink ) {
|
||||
global $permalink_manager_options;
|
||||
|
||||
// Ignore empty & numeric permalinks
|
||||
if ( empty( $permalink ) || is_numeric( $permalink ) ) {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
// Keep the original permalink in a separate variable
|
||||
$original_permalink = $permalink;
|
||||
$permalink_path = parse_url( $original_permalink, PHP_URL_PATH );
|
||||
$permalink_path = ( ! empty( $permalink_path ) ) ? trim( $permalink_path, '/' ) : $permalink_path;
|
||||
|
||||
$trailing_slash_mode = ( ! empty( $permalink_manager_options['general']['trailing_slashes'] ) ) ? $permalink_manager_options['general']['trailing_slashes'] : "";
|
||||
|
||||
// Ignore homepage URLs
|
||||
if ( filter_var( $permalink, FILTER_VALIDATE_URL ) && empty( $permalink_path ) ) {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
// Always remove trailing slashes from URLs/URIs that end with file extension (e.g. html)
|
||||
if ( preg_match( '/(http(?:s)\:\/\/[^\/]+\/)?.*\.([a-zA-Z]{3,4})[\/]*(\?[^\/]+|$)/', $permalink ) ) {
|
||||
$trailing_slash_mode = 2;
|
||||
}
|
||||
|
||||
// Add trailing slashes
|
||||
if ( in_array( $trailing_slash_mode, array( 1, 10 ) ) ) {
|
||||
$permalink = preg_replace( '/(.+?)([\/]*)([\?\#][^\/]+|$)/', '$1/$3', $permalink ); // Instead of trailingslashit()
|
||||
} // Remove trailing slashes
|
||||
else if ( in_array( $trailing_slash_mode, array( 2, 20 ) ) ) {
|
||||
$permalink = preg_replace( '/(.+?)([\/]*)([\?\#][^\/]+|$)/', '$1$3', $permalink ); // Instead of untrailingslashit()
|
||||
} // Default settings
|
||||
else {
|
||||
$permalink = user_trailingslashit( $permalink );
|
||||
}
|
||||
|
||||
// Remove double slashes
|
||||
$permalink = preg_replace( '/(?<!:)(\/{2,})/', '/', $permalink );
|
||||
|
||||
// Remove trailing slashes from URLs that end with query string or anchors
|
||||
$permalink = preg_replace( '/([\?\#]{1}[^\/]+)([\/]+)$/', '$1', $permalink );
|
||||
|
||||
return apply_filters( 'permalink_manager_control_trailing_slashes', $permalink, $original_permalink );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display 404 if requested page does not exist in pagination or the pagination format is incorrect
|
||||
*/
|
||||
function fix_pagination_pages() {
|
||||
global $wp_query, $pm_query, $post, $permalink_manager_options;
|
||||
|
||||
// 1. Check if the custom permalink was detected
|
||||
if ( empty( $pm_query['id'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Get the queried object
|
||||
$object = get_queried_object();
|
||||
|
||||
if ( ! empty( $object ) && ! empty( $object->taxonomy ) ) {
|
||||
$term = $object;
|
||||
} else if ( ! empty( $object->post_type ) ) {
|
||||
$post = $object;
|
||||
} else if ( empty( $object ) && ! empty( $wp_query->post ) ) {
|
||||
$post = $wp_query->post;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// 3.1. Validate the pages count
|
||||
if ( ( ! empty( $post->post_type ) && isset( $post->post_content ) ) || ( isset( $wp_query->max_num_pages ) && ! empty( $term->taxonomy ) ) ) {
|
||||
$current_page = ( ! empty( $wp_query->query_vars['page'] ) ) ? $wp_query->query_vars['page'] : 1;
|
||||
$current_page = ( empty( $wp_query->query_vars['page'] ) && ! empty( $wp_query->query_vars['paged'] ) ) ? $wp_query->query_vars['paged'] : $current_page;
|
||||
|
||||
// 2.1B. Count post pages
|
||||
$post_content = ( ! empty( $post->post_content ) ) ? $post->post_content : '';
|
||||
$num_pages = ( is_home() || is_archive() || is_search() ) ? $wp_query->max_num_pages : substr_count( strtolower( $post_content ), '<!--nextpage-->' ) + 1;
|
||||
|
||||
$is_404 = ( $current_page > 1 && ( $current_page > $num_pages ) ) ? true : false;
|
||||
} // 3.2. Force 404 if no posts are loaded
|
||||
else if ( ! empty( $wp_query->query['paged'] ) && $wp_query->post_count == 0 ) {
|
||||
$is_404 = true;
|
||||
}
|
||||
|
||||
// 3.4. Force 404 if endpoint value is not set or not numeric
|
||||
if ( ! empty( $pm_query['endpoint'] ) && $pm_query['endpoint'] == 'page' && ( empty( $pm_query['endpoint_value'] ) || ! is_numeric( $pm_query['endpoint_value'] ) ) ) {
|
||||
$is_404 = true;
|
||||
}
|
||||
|
||||
// 4. Block non-existent pages (Force 404 error or allow canonical redirect)
|
||||
if ( ! empty( $is_404 ) ) {
|
||||
$pagination_mode = ( ! empty( $permalink_manager_options['general']['pagination_redirect'] ) ) ? $permalink_manager_options['general']['pagination_redirect'] : false;
|
||||
|
||||
// Make sure that canonical redirect is not disabled in adjust_canonical_redirect() method
|
||||
if ( $pagination_mode == 2 ) {
|
||||
$wp_query->query_vars['do_not_redirect'] = 0;
|
||||
} else {
|
||||
$wp_query->query = $wp_query->queried_object = $wp_query->queried_object_id = $pm_query = $post = null;
|
||||
$wp_query->set_404();
|
||||
status_header( 404 );
|
||||
nocache_headers();
|
||||
}
|
||||
|
||||
$pm_query = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enhance the existing canonical redirect functionality, allowing users define custom redirects and support custom permalinks
|
||||
*/
|
||||
function new_uri_redirect_and_404() {
|
||||
global $wp_query, $wp, $wp_rewrite, $wpdb, $permalink_manager_uris, $permalink_manager_redirects, $permalink_manager_external_redirects, $permalink_manager_options, $pm_query;
|
||||
|
||||
// Get the redirection mode & trailing slashes settings
|
||||
$redirect_mode = ( ! empty( $permalink_manager_options['general']['redirect'] ) ) ? $permalink_manager_options['general']['redirect'] : false;
|
||||
$trailing_slashes_mode = ( ! empty( $permalink_manager_options['general']['trailing_slashes'] ) ) ? $permalink_manager_options['general']['trailing_slashes'] : false;
|
||||
$trailing_slashes_redirect = ( ! empty( $permalink_manager_options['general']['trailing_slashes_redirect'] ) ) ? $permalink_manager_options['general']['trailing_slashes_redirect'] : false;
|
||||
$extra_redirects = ( ! empty( $permalink_manager_options['general']['extra_redirects'] ) ) ? $permalink_manager_options['general']['extra_redirects'] : false;
|
||||
$canonical_redirect = ( ! empty( $permalink_manager_options['general']['canonical_redirect'] ) ) ? $permalink_manager_options['general']['canonical_redirect'] : false;
|
||||
$old_slug_redirect = ( ! empty( $permalink_manager_options['general']['old_slug_redirect'] ) ) ? $permalink_manager_options['general']['old_slug_redirect'] : false;
|
||||
$endpoint_redirect = ( ! empty( $permalink_manager_options['general']['endpoint_redirect'] ) ) ? $permalink_manager_options['general']['endpoint_redirect'] : false;
|
||||
$copy_query_redirect = ( ! empty( $permalink_manager_options['general']['copy_query_redirect'] ) ) ? $permalink_manager_options['general']['copy_query_redirect'] : false;
|
||||
$redirect_type = '-';
|
||||
|
||||
// Get home URL
|
||||
$home_url = rtrim( get_option( 'home' ), "/" );
|
||||
$home_dir = parse_url( $home_url, PHP_URL_PATH );
|
||||
|
||||
// Set up $correct_permalink variable
|
||||
$correct_permalink = '';
|
||||
|
||||
// Get query string & URI
|
||||
if ( empty( $_SERVER['REQUEST_URI'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$query_string = ( $copy_query_redirect && ! empty( $_SERVER['QUERY_STRING'] ) ) ? $_SERVER['QUERY_STRING'] : '';
|
||||
$old_uri = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );
|
||||
$old_uri = $old_uri_abs = ( empty( $old_uri ) ) ? strtok( $_SERVER["REQUEST_URI"], '?' ) : $old_uri;
|
||||
|
||||
// Fix for WP installed in directories (remove the directory name from the URI)
|
||||
if ( ! empty( $home_dir ) ) {
|
||||
$home_dir_regex = preg_quote( trim( $home_dir ), "/" );
|
||||
$old_uri = preg_replace( "/{$home_dir_regex}/", "", $old_uri, 1 );
|
||||
}
|
||||
|
||||
if ( is_front_page() || ( is_page() && get_option( 'show_on_front' ) === 'page' && get_queried_object_id() === (int) get_option( 'page_on_front' ) ) ) {
|
||||
$is_front_page = true;
|
||||
} else {
|
||||
$is_front_page = false;
|
||||
}
|
||||
|
||||
// Do not use custom redirects on author pages, search & front page
|
||||
if ( ! is_author() && ! $is_front_page && ! is_home() && ! is_feed() && ! is_search() && empty( $_GET['s'] ) ) {
|
||||
// Sometimes $wp_query indicates the wrong object if requested directly
|
||||
$queried_object = get_queried_object();
|
||||
|
||||
// Unset 404 if custom URI is detected
|
||||
if ( ! empty( $pm_query['id'] ) && ! empty( $queried_object->post_status ) ) {
|
||||
$wp_query->is_404 = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1A. External redirect
|
||||
*/
|
||||
if ( ! empty( $pm_query['id'] ) ) {
|
||||
if ( ! empty( $queried_object->ID ) && ! empty( $permalink_manager_external_redirects[ $queried_object->ID ] ) ) {
|
||||
$external_url = $permalink_manager_external_redirects[ $queried_object->ID ];
|
||||
} else if ( ! empty( $queried_object->term_id ) && ! empty( $permalink_manager_external_redirects["tax-{$queried_object->term_id}"] ) ) {
|
||||
$external_url = $permalink_manager_external_redirects["tax-{$queried_object->term_id}"];
|
||||
}
|
||||
|
||||
if ( ! empty( $external_url ) && filter_var( $external_url, FILTER_VALIDATE_URL ) ) {
|
||||
// Allow redirect
|
||||
$wp_query->query_vars['do_not_redirect'] = 0;
|
||||
|
||||
wp_redirect( $external_url, 301, PERMALINK_MANAGER_PLUGIN_NAME ); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- By design, the users can redirect the post/term to any external URL here
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 1B. Custom redirects
|
||||
*/
|
||||
if ( empty( $wp_query->query_vars['do_not_redirect'] ) && $extra_redirects && ! empty( $permalink_manager_redirects ) && is_array( $permalink_manager_redirects ) && ! empty( $wp->request ) && ! empty( $pm_query['uri'] ) ) {
|
||||
$uri = $pm_query['uri'];
|
||||
$endpoint_value = $pm_query['endpoint_value'];
|
||||
|
||||
// Make sure that URIs with non-ASCII characters are also detected + Check the URLs that end with number
|
||||
$decoded_url = urldecode( $uri );
|
||||
$endpoint_url = "{$uri}/{$endpoint_value}";
|
||||
|
||||
// Convert to lowercase to make case-insensitive
|
||||
$force_lowercase = apply_filters( 'permalink_manager_force_lowercase_uris', true );
|
||||
|
||||
if ( $force_lowercase ) {
|
||||
$uri = strtolower( $uri );
|
||||
$decoded_url = strtolower( $decoded_url );
|
||||
$endpoint_url = strtolower( $endpoint_url );
|
||||
}
|
||||
|
||||
// Check if the URI is not assigned to any post/term's redirects
|
||||
foreach ( $permalink_manager_redirects as $element => $redirects ) {
|
||||
if ( ! is_array( $redirects ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( in_array( $uri, $redirects ) || in_array( $decoded_url, $redirects ) || ( is_numeric( $endpoint_value ) && in_array( $endpoint_url, $redirects ) ) ) {
|
||||
// Post is detected
|
||||
if ( is_numeric( $element ) ) {
|
||||
$correct_permalink = get_permalink( $element );
|
||||
} // Term is detected
|
||||
else {
|
||||
$term_id = intval( preg_replace( "/[^0-9]/", "", $element ) );
|
||||
$correct_permalink = get_term_link( $term_id );
|
||||
}
|
||||
|
||||
// The custom redirect is found so there is no need to query the rest of array
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$redirect_type = ( ! empty( $correct_permalink ) ) ? 'custom_redirect' : $redirect_type;
|
||||
}
|
||||
|
||||
// Ignore WP-Content links
|
||||
if ( strpos( $_SERVER['REQUEST_URI'], '/wp-content' ) !== false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1C. Enhance native redirect
|
||||
*/
|
||||
if ( $canonical_redirect && empty( $wp_query->query_vars['do_not_redirect'] ) && ! empty( $queried_object ) && empty( $correct_permalink ) ) {
|
||||
// Affect only posts with custom URI and old URIs
|
||||
if ( ! empty( $queried_object->ID ) && isset( $permalink_manager_uris[ $queried_object->ID ] ) && empty( $wp_query->query['preview'] ) ) {
|
||||
// Ignore posts with specific statuses
|
||||
if ( ! ( empty( $queried_object->post_status ) ) && in_array( $queried_object->post_status, array( 'draft', 'pending', 'auto-draft', 'future' ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the post is excluded
|
||||
if ( Permalink_Manager_Helper_Functions::is_post_excluded( $queried_object ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the real URL
|
||||
$correct_permalink = get_permalink( $queried_object->ID );
|
||||
} // Affect only terms with custom URI and old URIs
|
||||
else if ( ! empty( $queried_object->term_id ) && isset( $permalink_manager_uris["tax-{$queried_object->term_id}"] ) && defined( 'PERMALINK_MANAGER_PRO' ) ) {
|
||||
// Check if the term is excluded
|
||||
if ( Permalink_Manager_Helper_Functions::is_term_excluded( $queried_object ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the real URL
|
||||
$correct_permalink = get_term_link( $queried_object->term_id, $queried_object->taxonomy );
|
||||
}
|
||||
|
||||
$redirect_type = ( ! empty( $correct_permalink ) ) ? 'native_redirect' : $redirect_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1D. Old slug redirect
|
||||
*/
|
||||
if ( $old_slug_redirect && ! empty( $pm_query['uri'] ) && empty( $wp_query->query_vars['do_not_redirect'] ) && is_404() && empty( $correct_permalink ) ) {
|
||||
$slug = basename( $pm_query['uri'] );
|
||||
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Direct SQL query is faster here
|
||||
$post_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id from {$wpdb->postmeta} WHERE meta_key = '_wp_old_slug' AND meta_value = %s", $slug ) );
|
||||
if ( ! empty( $post_id ) && Permalink_Manager_Helper_Functions::is_post_excluded( $post_id, true, true ) !== true ) {
|
||||
$correct_permalink = get_permalink( $post_id );
|
||||
$redirect_type = 'old_slug_redirect';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 2. Prevent redirect loop
|
||||
*/
|
||||
if ( ! empty( $correct_permalink ) && is_string( $correct_permalink ) && ! empty( $wp->request ) && $redirect_type != 'slash_redirect' ) {
|
||||
$current_uri = trim( $wp->request, "/" );
|
||||
$redirect_uri = trim( parse_url( $correct_permalink, PHP_URL_PATH ), "/" );
|
||||
|
||||
$correct_permalink = ( $redirect_uri == $current_uri ) ? null : $correct_permalink;
|
||||
}
|
||||
|
||||
/**
|
||||
* 3. Add endpoints to redirect URL
|
||||
*/
|
||||
if ( ! empty( $correct_permalink ) && $endpoint_redirect && ( ! empty( $pm_query['endpoint_value'] ) || ! empty( $pm_query['endpoint'] ) ) ) {
|
||||
$endpoint_value = $pm_query['endpoint_value'];
|
||||
|
||||
if ( empty( $pm_query['endpoint'] ) && is_numeric( $endpoint_value ) ) {
|
||||
$correct_permalink = sprintf( "%s/%d", trim( $correct_permalink, "/" ), $endpoint_value );
|
||||
} else if ( isset( $pm_query['endpoint'] ) && ! empty( $endpoint_value ) ) {
|
||||
if ( $pm_query['endpoint'] == 'cpage' ) {
|
||||
$correct_permalink = sprintf( "%s/%s-%s", trim( $correct_permalink, "/" ), $wp_rewrite->comments_pagination_base, $endpoint_value );
|
||||
} else {
|
||||
$correct_permalink = sprintf( "%s/%s/%s", trim( $correct_permalink, "/" ), $pm_query['endpoint'], $endpoint_value );
|
||||
}
|
||||
} else {
|
||||
$correct_permalink = sprintf( "%s/%s", trim( $correct_permalink, "/" ), $pm_query['endpoint'] );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$queried_object = '-';
|
||||
}
|
||||
|
||||
/**
|
||||
* 4. Check trailing & duplicated slashes (ignore links with query parameters)
|
||||
*/
|
||||
if ( ( ( $trailing_slashes_mode && $trailing_slashes_redirect ) || preg_match( '/\/{2,}/', $old_uri ) ) && empty( $is_front_page ) && empty( $_POST ) && empty( $correct_permalink ) && empty( $query_string ) && ! empty( $old_uri ) && $old_uri !== "/" ) {
|
||||
$trailing_slash = ( substr( $old_uri, - 1 ) == "/" ) ? true : false;
|
||||
$obsolete_slash = ( preg_match( '/\/{2,}/', $old_uri ) || preg_match( "/.*\.([a-zA-Z]{3,4})\/$/", $old_uri ) );
|
||||
|
||||
if ( ( $trailing_slashes_mode == 1 && ! $trailing_slash ) || ( $trailing_slashes_mode == 2 && $trailing_slash ) || $obsolete_slash ) {
|
||||
$new_uri = self::control_trailing_slashes( $old_uri );
|
||||
|
||||
if ( $new_uri !== $old_uri ) {
|
||||
$correct_permalink = sprintf( "%s/%s", $home_url, ltrim( $new_uri, '/' ) );
|
||||
$redirect_type = 'slash_redirect';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 5. WWW prefix | SSL mismatch redirect
|
||||
*/
|
||||
if ( ! empty( $permalink_manager_options['general']['sslwww_redirect'] ) && ! empty( $_SERVER['HTTP_HOST'] ) ) {
|
||||
$home_url_has_www = ( strpos( $home_url, 'www.' ) !== false ) ? true : false;
|
||||
$requested_url_has_www = ( strpos( $_SERVER['HTTP_HOST'], 'www.' ) !== false ) ? true : false;
|
||||
$home_url_has_ssl = ( strpos( $home_url, 'https' ) !== false ) ? true : false;
|
||||
|
||||
if ( ( $home_url_has_www !== $requested_url_has_www ) || ( ! is_ssl() && $home_url_has_ssl !== false ) ) {
|
||||
$new_uri = ltrim( $old_uri, '/' );
|
||||
$correct_permalink = sprintf( "%s/%s", $home_url, $new_uri );
|
||||
|
||||
$redirect_type = 'www_redirect';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 6. Debug redirect
|
||||
*/
|
||||
$correct_permalink = apply_filters( 'permalink_manager_filter_redirect', $correct_permalink, $redirect_type, $queried_object, $old_uri );
|
||||
|
||||
/**
|
||||
* 7. Ignore default URIs (or do nothing if redirects are disabled)
|
||||
*/
|
||||
if ( ! empty( $correct_permalink ) && is_string( $correct_permalink ) && ! empty( $redirect_mode ) ) {
|
||||
// Allow redirect
|
||||
$wp_query->query_vars['do_not_redirect'] = 0;
|
||||
|
||||
// Adjust trailing slashes
|
||||
$correct_permalink = self::control_trailing_slashes( $correct_permalink );
|
||||
|
||||
// Prevent redirect loop
|
||||
$rel_old_uri = wp_make_link_relative( $old_uri_abs );
|
||||
$rel_new_uri = wp_make_link_relative( $correct_permalink );
|
||||
|
||||
// Append query string
|
||||
$correct_permalink = ( ! empty( $query_string ) ) ? sprintf( "%s?%s", strtok( $correct_permalink, "?" ), $query_string ) : $correct_permalink;
|
||||
|
||||
if ( filter_var( $correct_permalink, FILTER_VALIDATE_URL ) && ( $redirect_type === 'www_redirect' || $rel_old_uri !== $rel_new_uri ) ) {
|
||||
wp_safe_redirect( $correct_permalink, $redirect_mode, PERMALINK_MANAGER_PLUGIN_NAME );
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Control how the canonical redirect function in WordPress and other popular plugins works
|
||||
*/
|
||||
function adjust_canonical_redirect() {
|
||||
global $permalink_manager_options, $wp, $wp_query, $wp_rewrite;
|
||||
|
||||
// Adjust rewrite settings for trailing slashes
|
||||
$trailing_slash_setting = ( ! empty( $permalink_manager_options['general']['trailing_slashes'] ) ) ? $permalink_manager_options['general']['trailing_slashes'] : "";
|
||||
if ( in_array( $trailing_slash_setting, array( 1, 10 ) ) ) {
|
||||
$wp_rewrite->use_trailing_slashes = true;
|
||||
} else if ( in_array( $trailing_slash_setting, array( 2, 20 ) ) ) {
|
||||
$wp_rewrite->use_trailing_slashes = false;
|
||||
}
|
||||
|
||||
// Get endpoints
|
||||
$endpoints = Permalink_Manager_Helper_Functions::get_endpoints();
|
||||
$endpoints_array = ( $endpoints ) ? explode( "|", $endpoints ) : array();
|
||||
|
||||
// Check if any endpoint is called (fix for endpoints)
|
||||
foreach ( $endpoints_array as $endpoint ) {
|
||||
if ( ! empty( $wp->query_vars[ $endpoint ] ) && ! in_array( $endpoint, array( 'attachment', 'page', 'paged', 'feed' ) ) ) {
|
||||
$wp_query->query_vars['do_not_redirect'] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Allow canonical redirect for ../1/ and ../page/1/
|
||||
if ( ( ! empty( $wp->query_vars['paged'] ) && $wp->query_vars['paged'] == 1 ) || ( ! empty( $wp->query_vars['page'] ) && $wp->query_vars['page'] == 1 ) ) {
|
||||
$wp_query->query_vars['do_not_redirect'] = 0;
|
||||
} // Allow canonical redirect for URL with specific query parameters
|
||||
else if ( ( is_single() && ( ! empty( $_GET['p'] ) || ! empty( $_GET['name'] ) ) ) || ( is_page() && ! empty( $_GET['page_id'] ) ) ) {
|
||||
$wp_query->query_vars['do_not_redirect'] = 0;
|
||||
}
|
||||
|
||||
if ( empty( $permalink_manager_options['general']['canonical_redirect'] ) ) {
|
||||
remove_action( 'template_redirect', 'redirect_canonical' );
|
||||
}
|
||||
|
||||
if ( empty( $permalink_manager_options['general']['old_slug_redirect'] ) ) {
|
||||
remove_action( 'template_redirect', 'wp_old_slug_redirect' );
|
||||
}
|
||||
|
||||
if ( ! empty( $wp_query->query_vars['do_not_redirect'] ) ) {
|
||||
if ( function_exists( 'rank_math' ) && ! empty( $permalink_manager_options['general']['rankmath_redirect'] ) ) {
|
||||
$rank_math_instance = rank_math();
|
||||
|
||||
if ( ! empty( $rank_math_instance->manager ) && is_object( $rank_math_instance->manager ) && method_exists( $rank_math_instance->manager, 'get_module' ) ) {
|
||||
$rank_math_redirections_module = $rank_math_instance->manager->get_module( 'redirections' );
|
||||
|
||||
if ( ! empty( $rank_math_redirections_module ) ) {
|
||||
remove_action( 'template_redirect', array( $rank_math_redirections_module, 'do_redirection' ), 11 );
|
||||
remove_action( 'wp', array( $rank_math_redirections_module, 'do_redirection' ), 11 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SEOPress
|
||||
remove_action( 'template_redirect', 'seopress_category_redirect', 1 );
|
||||
|
||||
remove_action( 'template_redirect', 'wp_old_slug_redirect' );
|
||||
remove_action( 'template_redirect', 'redirect_canonical' );
|
||||
add_filter( 'wpml_is_redirected', '__return_false', 99, 2 );
|
||||
add_filter( 'pll_check_canonical_url', '__return_false', 99, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable case-insensitive permalinks mode
|
||||
*/
|
||||
function case_insensitive_permalinks() {
|
||||
global $permalink_manager_uris;
|
||||
|
||||
if ( ! empty( $_SERVER['REQUEST_URI'] ) ) {
|
||||
$_SERVER['REQUEST_URI'] = strtolower( $_SERVER['REQUEST_URI'] );
|
||||
$permalink_manager_uris = array_map( 'strtolower', $permalink_manager_uris );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) exit;
|
||||
|
||||
/**
|
||||
* Additional debug functions for "Permalink Manager Pro"
|
||||
*/
|
||||
class Permalink_Manager_Debug_Functions {
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'debug_data' ), 99 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the debug functions to specific hooks
|
||||
*/
|
||||
public function debug_data() {
|
||||
global $permalink_manager_options;
|
||||
|
||||
if ( ! empty( $permalink_manager_options['general']['debug_mode'] ) || current_user_can( 'manage_options' ) ) {
|
||||
add_filter( 'permalink_manager_filter_query', array( $this, 'debug_query' ), 9, 5 );
|
||||
add_filter( 'permalink_manager_filter_redirect', array( $this, 'debug_redirect' ), 9, 3 );
|
||||
add_filter( 'wp_redirect', array( $this, 'debug_wp_redirect' ), 9, 2 );
|
||||
|
||||
if ( current_user_can( 'manage_options' ) ) {
|
||||
self::debug_custom_fields();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug the WordPress query filtered in the Permalink_Manager_Core_Functions::detect_post(); function
|
||||
*
|
||||
* @param array $query
|
||||
* @param array $old_query
|
||||
* @param array $uri_parts
|
||||
* @param array $pm_query
|
||||
* @param string $content_type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function debug_query( $query, $old_query = null, $uri_parts = null, $pm_query = null, $content_type = null ) {
|
||||
global $permalink_manager;
|
||||
|
||||
if ( isset( $_REQUEST['debug_url'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No data is saved here
|
||||
$debug_info['uri_parts'] = $uri_parts;
|
||||
$debug_info['old_query_vars'] = $old_query;
|
||||
$debug_info['new_query_vars'] = $query;
|
||||
$debug_info['pm_query'] = ( ! empty( $pm_query['id'] ) ) ? $pm_query['id'] : "-";
|
||||
$debug_info['content_type'] = ( ! empty( $content_type ) ) ? $content_type : "-";
|
||||
|
||||
// License key info
|
||||
if ( class_exists( 'Permalink_Manager_Pro_License' ) ) {
|
||||
$license_key = $permalink_manager->functions['pro-license']->get_license_key();
|
||||
|
||||
// Mask the license key
|
||||
$debug_info['license_key'] = preg_replace( '/([^-]+)-([^-]+)-([^-]+)-([^-]+)$/', '***-***-$3', $license_key );
|
||||
}
|
||||
|
||||
// Plugin version
|
||||
$debug_info['version'] = PERMALINK_MANAGER_VERSION;
|
||||
|
||||
self::display_debug_data( $debug_info );
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug the redirect controlled by Permalink_Manager_Core_Functions::new_uri_redirect_and_404();
|
||||
*
|
||||
* @param string $correct_permalink
|
||||
* @param string $redirect_type
|
||||
* @param mixed $queried_object
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function debug_redirect( $correct_permalink, $redirect_type, $queried_object ) {
|
||||
if ( isset( $_REQUEST['debug_redirect'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No data is saved here
|
||||
$debug_info['redirect_url'] = ( ! empty( $correct_permalink ) ) ? $correct_permalink : '-';
|
||||
$debug_info['redirect_type'] = ( ! empty( $redirect_type ) ) ? $redirect_type : "-";
|
||||
|
||||
self::display_debug_data( $debug_info );
|
||||
}
|
||||
|
||||
return $correct_permalink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug wp_redirect() function used in 3rd party plugins
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $status
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function debug_wp_redirect( $url, $status ) {
|
||||
if ( isset( $_GET['debug_wp_redirect'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No data is saved here
|
||||
$debug_info['url'] = $url;
|
||||
$debug_info['status'] = $status;
|
||||
$debug_info['backtrace'] = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 10 ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace -- Backtrace is a part of debug tools
|
||||
|
||||
self::display_debug_data( $debug_info );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the list of all custom fields assigned to specific post
|
||||
*/
|
||||
public static function debug_custom_fields() {
|
||||
global $pagenow;
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- No data is saved here
|
||||
if ( ! isset( $_GET['debug_custom_fields'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $pagenow == 'post.php' && isset( $_GET['post'] ) ) {
|
||||
$post_id = intval( $_GET['post'] );
|
||||
$custom_fields = get_post_meta( $post_id );
|
||||
}
|
||||
|
||||
if ( $pagenow == 'term.php' && isset( $_GET['tag_ID'] ) ) {
|
||||
$term_id = intval( $_GET['tag_ID'] );
|
||||
|
||||
$custom_fields = get_term_meta( $term_id );
|
||||
}
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
if ( isset ( $custom_fields ) ) {
|
||||
self::display_debug_data( $custom_fields );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function used to display the debug data in various functions
|
||||
*
|
||||
* @param mixed $debug_info
|
||||
*/
|
||||
public static function display_debug_data( $debug_info ) {
|
||||
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- print_r() is a part of debug tool
|
||||
$debug_txt = print_r( $debug_info, true );
|
||||
$debug_txt = sprintf( "<pre style=\"display:block;\">%s</pre>", esc_html( $debug_txt ) );
|
||||
|
||||
wp_die( wp_kses_post( $debug_txt ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a CSV file from array
|
||||
*
|
||||
* @param array $array
|
||||
* @param string $filename
|
||||
*/
|
||||
public static function output_csv( $array, $filename = 'debug.csv', $delimiter = ',' ) {
|
||||
if ( count( $array ) == 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Disable caching
|
||||
$now = gmdate( "D, d M Y H:i:s" );
|
||||
header( "Expires: Tue, 03 Jul 2001 06:00:00 GMT" );
|
||||
header( "Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate" );
|
||||
header( "Last-Modified: {$now} GMT" );
|
||||
|
||||
// Force download
|
||||
header( "Content-Type: application/force-download" );
|
||||
header( "Content-Type: application/octet-stream" );
|
||||
header( "Content-Type: application/download" );
|
||||
header( 'Content-Type: text/csv; charset=utf-8' );
|
||||
|
||||
// Disposition / encoding on response body
|
||||
header( "Content-Disposition: attachment;filename={$filename}" );
|
||||
header( "Content-Transfer-Encoding: binary" );
|
||||
|
||||
$df = fopen( "php://output", 'w' );
|
||||
|
||||
// Use the same delimiter for headers and data
|
||||
fputcsv( $df, array_keys( reset( $array ) ), $delimiter );
|
||||
foreach ( $array as $row ) {
|
||||
fputcsv( $df, $row, $delimiter );
|
||||
}
|
||||
|
||||
fclose( $df ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) exit;
|
||||
|
||||
/**
|
||||
* Support for Gutenberg editor
|
||||
*/
|
||||
class Permalink_Manager_Gutenberg {
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'enqueue_block_editor_assets', array( $this, 'init' ) );
|
||||
|
||||
add_action( 'wp_ajax_pm_get_uri_editor', array( $this, 'get_uri_editor' ) );
|
||||
add_action( 'wp_ajax_nopriv_pm_get_uri_editor', array( $this, 'get_uri_editor' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add URI Editor meta box to Gutenberg editor
|
||||
*/
|
||||
public function init() {
|
||||
global $current_screen, $post;
|
||||
|
||||
// Get displayed post type
|
||||
if ( empty( $current_screen->post_type ) || empty( $post->post_type ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop the hook (if needed)
|
||||
$show_uri_editor = apply_filters( "permalink_manager_show_uri_editor_post", true, $post, $post->post_type );
|
||||
if ( ! $show_uri_editor ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the user capabilities
|
||||
if ( Permalink_Manager_Admin_Functions::current_user_can_edit_uris() === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the post is excluded
|
||||
if ( ! empty( $post->ID ) && Permalink_Manager_Helper_Functions::is_post_excluded( $post ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_meta_box( 'permalink-manager', __( 'Permalink Manager', 'permalink-manager' ), array( $this, 'get_uri_editor' ), '', 'side', 'high' );
|
||||
|
||||
// wp_enqueue_script( 'permalink-manager-gutenberg', PERMALINK_MANAGER_URL . '/out/permalink-manager-gutenberg.js', array( 'wp-plugins', 'wp-edit-post', 'wp-i18n', 'wp-element' ) );
|
||||
// wp_enqueue_style( 'permalink-manager-gutenberg', PERMALINK_MANAGER_URL . '/out/permalink-manager-gutenberg.css', array(), PERMALINK_MANAGER_VERSION );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the URI Editor for specific post
|
||||
*
|
||||
* @param WP_Post|int $post
|
||||
*/
|
||||
public function get_uri_editor( $post = null ) {
|
||||
if ( empty( $post->ID ) && empty( $_REQUEST['post_id'] ) ) {
|
||||
return;
|
||||
} else if ( ! empty( $_REQUEST['post_id'] ) && is_numeric( $_REQUEST['post_id'] ) ) {
|
||||
$post = get_post( $_REQUEST['post_id'] );
|
||||
}
|
||||
|
||||
// Check if the user can edit this post
|
||||
if ( ! empty( $post->ID ) && current_user_can( 'edit_post', $post->ID ) ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo ( $post ) ? Permalink_Manager_UI_Elements::display_uri_box( $post, true ) : '';
|
||||
}
|
||||
|
||||
if ( wp_doing_ajax() && isset( $_GET['action'] ) && $_GET['action'] == 'pm_get_uri_editor' ) {
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+984
@@ -0,0 +1,984 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper functions used in classes and another subclasses
|
||||
*/
|
||||
class Permalink_Manager_Helper_Functions {
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'plugins_loaded', array( $this, 'early_init' ), 5 );
|
||||
add_action( 'plugins_loaded', array( $this, 'init' ), 20 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add early hooks used by plugin to filter the custom permalinks
|
||||
*/
|
||||
public function early_init() {
|
||||
// Reload the globals when the blog is switched (multisite)
|
||||
add_action( 'switch_blog', array( $this, 'reload_globals_in_network' ), 9 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add hooks used by plugin to filter the custom permalinks
|
||||
*/
|
||||
public function init() {
|
||||
global $permalink_manager_options;
|
||||
|
||||
// Clear the final default URIs
|
||||
add_filter( 'permalink_manager_filter_default_term_uri', array( $this, 'clear_single_uri' ), 20 );
|
||||
add_filter( 'permalink_manager_filter_default_post_uri', array( $this, 'clear_single_uri' ), 20 );
|
||||
|
||||
// Force unique URIs when saving them
|
||||
if ( ! empty( $permalink_manager_options['general']['force_unique_uris'] ) ) {
|
||||
add_filter( 'permalink_manager_pre_update_post_uri', array( $this, 'force_unique_uri' ), 100, 3 );
|
||||
add_filter( 'permalink_manager_filter_default_post_uri', array( $this, 'force_unique_uri' ), 100, 3 );
|
||||
add_filter( 'permalink_manager_pre_update_term_uri', array( $this, 'force_unique_uri' ), 100, 3 );
|
||||
add_filter( 'permalink_manager_filter_default_term_uri', array( $this, 'force_unique_uri' ), 100, 3 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the primary term for the specific post
|
||||
*
|
||||
* @param int $post_id
|
||||
* @param string $taxonomy
|
||||
* @param bool $slug_only
|
||||
*
|
||||
* @return array|string|WP_Term
|
||||
*/
|
||||
static function get_primary_term( $post_id, $taxonomy, $slug_only = true ) {
|
||||
global $permalink_manager_options;
|
||||
|
||||
$primary_term_enabled = ( isset( $permalink_manager_options['general']['primary_category'] ) ) ? (bool) $permalink_manager_options['general']['primary_category'] : true;
|
||||
$primary_term_enabled = apply_filters( 'permalink_manager_primary_term', $primary_term_enabled );
|
||||
|
||||
if ( ! $primary_term_enabled ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// A. Yoast SEO
|
||||
if ( class_exists( 'WPSEO_Primary_Term' ) ) {
|
||||
$yoast_primary_term_label = sprintf( 'yoast_wpseo_primary_%s_term', $taxonomy );
|
||||
|
||||
// Hotfix: Yoast SEO saves the primary term using 'save_post' hook with the highest priority, so the primary term ID is taken directly from $_POST
|
||||
if ( ! empty( $_POST[ $yoast_primary_term_label ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
$yoast_primary_term_id = filter_input( INPUT_POST, $yoast_primary_term_label, FILTER_SANITIZE_NUMBER_INT );
|
||||
} else {
|
||||
$yoast_primary_term = new WPSEO_Primary_Term( $taxonomy, $post_id );
|
||||
$yoast_primary_term_id = $yoast_primary_term->get_primary_term();
|
||||
}
|
||||
|
||||
$primary_term = ( is_numeric( $yoast_primary_term_id ) ) ? get_term( $yoast_primary_term_id, $taxonomy ) : '';
|
||||
} // B. The SEO Framework
|
||||
else if ( function_exists( 'the_seo_framework' ) || function_exists( 'tsf' ) ) {
|
||||
if ( class_exists( 'The_SEO_Framework\Data\Plugin\Post' ) ) {
|
||||
$primary_term = The_SEO_Framework\Data\Plugin\Post::get_primary_term( $post_id, $taxonomy );
|
||||
} elseif ( function_exists( 'the_seo_framework' ) && method_exists( the_seo_framework(), 'get_primary_term' ) ) {
|
||||
$primary_term = the_seo_framework()->get_primary_term( $post_id, $taxonomy );
|
||||
}
|
||||
} // C. RankMath
|
||||
else if ( class_exists( 'RankMath' ) ) {
|
||||
$primary_cat_id = get_post_meta( $post_id, "rank_math_primary_{$taxonomy}", true );
|
||||
$primary_term = ( ! empty( $primary_cat_id ) ) ? get_term( $primary_cat_id, $taxonomy ) : '';
|
||||
} // D. SEOPress
|
||||
else if ( function_exists( 'seopress_init' ) && $taxonomy == 'category' ) {
|
||||
$primary_cat_id = get_post_meta( $post_id, '_seopress_robots_primary_cat', true );
|
||||
$primary_term = ( ! empty( $primary_cat_id ) ) ? get_term( $primary_cat_id, 'category' ) : '';
|
||||
} // E. SmartCrawler
|
||||
else if ( class_exists( '\SmartCrawl\SmartCrawl' ) ) {
|
||||
$primary_cat_id = get_post_meta( $post_id, "wds_primary_{$taxonomy}", true );
|
||||
$primary_term = ( ! empty( $primary_cat_id ) ) ? get_term( $primary_cat_id, $taxonomy ) : '';
|
||||
} // F. All In One SEO Pro
|
||||
else if ( class_exists( '\AIOSEO\Plugin\Pro\Standalone\PrimaryTerm' ) ) {
|
||||
$primary_term_class = new \AIOSEO\Plugin\Pro\Standalone\PrimaryTerm();
|
||||
$primary_term = ( method_exists( $primary_term_class, 'getPrimaryTerm' ) ) ? $primary_term_class->getPrimaryTerm( $post_id, $taxonomy ) : '';
|
||||
}
|
||||
|
||||
if ( ! empty( $primary_term ) && ! is_wp_error( $primary_term ) ) {
|
||||
return ( $slug_only ) ? $primary_term->slug : $primary_term;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lowest level term/post in the specific array
|
||||
*
|
||||
* @param WP_Post|WP_Term|int $first_element
|
||||
* @param array $elements
|
||||
*
|
||||
* @return WP_Post|WP_Term|int
|
||||
*/
|
||||
static function get_lowest_element( $first_element, $elements ) {
|
||||
if ( ! empty( $elements ) && ! empty( $first_element ) ) {
|
||||
// Get the ID of first element
|
||||
if ( ! empty( $first_element->term_id ) ) {
|
||||
$first_element_id = $first_element->term_id;
|
||||
$parent_key = 'parent';
|
||||
} else if ( ! empty( $first_element->ID ) ) {
|
||||
$first_element_id = $first_element->ID;
|
||||
$parent_key = 'post_parent';
|
||||
} else if ( is_numeric( $first_element ) ) {
|
||||
$first_element_id = $first_element;
|
||||
$parent_key = 'post_parent';
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
$children = wp_filter_object_list( $elements, array( $parent_key => $first_element_id ) );
|
||||
if ( ! empty( $children ) ) {
|
||||
// Get the first term
|
||||
$child_term = reset( $children );
|
||||
$first_element = self::get_lowest_element( $child_term, $elements );
|
||||
}
|
||||
}
|
||||
|
||||
return $first_element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full (hierarchical) slug for specific term object
|
||||
*
|
||||
* @param WP_Term $term
|
||||
* @param mixed|WP_Term[] $terms
|
||||
* @param bool $mode
|
||||
* @param bool $native_uri
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static function get_term_full_slug( $term, $terms, $mode = false, $native_uri = false ) {
|
||||
global $permalink_manager_uris;
|
||||
|
||||
// Check if term is not empty
|
||||
if ( empty( $term->taxonomy ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Get taxonomy
|
||||
$taxonomy = $term->taxonomy;
|
||||
|
||||
// Check if mode is set
|
||||
if ( empty( $mode ) ) {
|
||||
$mode = ( is_taxonomy_hierarchical( $taxonomy ) ) ? 2 : 4;
|
||||
}
|
||||
|
||||
// A. Inherit the custom permalink from the term
|
||||
if ( $mode == 1 ) {
|
||||
$term_slug = ( ! empty( $permalink_manager_uris["tax-{$term->term_id}"] ) ) ? $permalink_manager_uris["tax-{$term->term_id}"] : '';
|
||||
} // B. Hierarchical taxonomy base
|
||||
else if ( $mode == 2 ) {
|
||||
$ancestors = get_ancestors( $term->term_id, $taxonomy, 'taxonomy' );
|
||||
$hierarchical_slugs = array();
|
||||
|
||||
foreach ( $ancestors as $ancestor ) {
|
||||
$ancestor_term = get_term( $ancestor, $taxonomy );
|
||||
$hierarchical_slugs[] = ( $native_uri ) ? $ancestor_term->slug : self::force_custom_slugs( $ancestor_term->slug, $ancestor_term );
|
||||
}
|
||||
$hierarchical_slugs = array_reverse( $hierarchical_slugs );
|
||||
$term_slug = implode( '/', $hierarchical_slugs );
|
||||
|
||||
// Append the term slug now
|
||||
$last_term_slug = ( $native_uri ) ? $term->slug : self::force_custom_slugs( $term->slug, $term );
|
||||
$term_slug = "{$term_slug}/{$last_term_slug}";
|
||||
} // C. Force flat taxonomy base - get the highest level term (if %taxonomy_top% tag is used)
|
||||
else if ( $mode == 3 ) {
|
||||
if ( ! empty( $term->parent ) ) {
|
||||
$ancestors = get_ancestors( $term->term_id, $taxonomy, 'taxonomy' );
|
||||
|
||||
if ( is_array( $ancestors ) ) {
|
||||
$top_ancestor = end( $ancestors );
|
||||
$top_ancestor_term = get_term( $top_ancestor, $taxonomy );
|
||||
$single_term = ( ! empty( $top_ancestor_term->slug ) ) ? $top_ancestor_term : $term;
|
||||
}
|
||||
}
|
||||
|
||||
$term_slug = ( ! empty( $single_term->slug ) ) ? self::force_custom_slugs( $single_term->slug, $single_term ) : $term->slug;
|
||||
} // D. Force flat taxonomy base - get primary or lowest level term (if term is non-hierarchical or %taxonomy_flat% tag is used)
|
||||
else {
|
||||
if ( ! empty( $term->slug ) ) {
|
||||
$term_slug = ( $native_uri ) ? $term->slug : Permalink_Manager_Helper_Functions::force_custom_slugs( $term->slug, $term );
|
||||
} else if ( ! empty ( $terms ) ) {
|
||||
foreach ( $terms as $single_term ) {
|
||||
if ( $single_term->parent == 0 ) {
|
||||
$term_slug = self::force_custom_slugs( $single_term->slug, $single_term );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ( ! empty( $term_slug ) ) ? $term_slug : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full (hierarchical) slug for specific post object
|
||||
*
|
||||
* @param WP_Post|int $post
|
||||
* @param bool $slugs_mode
|
||||
* @param bool $native_uri
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static function get_post_full_slug( $post, $slugs_mode = false, $native_uri = false ) {
|
||||
$post = ( ! empty( $post->ID ) ) ? $post : get_post( $post );
|
||||
|
||||
if ( ! empty( $post->post_type ) ) {
|
||||
$full_native_slug = $post->post_name;
|
||||
$full_custom_slug = Permalink_Manager_Helper_Functions::force_custom_slugs( $post->post_name, $post, false, $slugs_mode );
|
||||
|
||||
if ( $post->ancestors && is_post_type_hierarchical( $post->post_type ) ) {
|
||||
foreach ( $post->ancestors as $parent ) {
|
||||
$parent = get_post( $parent );
|
||||
if ( $parent && $parent->post_name ) {
|
||||
$full_native_slug = $parent->post_name . '/' . $full_native_slug;
|
||||
$full_custom_slug = Permalink_Manager_Helper_Functions::force_custom_slugs( $parent->post_name, $parent, false, $slugs_mode ) . '/' . $full_custom_slug;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$post_slug = ( $native_uri ) ? $full_native_slug : $full_custom_slug;
|
||||
}
|
||||
|
||||
return ( ! empty( $post_slug ) ) ? $post_slug : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow to disable post types and taxonomies
|
||||
*/
|
||||
static function get_disabled_post_types( $include_user_excluded = true ) {
|
||||
global $wp_post_types, $permalink_manager_options;
|
||||
|
||||
$allowed_post_types = array(
|
||||
'shop_coupon'
|
||||
);
|
||||
|
||||
$disabled_post_types = array(
|
||||
'revision',
|
||||
'nav_menu_item',
|
||||
'algolia_task',
|
||||
'fl_builder',
|
||||
'fl-builder',
|
||||
'fl-builder-template',
|
||||
'fl-theme-layout',
|
||||
'fusion_tb_layout',
|
||||
'fusion_tb_section',
|
||||
'fusion_template',
|
||||
'fusion_element',
|
||||
'wc_product_tab',
|
||||
'wc_voucher',
|
||||
'wc_voucher_template',
|
||||
'sliders',
|
||||
'thirstylink',
|
||||
'elementor_library',
|
||||
'elementor_menu_item',
|
||||
'cms_block',
|
||||
'nooz_coverage',
|
||||
'bricks_template'
|
||||
);
|
||||
|
||||
// 1. Disable post types that are not publicly_queryable
|
||||
foreach ( $wp_post_types as $post_type ) {
|
||||
if ( in_array( $post_type->name, $allowed_post_types ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! is_post_type_viewable( $post_type ) || ( empty( $post_type->query_var ) && empty( $post_type->rewrite ) && empty( $post_type->_builtin ) && ! empty( $permalink_manager_options['general']['partial_disable_strict'] ) ) ) {
|
||||
$disabled_post_types[] = $post_type->name;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Add post types disabled by user
|
||||
if ( $include_user_excluded ) {
|
||||
$disabled_post_types = ( ! empty( $permalink_manager_options['general']['partial_disable']['post_types'] ) ) ? array_merge( (array) $permalink_manager_options['general']['partial_disable']['post_types'], $disabled_post_types ) : $disabled_post_types;
|
||||
}
|
||||
|
||||
return apply_filters( 'permalink_manager_disabled_post_types', $disabled_post_types );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array of all (including/excluding user selected) disabled taxonomies
|
||||
*
|
||||
* @param bool $include_user_excluded
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static function get_disabled_taxonomies( $include_user_excluded = true ) {
|
||||
global $wp_taxonomies, $permalink_manager_options;
|
||||
|
||||
$disabled_taxonomies = array(
|
||||
'product_shipping_class',
|
||||
'post_status',
|
||||
'fl-builder-template-category',
|
||||
'post_format',
|
||||
'nav_menu',
|
||||
'language',
|
||||
'template_bundle'
|
||||
);
|
||||
|
||||
// 1. Disable taxonomies that are not publicly_queryable
|
||||
foreach ( $wp_taxonomies as $taxonomy ) {
|
||||
if ( ! is_taxonomy_viewable( $taxonomy ) || ( empty( $taxonomy->query_var ) && empty( $taxonomy->rewrite ) && empty( $taxonomy->_builtin ) && ! empty( $permalink_manager_options['general']['partial_disable_strict'] ) ) ) {
|
||||
$disabled_taxonomies[] = $taxonomy->name;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Add taxonomies disabled by user
|
||||
if ( $include_user_excluded ) {
|
||||
$disabled_taxonomies = ( ! empty( $permalink_manager_options['general']['partial_disable']['taxonomies'] ) ) ? array_merge( (array) $permalink_manager_options['general']['partial_disable']['taxonomies'], $disabled_taxonomies ) : $disabled_taxonomies;
|
||||
}
|
||||
|
||||
return apply_filters( 'permalink_manager_disabled_taxonomies', $disabled_taxonomies );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the post type should be ignored by Permalink Manager
|
||||
*
|
||||
* @param string $post_type
|
||||
* @param bool $check_if_exists
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
static public function is_post_type_disabled( $post_type, $check_if_exists = true ) {
|
||||
$disabled_post_types = self::get_disabled_post_types();
|
||||
$post_type_exists = ( $check_if_exists ) ? post_type_exists( $post_type ) : true;
|
||||
|
||||
return ( ( is_array( $disabled_post_types ) && in_array( $post_type, $disabled_post_types ) ) || empty( $post_type_exists ) ) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the taxonomy should be ignored by Permalink Manager
|
||||
*
|
||||
* @param string $taxonomy
|
||||
* @param bool $check_if_exists
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
static public function is_taxonomy_disabled( $taxonomy, $check_if_exists = true ) {
|
||||
$disabled_taxonomies = self::get_disabled_taxonomies();
|
||||
$taxonomy_exists = ( $check_if_exists ) ? taxonomy_exists( $taxonomy ) : true;
|
||||
|
||||
return ( ( is_array( $disabled_taxonomies ) && in_array( $taxonomy, $disabled_taxonomies ) ) || empty( $taxonomy_exists ) ) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all excluded posts' IDs
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_excluded_post_ids() {
|
||||
global $permalink_manager_options;
|
||||
|
||||
if ( ! empty( $permalink_manager_options["general"]["exclude_post_ids"] ) ) {
|
||||
$excluded_post_ids_raw = $permalink_manager_options["general"]["exclude_post_ids"];
|
||||
|
||||
$excluded_post_ids = self::get_ids_from_string( $excluded_post_ids_raw );
|
||||
} else {
|
||||
$excluded_post_ids = array();
|
||||
}
|
||||
|
||||
// Allow to filter the array via filter
|
||||
$excluded_post_ids = apply_filters( 'permalink_manager_excluded_post_ids', $excluded_post_ids );
|
||||
|
||||
// Only numeric IDs are allowed
|
||||
return ( ! empty( $excluded_post_ids ) ) ? array_filter( $excluded_post_ids, 'is_numeric' ) : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if specific post should be ignored by Permalink Manager
|
||||
*
|
||||
* @param WP_Post|int $post
|
||||
* @param bool $draft_check
|
||||
* @param bool $strict_draft_check
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_post_excluded( $post = null, $draft_check = false, $strict_draft_check = false ) {
|
||||
$post = ( is_numeric( $post ) ) ? get_post( $post ) : $post;
|
||||
|
||||
// 1. Check if post type is disabled
|
||||
if ( ! empty( $post->post_type ) && self::is_post_type_disabled( $post->post_type ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2. Get list of post IDs excluded in the plugin settings or via the filter
|
||||
$excluded_post_ids = self::get_excluded_post_ids();
|
||||
|
||||
// 3. Exclude post IDs excluded via the filter or in the plugin settings
|
||||
if ( is_array( $excluded_post_ids ) && ! empty( $post->ID ) && in_array( $post->ID, $excluded_post_ids ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// D. Check if post is a "draft", "pending", removed
|
||||
if ( $draft_check ) {
|
||||
return self::is_draft_excluded( $post, $strict_draft_check );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if specific post is a draft (or pending)
|
||||
*
|
||||
* @param WP_Post|int $post
|
||||
* @param bool $strict_draft_check
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_draft_excluded( $post = null, $strict_draft_check = false ) {
|
||||
global $permalink_manager_options;
|
||||
|
||||
$post = ( is_numeric( $post ) ) ? get_post( $post ) : $post;
|
||||
|
||||
// Check if post is a "draft", "pending" or moved to trash
|
||||
if ( ! empty( $post->post_status ) ) {
|
||||
if ( ! empty( $permalink_manager_options["general"]["ignore_drafts"] ) || $strict_draft_check ) {
|
||||
$post_statuses = ( $permalink_manager_options["general"]["ignore_drafts"] == 2 ) ? array( 'draft', 'pending' ) : array( 'draft' );
|
||||
|
||||
if ( in_array( $post->post_status, $post_statuses ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( in_array( $post->post_status, array( 'auto-draft', 'trash' ) ) || ( strpos( $post->post_name, 'revision-v1' ) !== false ) || ( ! empty( $post->post_name ) && $post->post_name == 'auto-draft' ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all excluded terms' IDs
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_excluded_term_ids() {
|
||||
global $permalink_manager_options;
|
||||
|
||||
if ( ! empty( $permalink_manager_options["general"]["exclude_term_ids"] ) ) {
|
||||
$excluded_term_ids_raw = $permalink_manager_options["general"]["exclude_term_ids"];
|
||||
|
||||
$excluded_term_ids = self::get_ids_from_string( $excluded_term_ids_raw );
|
||||
} else {
|
||||
$excluded_term_ids = array();
|
||||
}
|
||||
|
||||
// Allow to filter the array via filter
|
||||
$excluded_term_ids = apply_filters( 'permalink_manager_excluded_term_ids', $excluded_term_ids );
|
||||
|
||||
// Only numeric IDs are allowed
|
||||
return ( ! empty( $excluded_term_ids ) ) ? array_filter( $excluded_term_ids, 'is_numeric' ) : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if specific term should be ignored by Permalink Manager
|
||||
*
|
||||
* @param WP_Term $term
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_term_excluded( $term = null ) {
|
||||
$term = ( is_numeric( $term ) ) ? get_term( $term ) : $term;
|
||||
|
||||
// 1. Check if taxonomy is disabled
|
||||
if ( ! empty( $term->taxonomy ) && self::is_taxonomy_disabled( $term->taxonomy ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2. Get list of term IDs excluded in the plugin settings or via the filter
|
||||
$excluded_term_ids = self::get_excluded_term_ids();
|
||||
|
||||
// 3. Exclude term IDs excluded via the filter or in the plugin settings
|
||||
if ( is_array( $excluded_term_ids ) && ! empty( $term->term_id ) && in_array( $term->term_id, $excluded_term_ids ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all post types supported by Permalink Manager
|
||||
*
|
||||
* @param string $format
|
||||
* @param string $cpt
|
||||
* @param bool $include_user_excluded
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static function get_post_types_array( $format = null, $cpt = null, $include_user_excluded = false ) {
|
||||
global $wp_post_types;
|
||||
|
||||
$post_types_array = array();
|
||||
$disabled_post_types = self::get_disabled_post_types( ! $include_user_excluded );
|
||||
|
||||
foreach ( $wp_post_types as $post_type ) {
|
||||
if ( $format == 'full' ) {
|
||||
$post_types_array[ $post_type->name ] = array( 'label' => $post_type->labels->name, 'name' => $post_type->name );
|
||||
} else if ( $format == 'archive_slug' ) {
|
||||
// Ignore non-public post types
|
||||
if ( ! is_post_type_viewable( $post_type ) || empty( $post_type->has_archive ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! $post_type->has_archive ) {
|
||||
$archive_slug = $post_type->has_archive;
|
||||
} else if ( is_array( $post_type->rewrite ) && ! empty( $post_type->rewrite['slug'] ) ) {
|
||||
$archive_slug = $post_type->rewrite['slug'];
|
||||
} else {
|
||||
$archive_slug = $post_type->name;
|
||||
}
|
||||
|
||||
$post_types_array[ $post_type->name ] = $archive_slug;
|
||||
} else {
|
||||
$post_types_array[ $post_type->name ] = $post_type->labels->name;
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_array( $disabled_post_types ) ) {
|
||||
foreach ( $disabled_post_types as $post_type ) {
|
||||
if ( ! empty( $post_types_array[ $post_type ] ) ) {
|
||||
unset( $post_types_array[ $post_type ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ( empty( $cpt ) ) ? $post_types_array : $post_types_array[ $cpt ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all taxonomies supported by Permalink Manager
|
||||
*
|
||||
* @param string $format
|
||||
* @param string $tax
|
||||
* @param bool $include_user_excluded
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static function get_taxonomies_array( $format = null, $tax = null, $include_user_excluded = false ) {
|
||||
global $wp_taxonomies;
|
||||
|
||||
$taxonomies_array = array();
|
||||
$disabled_taxonomies = self::get_disabled_taxonomies( ! $include_user_excluded );
|
||||
|
||||
foreach ( $wp_taxonomies as $taxonomy ) {
|
||||
$taxonomy_name = ( ! empty( $taxonomy->labels->name ) ) ? $taxonomy->labels->name : '-';
|
||||
|
||||
$taxonomies_array[ $taxonomy->name ] = ( $format == 'full' ) ? array( 'label' => $taxonomy->labels->name, 'name' => $taxonomy->name ) : $taxonomy_name;
|
||||
}
|
||||
|
||||
if ( is_array( $disabled_taxonomies ) ) {
|
||||
foreach ( $disabled_taxonomies as $taxonomy ) {
|
||||
if ( ! empty( $taxonomies_array[ $taxonomy ] ) ) {
|
||||
unset( $taxonomies_array[ $taxonomy ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ksort( $taxonomies_array );
|
||||
|
||||
return ( empty( $tax ) ) ? $taxonomies_array : $taxonomies_array[ $tax ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all post statuses supported by Permalink Manager
|
||||
*/
|
||||
static function get_post_statuses() {
|
||||
$post_statuses = get_post_statuses();
|
||||
|
||||
if ( is_array( $post_statuses ) ) {
|
||||
$post_statuses['future'] = __( 'Scheduled', 'permalink-manager' );
|
||||
}
|
||||
|
||||
return apply_filters( 'permalink_manager_post_statuses', $post_statuses );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the endpoints registered for WP_Rewrite object
|
||||
*/
|
||||
static function get_endpoints() {
|
||||
global $wp_rewrite;
|
||||
|
||||
$pagination_endpoint = ( ! empty( $wp_rewrite->pagination_base ) ) ? $wp_rewrite->pagination_base : 'page';
|
||||
|
||||
// Start with default endpoints
|
||||
$endpoints = "{$pagination_endpoint}|feed|embed|attachment|trackback";
|
||||
|
||||
if ( ! empty( $wp_rewrite->endpoints ) ) {
|
||||
foreach ( $wp_rewrite->endpoints as $endpoint ) {
|
||||
$endpoints .= "|{$endpoint[1]}";
|
||||
}
|
||||
}
|
||||
|
||||
return apply_filters( "permalink_manager_endpoints", str_replace( "/", "\/", $endpoints ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the specific post is selected as a front-page
|
||||
*
|
||||
* @param int $page_id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
static function is_front_page( $page_id ) {
|
||||
$front_page_id = get_option( 'page_on_front' );
|
||||
$bool = ( ! empty( $front_page_id ) && $page_id == $front_page_id ) ? true : false;
|
||||
|
||||
return apply_filters( 'permalink_manager_is_front_page', $bool, $page_id, $front_page_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the advanced mode is turned on
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
static function is_advanced_mode_on() {
|
||||
global $permalink_manager_options;
|
||||
|
||||
$bool = ( ! empty( $permalink_manager_options["general"]["advanced_mode"] ) && $permalink_manager_options["general"]["advanced_mode"] == 1 ) ? true : false;
|
||||
|
||||
return apply_filters( 'permalink_manager_advanced_mode_on', $bool );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the multidimensional array
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static function sanitize_array( $data = array(), $sanitize = false ) {
|
||||
if ( ! is_array( $data ) || ! count( $data ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
foreach ( $data as $k => $v ) {
|
||||
if ( ! is_array( $v ) && ! is_object( $v ) ) {
|
||||
$data[ $k ] = ( $sanitize ) ? sanitize_text_field( trim( $v ) ) : htmlspecialchars( trim( $v ) );
|
||||
}
|
||||
if ( is_array( $v ) ) {
|
||||
$data[ $k ] = self::sanitize_array( $v );
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of strings for use in SQL IN clause
|
||||
*
|
||||
* @param array $array Array of strings to prepare
|
||||
* @param bool $sanitize
|
||||
*
|
||||
* @return string Comma-separated string with quoted values, e.g., "'value1','value2','value3'"
|
||||
*/
|
||||
static function prepare_array_for_sql_in( $array, $sanitize = true ) {
|
||||
// Ensure we have an array
|
||||
if ( ! is_array( $array ) ) {
|
||||
$array = (array) $array;
|
||||
}
|
||||
|
||||
// Remove empty values and sanitize
|
||||
$array = array_filter( $array );
|
||||
$array = ( $sanitize ) ? array_map( 'sanitize_text_field', $array ) : $array;
|
||||
|
||||
// Return empty string if array is empty
|
||||
if ( empty( $array ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Escape and wrap each value with quotes
|
||||
$escaped = array_map( function ( $value ) {
|
||||
return "'" . esc_sql( $value ) . "'";
|
||||
}, $array );
|
||||
|
||||
// Join with comma
|
||||
return implode( ',', $escaped );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the text containing IDs and/or ID ranges to an array
|
||||
*
|
||||
* @param string $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static function get_ids_from_string( $data ) {
|
||||
// Remove whitespaces and other invalid characters
|
||||
$raw_ids = esc_sql( preg_replace( '/[^\d,-]/', '', $data ) );
|
||||
|
||||
// Convert the string into the array with IDs and/or ranges
|
||||
preg_match_all( "/([\d]+(?:-?[\d]+)?)/x", $raw_ids, $groups );
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ( ! empty( $groups[1] ) ) {
|
||||
foreach ( $groups[1] as $group ) {
|
||||
if ( is_numeric( $group ) ) {
|
||||
$ids[] = $group;
|
||||
} else if ( preg_match( '/([\d]+)-([\d]+)/', $group, $range_limits ) ) {
|
||||
$range_start = (int) $range_limits[1];
|
||||
$range_end = (int) $range_limits[2];
|
||||
|
||||
if ( $range_start < $range_end ) {
|
||||
$ids = array_merge( $ids, range( $range_start, $range_end ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ids = array_unique( $ids );
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode URI and keep special characters
|
||||
*
|
||||
* @param string $uri
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static function encode_uri( $uri ) {
|
||||
return str_replace( array( '%2F', '%2C', '%7C', '%2B' ), array( '/', ',', '|', '+' ), urlencode( $uri ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the given string to URI-safe format
|
||||
*
|
||||
* @param string $str
|
||||
* @param bool $keep_percent_sign
|
||||
* @param bool $force_lowercase
|
||||
* @param bool $sanitize_slugs
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function sanitize_title( $str, $keep_percent_sign = false, $force_lowercase = null, $sanitize_slugs = null ) {
|
||||
global $permalink_manager_options;
|
||||
|
||||
// Force lowercase & hyphens
|
||||
$force_lowercase = ( ! is_null( $force_lowercase ) ) ? $force_lowercase : apply_filters( 'permalink_manager_force_lowercase_uris', true );
|
||||
|
||||
if ( is_null( $sanitize_slugs ) ) {
|
||||
$sanitize_slugs = ( ! empty( $permalink_manager_options['general']['disable_slug_sanitization'] ) ) ? false : true;
|
||||
}
|
||||
|
||||
// Allow to filter the slug before it is sanitized
|
||||
$str = apply_filters( 'permalink_manager_pre_sanitize_title', $str, $keep_percent_sign, $force_lowercase, $sanitize_slugs );
|
||||
|
||||
// Remove accents & entities
|
||||
$clean = ( empty( $permalink_manager_options['general']['keep_accents'] ) ) ? remove_accents( $str ) : $str;
|
||||
$clean = str_replace( array( '<', '>', '&' ), '', $clean );
|
||||
|
||||
$percent_sign = ( $keep_percent_sign ) ? "\%" : "";
|
||||
$sanitize_regex = apply_filters( "permalink_manager_sanitize_regex", "/[^\p{Xan}a-zA-Z0-9{$percent_sign}\/_\.|+, -]/ui", $percent_sign );
|
||||
$clean = preg_replace( $sanitize_regex, '', $clean );
|
||||
|
||||
if ( empty( $clean ) ) {
|
||||
return $str;
|
||||
}
|
||||
|
||||
// Lowercase with non-ASCII characters support
|
||||
if ( $force_lowercase && function_exists( 'mb_strtolower' ) && function_exists( 'wp_is_valid_utf8' ) && wp_is_valid_utf8( $clean ) ) {
|
||||
$clean = mb_strtolower( $clean, 'UTF-8' );
|
||||
} else if ( $force_lowercase ) {
|
||||
$clean = strtolower( $clean );
|
||||
}
|
||||
|
||||
// Remove ampersand
|
||||
$clean = str_replace( array( '%26', '&' ), '', $clean );
|
||||
|
||||
// Remove special characters
|
||||
if ( $sanitize_slugs !== false ) {
|
||||
$clean = preg_replace( "/[\s|+-]+/", "-", $clean );
|
||||
$clean = preg_replace( "/[,]+/", "", $clean );
|
||||
$clean = preg_replace( '/([\.]+)(?![a-z]{3,4}$)/i', '', $clean );
|
||||
$clean = preg_replace( '/([-\s+]\/[-\s+])/', '-', $clean );
|
||||
$clean = preg_replace( '|-+|', '-', $clean );
|
||||
} else {
|
||||
$clean = preg_replace( "/[\s]+/", "-", $clean );
|
||||
}
|
||||
|
||||
// Remove widow & duplicated slashes
|
||||
$clean = preg_replace( '/([-]*[\/]+[-]*)/', '/', $clean );
|
||||
$clean = preg_replace( '/([\/]+)/', '/', $clean );
|
||||
|
||||
// Trim slashes, dashes and whitespaces
|
||||
$clean = trim( $clean, " /-" );
|
||||
|
||||
// Allow to filter the slug after it is sanitized
|
||||
return apply_filters( 'permalink_manager_sanitize_title', $clean, $str, $keep_percent_sign, $force_lowercase, $sanitize_slugs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the string in custom permalink or native slug
|
||||
*
|
||||
* @param string $old_string
|
||||
* @param string $new_string
|
||||
* @param string $old_slug
|
||||
* @param string $old_uri
|
||||
* @param string $mode
|
||||
*
|
||||
* @return array|void
|
||||
*/
|
||||
public static function replace_uri_slug( $old_string, $new_string, $old_slug, $old_uri, $mode ) {
|
||||
if ( preg_match( "/^\#.+\#$/i", $old_string ) ) {
|
||||
$old_string = trim( $old_string, '#' );
|
||||
|
||||
$allowed_in_chars = '/[\w\d\s\.\*\+\-\?\!\/\|\(\)\{\}\[\]^$]/';
|
||||
$allowed_out_chars = '/^[a-zA-Z0-9\.\/\$\-\_]+$/';
|
||||
|
||||
if ( ! preg_match( $allowed_in_chars, $old_string ) || ! preg_match( $allowed_out_chars, $new_string ) ) {
|
||||
die( 'Invalid characters in REGEX formula.' );
|
||||
}
|
||||
|
||||
$pattern = "#{$old_string}#";
|
||||
|
||||
$new_slug = ( $mode == 'slugs' ) ? preg_replace( $pattern, $new_string, $old_slug ) : $old_slug;
|
||||
$new_uri = ( $mode != 'slugs' ) ? preg_replace( $pattern, $new_string, $old_uri ) : $old_uri;
|
||||
} else {
|
||||
$new_slug = ( $mode == 'slugs' ) ? str_replace( $old_string, $new_string, $old_slug ) : $old_slug;
|
||||
$new_uri = ( $mode != 'slugs' ) ? str_replace( $old_string, $new_string, $old_uri ) : $old_uri;
|
||||
}
|
||||
|
||||
return array( $new_slug, $new_uri );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the final custom permalink URI
|
||||
*
|
||||
* @param string $uri
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function clear_single_uri( $uri ) {
|
||||
return self::sanitize_title( $uri, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all slashes from given string
|
||||
*
|
||||
* @param string $uri
|
||||
* @param string $replacement
|
||||
*
|
||||
* @return array|string|string[]|null
|
||||
*/
|
||||
public static function remove_slashes( $uri, $replacement = '' ) {
|
||||
return preg_replace( "/[\/]+/", $replacement, $uri );
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the given slug with the actual title or custom permalink of specific post or term
|
||||
*
|
||||
* @param string $slug
|
||||
* @param WP_Post|WP_Term $object
|
||||
* @param bool $flat
|
||||
* @param null $force_custom_slugs
|
||||
* @param bool $allow_inherit
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function force_custom_slugs( $slug, $object, $flat = false, $force_custom_slugs = null, $allow_inherit = true ) {
|
||||
global $permalink_manager_options;
|
||||
|
||||
if ( empty( $force_custom_slugs ) ) {
|
||||
$force_custom_slugs = ( ! empty( $permalink_manager_options['general']['force_custom_slugs'] ) ) ? $permalink_manager_options['general']['force_custom_slugs'] : false;
|
||||
$force_custom_slugs = apply_filters( 'permalink_manager_force_custom_slugs', $force_custom_slugs, $slug, $object );
|
||||
}
|
||||
|
||||
if ( $force_custom_slugs ) {
|
||||
// A. Custom slug (title)
|
||||
if ( $force_custom_slugs == 1 ) {
|
||||
if ( ! empty( $object->name ) && ! empty( $object->taxonomy ) ) {
|
||||
$title = $object->name;
|
||||
} else if ( ! empty( $object->post_title ) && ! empty( $object->post_type ) ) {
|
||||
$title = $object->post_title;
|
||||
} else {
|
||||
return $slug;
|
||||
}
|
||||
|
||||
$title = wp_strip_all_tags( $title );
|
||||
$title = self::remove_slashes( $title, '-' );
|
||||
|
||||
$new_slug = self::sanitize_title( $title );
|
||||
|
||||
} // B. Custom slug (inherit custom permalink from the parent object)
|
||||
else if ( $allow_inherit ) {
|
||||
$new_slug = basename( Permalink_Manager_URI_Functions::get_single_uri( $object, false, true ) );
|
||||
}
|
||||
|
||||
$slug = ( ! empty( $new_slug ) ) ? preg_replace( '/([^\/]+)$/', $new_slug, $slug ) : $slug;
|
||||
}
|
||||
|
||||
if ( $flat ) {
|
||||
$slug = preg_replace( "/([^\/]+)(.*)/", "$1", $slug );
|
||||
}
|
||||
|
||||
return $slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that a permalink is unique by appending a numeric suffix if needed
|
||||
*
|
||||
* @param string $new_uri
|
||||
* @param string|int $element_id
|
||||
* @param string|WP_Post|WP_Term $element
|
||||
*
|
||||
* @return string A unique custom permalink string.
|
||||
*/
|
||||
function force_unique_uri( $new_uri, $element_id, $element = '' ) {
|
||||
// Determine the ID based on the object type
|
||||
if ( is_a( $element, 'WP_Term' ) && strpos( current_action(), "_term_" ) !== false ) {
|
||||
$element_id = $element->term_id;
|
||||
$is_tax = true;
|
||||
} elseif ( is_a( $element, 'WP_Post' ) ) {
|
||||
$element_id = $element->ID;
|
||||
}
|
||||
|
||||
if ( empty( $element_id ) || ! is_numeric( $element_id ) ) {
|
||||
return $new_uri;
|
||||
}
|
||||
|
||||
if ( ! empty( $is_tax ) ) {
|
||||
$element_id = "tax-{$element_id}";
|
||||
}
|
||||
|
||||
// Prepare base + extension
|
||||
if ( ! preg_match( '/^(.+?)(?:-([\d]+))?(\.[^\.]+$|$)/', $new_uri, $parts ) ) {
|
||||
return $new_uri; // fallback if regex fails
|
||||
}
|
||||
|
||||
$base = $parts[1];
|
||||
$index = empty( $parts[2] ) ? 1 : (int) $parts[2];
|
||||
$extension = $parts[3];
|
||||
|
||||
$unique_uri = $new_uri;
|
||||
|
||||
// Increment suffix until URI is unique
|
||||
while ( Permalink_Manager_URI_Functions::is_uri_duplicated( $unique_uri, $element_id ) ) {
|
||||
$index ++;
|
||||
$unique_uri = "{$base}-{$index}{$extension}";
|
||||
}
|
||||
|
||||
return $unique_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload the globals when the blog is switched (multisite)
|
||||
*
|
||||
* @param int $new_blog_id
|
||||
*/
|
||||
public function reload_globals_in_network( $new_blog_id ) {
|
||||
global $permalink_manager_uris, $permalink_manager_redirects, $permalink_manager_external_redirects;
|
||||
|
||||
if ( function_exists( 'get_blog_option' ) ) {
|
||||
$permalink_manager_uris = get_blog_option( $new_blog_id, 'permalink-manager-uris', array() );
|
||||
$permalink_manager_redirects = get_blog_option( $new_blog_id, 'permalink-manager-redirects', array() );
|
||||
$permalink_manager_external_redirects = get_blog_option( $new_blog_id, 'permalink-manager-external-redirects', array() );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) exit;
|
||||
|
||||
/**
|
||||
* Helper functions used for Permastructures (permalink formats)
|
||||
*/
|
||||
class Permalink_Manager_Permastructure_Functions {
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'plugins_loaded', array( $this, 'init' ), 5 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add hooks used by plugin to filter the custom permalinks
|
||||
*/
|
||||
function init() {
|
||||
// Replace empty placeholder tags & remove BOM
|
||||
add_filter( 'permalink_manager_filter_default_post_uri', array( $this, 'replace_empty_placeholder_tags' ), 10, 5 );
|
||||
add_filter( 'permalink_manager_filter_default_term_uri', array( $this, 'replace_empty_placeholder_tags' ), 10, 5 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default permalink format for specific post type
|
||||
*
|
||||
* @param string $post_type
|
||||
* @param bool $remove_post_tag
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static function get_default_permastruct( $post_type = 'page', $remove_post_tag = false ) {
|
||||
global $wp_rewrite;
|
||||
|
||||
// Get default permastruct
|
||||
if ( $post_type == 'page' ) {
|
||||
$permastruct = $wp_rewrite->get_page_permastruct();
|
||||
} else if ( $post_type == 'post' ) {
|
||||
$permastruct = get_option( 'permalink_structure' );
|
||||
} else {
|
||||
$permastruct = $wp_rewrite->get_extra_permastruct( $post_type );
|
||||
}
|
||||
|
||||
return ( $remove_post_tag ) ? trim( str_replace( array( "%postname%", "%pagename%", "%{$post_type}%" ), "", $permastruct ), "/" ) : $permastruct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post name permastructure tag for specific post type
|
||||
*
|
||||
* @param string $post_type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static function get_post_tag( $post_type ) {
|
||||
// Get the post type (with fix for posts & pages)
|
||||
if ( $post_type == 'page' ) {
|
||||
$post_type_tag = '%pagename%';
|
||||
} else if ( $post_type == 'post' ) {
|
||||
$post_type_tag = '%postname%';
|
||||
} else {
|
||||
$post_type_tag = "%{$post_type}%";
|
||||
}
|
||||
|
||||
return $post_type_tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any of slug tags is present inside Permastructure settings
|
||||
*
|
||||
* @param $default_uri
|
||||
* @param $slug_tags
|
||||
* @param $content_element
|
||||
*
|
||||
* @return bool|null
|
||||
*/
|
||||
public static function is_slug_tag_present( $default_uri, $slug_tags, $content_element ) {
|
||||
global $permalink_manager_options;
|
||||
|
||||
// Check if any post tag is present in custom permastructure
|
||||
if ( ! empty( $content_element->post_type ) ) {
|
||||
$content_type = $content_element->post_type;
|
||||
$content_type_key = 'post_types';
|
||||
} else if ( ! empty( $content_element->taxonomy ) ) {
|
||||
$content_type = $content_element->taxonomy;
|
||||
$content_type_key = 'taxonomies';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
$permastructure_settings = ( ! empty( $permalink_manager_options['permastructure-settings'] ) ) ? $permalink_manager_options['permastructure-settings'] : array();
|
||||
$do_not_append_settings = ( ! empty( $permastructure_settings['do_not_append_slug'] ) ) ? $permastructure_settings['do_not_append_slug'] : array();
|
||||
$do_not_append_slug = ( ! empty( $do_not_append_settings[ $content_type_key ] ) && ! empty( $do_not_append_settings[ $content_type_key ][ $content_type ] ) ) ? true : false;
|
||||
$do_not_append_slug = apply_filters( "permalink_manager_do_not_append_slug", $do_not_append_slug, $content_type, $content_element );
|
||||
|
||||
if ( ! $do_not_append_slug ) {
|
||||
foreach ( $slug_tags as $tag ) {
|
||||
if ( strpos( $default_uri, $tag ) !== false ) {
|
||||
$do_not_append_slug = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3F. Replace the post tags with slugs or append the slug if no post tag is defined
|
||||
if ( ! empty( $do_not_append_slug ) ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace empty placeholder tags & remove BOM
|
||||
*
|
||||
* @param string $default_uri
|
||||
* @param string $native_slug
|
||||
* @param string $element
|
||||
* @param string $slug
|
||||
* @param bool $native_uri
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function replace_empty_placeholder_tags( $default_uri, $native_slug = "", $element = "", $slug = "", $native_uri = false ) {
|
||||
// Remove the BOM
|
||||
$default_uri = str_replace( array( "\xEF\xBB\xBF", "%ef%bb%bf" ), '', $default_uri );
|
||||
|
||||
// Encode the URI before placeholders are removed
|
||||
$chunks = explode( '/', $default_uri );
|
||||
foreach ( $chunks as &$chunk ) {
|
||||
if ( ! preg_match( "/^(%.+?%)$/", $chunk ) && preg_match( '/%[A-F0-9]{2}%[A-F0-9]{2}/i', $chunk ) ) {
|
||||
$chunk = rawurldecode( $chunk );
|
||||
}
|
||||
}
|
||||
$default_uri = implode( "/", $chunks );
|
||||
|
||||
$empty_tag_replacement = apply_filters( 'permalink_manager_empty_tag_replacement', '', $element );
|
||||
$default_uri = preg_replace( "/%(.+?)%/", $empty_tag_replacement, $default_uri );
|
||||
$default_uri = str_replace( "//", "/", $default_uri );
|
||||
|
||||
return trim( $default_uri, "/" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the permalink base (home URL) for custom permalink
|
||||
*
|
||||
* @param string|int|WP_Post|WP_Term $element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_permalink_base( $element = null ) {
|
||||
$home_url = trim( get_option( 'home' ), "/" );
|
||||
|
||||
// Make sure that the custom permalinks have a valid scheme
|
||||
if ( strpos( $home_url, 'http' ) === false ) {
|
||||
$home_url = set_url_scheme( $home_url );
|
||||
}
|
||||
|
||||
return apply_filters( 'permalink_manager_filter_permalink_base', $home_url, $element );
|
||||
}
|
||||
}
|
||||
+485
@@ -0,0 +1,485 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) exit;
|
||||
|
||||
/**
|
||||
* Additional hooks for "Permalink Manager Pro"
|
||||
*/
|
||||
class Permalink_Manager_Pro_Functions {
|
||||
|
||||
public function __construct() {
|
||||
// Stop words
|
||||
add_filter( 'permalink_manager_filter_default_post_uri', array( $this, 'remove_stop_words' ), 9, 3 );
|
||||
add_filter( 'permalink_manager_filter_default_term_uri', array( $this, 'remove_stop_words' ), 9, 3 );
|
||||
|
||||
// Custom fields in permalinks
|
||||
add_filter( 'permalink_manager_filter_default_post_uri', array( $this, 'replace_custom_field_tags' ), 9, 5 );
|
||||
add_filter( 'permalink_manager_filter_default_term_uri', array( $this, 'replace_custom_field_tags' ), 9, 5 );
|
||||
|
||||
// Save redirects
|
||||
add_action( 'permalink_manager_updated_post_uri', array( $this, 'save_redirects' ), 9, 5 );
|
||||
add_action( 'permalink_manager_updated_term_uri', array( $this, 'save_redirects' ), 9, 5 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of languages where stop words are defined
|
||||
*/
|
||||
static function load_stop_words_languages() {
|
||||
return array(
|
||||
'ar' => __( 'Arabic', 'permalink-manager' ),
|
||||
'zh' => __( 'Chinese', 'permalink-manager' ),
|
||||
'da' => __( 'Danish', 'permalink-manager' ),
|
||||
'nl' => __( 'Dutch', 'permalink-manager' ),
|
||||
'en' => __( 'English', 'permalink-manager' ),
|
||||
'fi' => __( 'Finnish', 'permalink-manager' ),
|
||||
'fr' => __( 'French', 'permalink-manager' ),
|
||||
'de' => __( 'German', 'permalink-manager' ),
|
||||
'he' => __( 'Hebrew', 'permalink-manager' ),
|
||||
'hi' => __( 'Hindi', 'permalink-manager' ),
|
||||
'it' => __( 'Italian', 'permalink-manager' ),
|
||||
'ja' => __( 'Japanese', 'permalink-manager' ),
|
||||
'ko' => __( 'Korean', 'permalink-manager' ),
|
||||
'no' => __( 'Norwegian', 'permalink-manager' ),
|
||||
'fa' => __( 'Persian', 'permalink-manager' ),
|
||||
'pl' => __( 'Polish', 'permalink-manager' ),
|
||||
'pt' => __( 'Portuguese', 'permalink-manager' ),
|
||||
'ru' => __( 'Russian', 'permalink-manager' ),
|
||||
'es' => __( 'Spanish', 'permalink-manager' ),
|
||||
'sv' => __( 'Swedish', 'permalink-manager' ),
|
||||
'tr' => __( 'Turkish', 'permalink-manager' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load stop words for specific language (using ISO code)
|
||||
*
|
||||
* @param string $iso
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static function load_stop_words( $iso = '' ) {
|
||||
$json_dir = PERMALINK_MANAGER_DIR . "/includes/vendor/stopwords-json/dist/{$iso}.json";
|
||||
$json_a = array();
|
||||
|
||||
if ( file_exists( $json_dir ) ) {
|
||||
$string = file_get_contents( $json_dir );
|
||||
$json_a = json_decode( $string, true );
|
||||
}
|
||||
|
||||
return $json_a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the stop words from the default custom permalinks
|
||||
*
|
||||
* @param string $slug The slug that is being generated.
|
||||
* @param stdClass $object The object that the slug is being generated for.
|
||||
* @param string $name The name of the filter.
|
||||
*
|
||||
* @return string The slug.
|
||||
*/
|
||||
public function remove_stop_words( $slug, $object, $name ) {
|
||||
global $permalink_manager_options;
|
||||
|
||||
if ( ! empty( $permalink_manager_options['stop-words']['stop-words-enable'] ) && ! empty( $permalink_manager_options['stop-words']['stop-words-list'] ) ) {
|
||||
$stop_words = explode( ",", strtolower( stripslashes( $permalink_manager_options['stop-words']['stop-words-list'] ) ) );
|
||||
|
||||
foreach ( $stop_words as $stop_word ) {
|
||||
$stop_word = trim( $stop_word );
|
||||
$slug = preg_replace( "/([\/-]|^)({$stop_word})([\/-]|$)/", '$1$3', $slug );
|
||||
}
|
||||
|
||||
// Clear the slug
|
||||
$slug = preg_replace( "/(-+)/", "-", trim( $slug, "-" ) );
|
||||
$slug = preg_replace( "/(-\/-)|(\/-)|(-\/)/", "/", $slug );
|
||||
}
|
||||
|
||||
return $slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace custom field tags in the default custom permalinks
|
||||
*
|
||||
* @param string $default_uri
|
||||
* @param string $native_slug
|
||||
* @param WP_Post|WP_Term $element
|
||||
* @param string $slug
|
||||
* @param string $native_uri
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function replace_custom_field_tags( $default_uri, $native_slug, $element, $slug, $native_uri ) {
|
||||
// Do not affect native URIs
|
||||
if ( $native_uri ) {
|
||||
return $default_uri;
|
||||
}
|
||||
|
||||
preg_match_all( "/%__(.[^\%]+)%/", $default_uri, $custom_fields );
|
||||
|
||||
if ( ! empty( $custom_fields[1] ) ) {
|
||||
foreach ( $custom_fields[1] as $i => $custom_field ) {
|
||||
// Reset custom field value
|
||||
$custom_field_value = "";
|
||||
|
||||
// Check additional arguments (__custom_field.argument_value)
|
||||
if ( strpos( $custom_field, '.' ) !== false ) {
|
||||
$custom_field_split = preg_split( '/[\.]/', $custom_field );
|
||||
|
||||
if ( ! empty( $custom_field_split[1] ) ) {
|
||||
$custom_field_arg = $custom_field_split[1];
|
||||
$custom_field = $custom_field_split[0];
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Use WooCommerce fields (SKU)
|
||||
if ( class_exists( 'WooCommerce' ) && strtolower( $custom_field ) == 'sku' && ! empty( $element->ID ) ) {
|
||||
$product = wc_get_product( $element->ID );
|
||||
|
||||
$custom_field_value = ( is_a( $product, 'WC_Product' ) ) ? $product->get_sku() : '';
|
||||
} // 2. Try to get value using ACF API
|
||||
else if ( function_exists( 'get_field_object' ) ) {
|
||||
$acf_element_id = ( ! empty( $element->ID ) ) ? $element->ID : "{$element->taxonomy}_{$element->term_id}";
|
||||
$field_object = get_field_object( $custom_field, $acf_element_id );
|
||||
|
||||
// A. Relationship field
|
||||
if ( ! empty( $field_object['type'] ) && ( in_array( $field_object['type'], array( 'relationship', 'post_object', 'taxonomy' ) ) ) && ! empty( $field_object['value'] ) ) {
|
||||
$rel_elements = $field_object['value'];
|
||||
|
||||
// B1. Terms
|
||||
if ( $field_object['type'] == 'taxonomy' ) {
|
||||
if ( ( is_array( $rel_elements ) ) ) {
|
||||
if ( is_numeric( $rel_elements[0] ) && ! empty( $field_object['taxonomy'] ) ) {
|
||||
$rel_elements = get_terms( array( 'include' => $rel_elements, 'taxonomy' => $field_object['taxonomy'], 'hide_empty' => false, 'orderby' => 'term_id', 'order' => 'DESC' ) );
|
||||
}
|
||||
|
||||
// Get the lowest term
|
||||
if ( ! is_wp_error( $rel_elements ) && ! empty( $rel_elements ) && is_object( $rel_elements[0] ) ) {
|
||||
$rel_term = Permalink_Manager_Helper_Functions::get_lowest_element( $rel_elements[0], $rel_elements );
|
||||
}
|
||||
}
|
||||
if ( ! empty( $rel_elements->term_id ) ) {
|
||||
$rel_term = $rel_elements;
|
||||
} else if ( ! empty( $rel_elements ) && is_numeric( $rel_elements ) ) {
|
||||
$rel_term = get_term( $rel_elements, $field_object['taxonomy'] );
|
||||
}
|
||||
|
||||
// Get the replacement slug
|
||||
if ( ! empty( $rel_term->term_id ) ) {
|
||||
if ( ! empty( $custom_field_arg ) && is_numeric( $custom_field_arg ) ) {
|
||||
$custom_field_value = Permalink_Manager_Helper_Functions::force_custom_slugs( $rel_term->slug, $rel_term, false, $custom_field_arg );
|
||||
} else if ( ! empty( $custom_field_arg ) && $custom_field_arg == 'id' ) {
|
||||
$custom_field_value = $rel_term->term_id;
|
||||
} else if ( ! empty( $custom_field_arg ) && $custom_field_arg == 'full_slug' ) {
|
||||
$custom_field_value = Permalink_Manager_Helper_Functions::get_term_full_slug( $rel_term, $rel_elements );
|
||||
} else if ( ! empty( $custom_field_arg ) && $custom_field_arg == 'custom_permalink' ) {
|
||||
$custom_field_value = Permalink_Manager_URI_Functions::get_single_uri( $rel_term );
|
||||
} else {
|
||||
$custom_field_value = Permalink_Manager_Helper_Functions::force_custom_slugs( $rel_term->slug, $rel_term );
|
||||
}
|
||||
}
|
||||
} // B2. Posts
|
||||
else {
|
||||
if ( ( is_array( $rel_elements ) ) ) {
|
||||
if ( is_numeric( $rel_elements[0] ) ) {
|
||||
$rel_elements = get_posts( array( 'include' => $rel_elements, 'post_type' => 'any', 'orderby' => 'post__in' ) );
|
||||
}
|
||||
|
||||
// Get lowest element
|
||||
if ( ! is_wp_error( $rel_elements ) && ! empty( $rel_elements ) && is_object( $rel_elements[0] ) ) {
|
||||
$rel_post = Permalink_Manager_Helper_Functions::get_lowest_element( $rel_elements[0], $rel_elements );
|
||||
}
|
||||
} else if ( ! empty( $rel_elements->ID ) ) {
|
||||
$rel_post = $rel_elements;
|
||||
}
|
||||
|
||||
if ( ! empty( $rel_post->ID ) ) {
|
||||
$rel_post_object = $rel_post;
|
||||
} else if ( is_numeric( $rel_elements ) ) {
|
||||
$rel_post_object = get_post( $rel_elements );
|
||||
}
|
||||
|
||||
// Get the replacement slug
|
||||
if ( ! empty( $rel_post_object->ID ) ) {
|
||||
if ( ! empty( $custom_field_arg ) && is_numeric( $custom_field_arg ) ) {
|
||||
$custom_field_value = Permalink_Manager_Helper_Functions::force_custom_slugs( $rel_post_object->post_name, $rel_post_object, false, $custom_field_arg );
|
||||
} else if ( ! empty( $custom_field_arg ) && $custom_field_arg == 'id' ) {
|
||||
$custom_field_value = $rel_post_object->ID;
|
||||
} else if ( ! empty( $custom_field_arg ) && $custom_field_arg == 'full_slug' ) {
|
||||
$custom_field_value = Permalink_Manager_Helper_Functions::get_post_full_slug( $rel_post_object );
|
||||
} else if ( ! empty( $custom_field_arg ) && $custom_field_arg == 'custom_permalink' ) {
|
||||
$custom_field_value = Permalink_Manager_URI_Functions::get_single_uri( $rel_post_object );
|
||||
} else {
|
||||
$custom_field_value = Permalink_Manager_Helper_Functions::force_custom_slugs( $rel_post_object->post_name, $rel_post_object );
|
||||
}
|
||||
}
|
||||
}
|
||||
} // C. Text field
|
||||
else {
|
||||
$custom_field_value = ( ! empty( $field_object['value'] ) ) ? $field_object['value'] : "";
|
||||
$custom_field_value = ( ! empty( $custom_field_value['value'] ) ) ? $custom_field_value['value'] : $custom_field_value;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Use native method
|
||||
if ( empty( $custom_field_value ) ) {
|
||||
if ( ! empty( $element->ID ) ) {
|
||||
$custom_field_value = get_post_meta( $element->ID, $custom_field, true );
|
||||
|
||||
// Toolset
|
||||
if ( empty( $custom_field_value ) && ( defined( 'TYPES_VERSION' ) || defined( 'WPCF_VERSION' ) ) ) {
|
||||
$custom_field_value = get_post_meta( $element->ID, "wpcf-{$custom_field}", true );
|
||||
}
|
||||
} else if ( ! empty( $element->term_id ) ) {
|
||||
$custom_field_value = get_term_meta( $element->term_id, $custom_field, true );
|
||||
} else {
|
||||
$custom_field_value = "";
|
||||
}
|
||||
}
|
||||
|
||||
// Allow to filter the custom field value
|
||||
$custom_field_value = apply_filters( 'permalink_manager_custom_field_value', $custom_field_value, $custom_field, $element );
|
||||
|
||||
// Make sure that custom field is a string
|
||||
if ( ! empty( $custom_field_value ) && is_string( $custom_field_value ) ) {
|
||||
// Do not sanitize the custom field if 'no-sanitize' argument is added (e.g. %__custom-field-name.no-sanitize%)
|
||||
if ( empty( $custom_field_arg ) || strpos( $custom_field_arg, 'no-sanitize' ) === false ) {
|
||||
$custom_field_value = Permalink_Manager_Helper_Functions::sanitize_title( $custom_field_value );
|
||||
}
|
||||
|
||||
$default_uri = str_replace( $custom_fields[0][ $i ], $custom_field_value, $default_uri );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $default_uri;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save the custom, external redirects for specific post or term
|
||||
*
|
||||
* @param int|string $element_id The ID of the post (e.g. 123) or term (tax-456).
|
||||
* @param string $new_uri The new custom permalink
|
||||
* @param string $old_uri The previous custom permalink
|
||||
* @param string $native_uri The native permalink
|
||||
* @param string $default_uri The default custom permalink
|
||||
*/
|
||||
public function save_redirects( $element_id, $new_uri, $old_uri, $native_uri = '', $default_uri = '' ) {
|
||||
global $permalink_manager_options, $permalink_manager_redirects;
|
||||
|
||||
// Do not trigger if "Extra redirects" option is turned off
|
||||
if ( empty( $permalink_manager_options['general']['redirect'] ) || empty( $permalink_manager_options['general']['extra_redirects'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Terms IDs should be prepended with prefix
|
||||
$element_id = ( current_filter() == 'permalink_manager_updated_term_uri' ) ? "tax-{$element_id}" : $element_id;
|
||||
|
||||
// Make sure that $permalink_manager_redirects variable is an array
|
||||
$permalink_manager_redirects = ( is_array( $permalink_manager_redirects ) ) ? $permalink_manager_redirects : array();
|
||||
|
||||
// 1A. Post/term is saved or updated
|
||||
if ( isset( $_POST['permalink-manager-redirects'] ) && is_array( $_POST['permalink-manager-redirects'] ) ) {
|
||||
$permalink_manager_redirects[ $element_id ] = array_filter( $_POST['permalink-manager-redirects'] );
|
||||
$redirects_updated = true;
|
||||
} // 1B. All redirects are removed
|
||||
else if ( isset( $_POST['permalink-manager-redirects'] ) ) {
|
||||
$permalink_manager_redirects[ $element_id ] = array();
|
||||
$redirects_updated = true;
|
||||
}
|
||||
|
||||
// 1C. No longer needed
|
||||
if ( isset( $_POST['permalink-manager-redirects'] ) ) {
|
||||
unset( $_POST['permalink-manager-redirects'] );
|
||||
}
|
||||
|
||||
// 2. Custom URI is updated
|
||||
if ( get_option( 'page_on_front' ) !== $element_id && ! empty( $permalink_manager_options['general']['setup_redirects'] ) && ( $new_uri !== $old_uri ) ) {
|
||||
// Make sure that the array with redirects exists
|
||||
$permalink_manager_redirects[ $element_id ] = ( ! empty( $permalink_manager_redirects[ $element_id ] ) ) ? $permalink_manager_redirects[ $element_id ] : array();
|
||||
|
||||
// Append the old custom URI
|
||||
$permalink_manager_redirects[ $element_id ][] = $old_uri;
|
||||
$redirects_updated = true;
|
||||
}
|
||||
|
||||
// 3. Save the custom redirects
|
||||
if ( ! empty( $redirects_updated ) && is_array( $permalink_manager_redirects[ $element_id ] ) ) {
|
||||
// Remove empty redirects
|
||||
$permalink_manager_redirects[ $element_id ] = array_filter( $permalink_manager_redirects[ $element_id ] );
|
||||
|
||||
// Sanitize the array with redirects
|
||||
foreach ( $permalink_manager_redirects[ $element_id ] as $i => $redirect ) {
|
||||
$redirect = rawurldecode( $redirect );
|
||||
$redirect = Permalink_Manager_Helper_Functions::sanitize_title( $redirect, true );
|
||||
$permalink_manager_redirects[ $element_id ][ $i ] = $redirect;
|
||||
}
|
||||
|
||||
// Reset the keys
|
||||
$permalink_manager_redirects[ $element_id ] = array_values( $permalink_manager_redirects[ $element_id ] );
|
||||
|
||||
// Remove the duplicates
|
||||
$permalink_manager_redirects[ $element_id ] = array_unique( $permalink_manager_redirects[ $element_id ] );
|
||||
|
||||
Permalink_Manager_Actions::clear_single_element_duplicated_redirect( $element_id, false, $new_uri );
|
||||
|
||||
// Remove empty subarray
|
||||
$permalink_manager_redirects = array_filter( $permalink_manager_redirects );
|
||||
|
||||
update_option( 'permalink-manager-redirects', $permalink_manager_redirects );
|
||||
}
|
||||
|
||||
// 4. Save the external redirect
|
||||
if ( isset( $_POST['permalink-manager-external-redirect'] ) ) {
|
||||
self::save_external_redirect( $_POST['permalink-manager-external-redirect'], $element_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save external redirect
|
||||
*
|
||||
* @param string $url The full URL saved as external redirect
|
||||
* @param string|int $element_id The ID of the post (e.g. 123) or term (tax-456).
|
||||
*/
|
||||
public static function save_external_redirect( $url, $element_id ) {
|
||||
global $permalink_manager_external_redirects;
|
||||
|
||||
$url = filter_var( $url, FILTER_SANITIZE_URL );
|
||||
|
||||
if ( ( empty( $url ) || filter_var( $url, FILTER_VALIDATE_URL ) === false ) && ! empty( $permalink_manager_external_redirects[ $element_id ] ) && isset( $_POST['permalink-manager-external-redirect'] ) ) {
|
||||
unset( $permalink_manager_external_redirects[ $element_id ] );
|
||||
} else {
|
||||
$permalink_manager_external_redirects[ $element_id ] = esc_url( $url );
|
||||
}
|
||||
|
||||
update_option( 'permalink-manager-external-redirects', $permalink_manager_external_redirects );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new tab to the WooCommerce coupon edit page
|
||||
*
|
||||
* @param array $tabs The tabs array.
|
||||
*
|
||||
* @return array The tabs array with the new tab added.
|
||||
*/
|
||||
|
||||
public static function woocommerce_coupon_tabs( $tabs = array() ) {
|
||||
$tabs['coupon-url'] = array(
|
||||
'label' => __( 'Coupon Link', 'permalink-manager' ),
|
||||
'target' => 'permalink-manager-coupon-url',
|
||||
'class' => 'permalink-manager-coupon-url',
|
||||
);
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new panel to the WooCommerce coupon edit page
|
||||
*/
|
||||
public static function woocommerce_coupon_panel() {
|
||||
global $permalink_manager_uris, $post;
|
||||
|
||||
$custom_uri = ( ! empty( $permalink_manager_uris[ $post->ID ] ) ) ? $permalink_manager_uris[ $post->ID ] : "";
|
||||
|
||||
$html = "<div id=\"permalink-manager-coupon-url\" class=\"panel woocommerce_options_panel custom_uri_container permalink-manager\">";
|
||||
|
||||
// URI field
|
||||
ob_start();
|
||||
wp_nonce_field( 'permalink-manager-coupon-uri-box', 'permalink-manager-nonce' );
|
||||
|
||||
woocommerce_wp_text_input( array(
|
||||
'id' => 'custom_uri',
|
||||
'label' => __( 'Coupon URI', 'permalink-manager' ),
|
||||
'description' => '<span class="duplicated_uri_alert"></span>' . __( 'The URIs are case-insensitive, e.g. <strong>BLACKFRIDAY</strong> and <strong>blackfriday</strong> are equivalent.', 'permalink-manager' ),
|
||||
'value' => $custom_uri,
|
||||
'custom_attributes' => array( 'data-element-id' => $post->ID ),
|
||||
//'desc_tip' => true
|
||||
) );
|
||||
|
||||
$html .= ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
// URI preview
|
||||
$html .= "<p class=\"form-field coupon-full-url hidden\">";
|
||||
$html .= sprintf( "<label>%s</label>", __( "Coupon Full URL", "permalink-manager" ) );
|
||||
$html .= sprintf( "<code>%s/<span>%s</span></code>", trim( get_option( 'home' ), "/" ), $custom_uri );
|
||||
$html .= "</p>";
|
||||
|
||||
$html .= "</div>";
|
||||
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the custom permalink for specific coupon
|
||||
*
|
||||
* @param int $post_id
|
||||
* @param WC_Coupon $coupon
|
||||
*/
|
||||
public static function woocommerce_save_coupon_uri( $post_id, $coupon ) {
|
||||
// Verify nonce at first
|
||||
if ( ! isset( $_POST['permalink-manager-nonce'] ) || ! wp_verify_nonce( $_POST['permalink-manager-nonce'], 'permalink-manager-coupon-uri-box' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not do anything if post is auto-saved
|
||||
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$old_uri = Permalink_Manager_URI_Functions::get_single_uri( $post_id, false, true, false );
|
||||
$new_uri = ( ! empty( $_POST['custom_uri'] ) ) ? $_POST['custom_uri'] : "";
|
||||
|
||||
if ( $old_uri !== $new_uri ) {
|
||||
Permalink_Manager_URI_Functions::save_single_uri( $post_id, $new_uri, false, true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the URL contains a coupon code, and if it does, it adds the coupon code to the cart and redirects to the cart page
|
||||
*
|
||||
* @param array $query The query array.
|
||||
*
|
||||
* @return array The query array.
|
||||
*/
|
||||
public static function woocommerce_detect_coupon_code( $query ) {
|
||||
global $woocommerce, $pm_query;
|
||||
|
||||
// Check if custom URI with coupon URL is requested
|
||||
if ( ! empty( $query['shop_coupon'] ) && ! empty( $pm_query['id'] ) ) {
|
||||
// Check if cart/shop page is set & redirect to it
|
||||
$shop_page_id = wc_get_page_id( 'shop' );
|
||||
$cart_page_id = wc_get_page_id( 'cart' );
|
||||
|
||||
|
||||
if ( ! empty( $cart_page_id ) && WC()->cart->get_cart_contents_count() > 0 ) {
|
||||
$redirect_page = $cart_page_id;
|
||||
} else if ( ! empty( $shop_page_id ) ) {
|
||||
$redirect_page = $shop_page_id;
|
||||
}
|
||||
|
||||
$coupon_code = get_the_title( $pm_query['id'] );
|
||||
|
||||
// Set-up session
|
||||
if ( ! WC()->session->has_session() ) {
|
||||
WC()->session->set_customer_session_cookie( true );
|
||||
}
|
||||
|
||||
// Add the discount code
|
||||
if ( ! WC()->cart->has_discount( $coupon_code ) ) {
|
||||
$woocommerce->cart->add_discount( sanitize_text_field( $coupon_code ) );
|
||||
}
|
||||
|
||||
// Do redirect
|
||||
if ( ! empty( $redirect_page ) ) {
|
||||
wp_safe_redirect( get_permalink( $redirect_page ) );
|
||||
exit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
}
|
||||
+322
@@ -0,0 +1,322 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional hooks for "Permalink Manager Pro"
|
||||
*/
|
||||
class Permalink_Manager_Pro_License {
|
||||
|
||||
public $update_checker;
|
||||
|
||||
public function __construct() {
|
||||
define( 'PERMALINK_MANAGER_PRO', true );
|
||||
$plugin_name = preg_replace( '/(.*)\/([^\/]+\/[^\/]+.php)$/', '$2', PERMALINK_MANAGER_FILE );
|
||||
|
||||
// Permalink Manager Pro Alerts
|
||||
add_filter( 'permalink_manager_alerts', array( $this, 'pro_alerts' ), 9, 3 );
|
||||
|
||||
// Check for updates
|
||||
add_action( 'plugins_loaded', array( $this, 'check_for_updates' ), 10 );
|
||||
add_action( 'admin_init', array( $this, 'reload_license_key' ), 10 );
|
||||
add_action( 'wp_ajax_pm_get_exp_date', array( $this, 'get_expiration_date' ), 9 );
|
||||
|
||||
// Display License info on "Plugins" page
|
||||
add_action( "after_plugin_row_{$plugin_name}", array( $this, 'license_info_bar' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the license key from the database, constant defined in wp-config.php file, or $_POST variable
|
||||
*
|
||||
* @param string $load_from_db If set to true, the function will load the license key from the database, even if it's defined in wp-config.php.
|
||||
*
|
||||
* @return string The license key.
|
||||
*/
|
||||
public static function get_license_key( $load_from_db = false ) {
|
||||
$permalink_manager_options = get_option( 'permalink-manager', array() );
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
||||
// Key defined in wp-config.php
|
||||
if ( ( defined( 'PMP_LICENCE_KEY' ) || defined( 'PMP_LICENSE_KEY' ) ) && empty( $load_from_db ) ) {
|
||||
$license_key = defined( 'PMP_LICENCE_KEY' ) ? PMP_LICENCE_KEY : PMP_LICENSE_KEY;
|
||||
} // Network licence key (multisite)
|
||||
else if ( is_multisite() ) {
|
||||
$site_licence_key = get_site_option( 'permalink-manager-licence-key' );
|
||||
|
||||
// A. Move the license key to site options
|
||||
if ( ! empty( $site_licence_key ) && ! is_array( $site_licence_key ) ) {
|
||||
$new_license_key = $site_licence_key;
|
||||
} // B. Save the new license key in the plugin settings
|
||||
else if ( ! empty( $_POST['licence']['licence_key'] ) ) {
|
||||
$new_license_key = sanitize_text_field( $_POST['licence']['licence_key'] );
|
||||
}
|
||||
|
||||
if ( ! empty( $new_license_key ) ) {
|
||||
$site_licence_key = array(
|
||||
'licence_key' => sanitize_text_field( $new_license_key )
|
||||
);
|
||||
|
||||
update_site_option( 'permalink-manager-licence-key', $site_licence_key );
|
||||
}
|
||||
|
||||
$license_key = ( ! empty( $site_licence_key['licence_key'] ) ) ? $site_licence_key['licence_key'] : '';
|
||||
} // Single website license key
|
||||
else if ( ! empty( $_POST['licence']['licence_key'] ) ) {
|
||||
$license_key = sanitize_text_field( $_POST['licence']['licence_key'] );
|
||||
} else {
|
||||
$license_key = ( ! empty( $permalink_manager_options['licence']['licence_key'] ) ) ? $permalink_manager_options['licence']['licence_key'] : "";
|
||||
}
|
||||
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
||||
|
||||
return preg_replace( "/[^a-zA-Z0-9-]/", "", $license_key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the saved license key matches the "developer" format
|
||||
*
|
||||
* @param $license_key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_dev_license_key( $license_key ) {
|
||||
return preg_match( '/^([A-G0-9]{4,8})-([A-G0-9]{4,8})$/', $license_key ) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the update checker class and create an instance of it
|
||||
*/
|
||||
public function check_for_updates() {
|
||||
$license_key = self::get_license_key();
|
||||
|
||||
// Load Plugin Update Checker by YahnisElsts
|
||||
require_once PERMALINK_MANAGER_DIR . '/includes/vendor/plugin-update-checker/plugin-update-checker.php';
|
||||
|
||||
$this->update_checker = Puc_v4_Factory::buildUpdateChecker( "https://updates.permalinkmanager.pro/?action=get_metadata&slug=permalink-manager-pro&licence_key={$license_key}", PERMALINK_MANAGER_FILE, "permalink-manager-pro" );
|
||||
|
||||
add_filter( 'puc_request_info_result-permalink-manager-pro', array( $this, 'update_pro_info' ), 99, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the license key was changed and if so, delete the cached license data and get the new license data from the server
|
||||
*/
|
||||
public function reload_license_key() {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended
|
||||
if ( ! empty( $_POST['licence']['licence_key'] ) || ( ! empty( $_REQUEST['action'] ) && $_REQUEST['action'] == 'pm_get_exp_date' ) || ( ! empty( $_REQUEST['puc_slug'] ) && $_REQUEST['puc_slug'] == 'permalink-manager-pro' ) ) {
|
||||
delete_site_transient( 'permalink_manager_active' );
|
||||
$this->update_checker->requestInfo();
|
||||
} // Sync the license data saved in DB after license key was set in wp-config.php file
|
||||
else if ( defined( 'PMP_LICENCE_KEY' ) || defined( 'PMP_LICENSE_KEY' ) ) {
|
||||
$db_license_key = self::get_license_key( true );
|
||||
$license_key = self::get_license_key();
|
||||
|
||||
if ( ! empty( $db_license_key ) && ! empty( $license_key ) && $db_license_key !== $license_key ) {
|
||||
delete_site_transient( 'permalink_manager_active' );
|
||||
$this->update_checker->requestInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the cached license key needs to be changed
|
||||
*
|
||||
* @param stdClass $raw The raw response from the server.
|
||||
* @param array $result The response object from the API call.
|
||||
*
|
||||
* @return stdClass The plugin info
|
||||
*/
|
||||
public function update_pro_info( $raw, $result ) {
|
||||
$license_key = self::get_license_key();
|
||||
$permalink_manager_active = ( empty( $_POST['licence']['licence_key'] ) ) ? get_site_transient( 'permalink_manager_active' ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
// A. Do not do anything - the license info was saved before
|
||||
if ( ! empty( $license_key ) && ( $permalink_manager_active == $license_key ) ) {
|
||||
return $raw;
|
||||
} // B. The license info was not removed or not downloaded before
|
||||
else if ( empty( $permalink_manager_active ) && is_array( $result ) && ! empty( $result['body'] ) && ! empty( $license_key ) ) {
|
||||
$plugin_info = json_decode( $result['body'] );
|
||||
|
||||
if ( is_object( $plugin_info ) && isset( $plugin_info->version ) ) {
|
||||
$exp_date = ( ! empty( $plugin_info->expiration_date ) && strlen( $plugin_info->expiration_date ) > 6 ) ? strtotime( $plugin_info->expiration_date ) : '-';
|
||||
$websites = ( ! empty( $plugin_info->websites ) ) ? $plugin_info->websites : '';
|
||||
|
||||
$license_info = array(
|
||||
'licence_key' => $license_key,
|
||||
'expiration_date' => $exp_date,
|
||||
'websites' => $websites
|
||||
);
|
||||
|
||||
if ( is_multisite() ) {
|
||||
update_site_option( 'permalink-manager-licence-key', $license_info );
|
||||
} else {
|
||||
Permalink_Manager_Actions::save_settings( 'licence', $license_info, false );
|
||||
}
|
||||
|
||||
set_site_transient( 'permalink_manager_active', $license_key, 12 * HOUR_IN_SECONDS );
|
||||
}
|
||||
}
|
||||
|
||||
return $raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get license expiration date
|
||||
*
|
||||
* @param bool $basic_check
|
||||
* @param bool $empty_if_valid
|
||||
* @param bool $update_available
|
||||
*
|
||||
* @return int|string
|
||||
*/
|
||||
public static function get_expiration_date( $basic_check = false, $empty_if_valid = false, $update_available = true ) {
|
||||
global $permalink_manager_options;
|
||||
|
||||
// Get expiration info & the licence key
|
||||
if ( is_multisite() ) {
|
||||
$site_licence_key = get_site_option( 'permalink-manager-licence-key' );
|
||||
|
||||
$exp_date = ( ! empty( $site_licence_key['expiration_date'] ) ) ? $site_licence_key['expiration_date'] : false;
|
||||
$license_key = ( ! empty( $site_licence_key['licence_key'] ) ) ? $site_licence_key['licence_key'] : "";
|
||||
$websites = ( ! empty( $site_licence_key['websites'] ) ) ? $site_licence_key['websites'] : "";
|
||||
} else {
|
||||
$exp_date = ( ! empty( $permalink_manager_options['licence']['expiration_date'] ) ) ? $permalink_manager_options['licence']['expiration_date'] : false;
|
||||
$license_key = ( ! empty( $permalink_manager_options['licence']['licence_key'] ) ) ? $permalink_manager_options['licence']['licence_key'] : "";
|
||||
$websites = ( ! empty( $permalink_manager_options['licence']['websites'] ) ) ? $permalink_manager_options['licence']['websites'] : "";
|
||||
}
|
||||
|
||||
$license_info_page = ( ! empty( $license_key ) ) ? self::get_license_info_link( $license_key ) : "#";
|
||||
|
||||
// There is no license key defined
|
||||
if ( empty( $license_key ) ) {
|
||||
$settings_page_url = Permalink_Manager_Admin_Functions::get_admin_url( "§ion=settings" );
|
||||
// translators: %s is the URL to the settings page where users can manage their license keys.
|
||||
$expiration_info = sprintf( __( 'Please paste the license key to access all Permalink Manager Pro updates & features <a href="%s" target="_blank">on this page</a>.', 'permalink-manager' ), $settings_page_url );
|
||||
$expired = 3;
|
||||
} // License key is invalid
|
||||
else if ( $exp_date == '-' || ! preg_match( '/^([A-Z0-9]{5,8}-){1}[A-Z0-9]{5,8}((-[A-Z0-9]{5,8}){2})?$/i', $license_key ) ) {
|
||||
$expiration_info = __( 'Your Permalink Manager Pro license key is invalid!', 'permalink-manager' );
|
||||
$expired = 3;
|
||||
} else {
|
||||
// Key expired
|
||||
if ( ! empty( $exp_date ) && $exp_date < time() ) {
|
||||
// translators: %s is the URL to the Permalink Manager page where users can manage their license keys.
|
||||
$expiration_info = sprintf( __( '<strong>Your Permalink Manager Pro license has expired.</strong><br />Please renew your license key using <a href="%s" target="_blank">this link</a> to restore access to plugin updates.', 'permalink-manager' ), $license_info_page );
|
||||
$expired = 2;
|
||||
} // License key is abused
|
||||
else if ( ! empty( $exp_date ) && ! empty( $websites ) && $update_available === false ) {
|
||||
$expiration_info = sprintf( __( 'Your Permalink Manager Pro license is already in use on another website and cannot be used to request automatic update for this domain.', 'permalink-manager' ), $license_info_page ) . " ";
|
||||
// translators: %s is the URL to the Permalink Manager page where users can manage their license keys.
|
||||
$expiration_info .= sprintf( __( 'For further information, visit the <a href="%s" target="_blank"> License info</a> page.', 'permalink-manager' ), $license_info_page );
|
||||
$expired = 3;
|
||||
} // Valid lifetime license key
|
||||
else if ( gmdate( "Y", intval( $exp_date ) ) > gmdate( 'Y', strtotime( "+10 years" ) ) ) {
|
||||
$expiration_info = __( 'You own a lifetime license key.', 'permalink-manager' );
|
||||
$expired = 0;
|
||||
} // License key is valid
|
||||
else if ( $exp_date ) {
|
||||
// License key will expire in less than month & do not display the alert if the developer license key is used
|
||||
if ( $exp_date - MONTH_IN_SECONDS < time() && ! preg_match( '/^([A-G0-9]{4,8})-([A-G0-9]{4,8})$/', $license_key ) ) {
|
||||
// translators: %s is the Permalink Manager's license key expiry date.
|
||||
$expiration_info = sprintf( __( 'Your Permalink Manager Pro license key will expire on <strong>%s</strong>. Please renew it to maintain access to plugin updates and technical support!', 'permalink-manager' ), wp_date( get_option( 'date_format' ), $exp_date ) ) . " ";
|
||||
// translators: %s is the URL to the Permalink Manager page where users can manage their license keys.
|
||||
$expiration_info .= sprintf( __( 'For further information, visit the <a href="%s" target="_blank"> License info</a> page.', 'permalink-manager' ), $license_info_page );
|
||||
$expired = 1;
|
||||
} // License key can be used
|
||||
else {
|
||||
// Translators: %1$s is the expiration date, %2$s is the URL to the license info page.
|
||||
$expiration_info = sprintf( __( 'Your license key is valid until %1$s.<br />To prolong it please go to <a href="%2$s" target="_blank">this page</a> for more information.', 'permalink-manager' ), gmdate( get_option( 'date_format' ), $exp_date ), $license_info_page );
|
||||
$expired = 0;
|
||||
}
|
||||
} // Expiration data could not be downloaded
|
||||
else {
|
||||
$expiration_info = __( 'Expiration date could not be downloaded at this moment. Please try again in a few minutes.', 'permalink-manager' );
|
||||
$expired = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Do not return any text alert
|
||||
if ( $basic_check || ( $empty_if_valid && $expired == 0 ) ) {
|
||||
return $expired;
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended
|
||||
if ( ! empty( $_REQUEST['action'] ) && $_REQUEST['action'] == 'pm_get_exp_date' ) {
|
||||
echo wp_kses_post( $expiration_info );
|
||||
die();
|
||||
} else {
|
||||
return $expiration_info;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL to the license info page on the plugin's website
|
||||
*
|
||||
* @param $license_key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static function get_license_info_link( $license_key ) {
|
||||
$license_key = ( self::is_dev_license_key( $license_key ) ) ? '' : $license_key;
|
||||
$license_link = ( ! empty( $license_key ) ) ? sprintf( "https://permalinkmanager.pro/license-info/%s/", trim( $license_key ) ) : "https://permalinkmanager.pro/license-info/";
|
||||
|
||||
return esc_url( $license_link );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display license status in the "Plugins" table
|
||||
*
|
||||
* @param string $plugin_file
|
||||
* @param array $plugin_data
|
||||
*/
|
||||
function license_info_bar( $plugin_file, $plugin_data ) {
|
||||
global $wp_list_table;
|
||||
|
||||
$column_count = ( ! empty( $wp_list_table ) ) ? $wp_list_table->get_column_count() : 3;
|
||||
// $update_available = (empty($plugin_data['package']) && !empty($plugin_data['update'])) ? false : true;
|
||||
|
||||
$exp_info_text = self::get_expiration_date( false, true, false );
|
||||
$exp_info_code = self::get_expiration_date( true, true, false );
|
||||
|
||||
if ( ! empty( $exp_info_text ) && $exp_info_code >= 1 ) {
|
||||
printf( '<tr class="plugin-update-tr permalink-manager-pro_license-info active" data-slug="%s" data-plugin="%s"><td colspan="%d" class="plugin-update colspanchange plugin_license_info_row">', esc_attr( $plugin_data['slug'] ), esc_attr( $plugin_file ), esc_attr( $column_count ) );
|
||||
printf( '<div class="update-message notice inline notice-error notice-alt">%s</div>', wp_kses_post( wpautop( $exp_info_text ) ) );
|
||||
printf( '</td></tr>' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display license nag inside the URI Editor
|
||||
*
|
||||
*/
|
||||
public static function license_info_uri_editor() {
|
||||
$exp_info_text = self::get_expiration_date( false, true, false );
|
||||
$exp_info_code = self::get_expiration_date( true, true, false );
|
||||
|
||||
if ( ! empty( $exp_info_text ) && $exp_info_code == 2 ) {
|
||||
return sprintf( '<div class="notice inline notice-error notice-alt">%s</div>', wp_kses_post( wpautop( $exp_info_text ) ) );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide "Buy Permalink Manager Pro" alert
|
||||
*
|
||||
* @param array $alerts
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function pro_alerts( $alerts = array() ) {
|
||||
// Check expiration date
|
||||
$exp_info_text = self::get_expiration_date( false, true, false );
|
||||
$exp_info_code = self::get_expiration_date( true, true, false );
|
||||
|
||||
if ( ! empty( $exp_info_text ) && $exp_info_code >= 2 ) {
|
||||
$alerts['licence_key'] = array( 'txt' => $exp_info_text, 'type' => 'notice-error', 'plugin_only' => true, 'dismissed_time' => DAY_IN_SECONDS * 3 );
|
||||
}
|
||||
|
||||
return $alerts;
|
||||
}
|
||||
}
|
||||
+906
@@ -0,0 +1,906 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) exit;
|
||||
|
||||
/**
|
||||
* A set of functions for processing and applying the custom permalink to posts
|
||||
*/
|
||||
class Permalink_Manager_URI_Functions_Post {
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'admin_init', array( $this, 'admin_init' ), 99, 3 );
|
||||
|
||||
add_filter( '_get_page_link', array( $this, 'custom_post_permalinks' ), 99, 2 );
|
||||
add_filter( 'page_link', array( $this, 'custom_post_permalinks' ), 99, 3 );
|
||||
add_filter( 'post_link', array( $this, 'custom_post_permalinks' ), 99, 3 );
|
||||
add_filter( 'post_type_link', array( $this, 'custom_post_permalinks' ), 99, 3 );
|
||||
add_filter( 'attachment_link', array( $this, 'custom_post_permalinks' ), 99, 2 );
|
||||
|
||||
add_filter( 'permalink_manager_uris', array( $this, 'exclude_homepage' ), 99 );
|
||||
|
||||
add_filter( 'url_to_postid', array( $this, 'url_to_postid' ), 9 );
|
||||
|
||||
add_filter( 'get_sample_permalink_html', array( $this, 'edit_uri_box' ), 20, 5 );
|
||||
|
||||
add_action( 'save_post', array( $this, 'update_post_hook' ), 99, 1 );
|
||||
add_action( 'edit_attachment', array( $this, 'update_post_hook' ), 99, 1 );
|
||||
add_action( 'wp_insert_post', array( $this, 'insert_post_hook' ), 99, 1 );
|
||||
add_action( 'add_attachment', array( $this, 'insert_post_hook' ), 99, 1 );
|
||||
add_action( 'wp_trash_post', array( $this, 'remove_post_hook' ), 100, 1 );
|
||||
add_action( 'delete_post', array( $this, 'remove_post_hook' ), 100, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "Custom Permalink" input field to "Quick Edit" form
|
||||
*/
|
||||
function admin_init() {
|
||||
$post_types = Permalink_Manager_Helper_Functions::get_post_types_array();
|
||||
|
||||
// Add "URI Editor" to "Quick Edit" for all post_types
|
||||
foreach ( $post_types as $post_type => $label ) {
|
||||
add_filter( "manage_{$post_type}_posts_columns", array( $this, 'quick_edit_column' ) );
|
||||
add_filter( "manage_{$post_type}_posts_custom_column", array( $this, 'quick_edit_column_content' ), 10, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the custom permalinks to the posts
|
||||
*
|
||||
* @param string $permalink
|
||||
* @param WP_Post|int $post
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static function custom_post_permalinks( $permalink, $post, $leavename = false ) {
|
||||
global $permalink_manager_uris, $permalink_manager_options, $permalink_manager_ignore_permalink_filters;
|
||||
|
||||
// Do not filter permalinks in Customizer
|
||||
if ( function_exists( 'is_customize_preview' ) && is_customize_preview() ) {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
// Do not filter in WPML String Editor
|
||||
if ( ! empty( $_REQUEST['icl_ajx_action'] ) && $_REQUEST['icl_ajx_action'] == 'icl_st_save_translation' ) {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
// WPML (prevent duplicated posts)
|
||||
if ( ! empty( $_REQUEST['trid'] ) && ! empty( $_REQUEST['skip_sitepress_actions'] ) ) {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
// Do not run when metaboxes are loaded with Gutenberg
|
||||
/* if ( ! empty( $_REQUEST['meta-box-loader'] ) && empty( $_POST['custom_uri'] ) ) {
|
||||
return $permalink;
|
||||
}*/
|
||||
|
||||
// Do not filter if $permalink_manager_ignore_permalink_filters global is set
|
||||
if ( ! empty( $permalink_manager_ignore_permalink_filters ) ) {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
$post = ( is_integer( $post ) ) ? get_post( $post ) : $post;
|
||||
|
||||
// Do not run if post object is invalid or the permalink is not string
|
||||
if ( empty( $post ) || empty( $post->ID ) || empty( $post->post_type ) || ! is_string( $permalink ) ) {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
// Start with homepage URL
|
||||
$home_url = Permalink_Manager_Permastructure_Functions::get_permalink_base( $post );
|
||||
|
||||
// Check if the post is excluded
|
||||
if ( ! empty( $post->post_type ) && Permalink_Manager_Helper_Functions::is_post_excluded( $post ) && $post->post_type !== 'attachment' ) {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
// 2A. Do not change permalink of frontpage
|
||||
if ( Permalink_Manager_Helper_Functions::is_front_page( $post->ID ) ) {
|
||||
return $permalink;
|
||||
} // 2B. Do not change permalink for drafts and future posts (+ remove trailing slash from them)
|
||||
else if ( in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft', 'future' ) ) ) {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
// 3. Save the old permalink to a separate variable
|
||||
$old_permalink = $permalink;
|
||||
|
||||
// 4. Filter only the posts with custom permalink assigned
|
||||
if ( isset( $permalink_manager_uris[ $post->ID ] ) ) {
|
||||
// Encode URI?
|
||||
if ( ! empty( $permalink_manager_options['general']['decode_uris'] ) ) {
|
||||
$permalink = "{$home_url}/" . rawurldecode( "/{$permalink_manager_uris[$post->ID]}" );
|
||||
} else {
|
||||
$permalink = "{$home_url}/" . Permalink_Manager_Helper_Functions::encode_uri( "{$permalink_manager_uris[$post->ID]}" );
|
||||
}
|
||||
|
||||
// Keep the slug editor in Block Editor wherever it may help
|
||||
if ( $leavename && is_admin() ) {
|
||||
$placeholder = Permalink_Manager_Permastructure_Functions::get_post_tag( $post->post_type );
|
||||
$post_name_esc = preg_quote( get_page_uri( $post->ID ), '/' );
|
||||
|
||||
$permalink = preg_replace( "/\/({$post_name_esc})\/?$/", "/{$placeholder}/", $permalink );
|
||||
}
|
||||
} else if ( $post->post_type == 'attachment' && $post->post_parent > 0 && $post->post_parent != $post->ID && ! empty( $permalink_manager_uris[ $post->post_parent ] ) ) {
|
||||
$permalink = "{$home_url}/{$permalink_manager_uris[$post->post_parent]}/attachment/{$post->post_name}";
|
||||
}
|
||||
|
||||
return apply_filters( 'permalink_manager_filter_final_post_permalink', $permalink, $post, $old_permalink );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the provided slug is unique and then update it with SQL query.
|
||||
*
|
||||
* @param string $slug
|
||||
* @param int $id
|
||||
* @param bool $preview_mode
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static function update_slug_by_id( $slug, $id, $preview_mode = false ) {
|
||||
global $wpdb;
|
||||
|
||||
// Update slug and make it unique
|
||||
$slug = ( empty( $slug ) ) ? get_the_title( $id ) : $slug;
|
||||
$slug = sanitize_title( $slug );
|
||||
|
||||
$new_slug = wp_unique_post_slug( $slug, $id, get_post_status( $id ), get_post_type( $id ), 0 );
|
||||
|
||||
if ( ! $preview_mode ) {
|
||||
$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_name = %s WHERE ID = %d", $new_slug, $id ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
||||
clean_post_cache( $id );
|
||||
}
|
||||
|
||||
return $new_slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently used custom permalink (or default/empty URI)
|
||||
*
|
||||
* @param int $post_id
|
||||
* @param bool $native_uri
|
||||
* @param bool $no_fallback
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_post_uri( $post_id, $native_uri = false, $no_fallback = false ) {
|
||||
global $permalink_manager_uris;
|
||||
|
||||
// Check if input is post object
|
||||
$post_id = ( isset( $post_id->ID ) ) ? $post_id->ID : $post_id;
|
||||
|
||||
if ( ! empty( $permalink_manager_uris[ $post_id ] ) ) {
|
||||
$final_uri = $permalink_manager_uris[ $post_id ];
|
||||
} else if ( ! $no_fallback ) {
|
||||
$final_uri = self::get_default_post_uri( $post_id, $native_uri );
|
||||
} else {
|
||||
$final_uri = '';
|
||||
}
|
||||
|
||||
return $final_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default custom permalink (not overwritten by the user) or native permalink (unfiltered)
|
||||
*
|
||||
* @param WP_Post|int $post
|
||||
* @param bool $native_uri
|
||||
* @param bool $check_if_disabled
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_default_post_uri( $post, $native_uri = false, $check_if_disabled = false ) {
|
||||
global $permalink_manager_uris, $permalink_manager_permastructs, $wp_post_types;
|
||||
|
||||
// Disable WPML adjust ID filter
|
||||
if ( class_exists( 'SitePress' ) ) {
|
||||
add_filter( 'wpml_disable_term_adjust_id', '__return_true', 999 );
|
||||
}
|
||||
|
||||
// Load all bases & post
|
||||
$post = is_object( $post ) ? $post : get_post( $post );
|
||||
|
||||
// Check if post ID is defined (and front page permalinks should be empty)
|
||||
if ( empty( $post->ID ) || Permalink_Manager_Helper_Functions::is_front_page( $post->ID ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$post_type = $post->post_type;
|
||||
|
||||
if ( empty( $post->post_name ) ) {
|
||||
$pre_post_name = Permalink_Manager_Helper_Functions::sanitize_title( $post->post_title );
|
||||
$post_name = wp_unique_post_slug( $pre_post_name, $post->ID, 'publish', $post->post_type, $post->post_parent );
|
||||
} else {
|
||||
$post_name = $post->post_name;
|
||||
}
|
||||
|
||||
// 1A. Check if post type is allowed
|
||||
if ( $check_if_disabled && Permalink_Manager_Helper_Functions::is_post_type_disabled( $post_type ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 1A. Get the native permastructure
|
||||
if ( $post_type == 'attachment' ) {
|
||||
$parent_page = ( $post->post_parent > 0 && $post->post_parent != $post->ID ) ? get_post( $post->post_parent ) : false;
|
||||
|
||||
if ( ! empty( $parent_page->ID ) ) {
|
||||
$parent_page_uri = ( ! empty( $permalink_manager_uris[ $parent_page->ID ] ) ) ? $permalink_manager_uris[ $parent_page->ID ] : get_page_uri( $parent_page->ID );
|
||||
} else {
|
||||
$parent_page_uri = "";
|
||||
}
|
||||
|
||||
$native_permastructure = ( $parent_page ) ? trim( $parent_page_uri, "/" ) . "/attachment" : "";
|
||||
} else {
|
||||
$native_permastructure = Permalink_Manager_Permastructure_Functions::get_default_permastruct( $post_type );
|
||||
}
|
||||
|
||||
// 1B. Get the permastructure
|
||||
if ( $native_uri ) {
|
||||
$permastructure = $native_permastructure;
|
||||
} else {
|
||||
$permastructure = ( ! empty( $permalink_manager_permastructs['post_types'][ $post_type ] ) ) ? $permalink_manager_permastructs['post_types'][ $post_type ] : $native_permastructure;
|
||||
$permastructure = apply_filters( 'permalink_manager_filter_permastructure', $permastructure, $post );
|
||||
}
|
||||
|
||||
// 1C. Set the permastructure
|
||||
$default_base = ( ! empty( $permastructure ) ) ? trim( $permastructure, '/' ) : "";
|
||||
|
||||
// 2A. Get the date
|
||||
$date = explode( " ", date( 'Y m d H i s', strtotime( $post->post_date ) ) );
|
||||
$monthname = sanitize_title( date_i18n( 'F', strtotime( $post->post_date ) ) );
|
||||
|
||||
// 2B. Get the author (if needed)
|
||||
$author = '';
|
||||
if ( strpos( $default_base, '%author%' ) !== false ) {
|
||||
$authordata = get_userdata( $post->post_author );
|
||||
$author = $authordata->user_nicename;
|
||||
}
|
||||
|
||||
// 2C. Get the post type slug
|
||||
if ( ! empty( $wp_post_types[ $post_type ] ) ) {
|
||||
if ( ! empty( $wp_post_types[ $post_type ]->rewrite['slug'] ) ) {
|
||||
$post_type_slug = $wp_post_types[ $post_type ]->rewrite['slug'];
|
||||
} else if ( is_string( $wp_post_types[ $post_type ]->rewrite ) ) {
|
||||
$post_type_slug = $wp_post_types[ $post_type ]->rewrite;
|
||||
}
|
||||
}
|
||||
|
||||
$post_type_slug = ( ! empty( $post_type_slug ) ) ? $post_type_slug : $post_type;
|
||||
$post_type_slug = apply_filters( 'permalink_manager_filter_post_type_slug', $post_type_slug, $post, $post_type );
|
||||
$post_type_slug = preg_replace( '/(%([^%]+)%\/?)/', '', $post_type_slug );
|
||||
|
||||
// 3B. Get the full slug
|
||||
$post_name = Permalink_Manager_Helper_Functions::remove_slashes( $post_name );
|
||||
$custom_slug = $full_custom_slug = Permalink_Manager_Helper_Functions::force_custom_slugs( $post_name, $post, true, null, false );
|
||||
$post_title_slug = Permalink_Manager_Helper_Functions::force_custom_slugs( $post_name, $post, true, 1 );
|
||||
$full_native_slug = $post_name;
|
||||
|
||||
// 3A. Fix for hierarchical CPT (start)
|
||||
if ( $post->ancestors && is_post_type_hierarchical( $post_type ) ) {
|
||||
$full_native_slug = Permalink_Manager_Helper_Functions::get_post_full_slug( $post, false, true );
|
||||
$full_custom_slug = Permalink_Manager_Helper_Functions::get_post_full_slug( $post, false, false );
|
||||
}
|
||||
|
||||
// 3B. Allow filter the default slug (only custom permalinks)
|
||||
if ( ! $native_uri ) {
|
||||
$full_slug = apply_filters( 'permalink_manager_filter_default_post_slug', $full_custom_slug, $post, $post_name );
|
||||
} else {
|
||||
$full_slug = $full_native_slug;
|
||||
}
|
||||
|
||||
$post_type_tag = Permalink_Manager_Permastructure_Functions::get_post_tag( $post_type );
|
||||
|
||||
// 3C. Get the standard tags and replace them with their values
|
||||
$tags = array( '%year%', '%monthnum%', '%monthname%', '%day%', '%hour%', '%minute%', '%second%', '%post_id%', '%author%', '%post_type%' );
|
||||
$tags_replacements = array( $date[0], $date[1], $monthname, $date[2], $date[3], $date[4], $date[5], $post->ID, $author, $post_type_slug );
|
||||
$default_uri = str_replace( $tags, $tags_replacements, $default_base );
|
||||
|
||||
// 3D. Get the slug tags
|
||||
$slug_tags = array( $post_type_tag, "%postname%", "%postname_flat%", "%pagename_flat%", "%{$post_type}_flat%", "%native_slug%", '%native_title%' );
|
||||
$slug_tags_replacement = array( $full_slug, $full_slug, $custom_slug, $custom_slug, $custom_slug, $full_native_slug, $post_title_slug );
|
||||
|
||||
$do_not_append_slug = Permalink_Manager_Permastructure_Functions::is_slug_tag_present( $default_uri, $slug_tags, $post );
|
||||
|
||||
// 3E. Replace the post tags with slugs or append the slug if no post tag is defined
|
||||
if ( ! empty( $do_not_append_slug ) ) {
|
||||
$default_uri = str_replace( $slug_tags, $slug_tags_replacement, $default_uri );
|
||||
} else {
|
||||
$default_uri .= "/{$full_slug}";
|
||||
}
|
||||
|
||||
// 4. Replace taxonomies
|
||||
$taxonomies = get_taxonomies();
|
||||
|
||||
if ( $taxonomies ) {
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
// 0. Check if taxonomy tag is present
|
||||
if ( strpos( $default_uri, "%{$taxonomy}" ) === false ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 1. Get terms assigned to this post
|
||||
$terms = wp_get_object_terms( $post->ID, $taxonomy );
|
||||
|
||||
// 2. Sort the terms
|
||||
if ( ! empty( $terms ) ) {
|
||||
$terms = wp_list_sort( $terms, array(
|
||||
'parent' => 'DESC',
|
||||
'term_id' => 'ASC',
|
||||
) );
|
||||
}
|
||||
|
||||
// 3A. Try to use Yoast SEO Primary Term
|
||||
$replacement_term = Permalink_Manager_Helper_Functions::get_primary_term( $post->ID, $taxonomy, false );
|
||||
|
||||
// 3B. Get the first assigned term to this taxonomy
|
||||
if ( empty( $replacement_term ) ) {
|
||||
$replacement_term = ( ! is_wp_error( $terms ) && ! empty( $terms ) && is_object( $terms[0] ) ) ? Permalink_Manager_Helper_Functions::get_lowest_element( $terms[0], $terms ) : '';
|
||||
}
|
||||
|
||||
$replacement_term = apply_filters( 'permalink_manager_filter_post_terms', $replacement_term, $post, $terms, $taxonomy, $native_uri );
|
||||
|
||||
// 4A. Custom URI as term base
|
||||
if ( ! empty( $replacement_term->term_id ) && strpos( $default_uri, "%{$taxonomy}_custom_uri%" ) !== false && ! empty( $permalink_manager_uris["tax-{$replacement_term->term_id}"] ) ) {
|
||||
$mode = 1;
|
||||
} // 4B. Hierarchical term base
|
||||
else if ( ! empty( $replacement_term->term_id ) && strpos( $default_uri, "%{$taxonomy}_flat%" ) === false && strpos( $default_uri, "%{$taxonomy}_top%" ) === false && is_taxonomy_hierarchical( $taxonomy ) ) {
|
||||
$mode = 2;
|
||||
} // 4C. Force flat/non-hierarchical term base - get the highest level term (if %taxonomy_top% tag is used)
|
||||
else if ( strpos( $default_uri, "%{$taxonomy}_top%" ) !== false ) {
|
||||
$mode = 3;
|
||||
} // 4D. Force flat/non-hierarchical term base - get the lowest level term (if %taxonomy_flat% tag is used)
|
||||
else {
|
||||
$mode = 4;
|
||||
}
|
||||
|
||||
// Get the replacement slug (custom + native)
|
||||
$replacement = Permalink_Manager_Helper_Functions::get_term_full_slug( $replacement_term, $terms, $mode, $native_uri );
|
||||
$native_replacement = Permalink_Manager_Helper_Functions::get_term_full_slug( $replacement_term, $terms, $mode, true );
|
||||
|
||||
// Trim slashes
|
||||
$replacement = trim( $replacement, '/' );
|
||||
$native_replacement = trim( $native_replacement, '/' );
|
||||
|
||||
// Filter final category slug
|
||||
$replacement = apply_filters( 'permalink_manager_filter_term_slug', $replacement, $replacement_term, $post, $terms, $taxonomy, $native_uri );
|
||||
|
||||
// 4. Do the replacement
|
||||
$default_uri = ( ! empty( $replacement ) ) ? str_replace( array( "%{$taxonomy}%", "%{$taxonomy}_flat%", "%{$taxonomy}_custom_uri%", "%{$taxonomy}_top%" ), $replacement, $default_uri ) : $default_uri;
|
||||
$default_uri = ( ! empty( $native_replacement ) ) ? str_replace( "%{$taxonomy}_native_slug%", $native_replacement, $default_uri ) : $default_uri;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore WPML adjust ID filter
|
||||
if ( class_exists( 'SitePress' ) ) {
|
||||
remove_filter( 'wpml_disable_term_adjust_id', '__return_true', 999 );
|
||||
}
|
||||
|
||||
return apply_filters( 'permalink_manager_filter_default_post_uri', $default_uri, $post->post_name, $post, $post_name, $native_uri );
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclude the page selected as "Front page"
|
||||
*
|
||||
* @param array $uris
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function exclude_homepage( $uris ) {
|
||||
// Find the homepage URI
|
||||
$homepage_id = get_option( 'page_on_front' );
|
||||
|
||||
if ( is_array( $uris ) && ! empty( $uris[ $homepage_id ] ) ) {
|
||||
unset( $uris[ $homepage_id ] );
|
||||
}
|
||||
|
||||
return $uris;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support url_to_postid() function
|
||||
*
|
||||
* @param string $url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function url_to_postid( $url ) {
|
||||
global $pm_query;
|
||||
|
||||
// Filter only defined URLs
|
||||
if ( empty( $url ) ) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
// Make sure that $pm_query global is not changed
|
||||
$old_pm_query = $pm_query;
|
||||
$post = Permalink_Manager_Core_Functions::detect_post( array(), $url, true );
|
||||
$pm_query = $old_pm_query;
|
||||
|
||||
if ( ! empty( $post->ID ) ) {
|
||||
$native_url = "/?p={$post->ID}";
|
||||
}
|
||||
|
||||
return ( ! empty( $native_url ) ) ? $native_url : $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array with all post items based on the user-selected settings in the "Bulk tools" form
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public static function get_items() {
|
||||
global $wpdb, $permalink_manager_options;
|
||||
|
||||
// Check if post types & statuses are not empty
|
||||
if ( empty( $_POST['post_types'] ) || empty( $_POST['post_statuses'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$post_types_array = array_map( 'sanitize_key', $_POST['post_types'] );
|
||||
$post_statuses_array = array_map( 'sanitize_key', $_POST['post_statuses'] );
|
||||
$post_types_in = Permalink_Manager_Helper_Functions::prepare_array_for_sql_in( $post_types_array, false );
|
||||
$post_statuses_in = Permalink_Manager_Helper_Functions::prepare_array_for_sql_in( $post_statuses_array, false );
|
||||
|
||||
// Filter the posts by IDs
|
||||
$where = '';
|
||||
if ( ! empty( $_POST['ids'] ) ) {
|
||||
// Remove whitespaces and prepare array with IDs and/or ranges
|
||||
$ids = esc_sql( preg_replace( '/\s*/m', '', $_POST['ids'] ) );
|
||||
preg_match_all( "/([\d]+(?:-?[\d]+)?)/x", $ids, $groups );
|
||||
|
||||
// Prepare the extra ID filters
|
||||
$where .= "AND (";
|
||||
foreach ( $groups[0] as $group ) {
|
||||
$where .= ( $group == reset( $groups[0] ) ) ? "" : " OR ";
|
||||
// A. Single number
|
||||
if ( is_numeric( $group ) ) {
|
||||
$where .= "(ID = {$group})";
|
||||
} // B. Range
|
||||
else if ( substr_count( $group, '-' ) ) {
|
||||
$range_edges = explode( "-", $group );
|
||||
$where .= "(ID BETWEEN {$range_edges[0]} AND {$range_edges[1]})";
|
||||
}
|
||||
}
|
||||
$where .= ")";
|
||||
}
|
||||
|
||||
// Get excluded items
|
||||
$excluded_posts = (array) apply_filters( 'permalink_manager_excluded_post_ids', array() );
|
||||
if ( ! empty( $excluded_posts ) ) {
|
||||
$where .= sprintf( " AND ID NOT IN (%s) ", Permalink_Manager_Helper_Functions::prepare_array_for_sql_in( $excluded_posts ) );
|
||||
}
|
||||
|
||||
// Support for attachments
|
||||
$attachment_support = ( in_array( 'attachment', $post_types_array ) ) ? " OR (post_type = 'attachment')" : "";
|
||||
|
||||
// Check the auto-update mode
|
||||
// A. Allow only user-approved posts
|
||||
if ( ! empty( $permalink_manager_options["general"]["auto_update_uris"] ) && $permalink_manager_options["general"]["auto_update_uris"] == 2 ) {
|
||||
$where .= " AND pm.meta_value IN (1, -1) ";
|
||||
} // B. Allow all posts not disabled by the user
|
||||
else {
|
||||
$where .= " AND (pm.meta_value IS NULL OR pm.meta_value IN (1, -1)) ";
|
||||
}
|
||||
|
||||
// Get the rows before they are altered
|
||||
$query = "SELECT post_type, post_title, post_name, ID FROM {$wpdb->posts} AS p LEFT JOIN {$wpdb->postmeta} AS pm ON pm.post_ID = p.ID AND pm.meta_key = 'auto_update_uri' WHERE ((post_status IN ({$post_statuses_in}) AND post_type IN ({$post_types_in})){$attachment_support}) {$where}";
|
||||
$query = apply_filters( 'permalink_manager_get_items_query', $query, $where, 'post_types' );
|
||||
|
||||
return $wpdb->get_results( $query, ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the permalinks/slugs "Find & replace" & "Regenerate/rest" tool
|
||||
*
|
||||
* @param array $chunk
|
||||
* @param string $mode
|
||||
* @param string $operation
|
||||
* @param string $old_string
|
||||
* @param string $new_string
|
||||
* @param bool $preview_mode
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public static function bulk_process_items( $chunk = null, $mode = '', $operation = '', $old_string = '', $new_string = '', $preview_mode = false ) {
|
||||
// Reset variables
|
||||
$updated_slugs_count = 0;
|
||||
$updated_array = array();
|
||||
|
||||
// Get the rows before they are altered
|
||||
$posts_to_update = ( ! empty( $chunk ) ) ? $chunk : self::get_items();
|
||||
|
||||
if ( empty( $operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now if the array is not empty use IDs from each subarray as a key
|
||||
if ( $posts_to_update ) {
|
||||
foreach ( $posts_to_update as $row ) {
|
||||
// Get default & native URL
|
||||
$native_uri = self::get_default_post_uri( $row['ID'], true );
|
||||
$default_uri = self::get_default_post_uri( $row['ID'] );
|
||||
$old_custom_uri = Permalink_Manager_URI_Functions::get_single_uri( $row['ID'], true, true );
|
||||
$old_uri = ( ! empty( $old_custom_uri ) ) ? $old_custom_uri : $native_uri;
|
||||
|
||||
$old_post_name = $row['post_name'];
|
||||
|
||||
if ( $operation == 'regenerate' ) {
|
||||
if ( $mode == 'slugs' ) {
|
||||
$new_uri = $old_uri;
|
||||
$new_post_name = Permalink_Manager_Helper_Functions::sanitize_title( $row['post_title'] );
|
||||
} else if ( $mode == 'native' ) {
|
||||
$new_uri = $native_uri;
|
||||
$new_post_name = $old_post_name;
|
||||
} else {
|
||||
$new_uri = $default_uri;
|
||||
$new_post_name = $old_post_name;
|
||||
}
|
||||
} else {
|
||||
list( $new_post_name, $new_uri ) = Permalink_Manager_Helper_Functions::replace_uri_slug( $old_string, $new_string, $old_post_name, $old_uri, $mode );
|
||||
}
|
||||
|
||||
// Check if native slug should be changed
|
||||
if ( $mode == 'slugs' && $old_post_name !== $new_post_name ) {
|
||||
$new_post_name = self::update_slug_by_id( $new_post_name, $row['ID'], $preview_mode );
|
||||
}
|
||||
|
||||
$new_uri = apply_filters( 'permalink_manager_pre_update_post_uri', $new_uri, $row['ID'], $old_uri, $native_uri, $default_uri );
|
||||
|
||||
if ( ! ( empty( $new_uri ) ) && ( $old_custom_uri !== $new_uri ) || ( $old_post_name !== $new_post_name ) ) {
|
||||
if ( ! $preview_mode && ( $old_custom_uri !== $new_uri ) ) {
|
||||
Permalink_Manager_URI_Functions::save_single_uri( $row['ID'], $new_uri, false, false );
|
||||
do_action( 'permalink_manager_updated_post_uri', $row['ID'], $new_uri, $old_uri, $native_uri, $default_uri );
|
||||
}
|
||||
|
||||
$updated_array[] = array( 'item_title' => $row['post_title'], 'ID' => $row['ID'], 'old_uri' => $old_uri, 'new_uri' => $new_uri, 'old_slug' => $old_post_name, 'new_slug' => $new_post_name );
|
||||
$updated_slugs_count ++;
|
||||
}
|
||||
}
|
||||
|
||||
// Save all custom permalinks
|
||||
if ( ! $preview_mode ) {
|
||||
Permalink_Manager_URI_Functions::save_all_uris();
|
||||
}
|
||||
|
||||
$output = array( 'updated' => $updated_array, 'updated_count' => $updated_slugs_count );
|
||||
wp_reset_postdata();
|
||||
}
|
||||
|
||||
return ( ! empty( $output ) ) ? $output : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the custom permalinks in "Bulk URI Editor" tool
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
static public function update_all_permalinks() {
|
||||
// Setup needed variables
|
||||
$updated_slugs_count = 0;
|
||||
$updated_array = array();
|
||||
|
||||
$new_uris = isset( $_POST['uri'] ) ? $_POST['uri'] : array();
|
||||
|
||||
// Double check if the slugs and ids are stored in arrays
|
||||
if ( ! is_array( $new_uris ) ) {
|
||||
$new_uris = explode( ',', $new_uris );
|
||||
}
|
||||
|
||||
if ( ! empty( $new_uris ) ) {
|
||||
foreach ( $new_uris as $id => $new_uri ) {
|
||||
// Prepare variables
|
||||
$this_post = get_post( $id );
|
||||
$old_uri = Permalink_Manager_URI_Functions::get_single_uri( $this_post, false, true );
|
||||
|
||||
$final_uri = self::save_uri( $this_post, $new_uri, false, false, false );
|
||||
|
||||
if ( $final_uri ) {
|
||||
$updated_array[] = array( 'item_title' => get_the_title( $id ), 'ID' => $id, 'old_uri' => $old_uri, 'new_uri' => $final_uri );
|
||||
$updated_slugs_count ++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Save all custom permalinks
|
||||
Permalink_Manager_URI_Functions::save_all_uris();
|
||||
|
||||
$output = array( 'updated' => $updated_array, 'updated_count' => $updated_slugs_count );
|
||||
}
|
||||
|
||||
return ( ! empty( $output ) ) ? $output : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow to edit URIs from "Edit Post" admin pages
|
||||
*
|
||||
* @param string $html
|
||||
* @param int $id
|
||||
* @param string $new_title
|
||||
* @param string $new_slug
|
||||
* @param WP_Post $post
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function edit_uri_box( $html, $id, $new_title, $new_slug, $post ) {
|
||||
// Detect auto drafts
|
||||
$autosave = ( ! empty( $new_title ) && empty( $new_slug ) ) ? true : false;
|
||||
|
||||
// Check if the post is excluded
|
||||
if ( empty( $post->post_type ) || Permalink_Manager_Helper_Functions::is_post_excluded( $post, true ) ) {
|
||||
$show_uri_editor = false;
|
||||
} else {
|
||||
$show_uri_editor = true;
|
||||
}
|
||||
|
||||
// Stop the hook (if needed)
|
||||
$show_uri_editor = apply_filters( "permalink_manager_show_uri_editor_post", $show_uri_editor, $post, $post->post_type );
|
||||
if ( ! $show_uri_editor ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
// Make sure that home URL ends with slash
|
||||
$home_url = Permalink_Manager_Permastructure_Functions::get_permalink_base( $post );
|
||||
|
||||
// A. Display the original permalink on the front-page editor
|
||||
if ( Permalink_Manager_Helper_Functions::is_front_page( $id ) ) {
|
||||
preg_match( '/href="([^"]+)"/mi', $html, $matches );
|
||||
$sample_permalink = ( ! empty( $matches[1] ) ) ? $matches[1] : "";
|
||||
} else {
|
||||
// B. Do not change anything if post is not saved yet (display sample permalink instead)
|
||||
if ( $autosave || empty( $post->post_status ) ) {
|
||||
$sample_permalink_uri = self::get_default_post_uri( $id );
|
||||
} // C. Display custom URI (if set) or default custom URI (for drafts)
|
||||
else {
|
||||
$is_draft = ( $post->post_status == 'draft' ) ? true : false;
|
||||
$sample_permalink_uri = Permalink_Manager_URI_Functions::get_single_uri( $post, ! $is_draft, false );
|
||||
}
|
||||
|
||||
if ( empty( $sample_permalink_uri ) && $post->post_type !== 'attachment' ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
// Decode URI & allow to filter it
|
||||
$sample_permalink_uri = apply_filters( 'permalink_manager_filter_post_sample_uri', rawurldecode( $sample_permalink_uri ), $post );
|
||||
|
||||
// Prepare the sample & default permalink
|
||||
$sample_permalink = sprintf( "%s/<span class=\"editable\">%s</span>", $home_url, str_replace( "//", "/", $sample_permalink_uri ) );
|
||||
}
|
||||
|
||||
$sample_permalink_html = sprintf( "<span id=\"sample-permalink\"><span class=\"sample-permalink-span\"><a id=\"sample-permalink\" href=\"%s\">%s</a></span></span> ", strip_tags( $sample_permalink ), $sample_permalink );
|
||||
|
||||
// 1. Overwrite the sample permalink
|
||||
if ( preg_match( '/(<span id="sample-permalink"><a.*<\/a><\/span>)/m', $html ) ) {
|
||||
$new_html = preg_replace( '/(<span id="sample-permalink"><a.*<\/a><\/span>)/m', $sample_permalink_html, $html );
|
||||
} else if ( preg_match( '/(<a id="sample-permalink"[^<]*>.*<\/a>)/m', $html ) ) {
|
||||
$new_html = preg_replace( '/(<a id="sample-permalink"[^<]*>.*<\/a>)/m', $sample_permalink_html, $html );
|
||||
} else {
|
||||
$new_html = $html;
|
||||
}
|
||||
|
||||
// 2. Append the Permalink Editor
|
||||
$new_html .= Permalink_Manager_UI_Elements::display_uri_box( $post );
|
||||
|
||||
// 3. Hide the "Edit" slug button
|
||||
$new_html = str_replace( 'edit-slug button', 'edit-slug button hidden', $new_html );
|
||||
|
||||
// 4. Append hidden field with native slug
|
||||
$new_html .= ( ! empty( $post->post_name ) && strpos( $new_html, 'editable-post-name-full' ) === false ) ? "<span id=\"editable-post-name-full\">{$post->post_name}</span>" : "";
|
||||
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
return $new_html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "Current URI" input field to "Quick Edit" form
|
||||
*
|
||||
* @param array $columns
|
||||
*
|
||||
* @return array mixed
|
||||
*/
|
||||
function quick_edit_column( $columns ) {
|
||||
global $current_screen;
|
||||
|
||||
// Get post type
|
||||
$post_type = ( ! empty( $current_screen->post_type ) ) ? $current_screen->post_type : false;
|
||||
|
||||
// Check if post type is disabled
|
||||
if ( $post_type && Permalink_Manager_Helper_Functions::is_post_type_disabled( $post_type ) ) {
|
||||
return $columns;
|
||||
}
|
||||
|
||||
return ( is_array( $columns ) ) ? array_merge( $columns, array( 'permalink-manager-col' => __( 'Custom permalink', 'permalink-manager' ) ) ) : $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the URI of the current post in the "Custom Permalink" column
|
||||
*
|
||||
* @param string $column_name The name of the column to display. In this case, we named our column permalink-manager-col.
|
||||
* @param int $post_id The ID of the term.
|
||||
*/
|
||||
function quick_edit_column_content( $column_name, $post_id ) {
|
||||
global $permalink_manager_uris, $permalink_manager_options;
|
||||
|
||||
if ( $column_name == 'permalink-manager-col' ) {
|
||||
$exclude_drafts = ( isset( $permalink_manager_options['general']['ignore_drafts'] ) ) ? $permalink_manager_options['general']['ignore_drafts'] : false;
|
||||
$is_draft = ( get_post_status( $post_id ) == 'draft' ) ? true : false;
|
||||
|
||||
// A. Disable the 'Quick Edit' form for draft posts if 'Exclude drafts' option is turned on
|
||||
if ( $exclude_drafts && $is_draft ) {
|
||||
$disabled = 1;
|
||||
} // B. Get auto-update settings
|
||||
else {
|
||||
$auto_update_val = get_post_meta( $post_id, 'auto_update_uri', true );
|
||||
$disabled = ( ! empty( $auto_update_val ) ) ? $auto_update_val : $permalink_manager_options['general']['auto_update_uris'];
|
||||
}
|
||||
|
||||
$uri = ( ! empty( $permalink_manager_uris[ $post_id ] ) ) ? rawurldecode( $permalink_manager_uris[ $post_id ] ) : self::get_post_uri( $post_id, true, $is_draft );
|
||||
printf( '<span class="permalink-manager-col-uri" data-disabled="%s">%s</span>', esc_attr( intval( $disabled ) ), esc_html( $uri ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the custom permalink
|
||||
*
|
||||
* @param int|WP_Post $post
|
||||
* @param string $new_uri
|
||||
* @param bool $is_new_post
|
||||
* @param int|bool $auto_update_mode
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
static function save_uri( $post, $new_uri = '', $is_new_post = false, $auto_update_mode = false, $db_save = true ) {
|
||||
global $permalink_manager_options;
|
||||
|
||||
// Do not do anything if post is auto-saved
|
||||
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the post object
|
||||
if ( is_numeric( $post ) ) {
|
||||
$post_object = get_post( $post );
|
||||
} else if ( is_a( $post, 'WP_Post' ) ) {
|
||||
$post_object = $post;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if post is allowed
|
||||
if ( empty( $post_object->post_type ) || ( $is_new_post && empty( $post_object->post_title ) ) || Permalink_Manager_Helper_Functions::is_post_excluded( $post_object, true, $is_new_post ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Manage 'Auto-update URI' settings
|
||||
if ( ! empty( $auto_update_mode ) ) {
|
||||
$auto_update_uri = $auto_update_mode;
|
||||
update_post_meta( $post_object->ID, 'auto_update_uri', $auto_update_mode );
|
||||
} elseif ( $auto_update_mode === 0 ) {
|
||||
$auto_update_uri = $permalink_manager_options['general']['auto_update_uris'];
|
||||
delete_post_meta( $post_object->ID, 'auto_update_uri' );
|
||||
} else {
|
||||
$auto_update_uri = get_post_meta( $post_object->ID, 'auto_update_uri', true );
|
||||
$auto_update_uri = ( ! empty( $auto_update_uri ) ) ? $auto_update_uri : $permalink_manager_options['general']['auto_update_uris'];
|
||||
}
|
||||
|
||||
$default_uri = self::get_default_post_uri( $post_object );
|
||||
$native_uri = self::get_default_post_uri( $post_object, true );
|
||||
$old_uri = self::get_post_uri( $post_object->ID, false, true );
|
||||
|
||||
if ( $is_new_post ) {
|
||||
$new_uri = $default_uri;
|
||||
$allow_save = apply_filters( 'permalink_manager_allow_new_post_uri', true, $post_object );
|
||||
} else {
|
||||
$new_uri = ( ( $new_uri == '' || $auto_update_uri == 1 ) && ! in_array( $post_object->post_status, array( 'draft', 'auto-draft' ) ) ) ? $default_uri : Permalink_Manager_Helper_Functions::sanitize_title( $new_uri, true );
|
||||
$allow_save = apply_filters( 'permalink_manager_allow_update_post_uri', true, $post_object );
|
||||
}
|
||||
|
||||
$new_uri = apply_filters( 'permalink_manager_pre_update_post_uri', $new_uri, $post_object->ID, $old_uri, $native_uri, $default_uri );
|
||||
|
||||
// The update URI process is stopped by the hook above or disabled in "Auto-update" settings
|
||||
if ( ! $allow_save || ( ! empty( $auto_update_uri ) && $auto_update_uri == 2 ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save the URI only if $new_uri variable is set
|
||||
if ( ! empty( $new_uri ) && $new_uri !== $old_uri ) {
|
||||
Permalink_Manager_URI_Functions::save_single_uri( $post_object->ID, $new_uri, false, $db_save );
|
||||
$uri_saved = true;
|
||||
} // The $new_uri variable is empty or no change is detected
|
||||
else {
|
||||
$uri_saved = false;
|
||||
}
|
||||
|
||||
do_action( 'permalink_manager_updated_post_uri', $post_object->ID, $new_uri, $old_uri, $native_uri, $default_uri, $uri_saved );
|
||||
|
||||
return ( $uri_saved ) ? $new_uri : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the custom permalink when 'wp_insert_post' action is triggered
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
*/
|
||||
function insert_post_hook( $post_id ) {
|
||||
global $permalink_manager_uris;
|
||||
|
||||
// Do not trigger if post is a revision or imported via WP All Import (URI should be set after the post meta is added)
|
||||
if ( empty( $post_id ) || wp_is_post_revision( $post_id ) || ( ! empty( $_REQUEST['page'] ) && $_REQUEST['page'] == 'pmxi-admin-import' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop when products are imported with WooCommerce importer
|
||||
if ( ! empty( $_REQUEST['action'] ) && $_REQUEST['action'] == 'woocommerce_do_ajax_product_import' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not process REST API requests originating from Gutenberg JS functions
|
||||
if ( defined( 'REST_REQUEST' ) && REST_REQUEST && ! empty( $_SERVER['HTTP_X_WP_NONCE'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not do anything if the custom permalink was generated before or 'custom_uri' field is present in the request
|
||||
if ( isset( $permalink_manager_uris[ $post_id ] ) || ( isset( $_POST['custom_uri'] ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::save_uri( $post_id, '', true, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the custom permalink when 'save_post' action is triggered
|
||||
*
|
||||
* @param int $post_id Term ID.
|
||||
*/
|
||||
static function update_post_hook( $post_id ) {
|
||||
// Verify nonce at first
|
||||
if ( ! isset( $_POST['permalink-manager-nonce'] ) || ! wp_verify_nonce( $_POST['permalink-manager-nonce'], 'permalink-manager-edit-uri-box' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not do anything if the field with URI or element ID are not present or different from the provided post ID
|
||||
if ( ! isset( $_POST['custom_uri'] ) || empty( $_POST['permalink-manager-edit-uri-element-id'] ) || $_POST['permalink-manager-edit-uri-element-id'] != $post_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the user can edit this post
|
||||
if ( ! current_user_can( 'edit_post', $post_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fix for revisions
|
||||
$post_id = wp_is_post_revision( $post_id ) ? wp_is_post_revision( $post_id ) : $post_id;
|
||||
$post = get_post( $post_id );
|
||||
|
||||
// Get auto-update URI setting (if empty use global setting)
|
||||
if ( isset( $_POST["auto_update_uri"] ) && is_numeric( $_POST["auto_update_uri"] ) ) {
|
||||
$auto_update_mode = intval( $_POST["auto_update_uri"] );
|
||||
} else {
|
||||
$auto_update_mode = false;
|
||||
}
|
||||
|
||||
// Update the slug (if changed)
|
||||
if ( isset( $_POST['permalink-manager-edit-uri-element-slug'] ) && isset( $_POST['native_slug'] ) && ( $_POST['native_slug'] !== $post->post_name ) ) {
|
||||
// Make sure that '_wp_old_slug' is saved
|
||||
if ( ! empty( $_POST['post_name'] ) || ( isset( $_POST['action'] ) && in_array( $_POST['action'], array( 'pm_save_permalink', 'editpost' ) ) ) ) {
|
||||
$post_after = clone $post;
|
||||
$post_after->post_name = sanitize_title( $_POST['native_slug'] );
|
||||
|
||||
wp_check_for_changed_slugs( $post_id, $post_after, $post );
|
||||
}
|
||||
|
||||
self::update_slug_by_id( $_POST['native_slug'], $post_id );
|
||||
}
|
||||
|
||||
self::save_uri( $post_id, $_POST['custom_uri'], false, $auto_update_mode );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove URI from options array after post is moved to the trash
|
||||
*
|
||||
* @param int $post_id
|
||||
*/
|
||||
function remove_post_hook( $post_id ) {
|
||||
Permalink_Manager_URI_Functions::remove_single_uri( $post_id, false, true );
|
||||
}
|
||||
|
||||
}
|
||||
+682
@@ -0,0 +1,682 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of functions for processing and applying the custom permalink to terms.
|
||||
*/
|
||||
class Permalink_Manager_URI_Functions_Tax {
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'init' ), 100 );
|
||||
add_action( 'rest_api_init', array( $this, 'init' ) );
|
||||
|
||||
add_filter( 'term_link', array( $this, 'custom_tax_permalinks' ), 999, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow to edit URIs from "Edit Term" admin pages (register hooks)
|
||||
*/
|
||||
public function init() {
|
||||
global $permalink_manager_options;
|
||||
|
||||
$all_taxonomies = Permalink_Manager_Helper_Functions::get_taxonomies_array();
|
||||
|
||||
// Add "URI Editor" to "Quick Edit" for all taxonomies
|
||||
foreach ( $all_taxonomies as $tax => $label ) {
|
||||
// Check if taxonomy is allowed
|
||||
if ( Permalink_Manager_Helper_Functions::is_taxonomy_disabled( $tax ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
add_action( "edited_{$tax}", array( $this, 'update_term_uri' ), 10, 2 );
|
||||
add_action( "create_{$tax}", array( $this, 'update_term_uri' ), 10, 2 );
|
||||
add_action( "delete_{$tax}", array( $this, 'remove_term_uri' ), 10, 2 );
|
||||
|
||||
// Check the user capabilities
|
||||
if ( is_admin() ) {
|
||||
$edit_uris_cap = ( ! empty( $permalink_manager_options['general']['edit_uris_cap'] ) ) ? $permalink_manager_options['general']['edit_uris_cap'] : 'publish_posts';
|
||||
if ( current_user_can( $edit_uris_cap ) ) {
|
||||
add_action( "{$tax}_add_form_fields", array( $this, 'edit_uri_box' ), 10, 1 );
|
||||
add_action( "{$tax}_edit_form_fields", array( $this, 'edit_uri_box' ), 10, 1 );
|
||||
add_filter( "manage_edit-{$tax}_columns", array( $this, 'quick_edit_column' ) );
|
||||
add_filter( "manage_{$tax}_custom_column", array( $this, 'quick_edit_column_content' ), 20, 3 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the custom permalinks to the terms
|
||||
*
|
||||
* @param string $permalink
|
||||
* @param WP_Term|int $term
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function custom_tax_permalinks( $permalink, $term ) {
|
||||
global $permalink_manager_uris, $permalink_manager_options, $permalink_manager_ignore_permalink_filters;
|
||||
|
||||
// Do not filter permalinks in Customizer
|
||||
if ( function_exists( 'is_customize_preview' ) && is_customize_preview() ) {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
// Do not filter in WPML String Editor
|
||||
if ( ! empty( $_REQUEST['icl_ajx_action'] ) && $_REQUEST['icl_ajx_action'] == 'icl_st_save_translation' ) {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
// Do not filter if $permalink_manager_ignore_permalink_filters global is set
|
||||
if ( ! empty( $permalink_manager_ignore_permalink_filters ) ) {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
$term = ( is_numeric( $term ) ) ? get_term( $term ) : $term;
|
||||
|
||||
// Check if the term is allowed
|
||||
if ( empty( $term->term_id ) || Permalink_Manager_Helper_Functions::is_term_excluded( $term ) || ! is_string( $permalink ) ) {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
// Get term id
|
||||
$term_id = $term->term_id;
|
||||
|
||||
// Save the old permalink to separate variable
|
||||
$old_permalink = $permalink;
|
||||
|
||||
if ( isset( $permalink_manager_uris["tax-{$term_id}"] ) ) {
|
||||
// Start with homepage URL
|
||||
$permalink = Permalink_Manager_Permastructure_Functions::get_permalink_base( $term );
|
||||
|
||||
// Encode URI?
|
||||
if ( ! empty( $permalink_manager_options['general']['decode_uris'] ) ) {
|
||||
$permalink .= rawurldecode( "/{$permalink_manager_uris["tax-{$term_id}"]}" );
|
||||
} else {
|
||||
$permalink .= Permalink_Manager_Helper_Functions::encode_uri( "/{$permalink_manager_uris["tax-{$term_id}"]}" );
|
||||
}
|
||||
} else if ( ! empty( $permalink_manager_options['general']['decode_uris'] ) ) {
|
||||
$permalink = rawurldecode( $permalink );
|
||||
}
|
||||
|
||||
return apply_filters( 'permalink_manager_filter_final_term_permalink', $permalink, $term, $old_permalink );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the provided slug is unique and then update it with SQL query.
|
||||
*
|
||||
* @param string $slug
|
||||
* @param int $id
|
||||
* @param bool $preview_mode
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static function update_slug_by_id( $slug, $id, $preview_mode = false ) {
|
||||
global $wpdb;
|
||||
|
||||
// Update slug and make it unique
|
||||
$term = get_term( intval( $id ) );
|
||||
$slug = ( empty( $slug ) ) ? get_the_title( $term->name ) : $slug;
|
||||
$slug = sanitize_title( $slug );
|
||||
|
||||
$new_slug = wp_unique_term_slug( $slug, $term );
|
||||
|
||||
if ( ! $preview_mode ) {
|
||||
$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->terms} SET slug = %s WHERE term_id = %d", $new_slug, $id ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
||||
}
|
||||
|
||||
return $new_slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently used custom permalink (or default/empty URI)
|
||||
*
|
||||
* @param int $term_id
|
||||
* @param bool $native_uri
|
||||
* @param bool $no_fallback
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_term_uri( $term_id, $native_uri = false, $no_fallback = false ) {
|
||||
global $permalink_manager_uris;
|
||||
|
||||
// Check if input is term object
|
||||
$term = ( isset( $term_id->term_id ) ) ? $term_id->term_id : get_term( $term_id );
|
||||
|
||||
if ( ! empty( $permalink_manager_uris["tax-{$term_id}"] ) ) {
|
||||
$final_uri = $permalink_manager_uris["tax-{$term_id}"];
|
||||
} else if ( ! $no_fallback ) {
|
||||
$final_uri = self::get_default_term_uri( $term->term_id, $native_uri );
|
||||
} else {
|
||||
$final_uri = '';
|
||||
}
|
||||
|
||||
return $final_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default custom permalink (not overwritten by the user) or native permalink (unfiltered)
|
||||
*
|
||||
* @param WP_Term|int $term
|
||||
* @param bool $native_uri
|
||||
* @param bool $check_if_disabled
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_default_term_uri( $term, $native_uri = false, $check_if_disabled = false ) {
|
||||
global $permalink_manager_permastructs, $wp_taxonomies;
|
||||
|
||||
// Disable WPML adjust ID filter
|
||||
if ( class_exists( 'SitePress' ) ) {
|
||||
add_filter( 'wpml_disable_term_adjust_id', '__return_true', 999 );
|
||||
}
|
||||
|
||||
// 1. Load all bases & term
|
||||
$term = is_object( $term ) ? $term : get_term( $term );
|
||||
// $term_id = $term->term_id;
|
||||
$taxonomy_name = $term->taxonomy;
|
||||
$taxonomy = get_taxonomy( $taxonomy_name );
|
||||
$term_slug = $term->slug;
|
||||
$top_parent_slug = '';
|
||||
|
||||
// 1A. Check if taxonomy is allowed
|
||||
if ( $check_if_disabled && Permalink_Manager_Helper_Functions::is_taxonomy_disabled( $taxonomy ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 2A. Get the native permastructure
|
||||
$native_permastructure = Permalink_Manager_Permastructure_Functions::get_default_permastruct( $taxonomy_name );
|
||||
|
||||
// 2B. Get the permastructure
|
||||
if ( $native_uri || empty( $permalink_manager_permastructs['taxonomies'][ $taxonomy_name ] ) ) {
|
||||
$permastructure = $native_permastructure;
|
||||
} else {
|
||||
$permastructure = apply_filters( 'permalink_manager_filter_permastructure', $permalink_manager_permastructs['taxonomies'][ $taxonomy_name ], $term );
|
||||
}
|
||||
|
||||
// 2C. Set the permastructure
|
||||
$default_base = ( ! empty( $permastructure ) ) ? trim( $permastructure, '/' ) : "";
|
||||
|
||||
// 3A. Check if the taxonomy has custom permastructure set
|
||||
if ( empty( $default_base ) && ! isset( $permalink_manager_permastructs['taxonomies'][ $taxonomy_name ] ) ) {
|
||||
if ( 'category' == $taxonomy_name ) {
|
||||
$default_uri = "?cat={$term->term_id}";
|
||||
} elseif ( $taxonomy->query_var ) {
|
||||
$default_uri = "?{$taxonomy->query_var}={$term_slug}";
|
||||
} else if ( ! empty( $term_slug ) ) {
|
||||
$default_uri = "?taxonomy={$taxonomy_name}&term={$term_slug}";
|
||||
} else {
|
||||
$default_uri = '';
|
||||
}
|
||||
} // 3B. Use custom permastructure
|
||||
else {
|
||||
$default_uri = $default_base;
|
||||
|
||||
// 3B. Get the full slug
|
||||
$term_slug = Permalink_Manager_Helper_Functions::remove_slashes( $term_slug );
|
||||
$custom_slug = $full_custom_slug = Permalink_Manager_Helper_Functions::force_custom_slugs( $term_slug, $term, true, null, false );
|
||||
$term_title_slug = Permalink_Manager_Helper_Functions::force_custom_slugs( $term_slug, $term, true, 1 );
|
||||
$full_native_slug = $term_slug;
|
||||
|
||||
// Add ancestors to hierarchical taxonomy
|
||||
if ( is_taxonomy_hierarchical( $taxonomy_name ) ) {
|
||||
$ancestors = get_ancestors( $term->term_id, $taxonomy_name, 'taxonomy' );
|
||||
|
||||
foreach ( $ancestors as $ancestor ) {
|
||||
$ancestor_term = get_term( $ancestor, $taxonomy_name );
|
||||
|
||||
$full_native_slug = $ancestor_term->slug . '/' . $full_native_slug;
|
||||
$full_custom_slug = Permalink_Manager_Helper_Functions::force_custom_slugs( $ancestor_term->slug, $ancestor_term ) . '/' . $full_custom_slug;
|
||||
}
|
||||
|
||||
// Get top parent term
|
||||
if ( strpos( $default_uri, "%{$taxonomy_name}_top%" ) === false || strpos( $default_uri, "%term_top%" ) === false ) {
|
||||
$top_parent_slug = Permalink_Manager_Helper_Functions::get_term_full_slug( $term, $ancestors, 3, $native_uri );
|
||||
}
|
||||
}
|
||||
|
||||
// Allow filter the default slug (only custom permalinks)
|
||||
if ( ! $native_uri ) {
|
||||
$full_slug = apply_filters( 'permalink_manager_filter_default_term_slug', $full_custom_slug, $term, $term->name );
|
||||
} else {
|
||||
$full_slug = $full_native_slug;
|
||||
}
|
||||
|
||||
// Get the taxonomy slug
|
||||
if ( ! empty( $wp_taxonomies[ $taxonomy_name ]->rewrite['slug'] ) ) {
|
||||
$taxonomy_name_slug = $wp_taxonomies[ $taxonomy_name ]->rewrite['slug'];
|
||||
} else if ( is_string( $wp_taxonomies[ $taxonomy_name ]->rewrite ) ) {
|
||||
$taxonomy_name_slug = $wp_taxonomies[ $taxonomy_name ]->rewrite;
|
||||
} else {
|
||||
$taxonomy_name_slug = $taxonomy_name;
|
||||
}
|
||||
$taxonomy_name_slug = apply_filters( 'permalink_manager_filter_taxonomy_slug', $taxonomy_name_slug, $term, $taxonomy_name );
|
||||
|
||||
$slug_tags = array( "%term_name%", "%term_flat%", "%{$taxonomy_name}%", "%{$taxonomy_name}_flat%", "%term_top%", "%{$taxonomy_name}_top%", "%native_slug%", "%native_title%", "%taxonomy%", "%term_id%" );
|
||||
$slug_tags_replacement = array( $full_slug, $custom_slug, $full_slug, $custom_slug, $top_parent_slug, $top_parent_slug, $full_native_slug, $term_title_slug, $taxonomy_name_slug, $term->term_id );
|
||||
|
||||
// Check if any term tag is present in custom permastructure
|
||||
$do_not_append_slug = Permalink_Manager_Permastructure_Functions::is_slug_tag_present( $default_uri, $slug_tags, $term );
|
||||
|
||||
// Replace the term tags with slugs or append the slug if no term tag is defined
|
||||
if ( ! empty( $do_not_append_slug ) ) {
|
||||
$default_uri = str_replace( $slug_tags, $slug_tags_replacement, $default_uri );
|
||||
} else {
|
||||
$default_uri .= "/{$full_slug}";
|
||||
}
|
||||
}
|
||||
|
||||
// Restore WPML adjust ID filter
|
||||
if ( class_exists( 'SitePress' ) ) {
|
||||
remove_filter( 'wpml_disable_term_adjust_id', '__return_true', 999 );
|
||||
}
|
||||
|
||||
return apply_filters( 'permalink_manager_filter_default_term_uri', $default_uri, $term->slug, $term, $term_slug, $native_uri );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array with all term items based on the user-selected settings in the "Bulk tools" form
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public static function get_items() {
|
||||
global $wpdb, $permalink_manager_options;
|
||||
|
||||
// Check if taxonomies are not empty
|
||||
if ( empty( $_POST['taxonomies'] ) || ! is_array( $_POST['taxonomies'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$taxonomy_names_array = array_map( 'sanitize_key', $_POST['taxonomies'] );
|
||||
$taxonomy_names_in = Permalink_Manager_Helper_Functions::prepare_array_for_sql_in( $taxonomy_names_array, false );
|
||||
|
||||
// Filter the terms by IDs
|
||||
$where = '';
|
||||
if ( ! empty( $_POST['ids'] ) ) {
|
||||
// Remove whitespaces and prepare array with IDs and/or ranges
|
||||
$ids = esc_sql( preg_replace( '/\s*/m', '', $_POST['ids'] ) );
|
||||
preg_match_all( "/([\d]+(?:-?[\d]+)?)/x", $ids, $groups );
|
||||
|
||||
// Prepare the extra ID filters
|
||||
$where .= "AND (";
|
||||
foreach ( $groups[0] as $group ) {
|
||||
$where .= ( $group == reset( $groups[0] ) ) ? "" : " OR ";
|
||||
// A. Single number
|
||||
if ( is_numeric( $group ) ) {
|
||||
$where .= "(t.term_id = {$group})";
|
||||
} // B. Range
|
||||
else if ( substr_count( $group, '-' ) ) {
|
||||
$range_edges = explode( "-", $group );
|
||||
$where .= "(t.term_id BETWEEN {$range_edges[0]} AND {$range_edges[1]})";
|
||||
}
|
||||
}
|
||||
$where .= ")";
|
||||
}
|
||||
|
||||
// Get excluded items
|
||||
$excluded_terms = (array) apply_filters( 'permalink_manager_excluded_term_ids', array() );
|
||||
if ( ! empty( $excluded_terms ) ) {
|
||||
$where .= sprintf( " AND t.term_id NOT IN (%s) ", Permalink_Manager_Helper_Functions::prepare_array_for_sql_in( $excluded_terms ) );
|
||||
}
|
||||
|
||||
// Check the auto-update mode
|
||||
// A. Allow only user-approved posts
|
||||
if ( ! empty( $permalink_manager_options["general"]["auto_update_uris"] ) && $permalink_manager_options["general"]["auto_update_uris"] == 2 ) {
|
||||
$where .= " AND tm.meta_value IN (1, -1) ";
|
||||
} // B. Allow all posts not disabled by the user
|
||||
else {
|
||||
$where .= " AND (tm.meta_value IS NULL OR tm.meta_value IN (1, -1)) ";
|
||||
}
|
||||
|
||||
// Get the rows before they are altered
|
||||
$query = "SELECT t.slug, t.name, t.term_id, tt.taxonomy FROM {$wpdb->terms} AS t INNER JOIN {$wpdb->term_taxonomy} AS tt ON tt.term_id = t.term_id LEFT JOIN {$wpdb->termmeta} AS tm ON (tm.term_id = t.term_id AND tm.meta_key = 'auto_update_uri') WHERE tt.taxonomy IN ({$taxonomy_names_in}) {$where}";
|
||||
$query = apply_filters( 'permalink_manager_get_items_query', $query, $where, 'taxonomies' );
|
||||
|
||||
return $wpdb->get_results( $query, ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the permalinks/slugs "Find & replace" & "Regenerate/rest" tool
|
||||
*
|
||||
* @param array $chunk
|
||||
* @param string $mode
|
||||
* @param string $operation
|
||||
* @param string $old_string
|
||||
* @param string $new_string
|
||||
* @param bool $preview_mode
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public static function bulk_process_items( $chunk = null, $mode = '', $operation = '', $old_string = '', $new_string = '', $preview_mode = false ) {
|
||||
// Reset variables
|
||||
$updated_slugs_count = 0;
|
||||
$updated_array = array();
|
||||
|
||||
// Get the rows before they are altered
|
||||
$terms_to_update = ( ! empty( $chunk ) ) ? $chunk : self::get_items();
|
||||
|
||||
if ( empty( $operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now if the array is not empty use IDs from each subarray as a key
|
||||
if ( $terms_to_update ) {
|
||||
foreach ( $terms_to_update as $row ) {
|
||||
$this_term = get_term( $row['term_id'] );
|
||||
|
||||
// Get default & native URL
|
||||
$native_uri = self::get_default_term_uri( $this_term, true );
|
||||
$default_uri = self::get_default_term_uri( $this_term );
|
||||
$old_custom_uri = Permalink_Manager_URI_Functions::get_single_uri( $row['term_id'], true, true, true );
|
||||
$old_uri = ( ! empty( $old_custom_uri ) ) ? $old_custom_uri : $native_uri;
|
||||
|
||||
$old_term_name = $row['slug'];
|
||||
|
||||
if ( $operation == 'regenerate' ) {
|
||||
if ( $mode == 'slugs' ) {
|
||||
$new_uri = $old_uri;
|
||||
$new_term_name = Permalink_Manager_Helper_Functions::sanitize_title( $row['name'] );
|
||||
} else if ( $mode == 'native' ) {
|
||||
$new_uri = $native_uri;
|
||||
$new_term_name = $old_term_name;
|
||||
} else {
|
||||
$new_uri = $default_uri;
|
||||
$new_term_name = $old_term_name;
|
||||
}
|
||||
} else {
|
||||
list( $new_term_name, $new_uri ) = Permalink_Manager_Helper_Functions::replace_uri_slug( $old_string, $new_string, $old_term_name, $old_uri, $mode );
|
||||
}
|
||||
|
||||
// Check if native slug should be changed
|
||||
if ( $mode == 'slugs' && $old_term_name !== $new_term_name ) {
|
||||
$new_term_name = self::update_slug_by_id( $new_term_name, $row['term_id'], $preview_mode );
|
||||
}
|
||||
|
||||
$new_uri = apply_filters( 'permalink_manager_pre_update_term_uri', $new_uri, $row['term_id'], $old_uri, $native_uri, $default_uri );
|
||||
|
||||
if ( ! ( empty( $new_uri ) ) && ( $old_custom_uri !== $new_uri ) || ( $old_term_name !== $new_term_name ) ) {
|
||||
if ( ! $preview_mode && ( $old_custom_uri !== $new_uri ) ) {
|
||||
Permalink_Manager_URI_Functions::save_single_uri( $row['term_id'], $new_uri, true, false );
|
||||
do_action( 'permalink_manager_updated_term_uri', $row['term_id'], $new_uri, $old_uri, $native_uri, $default_uri );
|
||||
}
|
||||
|
||||
$updated_array[] = array( 'item_title' => $row['name'], 'ID' => $row['term_id'], 'old_uri' => $old_uri, 'new_uri' => $new_uri, 'old_slug' => $old_term_name, 'new_slug' => $new_term_name, 'tax' => $this_term->taxonomy );
|
||||
$updated_slugs_count ++;
|
||||
}
|
||||
}
|
||||
|
||||
// Save all custom permalinks
|
||||
if ( ! $preview_mode ) {
|
||||
Permalink_Manager_URI_Functions::save_all_uris();
|
||||
}
|
||||
|
||||
$output = array( 'updated' => $updated_array, 'updated_count' => $updated_slugs_count );
|
||||
wp_reset_postdata();
|
||||
}
|
||||
|
||||
return ( ! empty( $output ) ) ? $output : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the custom permalinks in "Bulk URI Editor" tool
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
static public function update_all_permalinks() {
|
||||
// Setup needed variables
|
||||
$updated_slugs_count = 0;
|
||||
$updated_array = array();
|
||||
|
||||
$new_uris = isset( $_POST['uri'] ) ? $_POST['uri'] : array();
|
||||
|
||||
// Double check if the slugs and ids are stored in arrays
|
||||
if ( ! is_array( $new_uris ) ) {
|
||||
$new_uris = explode( ',', $new_uris );
|
||||
}
|
||||
|
||||
if ( ! empty( $new_uris ) ) {
|
||||
foreach ( $new_uris as $id => $new_uri ) {
|
||||
// Remove prefix from field name to obtain term id
|
||||
$term_id = filter_var( str_replace( 'tax-', '', $id ), FILTER_SANITIZE_NUMBER_INT );
|
||||
|
||||
$this_term = get_term( $term_id );
|
||||
$old_uri = Permalink_Manager_URI_Functions::get_single_uri( $term_id, false, true, true );
|
||||
$new_uri = ( empty( $new_uri ) ) ? null : $new_uri; // If the string is empty, convert it to null to force the default permalink
|
||||
|
||||
$final_uri = self::save_uri( $this_term, $new_uri, false, false, false );
|
||||
|
||||
if ( $final_uri ) {
|
||||
$updated_array[] = array( 'item_title' => $this_term->name, 'ID' => $term_id, 'old_uri' => $old_uri, 'new_uri' => $final_uri, 'tax' => $this_term->taxonomy );
|
||||
$updated_slugs_count ++;
|
||||
}
|
||||
}
|
||||
|
||||
// Save all custom permalinks
|
||||
Permalink_Manager_URI_Functions::save_all_uris();
|
||||
|
||||
$output = array( 'updated' => $updated_array, 'updated_count' => $updated_slugs_count );
|
||||
}
|
||||
|
||||
return ( ! empty( $output ) ) ? $output : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow to edit URIs from "New Term" & "Edit Term" admin pages
|
||||
*
|
||||
* @param WP_Term $term
|
||||
*/
|
||||
public function edit_uri_box( $term = '' ) {
|
||||
// Check if the term is excluded
|
||||
if ( empty( $term ) || Permalink_Manager_Helper_Functions::is_term_excluded( $term ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop the hook (if needed)
|
||||
if ( ! empty( $term->taxonomy ) ) {
|
||||
$show_uri_editor = apply_filters( "permalink_manager_show_uri_editor_term", true, $term, $term->taxonomy );
|
||||
|
||||
if ( ! $show_uri_editor ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$label = __( "Custom URI", "permalink-manager" );
|
||||
$description = __( "Clear/leave the field empty to use the default permalink.", "permalink-manager" );
|
||||
|
||||
// A. New term
|
||||
if ( empty( $term->term_id ) ) {
|
||||
$html = "<div class=\"form-field\">";
|
||||
$html .= sprintf( "<label for=\"term_meta[uri]\">%s</label>", $label );
|
||||
$html .= "<input type=\"text\" name=\"custom_uri\" id=\"custom_uri\" value=\"\">";
|
||||
$html .= sprintf( "<p class=\"description\">%s</p>", $description );
|
||||
$html .= "</div>";
|
||||
|
||||
// Append nonce field
|
||||
$html .= wp_nonce_field( 'permalink-manager-edit-uri-box', 'permalink-manager-nonce', true, false );
|
||||
} // B. Edit term
|
||||
else {
|
||||
$html = "<tr id=\"permalink-manager\" class=\"form-field permalink-manager-edit-term permalink-manager\">";
|
||||
$html .= sprintf( "<th scope=\"row\"><label for=\"custom_uri\">%s</label></th>", $label );
|
||||
$html .= "<td><div>";
|
||||
$html .= Permalink_Manager_UI_Elements::display_uri_box( $term );
|
||||
$html .= "</div></td>";
|
||||
$html .= "</tr>";
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "Custom permalink" input field to "Quick Edit" form
|
||||
*
|
||||
* @param array $columns
|
||||
*
|
||||
* @return array mixed
|
||||
*/
|
||||
function quick_edit_column( $columns ) {
|
||||
return ( is_array( $columns ) ) ? array_merge( $columns, array( 'permalink-manager-col' => __( 'Custom permalink', 'permalink-manager' ) ) ) : $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the URI of the current term in the "Custom permalink" column
|
||||
*
|
||||
* @param string $content The column content.
|
||||
* @param string $column_name The name of the column to display. In this case, we named our column permalink-manager-col.
|
||||
* @param int $term_id The ID of the term.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function quick_edit_column_content( $content, $column_name, $term_id ) {
|
||||
global $permalink_manager_uris, $permalink_manager_options;
|
||||
|
||||
if ( $column_name == "permalink-manager-col" ) {
|
||||
$auto_update_val = get_term_meta( $term_id, "auto_update_uri", true );
|
||||
$disabled = ( ! empty( $auto_update_val ) ) ? $auto_update_val : $permalink_manager_options["general"]["auto_update_uris"];
|
||||
|
||||
$uri = ( ! empty( $permalink_manager_uris["tax-{$term_id}"] ) ) ? self::get_term_uri( $term_id ) : self::get_term_uri( $term_id, true );
|
||||
|
||||
$content = sprintf( '<span class="permalink-manager-col-uri" data-disabled="%s">%s</span>', intval( $disabled ), $uri );
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update URI from "Edit Term" admin page / Set the custom permalink for new term item
|
||||
*
|
||||
* @param int $term_id Term ID.
|
||||
* @param int $tt_term_id Term taxonomy ID.
|
||||
*/
|
||||
function update_term_uri( $term_id, $tt_term_id ) {
|
||||
// Term ID must be defined
|
||||
if ( empty( $term_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$current_filter = current_filter();
|
||||
|
||||
// Validate the nonce (if the permalink editor is displayed)
|
||||
if ( isset( $_POST['custom_uri'] ) && ( ! isset( $_POST['permalink-manager-nonce'] ) || ! wp_verify_nonce( $_POST['permalink-manager-nonce'], 'permalink-manager-edit-uri-box' ) ) ) {
|
||||
return;
|
||||
} // If term was added via "Edit Post" page, use the default URI
|
||||
else if ( ! empty( $current_filter ) && strpos( $current_filter, 'wp_ajax_add' ) !== false && empty( $_POST['custom_uri'] ) ) {
|
||||
$is_new_term = true;
|
||||
} else if ( ! empty( $current_filter ) && strpos( $current_filter, 'create_' ) !== false ) {
|
||||
$is_new_term = true;
|
||||
} else {
|
||||
$is_new_term = false;
|
||||
}
|
||||
|
||||
// Get auto-update URI setting
|
||||
if ( isset( $_POST["auto_update_uri"] ) ) {
|
||||
$auto_update_mode = intval( $_POST["auto_update_uri"] );
|
||||
} else {
|
||||
$auto_update_mode = false;
|
||||
}
|
||||
|
||||
// Check if the URI is provided in the input field
|
||||
if ( isset( $_POST['custom_uri'] ) && empty( $is_new_term ) && empty( $_POST['post_ID'] ) ) {
|
||||
$new_uri = ( ! empty( $_POST['custom_uri'] ) ) ? Permalink_Manager_Helper_Functions::sanitize_title( $_POST['custom_uri'] ) : '';
|
||||
} else if ( ! empty( $is_new_term ) ) {
|
||||
$new_uri = '';
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
self::save_uri( $term_id, $new_uri, $is_new_term, $auto_update_mode );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the custom permalink
|
||||
*
|
||||
* @param int|WP_Term $term
|
||||
* @param string $new_uri
|
||||
* @param bool $is_new_term
|
||||
* @param int|bool $auto_update_mode
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
static function save_uri( $term, $new_uri = '', $is_new_term = false, $auto_update_mode = false, $db_save = true ) {
|
||||
global $permalink_manager_options;
|
||||
|
||||
// Get the term object
|
||||
if ( is_numeric( $term ) ) {
|
||||
$term_object = get_term( $term );
|
||||
} else if ( is_a( $term, 'WP_Term' ) ) {
|
||||
$term_object = $term;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
$term_id = $term_object->term_id;
|
||||
|
||||
// Check if the term is allowed
|
||||
if ( empty( $term_object->taxonomy ) || Permalink_Manager_Helper_Functions::is_term_excluded( $term_object ) || empty( $term_id ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Manage 'Auto-update URI' settings
|
||||
if ( ! empty( $auto_update_mode ) ) {
|
||||
$auto_update_uri = $auto_update_mode;
|
||||
update_term_meta( $term_id, "auto_update_uri", $auto_update_mode );
|
||||
} else if ( $auto_update_mode === 0 ) {
|
||||
$auto_update_uri = $permalink_manager_options['general']['auto_update_uris'];
|
||||
delete_term_meta( $term_id, "auto_update_uri" );
|
||||
} else {
|
||||
$auto_update_uri = get_term_meta( $term_id, "auto_update_uri", true );
|
||||
$auto_update_uri = ( ! empty( $auto_update_uri ) ) ? $auto_update_uri : $permalink_manager_options['general']['auto_update_uris'];
|
||||
}
|
||||
|
||||
// Get default & native & user-submitted URIs
|
||||
$native_uri = self::get_default_term_uri( $term_object, true );
|
||||
$default_uri = self::get_default_term_uri( $term_object );
|
||||
$old_uri = self::get_term_uri( $term_id, false, true );
|
||||
|
||||
if ( ! empty( $new_uri ) && $auto_update_uri != 1 ) {
|
||||
$new_uri = Permalink_Manager_Helper_Functions::sanitize_title( $new_uri, true );
|
||||
} else if ( $is_new_term || $auto_update_uri == 1 || empty( $new_uri ) ) {
|
||||
$new_uri = $default_uri;
|
||||
} else {
|
||||
$new_uri = '';
|
||||
}
|
||||
|
||||
if ( $is_new_term ) {
|
||||
$allow_save = apply_filters( 'permalink_manager_allow_new_term_uri', true, $term_object );
|
||||
} else {
|
||||
$allow_save = apply_filters( 'permalink_manager_allow_update_term_uri', true, $term_object );
|
||||
}
|
||||
|
||||
$new_uri = apply_filters( 'permalink_manager_pre_update_term_uri', $new_uri, $term_id, $old_uri, $native_uri, $default_uri );
|
||||
|
||||
// The update URI process is stopped by the hook above or disabled in "Auto-update" settings
|
||||
if ( ! $allow_save || ( ! empty( $auto_update_uri ) && $auto_update_uri == 2 ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save the URI only if $new_uri variable is set
|
||||
if ( ! empty( $new_uri ) && $new_uri !== $old_uri ) {
|
||||
Permalink_Manager_URI_Functions::save_single_uri( $term_id, $new_uri, true, $db_save );
|
||||
$uri_saved = true;
|
||||
} // The $new_uri variable is empty or no change is detected
|
||||
else {
|
||||
$uri_saved = false;
|
||||
}
|
||||
|
||||
do_action( 'permalink_manager_updated_term_uri', $term_id, $new_uri, $old_uri, $native_uri, $default_uri, $uri_saved );
|
||||
|
||||
return ( $uri_saved ) ? $new_uri : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove URI from options array after term is moved to the trash
|
||||
*
|
||||
* @param int $term_id
|
||||
*/
|
||||
function remove_term_uri( $term_id ) {
|
||||
Permalink_Manager_URI_Functions::remove_single_uri( $term_id, true, true );
|
||||
}
|
||||
|
||||
}
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Functions used to create, edit and remove custom permalinks
|
||||
*/
|
||||
class Permalink_Manager_URI_Functions {
|
||||
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the custom permalink's array key for specific post or term
|
||||
*
|
||||
* @param WP_Post|WP_Term|int|string $element
|
||||
* @param bool $is_tax
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_single_uri_key( $element, $is_tax = false ) {
|
||||
if ( ! empty( $element->term_id ) ) {
|
||||
$is_term = true;
|
||||
$element_id = $element->term_id;
|
||||
} else if ( ! empty( $element->ID ) ) {
|
||||
$is_term = false;
|
||||
$element_id = $element->ID;
|
||||
} else if ( is_string( $element ) || is_numeric( $element ) ) {
|
||||
$is_term = ( strpos( $element, 'tax-' ) !== false ) ? true : $is_tax;
|
||||
$element_id = preg_replace( '/[^0-9]/', '', $element );
|
||||
} else {
|
||||
$element_id = "";
|
||||
$is_term = null;
|
||||
}
|
||||
|
||||
$array_index = ( $is_term && ! empty( $element_id ) ) ? sprintf( 'tax-%s', $element_id ) : $element_id;
|
||||
|
||||
return array( $element_id, $is_term, $array_index );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the single custom permalink
|
||||
*
|
||||
* @param WP_Post|WP_Term|int $element
|
||||
* @param bool $native_uri
|
||||
* @param bool $no_fallback
|
||||
*/
|
||||
public static function get_single_uri( $element, $native_uri = false, $no_fallback = false, $is_tax = false ) {
|
||||
// Get the element key
|
||||
list( $element_id, $is_term, $array_index ) = self::get_single_uri_key( $element, $is_tax );
|
||||
|
||||
if ( $is_term ) {
|
||||
$final_uri = ( class_exists( 'Permalink_Manager_URI_Functions_Tax' ) ) ? Permalink_Manager_URI_Functions_Tax::get_term_uri( $element_id, $native_uri, $no_fallback ) : '';
|
||||
} else {
|
||||
$final_uri = Permalink_Manager_URI_Functions_Post::get_post_uri( $element_id, $native_uri, $no_fallback );
|
||||
}
|
||||
|
||||
return $final_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save single custom permalink to the custom permalinks array
|
||||
*
|
||||
* @param int|string $element
|
||||
* @param string $element_uri
|
||||
* @param bool $is_tax
|
||||
* @param bool $db_save
|
||||
*/
|
||||
public static function save_single_uri( $element, $element_uri = null, $is_tax = false, $db_save = false ) {
|
||||
global $permalink_manager_uris;
|
||||
|
||||
// Get the element key
|
||||
list( $element_id, $is_term, $array_index ) = self::get_single_uri_key( $element, $is_tax );
|
||||
|
||||
// Save the custom permalink if the URI is not empty
|
||||
if ( ! empty( $array_index ) && ! empty( $element_uri ) ) {
|
||||
$permalink_manager_uris[ $array_index ] = Permalink_Manager_Helper_Functions::sanitize_title( $element_uri, true );
|
||||
|
||||
if ( $db_save ) {
|
||||
self::save_all_uris( $permalink_manager_uris );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove single custom permalink from the custom permalinks array
|
||||
*
|
||||
* @param int|string $element
|
||||
* @param bool $is_tax
|
||||
* @param bool $db_save
|
||||
*/
|
||||
public static function remove_single_uri( $element, $is_tax = false, $db_save = false ) {
|
||||
global $permalink_manager_uris;
|
||||
|
||||
// Get the element key
|
||||
list( $element_id, $is_term, $array_index ) = self::get_single_uri_key( $element, $is_tax );
|
||||
|
||||
// Check if the custom permalink is assigned to this element
|
||||
if ( ! empty( $array_index ) && isset( $permalink_manager_uris[ $array_index ] ) ) {
|
||||
unset( $permalink_manager_uris[ $array_index ] );
|
||||
}
|
||||
|
||||
if ( $db_save ) {
|
||||
self::save_all_uris( $permalink_manager_uris );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the ID(s) of the element(s) by its custom permalink
|
||||
*
|
||||
* @param string $search_query
|
||||
* @param bool $strict_search
|
||||
* @param string $content_type
|
||||
*
|
||||
* @return bool|string|array
|
||||
*/
|
||||
public static function find_uri( $search_query, $strict_search = true, $content_type = null ) {
|
||||
$custom_permalinks = self::get_all_uris();
|
||||
$found = false;
|
||||
|
||||
if ( $strict_search ) {
|
||||
$all_uris = array_flip( $custom_permalinks );
|
||||
|
||||
$found = ( ! empty( $all_uris[ $search_query ] ) ) ? $all_uris[ $search_query ] : false;
|
||||
} else {
|
||||
$found = array();
|
||||
$search_query = preg_quote( $search_query, '/' );
|
||||
|
||||
foreach ( $custom_permalinks as $id => $uri ) {
|
||||
if ( preg_match( "/\b$search_query\b/i", $uri ) ) {
|
||||
if ( $content_type == 'taxonomies' && ( strpos( $id, 'tax-' ) !== false ) ) {
|
||||
$found[] = (int) abs( filter_var( $id, FILTER_SANITIZE_NUMBER_INT ) );
|
||||
} else if ( $content_type == 'posts' && is_numeric( $id ) ) {
|
||||
$found[] = (int) filter_var( $id, FILTER_SANITIZE_NUMBER_INT );
|
||||
} else if ( empty( $content_type ) ) {
|
||||
$found[] = $id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a single URI is duplicated
|
||||
*
|
||||
* @param string $uri
|
||||
* @param int $element_id
|
||||
* @param array $duplicated_ids
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_uri_duplicated( $uri, $element_id, $duplicated_ids = array() ) {
|
||||
$custom_permalinks = Permalink_Manager_URI_Functions::get_all_uris();
|
||||
|
||||
if ( empty( $uri ) || empty( $element_id ) || empty( $custom_permalinks ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$uri = trim( trim( sanitize_text_field( $uri ) ), "/" );
|
||||
$element_id = sanitize_text_field( $element_id );
|
||||
|
||||
// Keep the URIs in a separate array just here
|
||||
if ( ! empty( $duplicated_ids ) ) {
|
||||
$all_duplicates = $duplicated_ids;
|
||||
} else if ( in_array( $uri, $custom_permalinks ) ) {
|
||||
$all_duplicates = array_keys( $custom_permalinks, $uri );
|
||||
}
|
||||
|
||||
if ( ! empty( $all_duplicates ) ) {
|
||||
// Get the language code of current element
|
||||
$this_uri_lang = apply_filters( 'permalink_manager_get_language_code', '', $element_id );
|
||||
|
||||
foreach ( $all_duplicates as $key => $duplicated_id ) {
|
||||
// Ignore custom redirects
|
||||
if ( strpos( $key, 'redirect-' ) !== false ) {
|
||||
unset( $all_duplicates[ $key ] );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $this_uri_lang ) {
|
||||
$duplicated_uri_lang = apply_filters( 'permalink_manager_get_language_code', '', $duplicated_id );
|
||||
}
|
||||
|
||||
// Ignore the URI for requested element and other elements in other languages to prevent the false alert
|
||||
if ( ( ! empty( $duplicated_uri_lang ) && $duplicated_uri_lang !== $this_uri_lang ) || $element_id == $duplicated_id ) {
|
||||
unset( $all_duplicates[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
return ( count( $all_duplicates ) > 0 ) ? true : false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array (or statistics) with custom permalinks
|
||||
*
|
||||
* @param bool $stats
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_all_uris( $stats = false ) {
|
||||
global $permalink_manager_uris;
|
||||
|
||||
if ( $stats ) {
|
||||
$custom_permalinks_size = strlen( serialize( $permalink_manager_uris ) );
|
||||
$custom_permalinks_count = count( $permalink_manager_uris );
|
||||
|
||||
return array( $custom_permalinks_size, $custom_permalinks_count );
|
||||
} else {
|
||||
return array_filter( $permalink_manager_uris );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the array with custom permalinks
|
||||
*
|
||||
* @param array $updated_uris
|
||||
*/
|
||||
public static function save_all_uris( $updated_uris = null ) {
|
||||
if ( is_null( $updated_uris ) ) {
|
||||
global $permalink_manager_uris;
|
||||
$updated_uris = $permalink_manager_uris;
|
||||
}
|
||||
|
||||
if ( is_array( $updated_uris ) && ! empty( $updated_uris ) ) {
|
||||
update_option( 'permalink-manager-uris', $updated_uris, false );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user