0

I need to use a dynamic permalink structure for WooCommerce products, basically, the structure I'm trying to achieve is the following: /<dynamic>/post_name.

So what I did is create a rewrite tag:

add_action('init', function () {
  add_rewrite_tag('%custom_string_only_for_products%', '(.+)', 'custom_part_of_product=');
});

add_filter('available_permalink_structure_tags', function (array $tags): array {
  $tags['custom_string_only_for_products'] = 'some custom_string_only_for_products thing';
  return $tags;
});

I've assigned the tag above only for the products permalink:

enter image description here

In order to change the permalink structure I used the post_type_link hook, essentially, the dynamic part must change depending on the category assigned to the product, eg:

add_filter('post_type_link', function (string $permalink, WP_Post $post): string {

  if (false === strpos($permalink, '%custom_string_only_for_products%')) {
    return $permalink;
  }

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

  $post_id = $post->ID;
  $custom_part = '';

  // watches
  $is_watch = (has_term('watches', 'product_cat', $post_id));
  if ($is_watch) {
    $brand = get_the_terms($post_id, 'product_brand');
    return custom_permalink_rewrite("watches/", $permalink, $brand);
  }

  return $permalink;
}, 1, 2);

function custom_permalink_rewrite($custom_part, $permalink, $brand = null)
{
  if (isset($brand[0])) {
    $brand = isset($brand[0]) ? sanitize_title($brand[0]->name) : '';
    $custom_part .= $brand;
  }
  return str_replace('%custom_string_only_for_products%', $custom_part, $permalink);
}

The function above check if the current $post is a product, if so, check if the product have a specific category and then rewrite the dynamic part of the permalink using a custom taxonomy product_brand.

So in the case above, if the product have the category watches, and the brand rolex is assigned, the final result will be:

https://example.com/watches/rolex/product_name

Until here all is working great but for some reason now, I can't load the pages. Seems that I'm obliged to add a static word on the permalink product otherwise Wordpress will load any page as front page, which is kinda weird, eg:

enter image description here

The main problem here is that my customer doesn't want the /product prefix, so I came up with another solution, within the post_type_link hook I wrote:

$permalink = str_replace('product/, '', $permalink);

and then I added this code within the init hook:

add_action('init', function () {
  $rewrite_obj = new WP_Rewrite();
  $rewrites    = $rewrite_obj->wp_rewrite_rules();
  $current_state = md5(json_encode($rewrites));
  $stored_state  = get_option('wpse_421338_rewrite_state', '');

  if ($current_state !== $stored_state) {
    $products = wc_get_products([
      'limit' => -1
    ]);

    foreach ($products as $prod) {
      $id = $prod->get_id();
      $permalink = $prod->get_permalink();
      $url_scheme = parse_url($permalink);
      $new_url = ltrim($url_scheme['path'], '/');

      add_rewrite_rule(
        "^$new_url?$",
        'index.php?post_type=product&p=' . $id . '&prod_brand=&matches[1]&sku=$matches[2]',
        'top'
      );
    }

    flush_rewrite_rules();
    update_option('wpse_421338_rewrite_state', $current_state);
  }
});

the code above create the rewrite rules necessary to assign the new url to the actual product, so Wordpress knows which product load for that specific url. Since the flush_rewrite_rules is an expensive computational operation, I tried to flush the permalinks only when the state changes, using a custom option.

The problem's that the site performance now are dropped ..

Is there anyone who somehow managed to get a dynamic permalink as an initial part for woocommerce products only?

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.