PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.1.7
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.1.7
4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 4.2.1 All 138 releases
learnpress / inc / block-template / class-block-controller.php

class-block-controller.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.1.7, at inc/block-template/class-block-controller.php

452 lines 16.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class LP_Block_Template_Controller {
4
5 protected static $instance = null;
6
7 /**
8 * Directory name of the block template directory.
9 *
10 * @var string
11 */
12 const TEMPLATES_DIR_NAME = 'block-templates';
13
14 /**
15 * Directory name of the block template parts directory.
16 *
17 * @var string
18 */
19 const TEMPLATE_PARTS_DIR_NAME = 'block-template-parts';
20
21 public function __construct() {
22 add_action( 'template_redirect', array( $this, 'render_block_template' ) );
23 // Detected file block template html.
24 add_filter( 'get_block_templates', array( $this, 'add_block_templates' ), 10, 3 );
25 add_action( 'enqueue_block_editor_assets', array( $this, 'block_editor' ) );
26 add_action( 'init', array( $this, 'register_block_template_post_type' ) );
27 add_filter( 'pre_get_block_file_template', array( $this, 'maybe_return_blocks_template' ), 10, 3 );
28 add_filter( 'page_template_hierarchy', array( $this, 'page_template_hierarchy' ), 10, 3 );
29 }
30
31 /**
32 * Fixed error on the function 'resolve_block_template' when call usort()
33 *
34 * apply_filters( "{$type}_template_hierarchy", $templates )
35 *
36 * @param array $templates
37 *
38 * @return array|string[]
39 */
40 public function page_template_hierarchy( array $templates = array() ): array {
41 if ( LP_PAGE_CHECKOUT === LP_Page_Controller::page_current() ) {
42 $templates = array( 'page-lp_checkout' );
43 }
44
45 return $templates;
46 }
47
48 public function block_editor() {
49 $wp_js = array(
50 'wp-block-editor',
51 'wp-blocks',
52 'wp-components',
53 'wp-element',
54 'wp-i18n',
55 'wp-primitives',
56 'lodash',
57 );
58
59 wp_enqueue_script( 'learnpress-gutenberg-editor', LP_PLUGIN_URL . 'assets/js/dist/blocks/index.js', $wp_js, LEARNPRESS_VERSION, true );
60 }
61
62 public function register_block_template_post_type() {
63 register_block_type(
64 'learnpress/template',
65 array(
66 'render_callback' => array( $this, 'render_content_block_template' ),
67 )
68 );
69 }
70
71 public function maybe_return_blocks_template( $template, $id, $template_type ) {
72 // 'get_block_template' was introduced in WP 5.9. We need to support
73 // 'gutenberg_get_block_template' for previous versions of WP with
74 // Gutenberg enabled.
75 if ( ! function_exists( 'gutenberg_get_block_template' ) && ! function_exists( 'get_block_template' ) ) {
76 return $template;
77 }
78 $template_name_parts = explode( '//', $id );
79 if ( count( $template_name_parts ) < 2 ) {
80 return $template;
81 }
82 list( , $slug ) = $template_name_parts;
83
84 // Remove the filter at this point because if we don't then this function will infinite loop.
85 remove_filter( 'pre_get_block_file_template', array( $this, 'maybe_return_blocks_template' ), 10, 3 );
86
87 // Check if the theme has a saved version of this template before falling back to the woo one. Please note how
88 // the slug has not been modified at this point, we're still using the default one passed to this hook.
89 $maybe_template = function_exists( 'gutenberg_get_block_template' ) ?
90 gutenberg_get_block_template( $id, $template_type ) :
91 get_block_template( $id, $template_type );
92
93 if ( null !== $maybe_template ) {
94 add_filter( 'pre_get_block_file_template', array( $this, 'maybe_return_blocks_template' ), 10, 3 );
95 return $maybe_template;
96 }
97
98 // Theme-based template didn't exist, try switching the theme to woocommerce and try again. This function has
99 // been unhooked so won't run again.
100 add_filter( 'get_block_file_template', array( $this, 'get_single_block_template' ), 10, 3 );
101 $maybe_template = function_exists( 'gutenberg_get_block_template' ) ?
102 gutenberg_get_block_template( LP_Block_Template_Utils::PLUGIN_SLUG . '//' . $slug, $template_type ) :
103 get_block_template( LP_Block_Template_Utils::PLUGIN_SLUG . '//' . $slug, $template_type );
104
105 // Re-hook this function, it was only unhooked to stop recursion.
106 add_filter( 'pre_get_block_file_template', array( $this, 'maybe_return_blocks_template' ), 10, 3 );
107 remove_filter( 'get_block_file_template', array( $this, 'get_single_block_template' ), 10, 3 );
108 if ( null !== $maybe_template ) {
109 return $maybe_template;
110 }
111
112 // At this point we haven't had any luck finding a template. Give up and let Gutenberg take control again.
113 return $template;
114 }
115
116 public function get_single_block_template( $template, $id, $template_type ) {
117
118 // The template was already found before the filter runs, just return it immediately.
119 if ( null !== $template ) {
120 return $template;
121 }
122
123 $template_name_parts = explode( '//', $id );
124 if ( count( $template_name_parts ) < 2 ) {
125 return $template;
126 }
127 list( , $slug ) = $template_name_parts;
128
129 // If this blocks template doesn't exist then we should just skip the function and let Gutenberg handle it.
130 if ( ! $this->block_template_is_available( $slug, $template_type ) ) {
131 return $template;
132 }
133
134 $available_templates = $this->get_block_templates( array( $slug ), $template_type );
135 return ( is_array( $available_templates ) && count( $available_templates ) > 0 )
136 ? LP_Block_Template_Utils::instance()->gutenberg_build_template_result_from_file( $available_templates[0], $available_templates[0]->type )
137 : $template;
138 }
139
140 /**
141 * Render block template
142 *
143 * @param $attributes
144 *
145 * @return false|string
146 */
147 public function render_content_block_template( $attributes ) {
148 $templates = array( 'archive-course', 'single-course', 'content-single-item', 'pages/checkout' );
149 $current_page = LP_Page_Controller::page_current();
150
151 if ( in_array( $attributes['template'], $templates, true ) ) {
152 // Fix something detected wrong template. - tungnx
153 if ( LP_PAGE_SINGLE_COURSE == $current_page ) {
154 $attributes['template'] = 'single-course';
155 }
156
157 return learn_press_get_template_content( $attributes['template'], array( 'is_block_theme' => true ) );
158 } else {
159 ob_start();
160
161 echo "You're using the Template block";
162
163 wp_reset_postdata();
164 return ob_get_clean();
165 }
166 }
167
168 public function render_block_template() {
169 if ( is_embed() || ! LP_Block_Template_Utils::instance()->supports_block_templates() ) {
170 return;
171 }
172
173 if ( is_singular( LP_COURSE_CPT ) && ! LP_Block_Template_Utils::instance()->theme_has_template( 'single-lp_course' ) && $this->block_template_is_available( 'single-lp_course' ) ) {
174 add_filter( 'learnpress_has_block_template', '__return_true', 10, 0 );
175 } elseif ( ( is_post_type_archive( LP_COURSE_CPT ) || ( ! empty( learn_press_get_page_id( 'courses' ) ) && is_page( learn_press_get_page_id( 'courses' ) ) ) ) && ! LP_Block_Template_Utils::instance()->theme_has_template( 'archive-lp_course' ) && $this->block_template_is_available( 'archive-lp_course' ) ) {
176 add_filter( 'learnpress_has_block_template', '__return_true', 10, 0 );
177 } elseif ( LP_PAGE_CHECKOUT === LP_Page_Controller::page_current() ) {
178 add_filter( 'learnpress_has_block_template', '__return_true', 10, 0 );
179 }
180 }
181
182 /**
183 * Detected if a block template is available
184 *
185 * @param $query_result
186 * @param $query
187 * @param $template_type
188 *
189 * @return array|mixed
190 */
191 public function add_block_templates( $query_result, $query, $template_type ) {
192 if ( ! LP_Block_Template_Utils::instance()->supports_block_templates() ) {
193 return $query_result;
194 }
195
196 $post_type = $query['post_type'] ?? '';
197 $slugs = $query['slug__in'] ?? array();
198
199 // Get file block template html.
200 $template_files = $this->get_block_templates( $slugs, $template_type );
201
202 // @todo: Add apply_filters to _gutenberg_get_template_files() in Gutenberg to prevent duplication of logic.
203 foreach ( $template_files as $template_file ) {
204
205 // Avoid adding the same template if it's already in the array of $query_result.
206 if (
207 array_filter(
208 $query_result,
209 function( $query_result_template ) use ( $template_file ) {
210 return $query_result_template->slug === $template_file->slug &&
211 $query_result_template->theme === $template_file->theme;
212 }
213 )
214 ) {
215 continue;
216 }
217
218 // If the current $post_type is set (e.g. on an Edit Post screen), and isn't included in the available post_types
219 // on the template file, then lets skip it so that it doesn't get added. This is typically used to hide templates
220 // in the template dropdown on the Edit Post page.
221 if ( $post_type &&
222 isset( $template_file->post_types ) &&
223 ! in_array( $post_type, $template_file->post_types, true )
224 ) {
225 continue;
226 }
227
228 // It would be custom if the template was modified in the editor, so if it's not custom we can load it from
229 // the filesystem.
230 if ( 'custom' !== $template_file->source ) {
231 $template = LP_Block_Template_Utils::instance()->gutenberg_build_template_result_from_file( $template_file, $template_type );
232 } else {
233 $query_result[] = $template_file;
234 continue;
235 }
236
237 $is_not_custom = false === array_search(
238 wp_get_theme()->get_stylesheet() . '//' . $template_file->slug,
239 array_column( $query_result, 'id' ),
240 true
241 );
242 $fits_slug_query = ! isset( $query['slug__in'] ) || in_array( $template_file->slug, $query['slug__in'], true );
243 $fits_area_query = ! isset( $query['area'] ) || $template_file->area === $query['area'];
244 $should_include = $is_not_custom && $fits_slug_query && $fits_area_query;
245
246 if ( $should_include ) {
247 $query_result[] = $template;
248 }
249 }
250
251 $query_result = $this->remove_theme_templates_with_custom_alternative( $query_result );
252
253 return $query_result;
254 }
255
256 /**
257 * Get content block
258 *
259 * @param array $slugs
260 * @param string $template_type
261 *
262 * @return mixed
263 */
264 public function get_block_templates( array $slugs = array(), string $template_type = 'wp_template' ) {
265 static $templates = null;
266
267 if ( ! is_null( $templates ) ) {
268 return $templates;
269 }
270
271 // Fixed page Checkout
272 if ( LP_PAGE_CHECKOUT === LP_Page_Controller::page_current() ) {
273 $slugs[] = 'page-lp_checkout';
274 }
275
276 // Get content template form DB on table posts, with post_type = $template_type.
277 $templates_from_db = $this->get_block_templates_from_db( $slugs, $template_type );
278
279 // Get content from file default.
280 $templates_from_lp = $this->get_block_templates_from_learnpress( $slugs, $templates_from_db, $template_type );
281 $templates = array_merge( $templates_from_db, $templates_from_lp );
282
283 return $templates;
284 }
285
286 /**
287 * @param array $slugs
288 * @param $already_found_templates
289 * @param string $template_type
290 *
291 * @return array
292 */
293 public function get_block_templates_from_learnpress( $slugs, $already_found_templates, $template_type = 'wp_template' ) {
294 global $wp;
295
296 $directory = $this->get_templates_directory( $template_type );
297 $template_files = LP_Block_Template_Utils::instance()->gutenberg_get_template_paths( $directory );
298 $templates = array();
299
300 if ( 'wp_template_part' === $template_type ) {
301 $dir_name = self::TEMPLATE_PARTS_DIR_NAME;
302 } else {
303 $dir_name = self::TEMPLATES_DIR_NAME;
304 }
305
306 foreach ( $template_files as $template_file ) {
307 $template_slug = LP_Block_Template_Utils::instance()->generate_template_slug_from_path( $template_file, $dir_name );
308
309 if ( ! empty( $wp->query_vars['course-item'] ) && $template_slug === 'single-lp_course' ) {
310 $template_slug = '';
311 }
312
313 $template_slug = $template_slug === 'content-single-lp_course-item' ? 'single-lp_course' : $template_slug;
314
315 if ( LP_PAGE_CHECKOUT === LP_Page_Controller::page_current() ) {
316 if ( str_contains( $template_file, 'page-lp_checkout' ) ) {
317 $template_slug = $slugs[0];
318 $templates[] = LP_Block_Template_Utils::instance()->create_new_block_template_object( $template_file, $template_type, $template_slug );
319 continue;
320 }
321 } elseif ( is_array( $slugs ) && count( $slugs ) > 0 && ! in_array( $template_slug, $slugs, true ) ) {
322 // This template does not have a slug we're looking for. Skip it.
323 continue;
324 }
325
326 // If the theme already has a template, or the template is already in the list (i.e. it came from the
327 // database) then we should not overwrite it with the one from the filesystem.
328 if ( LP_Block_Template_Utils::instance()->theme_has_template( $template_slug ) ||
329 count(
330 array_filter(
331 $already_found_templates,
332 function ( $template ) use ( $template_slug ) {
333 $template_obj = (object) $template; //phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.Found
334 return $template_obj->slug === $template_slug;
335 }
336 )
337 ) > 0 ) {
338 continue;
339 }
340
341 // If the theme has an archive-product.html template, but not a taxonomy-product_cat.html template let's use the themes archive-product.html template.
342 if ( 'taxonomy-lp_course_cat' === $template_slug && ! LP_Block_Template_Utils::instance()->theme_has_template( 'taxonomy-lp_course_cat' ) && LP_Block_Template_Utils::instance()->theme_has_template( 'archive-lp_course' ) ) {
343 $template_file = get_stylesheet_directory() . '/' . self::TEMPLATES_DIR_NAME . '/archive-course.html';
344 $templates[] = LP_Block_Template_Utils::instance()->create_new_block_template_object( $template_file, $template_type, $template_slug, true );
345 continue;
346 }
347
348 // If the theme has an archive-product.html template, but not a taxonomy-product_tag.html template let's use the themes archive-product.html template.
349 if ( 'taxonomy-lp_course_tag' === $template_slug && ! LP_Block_Template_Utils::instance()->theme_has_template( 'taxonomy-lp_course_tag' ) && LP_Block_Template_Utils::instance()->theme_has_template( 'archive-lp_course' ) ) {
350 $template_file = get_stylesheet_directory() . '/' . self::TEMPLATES_DIR_NAME . '/archive-course.html';
351 $templates[] = LP_Block_Template_Utils::instance()->create_new_block_template_object( $template_file, $template_type, $template_slug, true );
352 continue;
353 }
354
355 // At this point the template only exists in the Blocks filesystem and has not been saved in the DB,
356 // or superseded by the theme.
357 /*if ( ! isset( $templates[ $template_slug ] ) ) {
358 $templates[ $template_slug ] = LP_Block_Template_Utils::instance()->create_new_block_template_object( $template_file, $template_type, $template_slug );
359 }*/
360 $templates[] = LP_Block_Template_Utils::instance()->create_new_block_template_object( $template_file, $template_type, $template_slug );
361 }
362
363 return $templates;
364 }
365
366 public function get_block_templates_from_db( $slugs = array(), $template_type = 'wp_template' ) {
367 $invalid_plugin_slug = 'learnpress';
368
369 $check_query_args = array(
370 'post_type' => $template_type,
371 'posts_per_page' => -1,
372 'no_found_rows' => true,
373 'tax_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
374 array(
375 'taxonomy' => 'wp_theme',
376 'field' => 'name',
377 'terms' => array( $invalid_plugin_slug, LP_Block_Template_Utils::PLUGIN_SLUG, get_stylesheet() ),
378 ),
379 ),
380 );
381
382 if ( is_array( $slugs ) && count( $slugs ) > 0 ) {
383 $check_query_args['post_name__in'] = $slugs;
384 }
385
386 $check_query = new \WP_Query( $check_query_args );
387 $saved_woo_templates = $check_query->posts;
388
389 return array_map(
390 function( $saved_woo_template ) {
391 return LP_Block_Template_Utils::instance()->gutenberg_build_template_result_from_post( $saved_woo_template );
392 },
393 $saved_woo_templates
394 );
395 }
396
397 public function remove_theme_templates_with_custom_alternative( $templates ) {
398
399 // Get the slugs of all templates that have been customised and saved in the database.
400 $customised_template_slugs = array_map(
401 function( $template ) {
402 return $template->slug;
403 },
404 array_values(
405 array_filter(
406 $templates,
407 function( $template ) {
408 // This template has been customised and saved as a post.
409 return 'custom' === $template->source;
410 }
411 )
412 )
413 );
414
415 return array_values(
416 array_filter(
417 $templates,
418 function( $template ) use ( $customised_template_slugs ) {
419 // This template has been customised and saved as a post, so return it.
420 return ! ( 'theme' === $template->source && in_array( $template->slug, $customised_template_slugs, true ) );
421 }
422 )
423 );
424 }
425
426 public function block_template_is_available( $template_name, $template_type = 'wp_template' ) {
427 if ( ! $template_name ) {
428 return false;
429 }
430
431 $directory = $this->get_templates_directory( $template_type ) . '/' . $template_name . '.html';
432
433 return is_readable( $directory ) || $this->get_block_templates( array( $template_name ), $template_type );
434 }
435
436 protected function get_templates_directory( $template_type = 'wp_template' ) {
437 if ( 'wp_template_part' === $template_type ) {
438 return LP_PLUGIN_PATH . self::TEMPLATE_PARTS_DIR_NAME;
439 }
440 return LP_PLUGIN_PATH . self::TEMPLATES_DIR_NAME;
441 }
442
443 public static function instance() {
444 if ( ! self::$instance ) {
445 self::$instance = new self();
446 }
447 return self::$instance;
448 }
449 }
450
451 LP_Block_Template_Controller::instance();
452