PluginProbe ʕ •ᴥ•ʔ
Kirki – Freeform Page Builder, Website Builder & Customizer / 6.2.0
Kirki – Freeform Page Builder, Website Builder & Customizer v6.2.0
6.2.0 6.1.1 6.1.0 6.0.14 6.0.13 6.0.12 6.0.11 6.0.10 6.0.9 6.0.8 6.0.7 6.0.6 6.0.5 6.0.4 6.0.3 6.0.2 6.0.1 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 4.0.19 4.0.20 4.0.21 4.0.22 4.0.23 4.0.24 4.1 4.2.0 5.0.0 5.1.0 5.1.1 5.2.0 5.2.1 5.2.2 5.2.3 6.0.0 trunk 3.0.40 3.0.41 3.0.42 3.0.43 3.0.44 3.0.45 3.1.0 3.1.1 3.1.2
kirki / app / Supports / Template.php
kirki / app / Supports Last commit date
Facades 5 days ago Form 5 days ago ActionHooks.php 5 days ago Canvas.php 1 month ago CollectionItem.php 5 days ago ContentManager.php 1 month ago DateTime.php 1 month ago EditorPreview.php 2 weeks ago FileHandler.php 2 weeks ago FilterHooks.php 2 weeks ago PageUrl.php 5 days ago Recaptcha.php 5 days ago Role.php 1 month ago Session.php 5 days ago Template.php 5 days ago
Template.php
432 lines
1 <?php
2
3 namespace Kirki\App\Supports;
4
5 defined('ABSPATH') || exit;
6
7 use Kirki\App\Constants\PageContentTypes;
8 use Kirki\App\Constants\UtilityPageType;
9 use Kirki\App\DTO\Page\EditorPagePayloadDTO;
10 use Kirki\App\DTO\Symbol\SymbolDTO;
11 use Kirki\App\Models\Page as PageModel;
12 use Kirki\App\Models\Post as PostModel;
13 use Kirki\App\Services\PageService;
14 use Kirki\App\Supports\Facades\Symbol;
15 use Kirki\Framework\Sanitizer;
16 use Kirki\Framework\Supports\Facades\File;
17
18 use function Kirki\App\is_truthy;
19
20 class Template
21 {
22 /**
23 * @param string|string[] $name
24 * @param string|null $prefix
25 *
26 * @return string|string[]
27 */
28 public static function add_prefix_to_class_name($name, $prefix = null)
29 {
30
31 if (is_array($name)) {
32 foreach ($name as $key => $class_name) {
33 $name[$key] = static::add_prefix_to_class_name($class_name, $prefix);
34 }
35
36 return $name;
37 }
38
39 $name = strtolower($name);
40
41 if (!in_array($name, KIRKI_PRESERVED_CLASS_LIST)) {
42 $name = $prefix ? strtolower($prefix) . '-' . $name : $name;
43 }
44
45 return $name;
46 }
47
48 /**
49 * Assign utility page template
50 *
51 * @param int $page_id
52 * @param string $utility_page_type
53 *
54 * @return bool
55 */
56 public static function assign_utility_page_template(int $page_id, string $utility_page_type) {
57 if (in_array($utility_page_type, UtilityPageType::get_constant_values(), true)) {
58 $remote_url = KIRKI_PUBLIC_ASSETS_URL . '/pre-built-pages/basic/' . $utility_page_type . '.zip';
59 return static::process_template($page_id, $remote_url);
60 }
61
62 return false;
63 }
64
65 /**
66 * Assign custom page template
67 *
68 * @param int $page_id
69 * @param string $template_url
70 *
71 * @return bool
72 */
73 public static function assign_custom_page_template(int $page_id, string $template_url) {
74 return static::process_template($page_id, $template_url);
75 }
76
77 /**
78 * Process kirki template zip
79 *
80 * @param int $page_id
81 * @param string $remote_url
82 *
83 * @return bool
84 */
85 protected static function process_template(int $page_id, string $remote_url)
86 {
87 $file_name_new = uniqid('', true) . '.zip'; // 'random.ext'
88 $zip_file_path = FileHandler::download_zip_from_remote($remote_url, $file_name_new);
89
90 if ($zip_file_path) {
91 $json_data = static::save_kirki_template_from_zip($page_id, $zip_file_path);
92
93 if (!empty($json_data)) {
94 // delete zip file
95 File::delete($zip_file_path);
96 return true;
97 }
98 }
99
100 return false;
101 }
102
103 /**
104 * Process kirki template zip
105 *
106 * @param int $page_id
107 * @param string $zip_path
108 * @return bool|array
109 */
110 protected static function save_kirki_template_from_zip(int $page_id, string $zip_path)
111 {
112 if ($page_id === 0) {
113 return false;
114 }
115
116 $kirki_json_data = static::get_kirki_template_from_zip($zip_path);
117
118 $is_include_media = true;
119 $should_process_symbols = true;
120 $kirki_json_data = static::process_template_from_json(
121 $kirki_json_data,
122 !$is_include_media,
123 !$should_process_symbols
124 );
125
126 if (!is_truthy($kirki_json_data)) {
127 return false;
128 }
129
130 return static::save_template_data($page_id, $kirki_json_data)
131 ? $kirki_json_data
132 : false;
133 }
134
135 /**
136 * Persist an already-normalized Kirki template.
137 *
138 * This is the common final stage for downloaded templates and local
139 * application templates whose placeholders have already been bound.
140 *
141 * @param int $page_id Target page/template ID.
142 * @param array $kirki_json_data Normalized Kirki editor data.
143 * @return bool
144 */
145 public static function save_template_data(int $page_id, array $kirki_json_data)
146 {
147
148 $kirki_json_data['blocks']['root'] = [
149 'accept' => '*',
150 'children' => ['body'],
151 'id' => 'root',
152 'name' => 'root',
153 'styleIds' => [],
154 'title' => 'Root',
155 ];
156
157 foreach ($kirki_json_data['styles'] as $key => $style) {
158 $style['name'] = static::add_prefix_to_class_name($style['name'], 'post-' . $page_id);
159 unset($style['isGlobal']);
160 unset($style['isDefault']);
161 unset($style['isGlobalStyle']);
162 $kirki_json_data['styles'][$key] = $style;
163 }
164
165 $payload = EditorPagePayloadDTO::from_array([
166 'page' => PageModel::find($page_id),
167 'data' => $kirki_json_data
168 ]);
169
170 foreach (PageContentTypes::get_constant_values() as $page_content_type) {
171 (new PageService())->save_page_data($payload, $page_content_type);
172 }
173
174 return $kirki_json_data;
175 }
176
177 /**
178 * Process kirki template zip
179 *
180 * @param string $zip_path
181 * @return false|string
182 */
183 protected static function get_kirki_template_from_zip(string $zip_path)
184 {
185 $temp_folder_path = FileHandler::get_temp_folder_path();
186
187 $result = FileHandler::extract_zip_file($zip_path, $temp_folder_path);
188
189 if ($result === false) {
190 File::delete($temp_folder_path);
191 return false;
192 }
193
194 $kirki_json_file = $temp_folder_path . '/kirki-data.json';
195
196 if (File::missing($kirki_json_file)) {
197 File::delete($temp_folder_path);
198
199 return false;
200 }
201
202 $kirki_json_data = File::get($kirki_json_file);
203
204 // delete temp folder
205 File::delete($temp_folder_path);
206
207 if (empty($kirki_json_data)) {
208 return false;
209 }
210
211 return $kirki_json_data;
212 }
213
214 /**
215 * Process kirki template zip
216 *
217 * @param string $kirki_json_data
218 * @param boolean $is_include_media
219 * @param boolean $should_process_symbols
220 *
221 * @return array
222 */
223 protected static function process_template_from_json(string $kirki_json_data, bool $is_include_media = false, bool $should_process_symbols = true)
224 {
225 $kirki_json_data = json_decode($kirki_json_data, true);
226
227 $asset_urls = $kirki_json_data['asset_urls'] ?? [];
228 $blocks = $kirki_json_data['blocks'] ?? [];
229 $symbols = $kirki_json_data['symbols'] ?? [];
230
231 if ($is_include_media) {
232 $uploaded_attachment_ids = static::attach_assets_from_zip($asset_urls);
233 $assets_urls_map = [];
234
235 if (!empty($uploaded_attachment_ids)) {
236 $uploaded_attachment_urls = PostModel::query()
237 ->where_in('ID', array_filter(array_values($uploaded_attachment_ids)))
238 ->get(['ID', 'guid'])
239 ->pluck('guid', 'ID')
240 ->to_array();
241
242 foreach ($asset_urls as $key => $asset_item) {
243 $url = $asset_item['url'];
244 $assets_urls_map[$asset_item['id']] = $asset_item;
245
246 if (!isset($uploaded_attachment_ids[$url])) {
247 $asset_urls[$key] = array_merge($asset_item, [
248 'url' => null,
249 'attachment_id' => 0,
250 'index' => isset($asset_item['index']) ? $asset_item['index'] : null,
251 'thumbnail' => isset($asset_item['thumbnail']) ? $asset_item['thumbnail'] : false,
252 ]);
253
254 continue;
255 }
256
257 $attachment_id = $uploaded_attachment_ids[$url] ?? 0;
258 $attachment_url = $uploaded_attachment_urls[$attachment_id] ?? null;
259
260 $asset_urls[$key] = array_merge($asset_item, [
261 'url' => $attachment_url,
262 'attachment_id' => $attachment_id,
263 'index' => isset($asset_item['index']) ? $asset_item['index'] : null,
264 'thumbnail' => isset($asset_item['thumbnail']) ? $asset_item['thumbnail'] : false,
265 ]);
266 }
267 }
268
269 // update blocks with new asset urls
270 foreach ($asset_urls as $key => $asset_item) {
271 if (
272 !isset($blocks[$asset_item['id']]['name'], $asset_item['name'])
273 || $blocks[$asset_item['id']]['name'] !== $asset_item['name']
274 ) {
275 continue;
276 }
277
278 switch($asset_item['name']) {
279 case 'image':
280 $blocks[$asset_item['id']]['properties']['attributes']['src'] = $asset_item['url'];
281 $blocks[$asset_item['id']]['properties']['wp_attachment_id'] = $asset_item['attachment_id'];
282
283 break;
284 case 'video':
285 if ($asset_item['thumbnail']) {
286 $blocks[$asset_item['id']]['properties']['thumbnail']['url'] = $asset_item['url'];
287 break;
288 }
289
290 $blocks[$asset_item['id']]['properties']['attributes']['src'] = $asset_item['url'];
291 break;
292 case 'lottie':
293 $blocks[$asset_item['id']]['properties']['lottie']['src'] = $asset_item['url'];
294 break;
295 case 'lightbox':
296 if ($asset_item['thumbnail']) {
297 $blocks[ $asset_item['id'] ]['properties']['lightbox']['thumbnail']['src'] = $asset_item['url'];
298 break;
299 }
300
301 $blocks[$asset_item['id']]['properties']['lightbox']['media'][$asset_item['index']]['sources']['original'] = $asset_item['url'];
302 break;
303 }
304 }
305
306 if ($should_process_symbols) {
307 // update symbols with new asset urls
308 foreach ($symbols as $sym_key => $symbol) {
309 foreach ($symbol['symbolData']['data'] as $key => $block) {
310 $block_id = $block['id'];
311
312 if (isset($assets_urls_map[$block_id])) {
313 switch($assets_urls_map[$block_id]['name']) {
314 case 'image':
315 $symbol['symbolData']['data'][$key]['attributes']['src'] = $assets_urls_map[$block_id]['url'];
316 $symbol['symbolData']['data'][$key]['wp_attachment_id'] = $assets_urls_map[$block_id]['attachment_id'];
317 break;
318 case 'video':
319 if ($assets_urls_map[$block_id]['thumbnail']) {
320 $symbol['symbolData']['data'][$key]['thumbnail']['url'] = $assets_urls_map[$block_id]['url'];
321 break;
322 }
323
324 $symbol['symbolData']['data'][$key]['attributes']['src'] = $assets_urls_map[$block_id]['url'];
325 break;
326 case 'lottie':
327 $symbol['symbolData']['data'][$key]['lottie']['src'] = $assets_urls_map[$block_id]['url'];
328 break;
329 case 'lightbox':
330 if ( $assets_urls_map[$block_id]['thumbnail'] ) {
331 $symbol['symbolData']['data'][$key]['lightbox']['thumbnail']['src'] = $assets_urls_map[$block_id]['url'];
332 break;
333 }
334
335 $symbol['symbolData']['data'][$key]['lightbox']['media'][$assets_urls_map[$block_id]['index']]['sources']['original'] = $assets_urls_map[$block_id]['url'];
336 break;
337
338 }
339 }
340 }
341
342 $symbols[$sym_key]['symbolData']['data'] = $symbol['symbolData']['data'];
343 }
344 }
345 }
346
347 $saved_symbols_tracker = [];
348
349 if ($should_process_symbols && is_truthy($symbols)) {
350 foreach ($symbols as $symbol) {
351 $symbol_id = $symbol['id'];
352 $symbol_element_id = $symbol['elementId'];
353
354 // Check if the symbol is already saved
355 if (!isset($saved_symbols_tracker[$symbol_id])) {
356 // Save the symbol to the database
357 $saved_symbol = Symbol::save(SymbolDTO::from_array($symbol));
358
359 // Add the saved symbol to the tracker
360 if ($saved_symbol) {
361 $saved_symbols_tracker[$symbol_id] = $saved_symbol->id ?? null;
362 }
363 }
364
365 // Update all relevant elements with the symbol's ID
366 if (
367 isset($blocks[$symbol_element_id], $saved_symbols_tracker[$symbol_id])
368 && $blocks[$symbol_element_id]['name'] === 'symbol'
369 ) {
370 $blocks[$symbol_element_id]['properties']['symbolId'] = $saved_symbols_tracker[$symbol_id];
371 }
372 }
373 }
374
375 // remove asset_urls
376 unset($kirki_json_data['asset_urls']);
377
378 $kirki_json_data['blocks'] = $blocks;
379 $kirki_json_data['symbols'] = $symbols;
380
381 return $kirki_json_data;
382 }
383
384 protected static function attach_assets_from_zip(array $asset_urls)
385 {
386 $uploaded_attachment_ids = [];
387
388 foreach ($asset_urls as $asset_item) {
389 $url = $asset_item['url'];
390
391 if (isset($uploaded_attachment_ids[$url]) && !empty($uploaded_attachment_ids[$url])) {
392 continue;
393 }
394
395 $attachment_id = null;
396 $asset_name = basename($asset_item['url']);
397 $temp_folder_path = FileHandler::get_temp_folder_path();
398 $source_file_path = $temp_folder_path . '/' . Sanitizer::apply_rule($asset_name, Sanitizer::FILE_NAME);
399
400 if (File::exists($source_file_path)) {
401 $file_name = basename($source_file_path);
402
403 // Upload the file
404 $_FILES['file'] = [
405 'name' => Sanitizer::apply_rule($file_name, Sanitizer::FILE_NAME),
406 'tmp_name' => $source_file_path,
407 ];
408
409 if (!function_exists('media_handle_upload')) {
410 require_once ABSPATH . 'wp-admin/includes/image.php';
411 require_once ABSPATH . 'wp-admin/includes/media.php';
412 }
413
414 $attachment_id = media_handle_upload('file', 0, [], [
415 'test_form' => false,
416 'action' => 'upload-attachment',
417 ]
418 );
419
420 // Check if the upload was successful
421 if (is_wp_error($attachment_id)) {
422 $attachment_id = null;
423 }
424 }
425
426 $uploaded_attachment_ids[$url] = $attachment_id ? (int) $attachment_id : null;
427 }
428
429 return $uploaded_attachment_ids;
430 }
431 }
432