PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / trunk
Search Atlas SEO – OTTO AI SEO Automation for WordPress vtrunk
2.7.1 2.7.2 2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 All 141 releases
← All changes | includes/class-metasync-common.php +62 -17 2.6.17 → trunk View file →
@@ -48,15 +48,16 @@
48 48 */
49 49 public function get_attachment_by_name($attachment_name)
50 50 {
51 51 global $wpdb;
52 - $post = $wpdb->get_row(
52 + $post = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- attachment lookup by guid/post_name — guid search has no WordPress API
53 53 $wpdb->prepare(
54 54 "SELECT * FROM $wpdb->posts WHERE `post_name` = %s and `post_type` = 'attachment' LIMIT 1",
55 55 $attachment_name
56 56 )
57 57 );
58 - return get_post($post);
58 + // get_post(null) returns the global post — never a "not found" signal.
59 + return $post ? get_post($post) : null;
59 60 }
60 61
61 62 public function get_permalink_from_url($url)
62 63 {
@@ -71,16 +72,23 @@
71 72 */
72 73 public function get_file_name_by_url($url)
73 74 {
74 75 if (stripos($url, "https://cdn.midjourney.com/") !== false) {
75 - return pathinfo(str_replace("/", "_", parse_url($url, PHP_URL_PATH) ?? ''), PATHINFO_FILENAME);
76 + $path = wp_parse_url($url, PHP_URL_PATH);
77 + return pathinfo(false === $path ? '' : str_replace('/', '_', $path), PATHINFO_FILENAME);
76 78 } elseif (stripos($url, "https://drive.google.com/") !== false) {
77 79 $parse_url = wp_parse_url($url);
80 + // Modern permalinks are /file/d/<ID>/view — the ID lives in the path,
81 + // and there is no query component at all on those URLs.
82 + if (!empty($parse_url['path']) && preg_match('~/file/d/([^/]+)~', $parse_url['path'], $drive_matches)) {
83 + return $drive_matches[1];
84 + }
78 85 $args = [];
79 - wp_parse_str($parse_url['query'], $args);
80 - return $args['id'];
86 + wp_parse_str($parse_url['query'] ?? '', $args);
87 + return $args['id'] ?? null;
81 88 } else {
82 - return pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_FILENAME);
89 + $path = wp_parse_url($url, PHP_URL_PATH);
90 + return pathinfo(false === $path ? '' : $path, PATHINFO_FILENAME);
83 91 }
84 92 }
85 93
86 94 public function allowedDownloadSources($url)
@@ -100,18 +108,17 @@
100 108 public function get_media_id_from_url($url) {
101 109 global $wpdb;
102 110
103 111 // Search for any attachment matching the URL
104 - $query = $wpdb->prepare("
112 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- attachment lookup by guid/post_name — guid search has no WordPress API
113 + $attachment_id = $wpdb->get_var($wpdb->prepare("
105 114 SELECT ID
106 - FROM $wpdb->posts
115 + FROM {$wpdb->posts}
107 116 WHERE post_type = 'attachment'
108 117 AND guid = %s
109 118 LIMIT 1
110 - ", $url);
119 + ", $url));
111 120
112 - $attachment_id = $wpdb->get_var($query);
113 -
114 121 // Return the attachment ID if found, otherwise return false
115 122 return $attachment_id ? intval($attachment_id) : false;
116 123 }
117 124 /**
@@ -128,14 +135,18 @@
128 135
129 136 $tmp = download_url($url);
130 137 if (is_wp_error($tmp)){
131 138 $attachment_id = $this->get_media_id_from_url($url);
132 - error_log($attachment_id);
133 139 return $attachment_id;
134 140 }
135 141
136 142 $filename = $this->get_file_name_by_url($url);
137 143 // $filename = pathinfo($url, PATHINFO_FILENAME);
144 + // A null/empty name degenerates the post_name to "-<ext>", which collides
145 + // across unrelated images — fall back to the URL basename instead.
146 + if (null === $filename || '' === $filename) {
147 + $filename = pathinfo(wp_parse_url($url, PHP_URL_PATH) ?? '', PATHINFO_FILENAME);
148 + }
138 149 // eliminating query params from file name
139 150 $filename = explode("?", $filename)[0];
140 151 $extension = pathinfo($url, PATHINFO_EXTENSION);
141 152
@@ -163,9 +174,9 @@
163 174 $extension = $mime_extensions[$mime];
164 175 } else {
165 176 // Safely delete temporary file if it exists
166 177 if (file_exists($tmp)) {
167 - unlink($tmp);
178 + wp_delete_file($tmp);
168 179 }
169 180 return false;
170 181 }
171 182 }
@@ -181,12 +192,20 @@
181 192 );
182 193
183 194 $get_attachment = $this->get_attachment_by_name($args['post_name']);
184 195
185 -
186 196 # remove if null logic check on 11 march 2025 for issue 264 and merge request 320
187 197 if (empty($get_attachment)) {
188 198 $attachment_id = media_handle_sideload($args, 0, $args['name']);
199 + // The sideload can fail (invalid remote file, upload disallowed) — check
200 + // before the result is used as a post ID anywhere below.
201 + if (is_wp_error($attachment_id)) {
202 + // Safely delete temporary file if it exists
203 + if (file_exists($tmp)) {
204 + wp_delete_file($tmp);
205 + }
206 + return false;
207 + }
189 208 update_post_meta($attachment_id, '_wp_attachment_image_alt', $alt);
190 209 // check if the title is empty or not if it's has title update the title
191 210 if($title_text !== ''){
192 211 wp_update_post(
@@ -200,17 +219,43 @@
200 219 $attachment_id,
201 220 wp_get_original_image_path($attachment_id)
202 221 );
203 222 wp_update_attachment_metadata($attachment_id, $attach_data);
204 -
223 +
205 224 // Safely delete temporary file if it exists
206 225 if (file_exists($tmp)) {
207 - unlink($tmp);
226 + wp_delete_file($tmp);
208 227 }
209 228
210 - if (is_wp_error($attachment_id)) return false;
211 229 return $attachment_id;
212 230 } else {
231 + // An attachment record can outlive its file (e.g. the file was
232 + // deleted from disk outside WordPress). Since we already have a
233 + // fresh download, restore it into the existing attachment so its
234 + // URL stops 404ing — reusing the record keeps post references
235 + // intact and avoids piling up duplicate attachments.
236 + $existing_file = get_attached_file($get_attachment->ID);
237 + if (empty($existing_file) || !file_exists($existing_file)) {
238 + // wp_handle_sideload() takes $file by reference, so the
239 + // argument must be a variable — a literal array here is a
240 + // runtime fatal that kills the whole sync request.
241 + $file_array = array(
242 + 'name' => $args['name'],
243 + 'tmp_name' => $tmp,
244 + );
245 + $upload = wp_handle_sideload($file_array, array('test_form' => false));
246 + if (empty($upload['error']) && !empty($upload['file'])) {
247 + update_attached_file($get_attachment->ID, $upload['file']);
248 + $attach_data = wp_generate_attachment_metadata($get_attachment->ID, $upload['file']);
249 + wp_update_attachment_metadata($get_attachment->ID, $attach_data);
250 + }
251 + }
252 +
253 + // Delete the temporary file unless the sideload above moved it
254 + if (file_exists($tmp)) {
255 + wp_delete_file($tmp);
256 + }
257 +
213 258 // check if the title attribute is set on the image tag and then update the title
214 259 if($title_text !== ''){
215 260 wp_update_post(
216 261 array (