PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.5.2
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.5.2
3.8.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 All 112 releases
← All changes | includes/Core/Importer/WPImport.php +10 -98 3.7.2 → 3.5.2 View file →
@@ -119,10 +119,8 @@
119 119 private $menu_item_orphans = [];
120 120 private $mapped_terms_slug = [];
121 121
122 122 private $fetch_attachments = false;
123 - private $attachment_timeout = 300;
124 - private $attachment_retry_count = 3;
125 123 private $featured_images = [];
126 124
127 125 /**
128 126 * @var array[] [meta_key => meta_value] Meta value that should be set for every imported post.
@@ -1144,30 +1142,14 @@
1144 1142
1145 1143 if($saved_image = $this->get_saved_image($url)){
1146 1144 // $this->url_remap[ $url ] = wp_get_attachment_url( $saved_image );
1147 1145 // $this->url_remap[ $this->remove_extension($url) ] = $this->remove_extension(wp_get_attachment_url( $saved_image ));
1148 - $upload_url = set_url_scheme( wp_get_attachment_url( $saved_image ) );
1146 + $upload_url = wp_get_attachment_url( $saved_image );
1149 1147 $this->set_url_map($url, $upload_url, true);
1150 1148
1151 - // AI image replacement: the imported content still carries the ORIGINAL
1152 - // demo URL, so it must be remapped onto the replacement image here too.
1153 - // The fresh-upload branch below does this, but when the replacement
1154 - // image was already imported (a re-import, or the same stock photo
1155 - // reused) we land here instead — without the map the demo URL survives
1156 - // finalize and the pack's original images are silently kept.
1157 - if(!empty($post['original_attachment_url'])){
1158 - $this->set_url_map($post['original_attachment_url'], $upload_url, true);
1159 -
1160 - $original_hash = sha1( $post['original_attachment_url'] );
1161 -
1162 - // A stale hash from a previous import can still point the demo URL at
1163 - // the old, unreplaced attachment — re-point it at the replacement.
1164 - if( (int) $this->get_saved_image($post['original_attachment_url']) !== (int) $saved_image ){
1165 - $hash_meta_id = add_post_meta( $saved_image, '_elementor_source_image_hash', $original_hash );
1166 - add_post_meta( $saved_image, '_templately_image_hash_meta_id', $hash_meta_id );
1167 - }
1168 -
1169 - self::$_replace_image_ids[ $original_hash ] = (int) $saved_image;
1149 + if(!empty($post['original_attachment_url']) && !$this->get_saved_image($post['original_attachment_url'])){
1150 + add_post_meta( $saved_image, '_elementor_source_image_hash', sha1( $post['original_attachment_url'] ) );
1151 + self::$_replace_image_ids[ sha1( $post['original_attachment_url'] ) ] = $post_id;
1170 1152 }
1171 1153
1172 1154 $full_size_path = get_attached_file($saved_image);
1173 1155 $metadata = wp_get_attachment_metadata($saved_image);
@@ -1194,22 +1176,9 @@
1194 1176 return new WP_Error( 'upload_dir_error', $upload_dir['error'] );
1195 1177 }
1196 1178
1197 1179 // Move the file to the uploads dir.
1198 - //
1199 - // The attachment url is attacker-reachable — a cloud template can point an
1200 - // image anywhere — so the url-derived name is sanitized, and an extension
1201 - // WordPress does not recognise as an uploadable type is dropped rather than
1202 - // carried into the destination path. fetch_remote_file() re-derives the
1203 - // extension from the response and validates it before writing, so dropping
1204 - // an unusable one here costs nothing.
1205 - $file_name = sanitize_file_name( basename( parse_url( $url, PHP_URL_PATH ) ) );
1206 - if ( pathinfo( $file_name, PATHINFO_EXTENSION ) ) {
1207 - $url_filetype = wp_check_filetype( $file_name );
1208 - if ( empty( $url_filetype['type'] ) ) {
1209 - $file_name = pathinfo( $file_name, PATHINFO_FILENAME );
1210 - }
1211 - }
1180 + $file_name = basename( parse_url( $url, PHP_URL_PATH ) );
1212 1181 $file_name = wp_unique_filename( $upload_dir['path'], $file_name );
1213 1182 $dest_file = $upload_dir['path'] . "/$file_name";
1214 1183 $start = microtime(true);
1215 1184
@@ -1217,13 +1186,8 @@
1217 1186 if ( null === $upload ) {
1218 1187 $upload = $this->fetch_remote_file( $url, $dest_file, $upload_dir );
1219 1188 }
1220 1189
1221 - // Normalize URL scheme to match the current site scheme (fixes HTTP URLs on HTTPS multisites).
1222 - if ( ! is_wp_error( $upload ) && ! empty( $upload['url'] ) ) {
1223 - $upload['url'] = set_url_scheme( $upload['url'] );
1224 - }
1225 -
1226 1190 $end = microtime(true);
1227 1191 $duration = $end - $start;
1228 1192 error_log('Duration: ' . $duration);
1229 1193
@@ -1301,18 +1265,11 @@
1301 1265 }
1302 1266
1303 1267 private function remove_extension($url) {
1304 1268 $parts = pathinfo($url);
1305 - // pathinfo() omits 'extension' for a dotless name, and 'dirname' for an
1306 - // empty one. Remote attachment urls are not obliged to carry an extension
1307 - // (`.../media/1234`), and the url of an attachment that has since been
1308 - // deleted resolves to ''.
1309 - $dirname = isset( $parts['dirname'] ) ? $parts['dirname'] : '';
1310 - $basename = isset( $parts['basename'] ) ? $parts['basename'] : '';
1311 - $extension = isset( $parts['extension'] ) ? $parts['extension'] : '';
1312 - $name = '' === $extension ? $basename : basename($basename, ".{$extension}"); // PATHINFO_FILENAME in PHP 5.2
1269 + $name = basename($parts['basename'], ".{$parts['extension']}"); // PATHINFO_FILENAME in PHP 5.2
1313 1270
1314 - return $dirname . '/' . $name;
1271 + return $parts['dirname'] . '/' . $name;
1315 1272 }
1316 1273
1317 1274 public function set_url_map($original_url, $new_url, $remove_extension = false){
1318 1275 $this->url_remap[ $original_url ] = $new_url;
@@ -1346,13 +1303,13 @@
1346 1303 }
1347 1304
1348 1305 // Fetch the remote URL and write it to the placeholder file.
1349 1306 $attempt = 0;
1350 - $retry_count = $this->attachment_retry_count;
1307 + $retry_count = 3;
1351 1308 $remote_response = null;
1352 1309 do {
1353 1310 $remote_response = wp_safe_remote_get( $url, [
1354 - 'timeout' => $this->attachment_timeout,
1311 + 'timeout' => 300,
1355 1312 'stream' => true,
1356 1313 'filename' => $tmp_file_name,
1357 1314 'headers' => [
1358 1315 'Accept-Encoding' => 'identity',
@@ -1407,18 +1364,12 @@
1407 1364
1408 1365 return new WP_Error( 'import_file_error', sprintf( esc_html__( 'Remote file is too large, limit is %s', 'elementor' ), size_format( $max_size ) ) );
1409 1366 }
1410 1367
1411 - // Override file name with Content-Disposition header value. The header is
1412 - // whatever the remote chose to send, so it is sanitized before it is allowed
1413 - // anywhere near a path: sanitize_file_name() strips directory separators and
1414 - // neutralizes the inner extension of a double-extension name.
1368 + // Override file name with Content-Disposition header value.
1415 1369 if ( ! empty( $headers['content-disposition'] ) ) {
1416 1370 $file_name_from_disposition = self::get_filename_from_disposition( (array) $headers['content-disposition'] );
1417 1371 if ( $file_name_from_disposition ) {
1418 - $file_name_from_disposition = sanitize_file_name( $file_name_from_disposition );
1419 - }
1420 - if ( $file_name_from_disposition ) {
1421 1372 $file_name = $file_name_from_disposition;
1422 1373 }
1423 1374 }
1424 1375
@@ -1442,29 +1393,11 @@
1442 1393 $file_name = $proper_filename;
1443 1394 }
1444 1395
1445 1396 if ( ( ! $type || ! $ext ) && ! current_user_can( 'unfiltered_upload' ) ) {
1446 - @unlink( $tmp_file_name );
1447 -
1448 1397 return new WP_Error( 'import_file_error', esc_html__( 'Sorry, this file type is not permitted for security reasons.', 'elementor' ) );
1449 1398 }
1450 1399
1451 - // The type check above ran against $file_name (Content-Disposition), but the
1452 - // write lands on $new_file, whose name came from the request url path. When
1453 - // those two extensions disagree the check guarantees nothing about what is
1454 - // actually written — an image/gif verdict on `ok.gif` would let the bytes go
1455 - // to a `.php` destination. Re-derive the destination from the validated name
1456 - // so the two can never diverge. (CVE-2026-18438)
1457 - if ( $ext && strtolower( pathinfo( $new_file, PATHINFO_EXTENSION ) ) !== strtolower( $ext ) ) {
1458 - $file_name = wp_unique_filename( $uploads['path'], $file_name );
1459 - $new_file = $uploads['path'] . "/$file_name";
1460 - }
1461 -
1462 - // Whatever the branch above decided, the reported name must describe the file
1463 - // that is actually on disk — the remapped url in the imported content is built
1464 - // from it.
1465 - $file_name = wp_basename( $new_file );
1466 -
1467 1400 $move_new_file = copy( $tmp_file_name, $new_file );
1468 1401
1469 1402 if ( ! $move_new_file ) {
1470 1403 @unlink( $tmp_file_name );
@@ -1514,26 +1447,13 @@
1514 1447 if ( isset( self::$_replace_image_ids[ $hash ] ) ) {
1515 1448 return self::$_replace_image_ids[ $hash ];
1516 1449 }
1517 1450
1518 - // Newest row wins. A URL can be claimed by more than one attachment: an
1519 - // AI/customizer image replacement registers the ORIGINAL demo URL against
1520 - // the REPLACEMENT attachment (see process_attachment), while a previous
1521 - // plain import of the same pack already claimed that URL for the original
1522 - // image — and that older row is never cleaned up (clear_old_el_cache only
1523 - // tracks replacement hashes). Without the ordering the stale original wins
1524 - // and the replacement is silently ignored on every re-import.
1525 - //
1526 - // The static cache above short-circuits this, but the import is split
1527 - // across many requests (each SSE `continue` is a fresh PHP process), so
1528 - // the DB is the real source of truth for anything set in an earlier step.
1529 1451 $post_id = $wpdb->get_var(
1530 1452 $wpdb->prepare(
1531 1453 'SELECT `post_id` FROM `' . $wpdb->postmeta . '`
1532 1454 WHERE `meta_key` = \'_elementor_source_image_hash\'
1533 1455 AND `meta_value` = %s
1534 - ORDER BY `meta_id` DESC
1535 - LIMIT 1
1536 1456 ;',
1537 1457 $hash
1538 1458 )
1539 1459 );
@@ -1855,16 +1775,8 @@
1855 1775 }
1856 1776
1857 1777 if ( ! empty( $this->args['fetch_attachments'] ) ) {
1858 1778 $this->fetch_attachments = true;
1859 - }
1860 -
1861 - if ( isset( $this->args['attachment_timeout'] ) && is_numeric( $this->args['attachment_timeout'] ) ) {
1862 - $this->attachment_timeout = max( 1, (int) $this->args['attachment_timeout'] );
1863 - }
1864 -
1865 - if ( isset( $this->args['attachment_retries'] ) && is_numeric( $this->args['attachment_retries'] ) ) {
1866 - $this->attachment_retry_count = max( 1, (int) $this->args['attachment_retries'] + 1 );
1867 1779 }
1868 1780
1869 1781 if ( isset( $this->args['posts'] ) && is_array( $this->args['posts'] ) ) {
1870 1782 $this->processed_posts = $this->args['posts'];