skip to Main Content

I need to output a certain product page on the homepage. add_rewrite_rule doesn’t work for homepage for any reason (
there are actually no rewrite rules for the homepage in the database, WordPress seems to use some other functions to
query the homepage):

//works fine
add_rewrite_rule( 'certainproductpage/?$',
    'index.php?post_type=product&name=certainproduct',
    'top'
);
//does not work 
add_rewrite_rule( '', //tried everything like "/", "/?$" etc
    'index.php?post_type=product&name=certainproduct',
    'top'
);

After spending way too much time looking through wp / wc core code and stackoverflow I came across an alternative. I can
simply add a shortcode in the content of the page I need to be the homepage and a product page at the same
time: [product_page id=815]. Indeed it works great, but only if the shortcode is added in the admin editor or is
stored in the database (post_content). If I try to call the shortcode manually on the page template (
page-certainproductpage.php) then it outputs the product page without some necessary stuff (PayPal, PhotoSwipe and
Gallery js). Weirdly enough, if I keep the shortcode in the content (via Gutenberg / Code Editor) but don’t
call the_content and only echo the shortcode then everything works fine:

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

get_header( 'shop' );

//works fine only if the same shortcode is within the certainproductpage's content
echo do_shortcode("[product_page id='815']");
//the_content();

get_footer( 'shop' );

Also when I try to add the shortcode via the_content filter hook before the do_shortcode function is applied in core’s
default-filters.php ($priority < 11), then I get only the error:

NOTICE: PHP message: PHP Fatal error:  Maximum execution time of 30 seconds exceeded in /var/www/html/wp-includes/functions.php on line 5106

Unfortunately there is no stack trace logged. And the function around line 5107 is wp_ob_end_flush_all which is called on shutdown from default-filters.php

echo do_shortcode(apply_filters('the_content', "[product_page id=815]")); did not help either (same incomplete output as
with echo do_shortcode("[product_page id=815]");)

Also totally weird:
When I compare the string of the content from the editor and the string of the shortcode added programmatically it is
equal!:

add_filter( "the_content", function ( $content ){
            $wtf = "<!-- wp:paragraph -->
<p>[product_page id=815]</p>
<!-- /wp:paragraph -->";
            $result = $wtf === $content;
            ?><pre><?php var_dump($result)?></pre><?php
            return $content;
}, 1 );

But if I replace return $content with return $wtf – I get the maximimum exucution time exceeded error.

So how can I properly output a product page on the homepage ("/") or how can I get the same result with the shortcode
when applied within the the_content filter as when just adding the shortcode in the (Gutenberg) editor?

Update

Tested it with a simple custom shortcode outputting only a heading tag and it works fine with the_content filter. Also tried it on an absolutely clean site with only WooCommerce and PayPal installed – with the same results. Seems to be a bug on the WooCommerce side. Gonna run it through xDebug some day this week.

2

Answers


  1. Chosen as BEST ANSWER

    Ok, found a bit of a hacky solution. I just check on every page load whether the homepage is currently queried or not. Then I get the page content and check if it already contains the shortcode. If not then the page content gets updated in the database with the shortcode appended.

    //it has to be a hook which loads everything needed for the wp_update_post function 
    //but at the same time has not global $post set yet
    //if global $post is already set, the "certainproductpage"  will load content not modified by the following code
    add_action( "wp_loaded", function () {
        //check if homepage
        //there seems to be no other simple method to check which page is currently queried at this point
        if ( $_SERVER["REQUEST_URI"] === "/" ) {
            $page    = get_post(get_option('page_on_front'));
            $product = get_page_by_path( "certainproduct", OBJECT, "product" );
    
            if ( $page && $product ) {
                $page_content       = $page->post_content;
                $product_id         = $product->ID;
                $shortcode          = "[product_page id=$product_id]";
                        
                //add shortcode to the database's post_content if not already done
                $contains_shortcode = strpos( $page_content, $shortcode ) > - 1;
                if ( ! $contains_shortcode ) {
                    $shortcode_block = <<<EOT
    <!-- wp:shortcode -->
    {$shortcode}
    <!-- /wp:shortcode -->
    EOT;
                    $new_content     = $page_content . $shortcode_block;
    
                    wp_update_post( array(
                        'ID'           => $page->ID,
                        'post_content' => $new_content,
                        'post_status'  => "publish"
                    ) );
                }
            }
        }
    } );
    
    

  2. I’d recommend one step at a time. First of all, does this work?

    add_filter( "the_content", function ( $content ) {
       $content .= do_shortcode( '[product_page id=815]' );
       return $content;
    }, 1 );
    

    This should append a product page to every WordPress page/post.

    If it works, then you need to limit it to the homepage only, by using is_front_page() conditional in case it’s a static page:

    add_filter( "the_content", function ( $content ) {
       if ( is_front_page() ) {
          $content .= do_shortcode( '[product_page id=815]' );
       }
       return $content;
    }, 1 );
    

    If this works too, then we’ll see how to return a Gutenberg paragraph block, but not sure why you’d need that, so maybe give us more context

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search