PluginProbe
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More / 2.2.0
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More v2.2.0
2.3.0 2.2.0 2.1.1 2.1.0 2.0.0 1.10.0 1.9.1 1.9.0 1.2.1 1.2.2 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 All 59 releases
storeengine / includes / frontend / template.php

template.php in StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More 2.2.0, at includes/frontend/template.php

166 lines 5.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace StoreEngine\Frontend;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit;
7 }
8
9 use StoreEngine\Classes\TemplateLoader;
10 use StoreEngine\frontend\template\Block;
11 use StoreEngine\Utils\Helper;
12 use WP_Query;
13
14 class Template extends TemplateLoader {
15 public static function init() {
16 $self = new self();
17 $self->dispatch_hook();
18 if ( Helper::is_fse_theme() ) {
19 Block::init();
20 } else {
21 add_filter( 'template_include', array( $self, 'template_loader' ) );
22 }
23 }
24
25 public function dispatch_hook() {
26 add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ) );
27 add_filter( 'astra_blog_post_per_page_exclusions', [ $this, 'astra_product_per_page_exclusions' ] );
28 add_filter( 'comments_template', [ $this, 'load_comments_template' ] );
29 add_filter( 'pre_render_block', [ $this, 'prevent_shortcode_block_autop' ], 10, 2 );
30
31 // Redirect to log-in wp-screen.
32 //add_action( 'template_redirect', array( $this, 'frontend_dashboard_template_redirect' ) );
33 }
34
35 /**
36 * Stop the core/shortcode block from running wpautop() on StoreEngine markup.
37 *
38 * In FSE block templates WordPress runs do_shortcode() BEFORE do_blocks()
39 * (see get_the_block_template_html()), so by the time the core/shortcode
40 * block renders, its inner content is already the fully-expanded StoreEngine
41 * HTML. The block's render callback then calls wpautop() on it, which wraps
42 * our inline elements (e.g. the price <label> list) in stray <p> tags and
43 * injects <br> — breaking the single-product layout.
44 *
45 * We short-circuit the block render for our own output only: detection keys
46 * on the `storeengine-` class prefix, which exists only AFTER expansion. In
47 * the classic the_content path do_blocks() runs first, so the inner content
48 * is still the raw `[storeengine_*]` tag (an underscore, never `storeengine-`)
49 * and this never matches — leaving that path's existing behaviour intact.
50 *
51 * @param string|null $pre_render Pre-rendered content. Default null.
52 * @param array $parsed_block The parsed block.
53 *
54 * @return string|null
55 */
56 public function prevent_shortcode_block_autop( $pre_render, $parsed_block ) {
57 if ( null !== $pre_render || 'core/shortcode' !== ( $parsed_block['blockName'] ?? '' ) ) {
58 return $pre_render;
59 }
60
61 $inner = $parsed_block['innerHTML'] ?? '';
62 if ( false === strpos( $inner, 'storeengine-' ) ) {
63 return $pre_render;
64 }
65
66 // Already-expanded markup; do_shortcode() is a no-op safeguard. No wpautop.
67 return do_shortcode( $inner );
68 }
69
70 public function load_comments_template( $template ) {
71 if ( get_post_type() !== 'storeengine_product' ) {
72 return $template;
73 }
74
75 $check_dirs = array(
76 trailingslashit( get_stylesheet_directory() ) . Helper::template_path(),
77 trailingslashit( get_template_directory() ) . Helper::template_path(),
78 trailingslashit( get_stylesheet_directory() ),
79 trailingslashit( get_template_directory() ),
80 trailingslashit( Helper::plugin_path() ) . 'templates/',
81 );
82
83 if ( STOREENGINE_TEMPLATE_DEBUG_MODE ) {
84 $check_dirs = array( array_pop( $check_dirs ) );
85 }
86
87 foreach ( $check_dirs as $dir ) {
88 if ( file_exists( trailingslashit( $dir ) . 'single-product-comments.php' ) ) {
89 return trailingslashit( $dir ) . 'single-product-comments.php';
90 }
91 }
92
93 return $template;
94 }
95
96 /**
97 * Hook into pre_get_posts to do the main product query.
98 *
99 * @param WP_Query $q Query instance.
100 */
101 public function pre_get_posts( WP_Query $q ) {
102 if ( ! $q->is_main_query() || $q->is_feed() || is_admin() ) {
103 return;
104 }
105
106 if ( is_post_type_archive( Helper::PRODUCT_POST_TYPE ) ) {
107 // Astra requires `post_type` to be string for `astra_blog_post_per_page_exclusions` in_array check, we're setting array value.
108 // Removing this action safely removes the per_page settings for archive template set by astra.
109 remove_action( 'parse_tax_query', 'astra_blog_post_per_page' );
110
111 if ( isset( $_GET['orderby'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
112 $orderby = sanitize_text_field( wp_unslash( $_GET['orderby'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
113 } else {
114 $orderby = Helper::get_settings( 'product_archive_products_order', '' );
115 }
116
117 $paged = ( get_query_var( 'paged' ) ) ? absint( get_query_var( 'paged' ) ) : 1;
118 $q->set( 'post_type', apply_filters( 'storeengine/frontend/product_archive_post_types', array( Helper::PRODUCT_POST_TYPE ) ) );
119 $q->set( 'posts_per_page', (int) Helper::get_settings( 'product_archive_products_per_page', 12 ) );
120 $q->set( 'paged', $paged );
121 $q->set( 'orderby', $orderby );
122 $q->set( 'order', 'title' === $orderby ? 'ASC' : 'DESC' );
123 $q->set( 'meta_query', [
124 'relation' => 'OR',
125 [
126 'key' => '_storeengine_product_hide',
127 'value' => true,
128 'compare' => 'NOT EXISTS',
129 ],
130 [
131 'key' => '_storeengine_product_hide',
132 'value' => true,
133 'compare' => '!=',
134 ],
135 ] );
136 } elseif ( $q->is_tax() ) {
137 $q->set( 'meta_query', [
138 'relation' => 'OR',
139 [
140 'key' => '_storeengine_product_hide',
141 'value' => true,
142 'compare' => 'NOT EXISTS',
143 ],
144 [
145 'key' => '_storeengine_product_hide',
146 'value' => true,
147 'compare' => '!=',
148 ],
149 ] );
150 }
151 }
152
153 public function astra_product_per_page_exclusions( array $post_types ) {
154 $post_types[] = Helper::PRODUCT_POST_TYPE;
155
156 return $post_types;
157 }
158
159 public function frontend_dashboard_template_redirect() {
160 if ( ! is_user_logged_in() && (int) Helper::get_settings( 'dashboard_page' ) === get_the_ID() ) {
161 wp_safe_redirect( storeengine_login_url( Helper::get_dashboard_url() ) );
162 exit();
163 }
164 }
165 }
166