Advertisement
Guest User

Untitled

a guest
Jul 20th, 2019
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <?php
  2. /*
  3. * Plugin Name:       Post Permalinks Rewrite
  4. * Plugin URI:        http://maciejbis.net/
  5. * Description:       Plugin that allows to keep custom permalinks format in Wordpress
  6. * Version:           1.0.0
  7. * Author:            Maciej Bis
  8. * Author URI:        http://maciejbis.net/
  9. * License:           GPL-2.0+
  10. * License URI:       http://www.gnu.org/licenses/gpl-2.0.txt
  11. * Domain Path:       /languages
  12. */
  13.  
  14. /**
  15.  * Get a list of filtered post types
  16.  */
  17. function bis_get_post_types($post_type = null) {
  18.     $post_types = array(
  19.         'post' => '%category%/%postname%',
  20.     );
  21.  
  22.     return ($post_type && !empty($post_types[$post_type])) ? $post_types[$post_type] : $post_types;
  23. }
  24.  
  25. /**
  26. * Filter product & taxonomies permalinks
  27. */
  28. function bis_filter_custom_permalinks($url, $element) {
  29.     // Posts permalinks added after this date will be changed
  30.     if(strtotime($element->post_date) <= strtotime('2019-07-09')) {
  31.         return $url;
  32.     }
  33.  
  34.     $post_types = bis_get_post_types();
  35.     $home_base = trim(get_option('home'), '/');
  36.  
  37.     if(!empty($element->post_type) && (!empty($post_types[$element->post_type]))) {
  38.         $uris = bis_get_uris($element->post_type);
  39.         $uri = (!empty($uris[$element->ID])) ? $uris[$element->ID] : false;
  40.  
  41.         // Try to add the URI if it was not found
  42.         if(empty($uri)) {
  43.             $uri = bis_flush_single_uri($element);
  44.         }
  45.  
  46.         $url = ($uri) ? "{$home_base}/{$uri}" : $url;
  47.     }
  48.  
  49.     return user_trailingslashit($url);
  50. }
  51. add_filter('post_link', 'bis_filter_custom_permalinks', 999, 2);
  52.  
  53. function bis_unlimited_permalinks($request) {
  54.     global $wpdb, $wp;
  55.  
  56.     if(!empty($request['pagename']) || !empty($request['name']) || !empty($request['error'])) {
  57.         if(!empty($request['pagename'])) {
  58.             $name = $request['pagename'];
  59.         } else if(!empty($request['name'])) {
  60.             $name = $request['name'];
  61.         } else {
  62.             $name = $wp->request;
  63.         }
  64.  
  65.         $post_name = basename($name);
  66.  
  67.         $element = $wpdb->get_row($wpdb->prepare("
  68.             SELECT * FROM {$wpdb->posts}
  69.             WHERE post_name = %s
  70.             AND post_status = 'publish'
  71.             ",
  72.             $post_name
  73.         ));
  74.  
  75.         if($element->post_name && $element->post_type == 'post') {
  76.             unset($request['pagename']);
  77.             unset($request['error']);
  78.             $request['name'] = $post_name;
  79.             $request['do_not_redirect'] = true;
  80.  
  81.             // Disable canonical redirect
  82.             remove_action('template_redirect', 'redirect_canonical');
  83.             add_filter('wpml_is_redirected', '__return_false', 99, 2);
  84.         }
  85.     }
  86.  
  87.     return $request;
  88. }
  89. add_filter('request', 'bis_unlimited_permalinks', 999);
  90.  
  91. /**
  92.  * Get post term
  93.  */
  94. function bis_get_post_term_slug($post_id, $taxonomy) {
  95.     $slug = '';
  96.  
  97.     // Try to use Yoast's SEO primary term
  98.     if(class_exists('WPSEO_Primary_Term')) {
  99.         $primary_term = new WPSEO_Primary_Term($taxonomy, $post_id);
  100.         $primary_term = get_term($primary_term->get_primary_term());
  101.     }
  102.  
  103.     if(empty($primary_term->term_id)) {
  104.         $terms = wp_get_object_terms($post_id, $taxonomy);
  105.  
  106.         $primary_term = (!is_wp_error($terms) && !empty($terms) && is_object($terms[0])) ? bis_get_lowest_term($terms[0], $terms) : "";
  107.     }
  108.  
  109.     // No term was found
  110.     if(empty($primary_term->term_id)) {
  111.         return;
  112.     }
  113.  
  114.     // Get slug
  115.     $full_slug = $primary_term->slug;
  116.  
  117.     // Support hierarchical taxonomies
  118.     if(!empty($primary_term->parent)) {
  119.         $term = $primary_term;
  120.         while(!is_wp_error($term) && !empty($term->parent)) {
  121.             $term = get_term($term->parent, $taxonomy);
  122.             $full_slug = "{$term->slug}/{$full_slug}";
  123.         }
  124.     }
  125.  
  126.     return $full_slug;
  127. }
  128.  
  129. /**
  130.  * Get lowest level term/post
  131.  */
  132. function bis_get_lowest_term($first_element, $elements) {
  133.     if(!empty($elements) && !empty($first_element)) {
  134.         // Get the ID of first element
  135.         if(!empty($first_element->term_id)) {
  136.             $first_element_id = $first_element->term_id;
  137.             $parent_key = 'parent';
  138.         } else {
  139.             return false;
  140.         }
  141.  
  142.         $children = wp_filter_object_list($elements, array($parent_key => $first_element_id));
  143.         if(!empty($children)) {
  144.             // Get the first term
  145.             $child_term = reset($children);
  146.             $first_element = bis_get_lowest_term($child_term, $elements);
  147.         }
  148.     }
  149.  
  150.     return $first_element;
  151. }
  152.  
  153. /**
  154.  * Cache slugs to avoid extra SQL queries
  155.  */
  156. function bis_get_uris($post_type = null, $fix_uris = false) {
  157.     global $wpdb;
  158.  
  159.     // 1. Try to use transient
  160.     $transient_name = "bis_slugs_posts_{$post_type}";
  161.     $slugs = (array) get_transient($transient_name);
  162.  
  163.     if(empty($slugs) || $fix_uris) {
  164.         $results = $wpdb->get_col("SELECT ID FROM {$wpdb->posts} WHERE post_type = '{$post_type}' AND post_status = 'publish'");
  165.  
  166.         // Omit defined URIs
  167.         if($fix_uris) {
  168.             $ignore_ids = array_keys($slugs);
  169.             $results = array_diff($results, $ignore_ids);
  170.         }
  171.  
  172.         // Schedule URI regenerate and split into chunks (if there are more than 1000 posts)
  173.         if(count($results) > 1000) {
  174.             $chunks = array_chunk($results, 250);
  175.  
  176.             foreach($chunks as $i => $chunk) {
  177.                 if($i == 0) {
  178.                     bis_flush_uris($chunk, $post_type);
  179.                 } else {
  180.                     wp_schedule_single_event(time() + ($i * 60), 'bis_flush_uris_hook', array($chunk, $post_type));
  181.                 }
  182.             }
  183.         } else {
  184.             bis_flush_uris($results, $post_type);
  185.         }
  186.     }
  187.  
  188.     return $slugs;
  189. }
  190.  
  191. /**
  192.  * Prepare URIs
  193.  */
  194. function bis_flush_uris($posts, $post_type) {
  195.     $transient_name = "bis_slugs_posts_{$post_type}";
  196.     $slugs = get_transient($transient_name);
  197.     $slugs = (is_array($slugs)) ? $slugs : array();
  198.  
  199.     // Parse the results - ID -> URI
  200.     foreach($posts as $post_id) {
  201.         $slugs[$post_id] = bis_get_post_custom_uri($post_id, $post_type);
  202.     }
  203.  
  204.     set_transient($transient_name, array_filter($slugs));
  205. }
  206. add_action('bis_flush_uris_hook', 'bis_flush_uris', 9, 2);
  207.  
  208. /**
  209.  * Flush slugs when product, category or tag is added/edited or removed
  210.  */
  211. function bis_flush_single_uri_init() {
  212.     add_action('wp_insert_post', 'bis_flush_single_uri', 9);
  213.     add_action('wp_trash_post', 'bis_flush_single_uri', 9);
  214.     add_action('save_post', 'bis_flush_single_uri', 9);
  215.  
  216.     // Support REST API
  217.     $post_types = bis_get_post_types();
  218.     foreach($post_types as $post_type => $structure) {
  219.         add_action("rest_after_insert_{$post_type}", 'bis_flush_single_uri', 9);
  220.     }
  221. }
  222. add_action('init', 'bis_flush_single_uri_init');
  223.  
  224. function bis_flush_single_uri($post) {
  225.     $post = (!empty($post->ID)) ? $post : get_post($post);
  226.     $uri = null;
  227.  
  228.     if(!empty($post->post_type)) {
  229.         $transient_name = "bis_slugs_posts_{$post->post_type}";
  230.         $slugs = (array) get_transient($transient_name);
  231.  
  232.         // Set new URI for new post
  233.         $slugs[$post->ID] = $uri = bis_get_post_custom_uri($post->ID, $post->post_type);
  234.  
  235.         set_transient($transient_name, $slugs);
  236.  
  237.         return $uri;
  238.     }
  239. }
  240.  
  241. /**
  242.  * Get single post custom URI
  243.  */
  244. function bis_get_post_custom_uri($post_id, $post_type) {
  245.     // Get full slug
  246.     $slug = get_page_uri($post_id);
  247.  
  248.     // Get permalink format
  249.     $uri_format = bis_get_post_types($post_type);
  250.  
  251.     // Stop if the format is not a string
  252.     if(is_array($uri_format)) { return; }
  253.  
  254.     // Add post slug
  255.     $uri = str_replace('%postname%', $slug, $uri_format);
  256.  
  257.     // Add taxonomy tags
  258.     preg_match_all("/%(.[^\%]+)%/", $uri, $taxonomy_tags);
  259.     if(!empty($taxonomy_tags[1])) {
  260.         foreach($taxonomy_tags[1] as $taxonomy) {
  261.             $term_slug = bis_get_post_term_slug($post_id, $taxonomy);
  262.  
  263.             $uri = ($term_slug) ? str_replace("%{$taxonomy}%", $term_slug, $uri) : $uri;
  264.         }
  265.     }
  266.  
  267.     return $uri;
  268. }
  269.  
  270. /**
  271.  * Debug transients
  272.  */
  273. function bis_debug_slugs() {
  274.     // if(!is_user_logged_in()) { return; }
  275.  
  276.     if(isset($_GET['debug_uris'])) {
  277.         $uris = (array) bis_get_uris($_GET['debug_uris']);
  278.         print_r($uris);
  279.         die();
  280.     }
  281.  
  282.     if(isset($_GET['fix_uris'])) {
  283.         $uris = (array) bis_get_uris($_GET['fix_uris'], true);
  284.         print_r($uris);
  285.         die();
  286.     }
  287.  
  288.     if(!empty($_GET['flush_uris'])) {
  289.         $post_type = sanitize_text_field($_GET['flush_uris']);
  290.         delete_transient("bis_slugs_posts_{$post_type}");
  291.  
  292.         $uris = (array) bis_get_uris($_GET['debug_uris']);
  293.         print_r($uris);
  294.         die();
  295.     }
  296. }
  297. add_action('init', 'bis_debug_slugs', 999);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement