PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.0
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.0
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
metasync / includes / class-metasync-common.php

class-metasync-common.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.7.0, at includes/class-metasync-common.php

299 lines 9.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * The database operations for the 404 error monitor.
5 *
6 * @since 1.0.0
7 * @package Metasync
8 * @subpackage Metasync/404-monitor
9 * @author Engineering Team <[email protected]>
10 */
11 class Metasync_Common
12 {
13 /**
14 * Sanitize a array with urls and text field.
15 * @param $data Pass a Array.
16 */
17 public function sanitize_array($data)
18 {
19 // Ensure $data is always an array from the start
20 if (!is_array($data)) {
21 $data = (array) $data;
22 }
23
24 foreach ($data as $key => $value) {
25 if (is_array($value) && !empty($value)) {
26 $data[$key] = $this->sanitize_array($value);
27 } else {
28 if ($value) {
29 // Ensure $value is a string before processing
30 if (!is_string($value) && !is_numeric($value)) {
31 $value = (string) $value;
32 }
33
34 if (filter_var($value, FILTER_VALIDATE_URL)) {
35 $data[$key] = sanitize_url($value);
36 } else {
37 $data[$key] = sanitize_text_field($value);
38 }
39 }
40 }
41 }
42 return $data;
43 }
44
45 /**
46 * Get post by post name.
47 * @param $attachment_name Attachment name will be string.
48 */
49 public function get_attachment_by_name($attachment_name)
50 {
51 global $wpdb;
52 $post = $wpdb->get_row(
53 $wpdb->prepare(
54 "SELECT * FROM $wpdb->posts WHERE `post_name` = %s and `post_type` = 'attachment' LIMIT 1",
55 $attachment_name
56 )
57 );
58 // get_post(null) returns the global post — never a "not found" signal.
59 return $post ? get_post($post) : null;
60 }
61
62 public function get_permalink_from_url($url)
63 {
64 $parse_url = wp_parse_url($url);
65 $path = isset($parse_url['path']) ? $parse_url['path'] : '';
66 return end(array_diff(explode('/', $path), array('')));
67 }
68
69 /**
70 * Get file name from a URL.
71 * @param $url Valid URL as string.
72 */
73 public function get_file_name_by_url($url)
74 {
75 if (stripos($url, "https://cdn.midjourney.com/") !== false) {
76 return pathinfo(str_replace("/", "_", parse_url($url, PHP_URL_PATH) ?? ''), PATHINFO_FILENAME);
77 } elseif (stripos($url, "https://drive.google.com/") !== false) {
78 $parse_url = wp_parse_url($url);
79 // Modern permalinks are /file/d/<ID>/view — the ID lives in the path,
80 // and there is no query component at all on those URLs.
81 if (!empty($parse_url['path']) && preg_match('~/file/d/([^/]+)~', $parse_url['path'], $drive_matches)) {
82 return $drive_matches[1];
83 }
84 $args = [];
85 wp_parse_str($parse_url['query'] ?? '', $args);
86 return $args['id'] ?? null;
87 } else {
88 return pathinfo(parse_url($url, PHP_URL_PATH) ?? '', PATHINFO_FILENAME);
89 }
90 }
91
92 public function allowedDownloadSources($url)
93 {
94 return false;
95 $allowed_sources = array(
96 "https://storage.googleapis.com",
97 "https://drive.google.com"
98 );
99 foreach ($allowed_sources as $source) {
100 if (stripos($url, $source) !== false)
101 return true;
102 }
103 return false;
104 }
105
106 public function get_media_id_from_url($url) {
107 global $wpdb;
108
109 // Search for any attachment matching the URL
110 $query = $wpdb->prepare("
111 SELECT ID
112 FROM $wpdb->posts
113 WHERE post_type = 'attachment'
114 AND guid = %s
115 LIMIT 1
116 ", $url);
117
118 $attachment_id = $wpdb->get_var($query);
119
120 // Return the attachment ID if found, otherwise return false
121 return $attachment_id ? intval($attachment_id) : false;
122 }
123 /**
124 * Upload image to media library if URL is valid.
125 * @param $url Valid URL.
126 * add title to the image default value value is empty string
127 */
128 public function upload_image_by_url($url,$alt='',$title_text='')
129 {
130 require_once(ABSPATH . "/wp-load.php");
131 require_once(ABSPATH . "/wp-admin/includes/image.php");
132 require_once(ABSPATH . "/wp-admin/includes/file.php");
133 require_once(ABSPATH . "/wp-admin/includes/media.php");
134
135 $tmp = download_url($url);
136 if (is_wp_error($tmp)){
137 $attachment_id = $this->get_media_id_from_url($url);
138 error_log($attachment_id);
139 return $attachment_id;
140 }
141
142 $filename = $this->get_file_name_by_url($url);
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 }
149 // eliminating query params from file name
150 $filename = explode("?", $filename)[0];
151 $extension = pathinfo($url, PATHINFO_EXTENSION);
152
153 if (!$extension || strlen($extension) > 4) {
154 // fileinfo extension is not always enabled on shared hosts — guard the call
155 // and fall back to WordPress's extension-based detection.
156 if (function_exists('mime_content_type')) {
157 $mime = mime_content_type($tmp);
158 } else {
159 $filetype = wp_check_filetype(basename($url));
160 $mime = $filetype['type'] ?? false;
161 }
162 $mime = is_string($mime) ? sanitize_mime_type($mime) : false;
163
164 $mime_extensions = array(
165 'image/jpe' => 'jpe',
166 'image/jpg' => 'jpg',
167 'image/jpeg' => 'jpeg',
168 'image/gif' => 'gif',
169 'image/png' => 'png',
170 'image/webp' => 'webp'
171 );
172
173 if (isset($mime_extensions[$mime])) {
174 $extension = $mime_extensions[$mime];
175 } else {
176 // Safely delete temporary file if it exists
177 if (file_exists($tmp)) {
178 unlink($tmp);
179 }
180 return false;
181 }
182 }
183
184 $args = array(
185 'name' => "$filename.$extension",
186 /*
187 Generate a sanitized post_name by replacing double dashes with a single dash
188 and appending the file extension with a hyphen
189 */
190 'post_name' => str_replace('--', '-', $filename ?? '') ."-".$extension,
191 'tmp_name' => $tmp,
192 );
193
194 $get_attachment = $this->get_attachment_by_name($args['post_name']);
195
196 # remove if null logic check on 11 march 2025 for issue 264 and merge request 320
197 if (empty($get_attachment)) {
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 unlink($tmp);
205 }
206 return false;
207 }
208 update_post_meta($attachment_id, '_wp_attachment_image_alt', $alt);
209 // check if the title is empty or not if it's has title update the title
210 if($title_text !== ''){
211 wp_update_post(
212 array (
213 'ID' => $attachment_id,
214 'post_title' => $title_text
215 )
216 );
217 }
218 $attach_data = wp_generate_attachment_metadata(
219 $attachment_id,
220 wp_get_original_image_path($attachment_id)
221 );
222 wp_update_attachment_metadata($attachment_id, $attach_data);
223
224 // Safely delete temporary file if it exists
225 if (file_exists($tmp)) {
226 unlink($tmp);
227 }
228
229 return $attachment_id;
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 unlink($tmp);
256 }
257
258 // check if the title attribute is set on the image tag and then update the title
259 if($title_text !== ''){
260 wp_update_post(
261 array (
262 'ID' => $get_attachment->ID,
263 'post_title' => $title_text
264 )
265 );
266 }
267 // update the alt attribute in the image
268 update_post_meta($get_attachment->ID, '_wp_attachment_image_alt', $alt);
269 return $get_attachment->ID;
270 }
271 }
272 /**
273 * Check if Gutenberg is enabled as the default page editor
274 */
275 protected function is_gutenberg_enabled() {
276 $current_screen = get_current_screen();
277 return method_exists($current_screen, 'is_block_editor') && $current_screen->is_block_editor();
278 }
279 /**
280 * Check if Elementor is active
281 */
282 protected function is_elementor_active() {
283 return class_exists('Elementor\Plugin') && \Elementor\Plugin::$instance->preview->is_preview_mode();
284 }
285 /**
286 * Check if Gutenberg is enabled or Elementor is active
287 */
288 public static function check_default_page_editor() {
289 $instance = new self();
290 if ($instance->is_gutenberg_enabled()) {
291 return 'gutenberg';
292 } elseif ($instance->is_elementor_active()) {
293 return 'elementor';
294 } else {
295 return 'neither';
296 }
297 }
298 }
299