PluginProbe ʕ •ᴥ•ʔ
Superb Addons: Blocks, Patterns, Pre-built Pages, Sliders, Popups, Free Forms, Animations & More / 3.7.1
Superb Addons: Blocks, Patterns, Pre-built Pages, Sliders, Popups, Free Forms, Animations & More v3.7.1
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 trunk 1.0.0 2.0.0 2.0.1 2.0.2 2.0.3 3.0 3.0.1 3.0.2 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.2 3.1.3 3.2.0 3.2.1 3.2.2 3.2.4 3.2.5 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.4.5 3.4.6 3.5.0 3.5.1 3.5.2 3.5.3 3.5.4 3.5.6 3.5.7 3.5.8 3.5.9 3.6.0 3.6.1 3.6.2 3.7.0 3.7.1
superb-blocks / src / data / utils / wizard / class-wizard-template-provider.php
superb-blocks / src / data / utils / wizard Last commit date
wizard-items 5 months ago class-wizard-constants.php 5 months ago class-wizard-creation-util.php 5 months ago class-wizard-exception.php 5 months ago class-wizard-menu-creator.php 5 months ago class-wizard-page-creator.php 5 months ago class-wizard-part-creator.php 5 months ago class-wizard-stage-util.php 5 months ago class-wizard-template-provider.php 5 months ago
class-wizard-template-provider.php
509 lines
1 <?php
2
3 namespace SuperbAddons\Data\Utils\Wizard;
4
5 use SuperbAddons\Admin\Controllers\Wizard\WizardRestorationPointController;
6 use SuperbAddons\Data\Controllers\KeyController;
7 use SuperbAddons\Data\Controllers\RestController;
8 use SuperbAddons\Library\Controllers\LibraryRequestController;
9
10 use WP_REST_Request;
11
12 defined('ABSPATH') || exit();
13
14 class WizardTemplateProvider
15 {
16 private $headerTemplates;
17 private $footerTemplates;
18 private $blogTemplates;
19 private $homeTemplates;
20 private $indexTemplates;
21 private $frontPageTemplates;
22 private $templatePages;
23
24 private $hasFrontPageTemplate;
25 private $hasHomeTemplate;
26 private $hasIndexTemplate;
27
28 private $totalHeaderParts;
29 private $totalFooterParts;
30
31 private $userIsPremium;
32
33 public function __construct()
34 {
35 $this->headerTemplates = array();
36 $this->footerTemplates = array();
37 $this->blogTemplates = array();
38 $this->homeTemplates = array();
39 $this->indexTemplates = array();
40 $this->frontPageTemplates = array();
41 $this->templatePages = array();
42
43 $this->totalHeaderParts = 0;
44 $this->totalFooterParts = 0;
45
46 $this->hasFrontPageTemplate = false;
47 $this->hasHomeTemplate = false;
48 $this->hasIndexTemplate = false;
49 $this->userIsPremium = KeyController::HasValidPremiumKey();
50 }
51
52 private function HasModifiedTemplate($slug, $template_type, $area = false)
53 {
54 $args = array(
55 'post_type' => $template_type,
56 'posts_per_page' => 1,
57 'post_name__in' => array($slug),
58 // Ensure we only get template parts for the current theme -> Tax query is used like in WP core
59 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
60 'tax_query' => array(
61 array(
62 'taxonomy' => 'wp_theme',
63 'field' => 'name',
64 'terms' => get_stylesheet()
65 )
66 )
67 );
68 if ($template_type === WizardItemTypes::WP_TEMPLATE_PART) {
69 $args['tax_query'][] = array(
70 'taxonomy' => 'wp_template_part_area',
71 'field' => 'name',
72 'terms' => $area ? $area : $slug
73 );
74 $args['tax_query']['relation'] = 'AND';
75 }
76
77 $modifiedTemplatePost = get_posts($args);
78
79 return $modifiedTemplatePost && !empty($modifiedTemplatePost) && $modifiedTemplatePost[0]->post_name === $slug;
80 }
81
82 private function InitializePart($slugOrWizardItem, $type, $area, $regularTitle, $modifiedTitle, $baseTitle)
83 {
84 if ($slugOrWizardItem instanceof WizarditemRestorationPoint) {
85 $this->AddToAppropriateArray($slugOrWizardItem, $area);
86 return;
87 }
88
89 $datatype = false;
90 if ($slugOrWizardItem instanceof WizardItem) {
91 $datatype = $slugOrWizardItem->datatype;
92 $slug = $slugOrWizardItem->GetBaseSlug();
93 } else {
94 $slug = $slugOrWizardItem;
95 }
96
97 $partTemplate = get_block_template(get_stylesheet() . '//' . $slug, $type);
98 if (!$partTemplate) {
99 return;
100 }
101
102 $hasModifiedPart = $this->HasModifiedTemplate($slug, $type, $area);
103 if ($partTemplate) {
104 $partItem = new WizardItemTemplate($partTemplate, $regularTitle, $modifiedTitle, $hasModifiedPart);
105 if ($datatype) {
106 $partItem->datatype = $datatype;
107 }
108 if ($area === 'header' && !has_block('core/navigation', $partTemplate->content)) {
109 $partItem->is_missing_navigation_block = true;
110 }
111 }
112
113 if ($hasModifiedPart) {
114 if ($area === $slug) {
115 // To avoid clutter, we don't need to add the modified part for all variants
116 $this->AddToAppropriateArray($partItem, $area);
117 }
118
119 $themePartTemplate = get_block_file_template(get_stylesheet() . '//' . $slug, $type);
120 if (!$themePartTemplate) {
121 // No theme part exists, add the modified part -> likely a custom part
122 $partItem->title = $baseTitle . __(" (Custom)", "superb-blocks");
123 $this->AddToAppropriateArray($partItem, $area);
124 return;
125 }
126 // Get the original part template from the theme file
127 $themePartItem = new WizardItemFile($slug, $type, $regularTitle);
128 if ($datatype) {
129 $themePartItem->datatype = $datatype;
130 }
131
132 if ($type === WizardItemTypes::WP_TEMPLATE_PART && $area === 'header') {
133 if (!has_block('core/navigation', $themePartTemplate->content)) {
134 $themePartItem->is_missing_navigation_block = true;
135 }
136 }
137 $this->AddToAppropriateArray($themePartItem, $area);
138 return;
139 }
140
141
142 // No modified part exists, add the block template part
143 $this->AddToAppropriateArray($partItem, $area);
144 }
145
146 public function InitializePatterns($required_plugin = false)
147 {
148 // Get all block template parts
149 $templates = get_block_templates([], 'wp_template_part');
150
151 $this->totalHeaderParts = 0;
152 $this->totalFooterParts = 0;
153 // Filter for header/footer patterns and collect template parts
154 foreach ($templates as $template) {
155 if (isset($template->area)) {
156 $regularTitleAffix = isset($template->source) && $template->source === 'theme' ? __(" (Theme)", "superb-blocks") : "";
157 if ($template->area === 'header') {
158 $this->InitializePart($template->slug, WizardItemTypes::WP_TEMPLATE_PART, 'header', $template->title . $regularTitleAffix, $template->title . __(" (Current)", "superb-blocks"), $template->title);
159 $this->totalHeaderParts++;
160 }
161 if ($template->area === 'footer') {
162 $this->InitializePart($template->slug, WizardItemTypes::WP_TEMPLATE_PART, 'footer', $template->title . $regularTitleAffix, $template->title . __(" (Current)", "superb-blocks"), $template->title);
163 $this->totalFooterParts++;
164 }
165 }
166 }
167
168 try {
169 $request = new WP_REST_Request('GET', '/' . RestController::NAMESPACE . LibraryRequestController::GUTENBERG_LIST_ROUTE . 'patterns');
170 $patterns_response = rest_do_request($request);
171 if (!$patterns_response || is_wp_error($patterns_response) || $patterns_response->is_error() || !isset($patterns_response->data) || !isset($patterns_response->data->items)) {
172 throw new WizardException(__("An error occurred while fetching available patterns.", "superb-blocks"));
173 }
174
175 // Order free to the top of list array if the user is not premium
176 if (!$this->userIsPremium) {
177 $freePatterns = array();
178 $premiumPatterns = array();
179 foreach ($patterns_response->data->items as $pattern) {
180 if (isset($pattern->package) && $pattern->package === 'premium') {
181 $premiumPatterns[] = $pattern;
182 } else {
183 $freePatterns[] = $pattern;
184 }
185 }
186 $patterns_response->data->items = array_merge($freePatterns, $premiumPatterns);
187 }
188 // Get header and footer templates from patterns
189 foreach ($patterns_response->data->items as $pattern) {
190 if ($required_plugin && !isset($pattern->required_plugins) || $required_plugin && !in_array($required_plugin, $pattern->required_plugins)) {
191 continue;
192 }
193 $patternItem = new WizardItemPattern($pattern);
194 foreach ($pattern->categories as $category) {
195 if ($category->id === WizardDataCategory::NAVIGATION) {
196 $this->headerTemplates[] = $patternItem;
197 } else if ($category->id === WizardDataCategory::FOOTER) {
198 $this->footerTemplates[] = $patternItem;
199 }
200 }
201 }
202
203 // 'header' slug should always be first in the header templates
204 if (!empty($this->headerTemplates) && count($this->headerTemplates) > 1) {
205 usort($this->headerTemplates, function ($a, $b) {
206 if ($a->GetBaseSlug() === 'header') {
207 return -1;
208 }
209 if ($b->GetBaseSlug() === 'header') {
210 return 1;
211 }
212 return 0;
213 });
214 }
215 // 'footer' slug should always be first in the footer templates
216 if (!empty($this->footerTemplates) && count($this->footerTemplates) > 1) {
217 usort($this->footerTemplates, function ($a, $b) {
218 if ($a->GetBaseSlug() === 'footer') {
219 return -1;
220 }
221 if ($b->GetBaseSlug() === 'footer') {
222 return 1;
223 }
224 return 0;
225 });
226 }
227 } catch (WizardException $e) {
228 // Exception is automatically logged. Catch it so that the wizard can continue with the available theme templates.
229 }
230 }
231
232 public function InitalizePageTemplates()
233 {
234 $acceptedTemplates = $this->GetAcceptedTemplates();
235
236 // Initial sort templates by slug
237 $this->SortTemplatesIntoArraysBySlug($acceptedTemplates);
238
239 // Additional template logic
240 $this->HandleTemplateLogic();
241
242 // Add addons service templates
243 try {
244 $request = new WP_REST_Request('GET', '/' . RestController::NAMESPACE . LibraryRequestController::GUTENBERG_LIST_ROUTE . 'pages');
245 $pages_response = rest_do_request($request);
246 if (!$pages_response || is_wp_error($pages_response) || $pages_response->is_error() || !isset($pages_response->data) || !isset($pages_response->data->items)) {
247 throw new WizardException(__("An error occurred while fetching available pages.", "superb-blocks"));
248 }
249
250 // Order free to the top of list array if the user is not premium
251 if (!$this->userIsPremium) {
252 $freePages = array();
253 $premiumPages = array();
254 foreach ($pages_response->data->items as $page) {
255 if (isset($page->package) && $page->package === 'premium') {
256 $premiumPages[] = $page;
257 } else {
258 $freePages[] = $page;
259 }
260 }
261 $pages_response->data->items = array_merge($freePages, $premiumPages);
262 }
263
264 foreach ($pages_response->data->items as $page) {
265 $pageItem = new WizardItemPage($page);
266 $pageItem->use_custom_page_template_preview = 1;
267 $this->templatePages[] = $pageItem;
268
269 // Add landing page templates to the front page templates
270 foreach ($page->categories as $category) {
271 if ($category->id === WizardDataCategory::LANDING_PAGE) {
272 $landingPageItem = new WizardItemPage($page);
273 $this->frontPageTemplates[] = $landingPageItem;
274 }
275 if ($category->id === WizardDataCategory::BLOG) {
276 $this->blogTemplates[] = $pageItem;
277 }
278 }
279 }
280 } catch (WizardException $e) {
281 // Exception is automatically logged. Catch it so that the wizard can continue with the available theme templates.
282 }
283 }
284
285 private function HandleTemplateLogic($logicType = 'default')
286 {
287 // Check for static pages
288 $has_static_pages = get_option('show_on_front') === 'page';
289 $staticFrontPageID = get_option('page_on_front');
290 $hasStaticFrontPage = $has_static_pages && $staticFrontPageID && $staticFrontPageID !== 0;
291 $staticBlogPageID = get_option('page_for_posts');
292 $hasStaticBlogPage = $has_static_pages && $staticBlogPageID && $staticBlogPageID !== 0;
293
294 if ($logicType === "default") {
295 // Front page templates additional logic
296 if (!$this->hasFrontPageTemplate) {
297 // If no front page template exists, set regular theme templates
298 $this->frontPageTemplates = $this->templatePages;
299
300 if ($hasStaticFrontPage) {
301 $static_page = new WizardItemStatic(__("Static Homepage (Current)", "superb-blocks"), $staticFrontPageID);
302 $this->frontPageTemplates = array_merge(array($static_page), $this->frontPageTemplates);
303 }
304 }
305
306 // Add "No blog page" selection
307 $noBlogPage = array(new WizardItemIgnore(__("No Blog Page", "superb-blocks")));
308 // Blog templates logic
309 if ($this->hasHomeTemplate || $this->hasIndexTemplate) {
310 $this->blogTemplates = array_merge($noBlogPage, $this->homeTemplates, $this->indexTemplates, $this->blogTemplates);
311 } else {
312 if ($hasStaticBlogPage) {
313 $static_page = array(new WizardItemStatic(__("Static Blog Page (Current)", "superb-blocks"), $staticBlogPageID));
314 $this->blogTemplates = array_merge($noBlogPage, $static_page);
315 } else {
316 $this->blogTemplates = $noBlogPage;
317 }
318 }
319
320 // If home templates exist and no front page template exists, add the home templates to the front page templates
321 if (!empty($this->homeTemplates) && !$this->hasFrontPageTemplate) {
322 if ($hasStaticFrontPage) {
323 // Add the home templates after the first item
324 array_splice($this->frontPageTemplates, 1, 0, $this->homeTemplates);
325 } else {
326 // Add the home templates to the front of the front page templates
327 $this->frontPageTemplates = array_merge($this->homeTemplates, $this->frontPageTemplates);
328 }
329 }
330 }
331
332 if ($logicType === "restoration") {
333 if (!empty($this->headerTemplates)) {
334 $currentHeader = get_block_template(get_stylesheet() . '//header', WizardItemTypes::WP_TEMPLATE_PART);
335 $currentHeader->title = $currentHeader->title . __(" (Current)", "superb-blocks");
336 $currentHeader = new WizardItem($currentHeader);
337 $this->headerTemplates = array_merge(array($currentHeader), $this->headerTemplates);
338 }
339
340 if (!empty($this->footerTemplates)) {
341 $currentFooter = get_block_template(get_stylesheet() . '//footer', WizardItemTypes::WP_TEMPLATE_PART);
342 $currentFooter->title = $currentFooter->title . __(" (Current)", "superb-blocks");
343 $currentFooter = new WizardItem($currentFooter);
344 $this->footerTemplates = array_merge(array($currentFooter), $this->footerTemplates);
345 }
346
347
348 if (!empty($this->frontPageTemplates)) {
349 if ($this->hasFrontPageTemplate) {
350 $currentFrontPage = get_block_template(get_stylesheet() . '//' . 'front-page', WizardItemTypes::WP_TEMPLATE);
351 $currentFrontPage->title = $currentFrontPage->title . __(" (Current)", "superb-blocks");
352 $currentFrontPage = new WizardItem($currentFrontPage);
353 $this->frontPageTemplates = array_merge(array($currentFrontPage), $this->frontPageTemplates);
354 }
355 }
356
357 $this->blogTemplates = array_merge($this->homeTemplates, $this->indexTemplates, $this->blogTemplates);
358 if (!empty($this->blogTemplates)) {
359 if ($this->hasHomeTemplate) {
360 $currentBlogPage = get_block_template(get_stylesheet() . '//' . 'home', WizardItemTypes::WP_TEMPLATE);
361 } elseif ($this->hasIndexTemplate) {
362 $currentBlogPage = get_block_template(get_stylesheet() . '//' . 'index', WizardItemTypes::WP_TEMPLATE);
363 }
364
365 if ($currentBlogPage) {
366 $currentBlogPage->datatype = 'blog';
367 $currentBlogPage->title = $currentBlogPage->title . __(" (Current)", "superb-blocks");
368 $currentBlogPage = new WizardItem($currentBlogPage);
369 $this->blogTemplates = array_merge(array($currentBlogPage), $this->blogTemplates);
370 }
371 }
372 }
373 }
374
375 private function GetAcceptedTemplates()
376 {
377 $templates = get_block_templates();
378 $acceptedTemplates = array();
379 // Filter out templates that are not accepted for the current theme
380 foreach ($templates as $template) {
381 if ($template->status !== 'publish') continue;
382 if ($template->type !== WizardItemTypes::WP_TEMPLATE) continue;
383 if ($template->theme !== get_stylesheet()) continue;
384 if ($template->slug === AddonsPageTemplateUtil::TEMPLATE_ID) continue; // Do not include the wizard page creation template
385 if ($template->slug !== 'front-page' && $template->slug !== 'home' && $template->slug !== 'index') {
386 if (!$template->is_custom) continue;
387 if (!$template->post_types || !in_array('page', $template->post_types)) continue;
388 }
389 $acceptedTemplates[] = new WizardItem($template);
390 }
391 return $acceptedTemplates;
392 }
393
394 public function InitializeRestorationTemplates()
395 {
396 $theme_restoration = WizardRestorationPointController::GetThemeRestorationPoints();
397 if (!$theme_restoration) {
398 return;
399 }
400
401 $restoration_templates = [];
402 foreach ($theme_restoration as $restorationId => $restorationPointArray) {
403 $restoration_templates[] = new WizarditemRestorationPoint($restorationId, $restorationPointArray);
404 }
405
406 // Sort restoration templates by timestamp
407 usort($restoration_templates, function ($a, $b) {
408 return $a->timestamp <=> $b->timestamp;
409 });
410
411 $this->SortTemplatesIntoArraysBySlug($restoration_templates, "restoration");
412 $this->HandleTemplateLogic('restoration');
413 }
414
415 private function SortTemplatesIntoArraysBySlug($acceptedTemplates, $logicType = "default")
416 {
417 foreach ($acceptedTemplates as $template) {
418 $slug = $template->GetBaseSlug();
419
420 if ($slug === 'front-page' || $slug === 'home' || $slug === 'index') {
421 switch ($slug) {
422 case "front-page":
423 $base_label = __("Front Page", "superb-blocks");
424 break;
425 case "home":
426 $template->datatype = 'blog';
427 $base_label = __("Blog Home", "superb-blocks");
428 break;
429 case "index":
430 $template->datatype = 'blog';
431 $base_label = __("Index", "superb-blocks");
432 break;
433 }
434 $this->InitializePart($template, WizardItemTypes::WP_TEMPLATE, $slug, $base_label . __(" (Theme)", "superb-blocks"), $base_label . __(" (Current)", "superb-blocks"), $base_label);
435 } else {
436 if ($logicType === "default") {
437 $template->title = $template->title . ' (' . __('Theme', 'superb-blocks') . ')';
438 }
439 $this->AddToAppropriateArray($template, $template->category);
440 }
441 }
442 }
443
444 private function AddToAppropriateArray($item, $category)
445 {
446 switch ($category) {
447 case 'header':
448 $this->headerTemplates[] = $item;
449 break;
450 case 'footer':
451 $this->footerTemplates[] = $item;
452 break;
453 case 'front-page':
454 $this->hasFrontPageTemplate = true;
455 $this->frontPageTemplates[] = $item;
456 break;
457 case 'home':
458 $this->hasHomeTemplate = true;
459 $this->homeTemplates[] = $item;
460 break;
461 case 'index':
462 $this->hasIndexTemplate = true;
463 $this->indexTemplates[] = $item;
464 break;
465 default:
466 if (strpos($category, 'blog') !== false) {
467 $this->blogTemplates[] = $item;
468 }
469 $this->templatePages[] = $item;
470 break;
471 }
472 }
473
474 public function GetHeaderTemplates()
475 {
476 return $this->headerTemplates;
477 }
478
479 public function GetFooterTemplates()
480 {
481 return $this->footerTemplates;
482 }
483
484 public function HasMultipleHeaderParts()
485 {
486 return $this->totalHeaderParts > 1;
487 }
488
489 public function HasMultipleFooterParts()
490 {
491 return $this->totalFooterParts > 1;
492 }
493
494 public function GetBlogTemplates()
495 {
496 return $this->blogTemplates;
497 }
498
499 public function GetFrontPageTemplates()
500 {
501 return $this->frontPageTemplates;
502 }
503
504 public function GetTemplatePages()
505 {
506 return $this->templatePages;
507 }
508 }
509