I did something very similar not long ago, and I did it by cheating.
If you find the built in rewrite rules too complicated or unable to do the job, you may find it easier to catch the request and filter the results. A simplified version:
add_action('parse_request', 'my_parse_request');
function my_parse_request (&$wp) {
$path = $wp->request;
$groups = array();
if (preg_match("%shop/product/([a-zA-Z0-9-]+)%", $path, $groups)) {
$code = $groups[1];
$product = get_product($code); // your own code here
if (isset($product)) {
add_filter('the_posts', 'my_product_filter_posts');
}
}
}
function my_product_filter_posts ($posts) {
ob_start();
echo "stuff goes here"; // your body here
$content = ob_get_contents();
ob_end_clean();
return array(new DummyResult(0, "Product name", $content));
}
To explain:
The action on parse_request
is called before the database lookup. Based on the URL, it installs the other actions and filters.
The filter on posts replaces the results of the database lookup with fake results.
DummyResult is a simple class that has the same fields as a post, or just enough of them to get away with it:
class DummyResult {
public $ID;
public $post_title;
public $post_content;
public $post_author;
public $comment_status = "closed";
public $post_status = "publish";
public $ping_status = "closed";
public $post_type = "page";
public $post_date = "";
function __construct ($ID, $title, $content) {
$this->ID = $ID;
$this->post_title = $title;
$this->post_content = $content;
$this->post_author = get_default_author(); // implement this function
}
}
There's a lot of homework left for the reader in the above, but it's an ugly, working approach. You'll probably want to add a filter for template_redirect
, to replace the normal page template with a product-specific one. And you may need to adjust the URL regex if you want pretty permalinks.