PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.6.0
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.6.0
3.7.5 3.7.4 3.7.3 3.7.2 1-final 3.7.1 3.7.0 3.6.8 3.6.7 3.6.6 3.6.5 3.6.4 3.6.3 3.6.2 3.6.1 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.10 All 111 releases
templately / includes / Core / Importer / Runners / Attachments.php

Attachments.php in Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! 3.6.0, at includes/Core/Importer/Runners/Attachments.php

343 lines 9.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Templately\Core\Importer\Runners;
4
5 use Templately\Core\Importer\WPImport;
6
7 class Attachments extends WPContent {
8
9 private $data = [];
10
11 public function __construct($request_params) {
12 parent::__construct($request_params);
13 $this->attachments_init();
14 }
15
16 public function get_name(): string {
17 return 'attachments';
18 }
19
20 public function get_label(): string {
21 return __('Attachments', 'templately');
22 }
23
24 public function should_log(): bool {
25 return true;
26 }
27
28 public function get_action(): string {
29 return 'updateLog';
30 }
31
32 public function log_message(): string {
33 if ($this->total > 0) {
34 return __('Importing Attachments: (' . $this->get_processed() . '/' . $this->total . ')', 'templately');
35 }
36 return __('Importing Attachment.', 'templately');
37 }
38
39 public function should_run($data, $imported_data = []): bool {
40 return !empty($this->manifest['has_attachments']);
41 }
42
43 public function import($data, $imported_data): array {
44 $path = $this->dir_path;
45 $taxonomies = [];
46 $terms = [];
47 $results = [];
48 $this->data = $data;
49
50 $this->clear_old_el_cache();
51
52 $this->import_actions();
53
54 $import = $this->_import_type_data('attachments', $path, $imported_data, $taxonomies, $terms);
55 $results['attachments'] = $import['summary']['posts'];
56 $results['attachments_errors'] = $import['errors'];
57
58 $this->import_actions(true);
59
60 return $results;
61 }
62
63 /**
64 * Clear old Elementor cache and image hash metadata
65 *
66 * This method removes cached Elementor image hash data from previous imports to prevent
67 * the second image hash check (for original_attachment_url) from picking up attachments
68 * from previous imports. This ensures clean attachment mapping for each import session.
69 *
70 * Process:
71 * 1. Checks if cache has already been cleared for this session (via loop result)
72 * 2. Retrieves all meta_ids stored in '_templately_image_hash_meta_id' meta keys
73 * 3. Deletes the actual hash metadata entries referenced by those meta_ids
74 * 4. Removes the tracking meta_keys themselves
75 *
76 * @return void
77 */
78 public function clear_old_el_cache() {
79 global $wpdb;
80
81 $has_processed = $this->get_loop_result(false, 'attachments-cleared-old-el-cache', false);
82 if($has_processed){
83 return;
84 }
85
86 // Step 1: Retrieve all meta values where the meta_key is '_templately_image_hash_meta_id'
87 $meta_ids = $wpdb->get_col(
88 $wpdb->prepare(
89 "SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s",
90 '_templately_image_hash_meta_id'
91 )
92 );
93
94 // Step 2: Delete the corresponding meta entries using the retrieved meta_ids
95 if (!empty($meta_ids)) {
96 $placeholders = implode(',', array_fill(0, count($meta_ids), '%d'));
97 $wpdb->query(
98 $wpdb->prepare(
99 "DELETE FROM {$wpdb->postmeta} WHERE meta_id IN ($placeholders)",
100 ...$meta_ids
101 )
102 );
103
104 if (defined('TEMPLATELY_DEBUG_LOG') && TEMPLATELY_DEBUG_LOG) {
105 error_log('Deleted _elementor_source_image_hash entries with meta_ids: ' . implode(', ', $meta_ids));
106 }
107 }
108
109 // Step 3: Delete all '_templately_image_hash_meta_id' entries
110 $wpdb->delete(
111 $wpdb->postmeta,
112 array('meta_key' => '_templately_image_hash_meta_id'),
113 array('%s')
114 );
115
116 // Check for errors
117 if (defined('TEMPLATELY_DEBUG_LOG') && TEMPLATELY_DEBUG_LOG) {
118 if($wpdb->last_error){
119 error_log('MySQL Error during image hash cleanup: ' . $wpdb->last_error);
120 }
121 }
122
123 // Mark this operation as complete to prevent redundant execution
124 $this->set_loop_result(true, 'attachments-cleared-old-el-cache');
125 }
126
127 protected function import_actions($remove = false) {
128 parent::import_actions($remove);
129
130 if ($remove) {
131 remove_filter('templately_import_copy_attachment', [$this, 'copy_attachment_file'], 10);
132 remove_filter('wp_import_post_data_raw', [$this, 'ai_image_replacement_url'], 10);
133 remove_filter('wp_import_post_meta', [$this, 'ai_image_replacement_metadata'], 10);
134 } else {
135 add_filter('templately_import_copy_attachment', [$this, 'copy_attachment_file'], 10, 4);
136 add_filter('wp_import_post_data_raw', [$this, 'ai_image_replacement_url'], 10, 2);
137 add_filter('wp_import_post_meta', [$this, 'ai_image_replacement_metadata'], 10, 3);
138 }
139 }
140
141 public function copy_attachment_file($return, $att_id, $dest_file, $upload_dir) {
142 // @todo check mapping url to new id
143
144 if (!empty($att_id)) {
145 // skip ai image replacement from local file
146 if ($this->is_ai_image($att_id)) {
147 return $return;
148 }
149
150 $file_name = basename($dest_file);
151 $path = $this->dir_path . 'attachments' . DIRECTORY_SEPARATOR;
152 $wp_filetype = wp_check_filetype($file_name);
153 $ext = $wp_filetype['ext'];
154
155 $source_path = "{$path}{$att_id}.{$ext}";
156
157 if (!file_exists($source_path)) {
158 return $return;
159 }
160
161 $move_new_file = copy($source_path, $dest_file);
162
163 if (!$move_new_file) {
164 return $return;
165 }
166
167 $wp_filetype = wp_check_filetype_and_ext($source_path, $file_name);
168
169 // Set correct file permissions.
170 $stat = stat(dirname($dest_file));
171 $perms = $stat['mode'] & 0000666;
172 chmod($dest_file, $perms);
173
174 return [
175 'file' => $dest_file,
176 'url' => $upload_dir['url'] . "/$file_name",
177 'type' => $wp_filetype['type'],
178 'error' => false,
179 ];
180 }
181
182
183 return $return;
184 }
185
186 public function is_ai_image($post_id) {
187 if (!empty($post_id) && !empty($this->data["image_mappings"][$post_id])) {
188 return true;
189 }
190 return false;
191 }
192
193 /**
194 * @param $post
195 * @param WPImport $wp_importer
196 * @return array
197 */
198 public function ai_image_replacement_url($post, $wp_importer) {
199 $post_id = $post['post_id'] ?? null;
200 if ($this->is_ai_image($post_id) && !empty($post['post_type']) && $post['post_type'] === 'attachment') {
201 $image_data = $this->data["image_mappings"][$post_id];
202
203 if (!empty($image_data["newData"]["original"])) {
204 $source = $image_data["source"];
205 if($source === 'upload'){
206 $new_id = $image_data["newData"]["id"];
207 $original_url = $image_data["originalUrl"];
208 $new_url = $image_data["newUrl"];
209
210 $wp_importer->update_post_meta( $new_id );
211
212 // Map pre-import ID to local ID.
213 $wp_importer->processed_posts[ (int) $post_id ] = (int) $new_id;
214
215 $wp_importer->set_url_map($original_url, $new_url);
216 $wp_importer->set_url_map($original_url, $new_url, true);
217
218 return $new_id;
219 }
220 else if($source ==='stock' && $image_data['newData']['provider'] == 'pexels'){
221 $post['original_attachment_url'] = $post['attachment_url'];
222 $post['guid'] = $image_data["newData"]["original"];
223 $post['attachment_url'] = $image_data["newData"]["original"];
224 }
225 else if($source === 'ai'){
226 // @todo: coming soon
227 }
228 }
229 }
230 return $post;
231 }
232
233 public function ai_image_replacement_metadata($postmeta, $post_id, $post) {
234
235 if ($this->is_ai_image($post_id)) {
236 $image_data = $this->data["image_mappings"][$post_id]["newData"] ?? [];
237 // alt. provider, photographer
238 if (!empty($image_data["alt"])) {
239 $postmeta[] = [
240 'key' => '_wp_attachment_image_alt',
241 'value' => $image_data["alt"],
242 ];
243 }
244 if (!empty($image_data["provider"])) {
245 $postmeta[] = [
246 'key' => '_templately_ai_image_provider',
247 'value' => $image_data["provider"],
248 ];
249 }
250 if (!empty($image_data["photographer"])) {
251 $postmeta[] = [
252 'key' => '_templately_ai_image_photographer',
253 'value' => $image_data["photographer"],
254 ];
255 }
256 }
257
258 return $postmeta;
259 }
260
261 public function get_processed() {
262 $processed = $this->processed ?? [];
263 $succeed = $processed['succeed'] ?? [];
264 $failed = $processed['failed'] ?? [];
265
266 return count($succeed) + count($failed);
267 }
268
269 public function post_log($post, $result) {
270 if (isset($post['post_type'])) {
271 if ($post['post_type'] !== 'attachment') {
272 return;
273 }
274
275 // need to assign to processed so log_message() can use get_processed() to calculate progress
276 // also bellow code used it to calculate progress
277 $this->processed = $result;
278
279 $type = $post['post_type'];
280 $title = $post['post_title'];
281 }
282
283 if (empty($type) || empty($title)) {
284 return;
285 }
286
287 $progress = $this->total > 0 ? ceil((100 * ($this->get_processed())) / $this->total) : 100;
288
289 $this->log($progress);
290 }
291
292 public function attachments_init() {
293 add_filter('pre_http_request', [$this, 'pre_http_request'], 10, 3);
294 add_filter('http_response', [$this, 'http_response'], 10, 3);
295 // attachment insert hooks
296 add_filter('wp_insert_attachment_data', [$this, 'before_insert_attachment'], 10, 2);
297 add_action('add_attachment', [$this, 'after_insert_attachment'], 10, 1);
298 add_filter('wp_update_attachment_metadata', [$this, 'wp_update_attachment_metadata'], 99999, 2);
299 }
300
301 public function pre_http_request($preempt, $parsed_args, $url) {
302 // error_log(print_r([$preempt, $parsed_args, $url], true));
303
304 $this->sse_log('attachments', 'Before downloading attachment: ' . esc_url($url), 1, 'eventLog');
305
306 return $preempt;
307 }
308
309 public function http_response($response, $parsed_args, $url) {
310 // error_log(print_r([$response, $parsed_args, $url], true));
311 $this->sse_log('attachments', 'After downloading attachment: ' . $url, 1, 'eventLog');
312 return $response;
313 }
314
315 /**
316 * Log before inserting attachment.
317 */
318 public function before_insert_attachment($data, $postarr) {
319 $this->sse_log('attachments', 'Before inserting attachment: ' . ($data['post_title'] ?? ''), 1, 'eventLog');
320 return $data;
321 }
322
323 /**
324 * Log after attachment is inserted.
325 */
326 public function after_insert_attachment($post_ID) {
327 $post = get_post($post_ID);
328 $this->sse_log('attachments', 'After inserting attachment: ' . ($post->post_title ?? ''), 1, 'eventLog');
329 }
330
331 public function wp_update_attachment_metadata($metadata, $attachment_id) {
332 $this->sse_log('attachments', 'Updated attachment metadata: ' . $attachment_id, 1, 'eventLog');
333 // $this->sse_message([
334 // "action" => "eventLog",
335 // "type" => "attachments",
336 // "progress" => 1,
337 // "message" => "Updated attachment metadata => " . $attachment_id,
338 // "backtrace" => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 30),
339 // ]);
340 return $metadata;
341 }
342 }
343