From 1ec3a40bb43e3731a5f3a8650b412e8eb243cdac Mon Sep 17 00:00:00 2001 From: Thomas Zwirner Date: Sat, 7 Dec 2024 16:14:16 +0100 Subject: [PATCH 1/8] do not download not local saved files --- app/ExternalFiles/File.php | 6 ++++++ app/ExternalFiles/Protocol_Base.php | 25 +++++++++++++++++++++++++ app/ExternalFiles/Protocols/Http.php | 25 +++++++++++++++++++------ app/ThirdParty/Exmage.php | 3 +++ changelog.md | 10 ++++++++++ 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/app/ExternalFiles/File.php b/app/ExternalFiles/File.php index c7e467a..ac8e76b 100644 --- a/app/ExternalFiles/File.php +++ b/app/ExternalFiles/File.php @@ -395,6 +395,9 @@ public function add_to_cache(): void { return; } + // force the local check as we need the file for the cache. + $protocol_handler_obj->force_local_check(); + /** * Get info about the external file. */ @@ -579,6 +582,9 @@ public function switch_to_local(): bool { // prevent duplicate check for this file. add_filter( 'eml_duplicate_check', array( $this, 'prevent_duplicate_check' ), 10, 2 ); + // force the local check as we need the file local. + $protocol_handler_obj->force_local_check(); + // get external file infos. $file_data = $protocol_handler_obj->get_url_infos(); diff --git a/app/ExternalFiles/Protocol_Base.php b/app/ExternalFiles/Protocol_Base.php index 8323ff0..b7f8067 100644 --- a/app/ExternalFiles/Protocol_Base.php +++ b/app/ExternalFiles/Protocol_Base.php @@ -52,6 +52,13 @@ class Protocol_Base { */ private bool $queue_mode = false; + /** + * Marker to force local check of file. + * + * @var bool + */ + private bool $force_local_check = false; + /** * Constructor, not used as this a Singleton object. * @@ -71,6 +78,24 @@ public function get_url(): string { } /** + * Set to force local check of this file. + * + * @return void + */ + public function force_local_check(): void { + $this->force_local_check = true; + } + + /** + * Return whether local check of the file is forced. + * + * @return bool + */ + protected function is_local_check_forced(): bool { + return $this->force_local_check; + } + + /** * Return the tcp protocols of this protocol object. * * @return array diff --git a/app/ExternalFiles/Protocols/Http.php b/app/ExternalFiles/Protocols/Http.php index 5e55a84..2f5e262 100644 --- a/app/ExternalFiles/Protocols/Http.php +++ b/app/ExternalFiles/Protocols/Http.php @@ -10,7 +10,6 @@ // prevent direct access. defined( 'ABSPATH' ) || exit; -use ExternalFilesInMediaLibrary\ExternalFiles\File_Types; use ExternalFilesInMediaLibrary\ExternalFiles\Files; use ExternalFilesInMediaLibrary\ExternalFiles\Protocol_Base; use ExternalFilesInMediaLibrary\ExternalFiles\Queue; @@ -222,7 +221,7 @@ public function get_url_infos(): array { if ( ! empty( $results ) ) { // bail if URL is already in media library. if ( $this->check_for_duplicate( $this->get_url() ) ) { - Log::get_instance()->create( __( 'Given URL already exist in media library.', 'external-files-in-media-library' ), esc_url( $file_url ), 'error' ); + Log::get_instance()->create( __( 'Given URL already exist in media library.', 'external-files-in-media-library' ), esc_url( $this->get_url() ), 'error' ); // return empty array to prevent import of this URL. return array(); @@ -464,6 +463,7 @@ public function get_url_info( string $url ): array { 'local' => false, 'url' => $url, 'last-modified' => '', + 'tmp-file' => '' ); // set file size in result-array. @@ -492,10 +492,23 @@ public function get_url_info( string $url ): array { } } - // download file as temporary file for further analyses. - add_filter( 'http_request_args', array( $this, 'set_download_url_header' ) ); - $results['tmp-file'] = download_url( $url ); - remove_filter( 'http_request_args', array( $this, 'set_download_url_header' ) ); + // download file as temporary file for further analyses if it should be saved local or local check should be forced. + if( $results['local'] || $this->is_local_check_forced() ) { + // log event. + Log::get_instance()->create( __( 'File will be downloaded. This may take some time.', 'external-files-in-media-library' ), esc_url( $this->get_url() ), 'info', 2 ); + + // set filter for the request. + add_filter( 'http_request_args', array( $this, 'set_download_url_header' ) ); + + // download the file. + $results['tmp-file'] = download_url( $url ); + + // remove the filter for the request, + remove_filter( 'http_request_args', array( $this, 'set_download_url_header' ) ); + + // log event. + Log::get_instance()->create( __( 'File has been downloaded.', 'external-files-in-media-library' ), esc_url( $this->get_url() ), 'info', 2 ); + } // bail if error occurred. if ( is_wp_error( $results['tmp-file'] ) ) { diff --git a/app/ThirdParty/Exmage.php b/app/ThirdParty/Exmage.php index eb359c5..cd12521 100644 --- a/app/ThirdParty/Exmage.php +++ b/app/ThirdParty/Exmage.php @@ -229,6 +229,9 @@ public function migrate(): void { // check and set availability. $external_files_obj->set_availability( $protocol_handler->check_availability( $url ) ); + // force local check of this file. + $protocol_handler->force_local_check(); + // get the file infos. $file_data = $protocol_handler->get_url_info( $url ); diff --git a/changelog.md b/changelog.md index 05fa5a4..582762a 100644 --- a/changelog.md +++ b/changelog.md @@ -2,15 +2,25 @@ ## [Unreleased] +### Added + - Added possibility to add YouTube- and Vimeo-videos as external files - Added possibility to import Youtube-Channel-Videos as external files via YouTube API - Added more hooks + +### Changed + - Introduced Services to platforms which host files (like Imgur or GoogleDrive) +- Does not download files via http protocol which should not be hosted locally - Optimized updating or installing log- and queue-tables during plugin update - Updated dependencies - Moved changelog from readme.txt in GitHub-repository + +### Fixed + - Fixed potential error with import of YouTube videos - Fixed output of hint it file is not available +- Fixed potential error if URL is already on media library ## [2.0.2] - 2024-11-23 From d8707212d8ea59de7b15c22d94149d57810d8921 Mon Sep 17 00:00:00 2001 From: Thomas Zwirner Date: Sat, 7 Dec 2024 22:47:48 +0100 Subject: [PATCH 2/8] prevent download of not local saved files --- app/ExternalFiles/File.php | 119 +++++++++++++++++++------ app/ExternalFiles/File_Types/Audio.php | 20 ----- app/ExternalFiles/File_Types/Image.php | 38 ++++++-- app/ExternalFiles/File_Types/Video.php | 20 ----- app/ExternalFiles/File_Types_Base.php | 4 +- app/ExternalFiles/Files.php | 67 +++----------- app/ExternalFiles/Protocol_Base.php | 69 ++++++++------ app/ExternalFiles/Protocols/File.php | 16 +--- app/ExternalFiles/Protocols/Ftp.php | 13 +-- app/ExternalFiles/Protocols/Http.php | 88 +++++++++--------- app/ExternalFiles/Protocols/Sftp.php | 22 +---- app/Plugin/Cli.php | 2 +- app/Plugin/Tables/Queue.php | 2 +- app/ThirdParty/Exmage.php | 18 +--- changelog.md | 1 + 15 files changed, 236 insertions(+), 263 deletions(-) diff --git a/app/ExternalFiles/File.php b/app/ExternalFiles/File.php index ac8e76b..c4b024c 100644 --- a/app/ExternalFiles/File.php +++ b/app/ExternalFiles/File.php @@ -199,12 +199,19 @@ public function set_mime_type( string $mime_type ): void { ); wp_update_post( $query ); - // Update the meta-field for mime_type. + // get the meta-data for this attachment. $meta = wp_get_attachment_metadata( $this->get_id(), true ); - if ( is_array( $meta ) ) { - $meta['mime_type'] = $mime_type; - wp_update_attachment_metadata( $this->get_id(), $meta ); + + // if no meta-data are set, create an array for them. + if( ! is_array( $meta ) ) { + $meta = array(); } + + // set the mime type. + $meta['mime_type'] = $mime_type; + + // save the updated meta-data. + wp_update_attachment_metadata( $this->get_id(), $meta ); } /** @@ -293,14 +300,21 @@ public function get_filesize(): int { * @return void */ public function set_filesize( int $file_size ): void { - // Update the thumbnail filename. + // get the meta-data for this attachment. $meta = wp_get_attachment_metadata( $this->get_id(), true ); - if ( is_array( $meta ) ) { - $meta['filesize'] = $file_size; - wp_update_attachment_metadata( $this->get_id(), $meta ); + + // if no meta-data are set, create an array for them. + if( ! is_array( $meta ) ) { + $meta = array(); } - // set in object. + // add the file size. + $meta['filesize'] = $file_size; + + // update the meta data. + wp_update_attachment_metadata( $this->get_id(), $meta ); + + // set the file size in object. $this->filesize = $file_size; } @@ -379,6 +393,11 @@ public function add_to_cache(): void { return; } + // bail if file is locally saved. + if( $this->is_locally_saved() ) { + return; + } + global $wp_filesystem; require_once ABSPATH . 'wp-admin/includes/file.php'; WP_Filesystem(); @@ -386,7 +405,7 @@ public function add_to_cache(): void { /** * Get the handler for this URL depending on its protocol. */ - $protocol_handler_obj = Protocols::get_instance()->get_protocol_object_for_external_file( $this ); + $protocol_handler_obj = $this->get_protocol_handler_obj(); /** * Do nothing if URL is using a not supported tcp protocol. @@ -395,9 +414,6 @@ public function add_to_cache(): void { return; } - // force the local check as we need the file for the cache. - $protocol_handler_obj->force_local_check(); - /** * Get info about the external file. */ @@ -414,8 +430,16 @@ public function add_to_cache(): void { return; } + // get temp file. + $tmp_file = $protocol_handler_obj->get_temp_file( $this->get_url( true )); + + // bail if temp file could not be loaded. + if( ! $tmp_file ) { + return; + } + // get the body. - $body = $wp_filesystem->get_contents( $file_data['tmp-file'] ); + $body = $wp_filesystem->get_contents( $tmp_file ); // check mime-type of the binary-data and compare it with header-data. $binary_data_info = new finfo( FILEINFO_MIME_TYPE ); @@ -424,6 +448,9 @@ public function add_to_cache(): void { return; } + // delete the temporary file. + $protocol_handler_obj->cleanup_temp_file( $tmp_file ); + // set path incl. md5-filename and extension. $path = $this->get_cache_file(); @@ -577,19 +604,23 @@ public function switch_to_local(): bool { global $wp_filesystem; // get the handler for this URL depending on its protocol. - $protocol_handler_obj = Protocols::get_instance()->get_protocol_object_for_external_file( $this ); + $protocol_handler_obj = $this->get_protocol_handler_obj(); - // prevent duplicate check for this file. - add_filter( 'eml_duplicate_check', array( $this, 'prevent_duplicate_check' ), 10, 2 ); + // bail if no protocol handler could be loaded. + if( ! $protocol_handler_obj ) { + return false; + } - // force the local check as we need the file local. - $protocol_handler_obj->force_local_check(); + // prevent duplicate check for this file. + add_filter( 'eml_duplicate_check', array( $this, 'prevent_checks' ), 10, 2 ); + add_filter( 'eml_locale_file_check', array( $this, 'prevent_checks' ), 10, 2 ); // get external file infos. $file_data = $protocol_handler_obj->get_url_infos(); // remove prevent duplicate check for this file. - remove_filter( 'eml_duplicate_check', array( $this, 'prevent_duplicate_check' ) ); + remove_filter( 'eml_duplicate_check', array( $this, 'prevent_checks' ) ); + remove_filter( 'eml_locale_file_check', array( $this, 'prevent_checks' ) ); // bail if no file data could be loaded. if ( empty( $file_data ) ) { @@ -600,7 +631,7 @@ public function switch_to_local(): bool { $array = array( 'name' => $this->get_title(), 'type' => $file_data[0]['mime-type'], - 'tmp_name' => $file_data[0]['tmp-file'], + 'tmp_name' => '', 'error' => 0, 'size' => $file_data[0]['filesize'], 'url' => $this->get_url(), @@ -621,6 +652,17 @@ public function switch_to_local(): bool { 'post_author' => $user_id, ); + // get temp file. + $tmp_file = $protocol_handler_obj->get_temp_file( $this->get_url() ); + + // bail if no temp file could be loaded. + if( ! $tmp_file ) { + return false; + } + + // set temp file for side load. + $array['tmp_name'] = $tmp_file; + // upload the external file. $attachment_id = media_handle_sideload( $array, 0, null, $post_array ); @@ -629,8 +671,16 @@ public function switch_to_local(): bool { return false; } + // get meta-data from original. + $meta_data = wp_get_attachment_metadata( $attachment_id ); + + // create array for meta-data if it is not one. + if( ! is_array( $meta_data ) ) { + $meta_data = array(); + } + // copy the relevant settings of the new uploaded file to the original. - wp_update_attachment_metadata( $this->get_id(), wp_get_attachment_metadata( $attachment_id ) ); + wp_update_attachment_metadata( $this->get_id(), $meta_data ); // get the new local url. $local_url = wp_get_attachment_url( $attachment_id ); @@ -700,7 +750,7 @@ public function switch_to_external(): bool { } // get protocol object for this file. - $protocol_handler_obj = Protocols::get_instance()->get_protocol_object_for_external_file( $this ); + $protocol_handler_obj = $this->get_protocol_handler_obj(); // bail if protocol does not support external hosting. if ( $protocol_handler_obj->should_be_saved_local() ) { @@ -724,19 +774,20 @@ public function switch_to_external(): bool { } /** - * Prevent duplicate check. + * Prevent check (for duplicate or local file). * * @param bool $return_value The resulting value. * @param string $url The used URL. * * @return bool */ - public function prevent_duplicate_check( bool $return_value, string $url ): bool { + public function prevent_checks( bool $return_value, string $url ): bool { // bail if URL is not our URL. if ( $url !== $this->get_url( true ) ) { return $return_value; } + // return true to prevent the check. return true; } @@ -787,4 +838,22 @@ public function delete_thumbs(): void { public function get_file_type_obj(): File_Types_Base { return File_Types::get_instance()->get_type_object_for_file_obj( $this ); } + + /** + * Set the file meta-data. + * + * @return void + */ + public function set_metadata(): void { + $this->get_file_type_obj()->set_metadata(); + } + + /** + * Return the protocol handler of this file. + * + * @return Protocol_Base|false + */ + public function get_protocol_handler_obj(): Protocol_Base|false { + return Protocols::get_instance()->get_protocol_object_for_external_file( $this ); + } } diff --git a/app/ExternalFiles/File_Types/Audio.php b/app/ExternalFiles/File_Types/Audio.php index 49ac047..d55d62a 100644 --- a/app/ExternalFiles/File_Types/Audio.php +++ b/app/ExternalFiles/File_Types/Audio.php @@ -73,26 +73,6 @@ public function get_proxied_file(): void { exit; } - /** - * Set meta-data for the file by given file data. - * - * @param array $file_data The file data. - * - * @return void - */ - public function set_metadata( array $file_data ): void { - // get the file object. - $external_file_obj = $this->get_file(); - - // collect meta data. - $video_meta = array( - 'filesize' => $file_data['filesize'], - ); - - // save the resulting image-data. - wp_update_attachment_metadata( $external_file_obj->get_id(), $video_meta ); - } - /** * Return whether this file should be proxied. * diff --git a/app/ExternalFiles/File_Types/Image.php b/app/ExternalFiles/File_Types/Image.php index 89e467b..e20e102 100644 --- a/app/ExternalFiles/File_Types/Image.php +++ b/app/ExternalFiles/File_Types/Image.php @@ -67,26 +67,50 @@ public function get_proxied_file(): void { } /** - * Set meta-data for the file by given file data. - * - * @param array $file_data The file data. + * Set meta-data for the file if it is hosted extern and with proxy. * * @return void */ - public function set_metadata( array $file_data ): void { + public function set_metadata(): void { // get the file object. $external_file_obj = $this->get_file(); + // bail if file should be saved locally (then WP will handle this for us). + if( $external_file_obj->is_locally_saved() ) { + return; + } + + // bail if proxy is not enabled for images. + if( ! $this->is_proxy_enabled() ) { + return; + } + + // get the protocol handler for this file. + $protocol_handler = $external_file_obj->get_protocol_handler_obj(); + + // bail if no handler found. + if( ! $protocol_handler ) { + return; + } + + // get temporary file. + $tmp_file = $protocol_handler->get_temp_file( $external_file_obj->get_url( true ) ); + + // bail if no tmp file returned. + if( ! $tmp_file ) { + return; + } + // create the image meta data. - $image_meta = wp_create_image_subsizes( $file_data['tmp-file'], $external_file_obj->get_id() ); + $image_meta = wp_create_image_subsizes( $tmp_file, $external_file_obj->get_id() ); // set file to our url. - $image_meta['file'] = $file_data['url']; + $image_meta['file'] = $external_file_obj->get_url( true ); // change file name for each size, if given. if ( ! empty( $image_meta['sizes'] ) ) { foreach ( $image_meta['sizes'] as $size_name => $size_data ) { - $image_meta['sizes'][ $size_name ]['file'] = Helper::generate_sizes_filename( $file_data['title'], $size_data['width'], $size_data['height'], $external_file_obj->get_file_extension() ); + $image_meta['sizes'][ $size_name ]['file'] = Helper::generate_sizes_filename( $external_file_obj->get_title(), $size_data['width'], $size_data['height'], $external_file_obj->get_file_extension() ); } } diff --git a/app/ExternalFiles/File_Types/Video.php b/app/ExternalFiles/File_Types/Video.php index ec2fc1f..7b78a95 100644 --- a/app/ExternalFiles/File_Types/Video.php +++ b/app/ExternalFiles/File_Types/Video.php @@ -75,26 +75,6 @@ public function get_proxied_file(): void { exit; } - /** - * Set meta-data for the file by given file data. - * - * @param array $file_data The file data. - * - * @return void - */ - public function set_metadata( array $file_data ): void { - // get the file object. - $external_file_obj = $this->get_file(); - - // collect meta data. - $video_meta = array( - 'filesize' => $file_data['filesize'], - ); - - // save the resulting image-data. - wp_update_attachment_metadata( $external_file_obj->get_id(), $video_meta ); - } - /** * Return whether this file should be proxied. * diff --git a/app/ExternalFiles/File_Types_Base.php b/app/ExternalFiles/File_Types_Base.php index 2b25e3c..de14ed0 100644 --- a/app/ExternalFiles/File_Types_Base.php +++ b/app/ExternalFiles/File_Types_Base.php @@ -116,11 +116,9 @@ private function get_mime_types(): array { /** * Set meta-data for the file by given file data. * - * @param array $file_data The file data. - * * @return void */ - public function set_metadata( array $file_data ): void {} + public function set_metadata(): void {} /** * Return the object name. diff --git a/app/ExternalFiles/Files.php b/app/ExternalFiles/Files.php index 86d6c01..5ff4a6a 100644 --- a/app/ExternalFiles/Files.php +++ b/app/ExternalFiles/Files.php @@ -385,18 +385,6 @@ public function add_url( string $url, bool $add_to_queue = false ): bool { */ do_action( 'eml_before_file_save', $file_data ); - // bail if file is given, but has an error. - if ( ! empty( $file_data['tmp-file'] ) && is_wp_error( $file_data['tmp-file'] ) ) { - /* translators: %1$s will be replaced by an error-code. */ - $log->create( sprintf( __( 'Given URL results in error during request: %1$s', 'external-files-in-media-library' ), '' . wp_json_encode( $file_data['tmp-file'] ) . '' ), esc_url( $url ), 'error', 0 ); - - // show progress. - $progress ? $progress->tick() : ''; - - // bail to next file. - continue; - } - /** * Filter the title for a single file during import. * @@ -443,11 +431,14 @@ public function add_url( string $url, bool $add_to_queue = false ): bool { // log this event. $log->create( __( 'URL will be saved local.', 'external-files-in-media-library' ), $file_data['url'], 'info', 2 ); + // get temporary file. + $tmp_file = $this->get_temp_file( $file_data['url'] ); + // import file as image via WP-own functions. $array = array( 'name' => $title, 'type' => $file_data['mime-type'], - 'tmp_name' => $file_data['tmp-file'], + 'tmp_name' => $tmp_file, 'error' => 0, 'size' => $file_data['filesize'], ); @@ -511,17 +502,11 @@ public function add_url( string $url, bool $add_to_queue = false ): bool { $external_file_obj->set_login( $this->get_login() ); $external_file_obj->set_password( $this->get_password() ); - // set meta-data for the file if mode is enabled for this. - if ( false === $file_data['local'] && ! empty( $file_data['tmp-file'] ) ) { - // log event. - $log->create( __( 'Additional data are collected for this not local saved file.', 'external-files-in-media-library' ), $file_data['url'], 'info', 2 ); + // save file-type-specific meta data. + $external_file_obj->set_metadata(); - $file_type = File_Types::get_instance()->get_type_object_for_file_obj( $external_file_obj ); - $file_type->set_metadata( $file_data ); - - // add file to local cache if it is an image. - $external_file_obj->add_to_cache(); - } + // add file to local cache, if necessary. + $external_file_obj->add_to_cache(); // log that URL has been added as file in media library. $log->create( __( 'URL successfully added in media library.', 'external-files-in-media-library' ), $file_data['url'], 'success', 0 ); @@ -535,9 +520,6 @@ public function add_url( string $url, bool $add_to_queue = false ): bool { */ do_action( 'eml_after_file_save', $external_file_obj, $file_data ); - // cleanup the temporary file. - $this->cleanup_temp_file( $file_data['tmp-file'] ); - // show progress. $progress ? $progress->tick() : ''; } @@ -625,7 +607,7 @@ public function check_files(): void { } // get the protocol handler for this URL. - $protocol_handler = Protocols::get_instance()->get_protocol_object_for_external_file( $external_file_obj ); + $protocol_handler = $external_file_obj->get_protocol_handler_obj(); // bail if handler is false. if ( ! $protocol_handler ) { @@ -882,7 +864,7 @@ public function add_media_box_with_file_info( WP_Post $post ): void { } // get protocol handler for this URL. - $protocol_handler = Protocols::get_instance()->get_protocol_object_for_external_file( $external_file_obj ); + $protocol_handler = $external_file_obj->get_protocol_handler_obj(); // bail if no protocol handler could be loaded. if ( ! $protocol_handler ) { @@ -1013,7 +995,7 @@ public function check_file_availability_via_ajax(): void { } // get protocol handler for this url. - $protocol_handler = Protocols::get_instance()->get_protocol_object_for_external_file( $external_file_obj ); + $protocol_handler = $external_file_obj->get_protocol_handler_obj(); // bail if protocol handler could not be loaded. if ( ! $protocol_handler ) { @@ -1693,33 +1675,6 @@ public function check_runtime( string $url, array $file_list ): void { } } - /** - * Cleanup temporary files. - * - * @param string $file The path to the file. - * - * @return void - */ - public function cleanup_temp_file( string $file ): void { - // bail if string is empty. - if ( empty( $file ) ) { - return; - } - - // bail if file does not exist. - if ( ! file_exists( $file ) ) { - return; - } - - // get WP Filesystem-handler. - require_once ABSPATH . '/wp-admin/includes/file.php'; - \WP_Filesystem(); - global $wp_filesystem; - - // delete the temporary file. - $wp_filesystem->delete( $file ); - } - /** * Add help for the settings of this plugin. * diff --git a/app/ExternalFiles/Protocol_Base.php b/app/ExternalFiles/Protocol_Base.php index b7f8067..2824c44 100644 --- a/app/ExternalFiles/Protocol_Base.php +++ b/app/ExternalFiles/Protocol_Base.php @@ -52,13 +52,6 @@ class Protocol_Base { */ private bool $queue_mode = false; - /** - * Marker to force local check of file. - * - * @var bool - */ - private bool $force_local_check = false; - /** * Constructor, not used as this a Singleton object. * @@ -77,24 +70,6 @@ public function get_url(): string { return $this->url; } - /** - * Set to force local check of this file. - * - * @return void - */ - public function force_local_check(): void { - $this->force_local_check = true; - } - - /** - * Return whether local check of the file is forced. - * - * @return bool - */ - protected function is_local_check_forced(): bool { - return $this->force_local_check; - } - /** * Return the tcp protocols of this protocol object. * @@ -347,4 +322,48 @@ protected function is_queue_mode(): bool { public function set_queue_mode( bool $add_to_queue ): void { $this->queue_mode = $add_to_queue; } + + /** + * Get temp file from given URL. + * + * @param string $url The given URL. + * + * @return bool|string + */ + public function get_temp_file( string $url ): false|string { + // bail if url is empty. + if( empty( $url ) ) { + return false; + } + + // return false in any other case. + return false; + } + + /** + * Cleanup temporary files. + * + * @param string $file The path to the file. + * + * @return void + */ + public function cleanup_temp_file( string $file ): void { + // bail if string is empty. + if ( empty( $file ) ) { + return; + } + + // bail if file does not exist. + if ( ! file_exists( $file ) ) { + return; + } + + // get WP Filesystem-handler. + require_once ABSPATH . '/wp-admin/includes/file.php'; + \WP_Filesystem(); + global $wp_filesystem; + + // delete the temporary file. + $wp_filesystem->delete( $file ); + } } diff --git a/app/ExternalFiles/Protocols/File.php b/app/ExternalFiles/Protocols/File.php index 75f1dab..b1ea66b 100644 --- a/app/ExternalFiles/Protocols/File.php +++ b/app/ExternalFiles/Protocols/File.php @@ -180,26 +180,12 @@ private function get_url_info( string $file_path ): array { \WP_Filesystem(); global $wp_filesystem; - // get the file contents. - $file_content = $wp_filesystem->get_contents( $file_path ); - if ( empty( $file_content ) ) { - Log::get_instance()->create( __( 'File-URL returns an empty file.', 'external-files-in-media-library' ), $this->get_url(), 'error', 0 ); - - return array(); - } - - // save this file in a temporary directory. - $temp_file = wp_tempnam( $results['title'] ); - if ( $wp_filesystem->put_contents( $temp_file, $file_content ) ) { - $results['tmp-file'] = $temp_file; - } - // get the mime types. $mime_type = wp_check_filetype( $results['title'] ); $results['mime-type'] = $mime_type['type']; // get the size. - $results['filesize'] = wp_filesize( $temp_file ); + $results['filesize'] = $wp_filesystem->size( $file_path ); // get the last modified date. $results['last-modified'] = $wp_filesystem->mtime( $file_path ); diff --git a/app/ExternalFiles/Protocols/Ftp.php b/app/ExternalFiles/Protocols/Ftp.php index ddda058..bc029e3 100644 --- a/app/ExternalFiles/Protocols/Ftp.php +++ b/app/ExternalFiles/Protocols/Ftp.php @@ -315,23 +315,12 @@ private function get_url_info( string $file_path, WP_Filesystem_FTPext $ftp_conn return array(); } - // get WP Filesystem-handler. - require_once ABSPATH . '/wp-admin/includes/file.php'; - WP_Filesystem(); - global $wp_filesystem; - - // save this file in a temporary directory. - $temp_file = wp_tempnam( $results['title'] ); - if ( $wp_filesystem->put_contents( $temp_file, $file_content ) ) { - $results['tmp-file'] = $temp_file; - } - // get the mime types. $mime_type = wp_check_filetype( $results['title'] ); $results['mime-type'] = $mime_type['type']; // get the size. - $results['filesize'] = wp_filesize( $temp_file ); + $results['filesize'] = $ftp_connection->size( $file_path ); // get the last modified date. $results['last-modified'] = $ftp_connection->mtime( $file_path ); diff --git a/app/ExternalFiles/Protocols/Http.php b/app/ExternalFiles/Protocols/Http.php index 2f5e262..b2a6dab 100644 --- a/app/ExternalFiles/Protocols/Http.php +++ b/app/ExternalFiles/Protocols/Http.php @@ -245,23 +245,14 @@ public function get_url_infos(): array { \WP_Filesystem(); global $wp_filesystem; - // save the content of the URL in a temporary file. - add_filter( 'http_request_args', array( $this, 'set_download_url_header' ) ); - $tmp_content_file = download_url( $this->get_url() ); - remove_filter( 'http_request_args', array( $this, 'set_download_url_header' ) ); - - // bail if temp file resulted in error. - if ( is_wp_error( $tmp_content_file ) ) { - /* translators: %1$s by the error in JSON-format */ - Log::get_instance()->create( sprintf( __( 'Temp file could not be created because of the following error: %1$s', 'external-files-in-media-library' ), '' . wp_strip_all_tags( wp_json_encode( $tmp_content_file ) ) . '' ), esc_url( $this->get_url() ), 'error' ); - return array(); - } + // get temp file. + $tmp_file = $this->get_temp_file( $this->get_url() ); // get the content. - $content = $wp_filesystem->get_contents( $tmp_content_file ); + $content = $wp_filesystem->get_contents( $tmp_file ); // delete the temporary file. - Files::get_instance()->cleanup_temp_file( $tmp_content_file ); + $this->cleanup_temp_file( $tmp_file ); // bail if saving has been failed. if ( ! $content ) { @@ -463,7 +454,6 @@ public function get_url_info( string $url ): array { 'local' => false, 'url' => $url, 'last-modified' => '', - 'tmp-file' => '' ); // set file size in result-array. @@ -492,34 +482,6 @@ public function get_url_info( string $url ): array { } } - // download file as temporary file for further analyses if it should be saved local or local check should be forced. - if( $results['local'] || $this->is_local_check_forced() ) { - // log event. - Log::get_instance()->create( __( 'File will be downloaded. This may take some time.', 'external-files-in-media-library' ), esc_url( $this->get_url() ), 'info', 2 ); - - // set filter for the request. - add_filter( 'http_request_args', array( $this, 'set_download_url_header' ) ); - - // download the file. - $results['tmp-file'] = download_url( $url ); - - // remove the filter for the request, - remove_filter( 'http_request_args', array( $this, 'set_download_url_header' ) ); - - // log event. - Log::get_instance()->create( __( 'File has been downloaded.', 'external-files-in-media-library' ), esc_url( $this->get_url() ), 'info', 2 ); - } - - // bail if error occurred. - if ( is_wp_error( $results['tmp-file'] ) ) { - // file is available. - /* translators: %1$s by the error in JSON-format */ - Log::get_instance()->create( sprintf( __( 'Temp file could not be created because of the following error: %1$s', 'external-files-in-media-library' ), '' . wp_strip_all_tags( wp_json_encode( $results['tmp-file'] ) ) . '' ), esc_url( $this->get_url() ), 'error', 0 ); - - // return empty array as we got not the file. - return array(); - } - /** * Filter the data of a single file during import. * @@ -674,6 +636,7 @@ private function url_should_be_saved_local( string $url, string $mime_type ): bo return true; } + // TODO should be file-type-specific. // if setting enables local saving for images, file should be saved local. $result = 'local' === get_option( 'eml_images_mode', 'external' ) && Helper::is_image_by_mime_type( $mime_type ); /** @@ -767,7 +730,48 @@ public function is_available(): bool { * @return bool */ private function is_local_file( string $url ): bool { + $false = false; + /** + * Filter to prevent locale file check. + * + * @since 2.1.0 Available since 2.1.0. + * @param bool $false Must be true to prevent check. + * @param string $url The used URL. + * + * @noinspection PhpConditionAlreadyCheckedInspection + */ + if ( apply_filters( 'eml_locale_file_check', $false, $url ) ) { + return false; + } + $attachment_id = attachment_url_to_postid( $url ); return 0 !== $attachment_id; } + + /** + * Get temp file from given URL. + * + * @param string $url The given URL. + * + * @return bool|string + */ + public function get_temp_file( string $url ): false|string { + // download file as temporary file. + add_filter( 'http_request_args', array( $this, 'set_download_url_header' ) ); + $tmp_file = download_url( $this->get_url() ); + remove_filter( 'http_request_args', array( $this, 'set_download_url_header' ) ); + + // bail if error occurred. + if ( is_wp_error( $tmp_file ) ) { + // file is available. + /* translators: %1$s by the error in JSON-format. */ + Log::get_instance()->create( sprintf( __( 'Temp file could not be created because of the following error: %1$s', 'external-files-in-media-library' ), '' . wp_strip_all_tags( wp_json_encode( $tmp_file ) ) . '' ), esc_url( $this->get_url() ), 'error', 0 ); + + // return empty array as we got not the file. + return false; + } + + // return the temp file. + return $tmp_file; + } } diff --git a/app/ExternalFiles/Protocols/Sftp.php b/app/ExternalFiles/Protocols/Sftp.php index eb79f11..3c3896d 100644 --- a/app/ExternalFiles/Protocols/Sftp.php +++ b/app/ExternalFiles/Protocols/Sftp.php @@ -237,32 +237,12 @@ private function get_url_info( string $file_path, WP_Filesystem_SSH2 $ssh_connec return array(); } - // get the file contents. - $file_content = $ssh_connection->get_contents( $file_path ); - if ( empty( $file_content ) ) { - Log::get_instance()->create( __( 'SFTP-URL returns an empty file.', 'external-files-in-media-library' ), $this->get_url(), 'error', 0 ); - - // return empty array as we got not the file. - return array(); - } - - // get WP Filesystem-handler. - require_once ABSPATH . '/wp-admin/includes/file.php'; - WP_Filesystem(); - global $wp_filesystem; - - // save this file in a temporary directory. - $temp_file = wp_tempnam( $results['title'] ); - if ( $wp_filesystem->put_contents( $temp_file, $file_content ) ) { - $results['tmp-file'] = $temp_file; - } - // get the mime types. $mime_type = wp_check_filetype( $results['title'] ); $results['mime-type'] = $mime_type['type']; // get the size. - $results['filesize'] = wp_filesize( $temp_file ); + $results['filesize'] = $ssh_connection->size( $file_path ); // get the last modified date. $results['last-modified'] = $ssh_connection->mtime( $file_path ); diff --git a/app/Plugin/Cli.php b/app/Plugin/Cli.php index d6a3fbb..ec69be6 100644 --- a/app/Plugin/Cli.php +++ b/app/Plugin/Cli.php @@ -221,7 +221,7 @@ public function check( array $urls = array() ): void { } // get the protocol handler for this URL. - $protocol_handler = Protocols::get_instance()->get_protocol_object_for_external_file( $external_file_obj ); + $protocol_handler = $external_file_obj->get_protocol_handler_obj(); // bail if handler is false. if ( ! $protocol_handler ) { diff --git a/app/Plugin/Tables/Queue.php b/app/Plugin/Tables/Queue.php index 11559ca..b8052a4 100644 --- a/app/Plugin/Tables/Queue.php +++ b/app/Plugin/Tables/Queue.php @@ -112,7 +112,7 @@ public function column_default( $item, $column_name ) { } /** - * Add proccess-button on top of table. + * Add process-button on top of table. * * @param string $which The position. * @return void diff --git a/app/ThirdParty/Exmage.php b/app/ThirdParty/Exmage.php index cd12521..93bcaf5 100644 --- a/app/ThirdParty/Exmage.php +++ b/app/ThirdParty/Exmage.php @@ -210,7 +210,7 @@ public function migrate(): void { $external_files_obj->set_url( $url ); // get the protocol handler for this file. - $protocol_handler = Protocols::get_instance()->get_protocol_object_for_external_file( $external_files_obj ); + $protocol_handler = $external_files_obj->get_protocol_handler_obj(); // bail if protocol is not supported. if ( ! $protocol_handler ) { @@ -229,20 +229,8 @@ public function migrate(): void { // check and set availability. $external_files_obj->set_availability( $protocol_handler->check_availability( $url ) ); - // force local check of this file. - $protocol_handler->force_local_check(); - - // get the file infos. - $file_data = $protocol_handler->get_url_info( $url ); - - // get the meta data. - $image_meta = wp_create_image_subsizes( $file_data['tmp-file'], $post_id ); - - // set file to our url. - $image_meta['file'] = $file_data['url']; - - // save the resulting image-data. - wp_update_attachment_metadata( $post_id, $image_meta ); + // set the meta-data for this file. + $external_files_obj->set_metadata(); // remove exmage marker from this item. delete_post_meta( $post_id, '_exmage_external_url' ); diff --git a/changelog.md b/changelog.md index 582762a..9b1facc 100644 --- a/changelog.md +++ b/changelog.md @@ -21,6 +21,7 @@ - Fixed potential error with import of YouTube videos - Fixed output of hint it file is not available - Fixed potential error if URL is already on media library +- Fixed partially wrong saving of meta-data on external media files ## [2.0.2] - 2024-11-23 From b39aa2c1a1aee3c779b3608b35af4d053c342aee Mon Sep 17 00:00:00 2001 From: Thomas Zwirner Date: Sat, 7 Dec 2024 22:48:24 +0100 Subject: [PATCH 3/8] fixed handling of YouTube channels --- app/Plugin/Settings/Fields/Table.php | 2 +- app/Services/Youtube.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Plugin/Settings/Fields/Table.php b/app/Plugin/Settings/Fields/Table.php index 8c225c0..ddfdf56 100644 --- a/app/Plugin/Settings/Fields/Table.php +++ b/app/Plugin/Settings/Fields/Table.php @@ -62,7 +62,7 @@ public function display( array $attr ): void { // get values. $values = get_option( $setting->get_name() ); - if ( ! is_array( $values ) ) { + if ( ! is_array( $values ) || empty( $values[0] ) ) { $values = array(); } diff --git a/app/Services/Youtube.php b/app/Services/Youtube.php index 616dd08..b7a5469 100644 --- a/app/Services/Youtube.php +++ b/app/Services/Youtube.php @@ -674,7 +674,7 @@ public function get_youtube_channels(): array { $channels = get_option( 'eml_youtube_channels' ); // bail if list is empty. - if ( empty( $channels ) ) { + if ( empty( $channels ) || empty( $channels[0]) ) { return array(); } From 3a2bbaec063c6e842e8742ab7f0316264da91ea0 Mon Sep 17 00:00:00 2001 From: Thomas Zwirner Date: Sun, 8 Dec 2024 14:31:05 +0100 Subject: [PATCH 4/8] optimized proxy handling --- app/ExternalFiles/File.php | 34 +++- app/ExternalFiles/File_Types.php | 34 ++++ app/ExternalFiles/File_Types/Audio.php | 10 + app/ExternalFiles/File_Types/File.php | 5 + app/ExternalFiles/File_Types/Image.php | 23 ++- app/ExternalFiles/File_Types/Video.php | 10 + app/ExternalFiles/File_Types_Base.php | 26 ++- app/ExternalFiles/Files.php | 243 ++++++++++++------------- app/ExternalFiles/Protocol_Base.php | 4 +- app/ExternalFiles/Proxy.php | 4 +- app/Plugin/Settings.php | 81 ++++++--- app/Plugin/Update.php | 17 ++ app/Services/Youtube.php | 2 +- changelog.md | 2 + 14 files changed, 322 insertions(+), 173 deletions(-) diff --git a/app/ExternalFiles/File.php b/app/ExternalFiles/File.php index c4b024c..532f84d 100644 --- a/app/ExternalFiles/File.php +++ b/app/ExternalFiles/File.php @@ -115,7 +115,7 @@ public function get_url( bool $unproxied = false ): string { return $this->url; } - // bail if file is not proxy compatible. + // bail if file type is not proxy compatible. if ( ! $this->get_file_type_obj()->is_proxy_enabled() ) { return $this->url; } @@ -203,7 +203,7 @@ public function set_mime_type( string $mime_type ): void { $meta = wp_get_attachment_metadata( $this->get_id(), true ); // if no meta-data are set, create an array for them. - if( ! is_array( $meta ) ) { + if ( ! is_array( $meta ) ) { $meta = array(); } @@ -304,7 +304,7 @@ public function set_filesize( int $file_size ): void { $meta = wp_get_attachment_metadata( $this->get_id(), true ); // if no meta-data are set, create an array for them. - if( ! is_array( $meta ) ) { + if ( ! is_array( $meta ) ) { $meta = array(); } @@ -365,6 +365,11 @@ public function set_is_local_saved( bool $locally_saved ): void { * @return bool */ public function is_cached(): bool { + // bail if file is not marked as cached in DB. + if ( empty( get_post_meta( $this->get_id(), 'eml_proxied', true ) ) ) { + return false; + } + // get path for cached file. $cached_file = $this->get_cache_file(); @@ -394,7 +399,7 @@ public function add_to_cache(): void { } // bail if file is locally saved. - if( $this->is_locally_saved() ) { + if ( $this->is_locally_saved() ) { return; } @@ -431,10 +436,10 @@ public function add_to_cache(): void { } // get temp file. - $tmp_file = $protocol_handler_obj->get_temp_file( $this->get_url( true )); + $tmp_file = $protocol_handler_obj->get_temp_file( $this->get_url( true ) ); // bail if temp file could not be loaded. - if( ! $tmp_file ) { + if ( ! $tmp_file ) { return; } @@ -456,6 +461,9 @@ public function add_to_cache(): void { // save the given content to the path. $wp_filesystem->put_contents( $path, $body ); + + // save that file has been cached. + update_post_meta( $this->get_id(), 'eml_proxied', time() ); } /** @@ -513,6 +521,9 @@ public function delete_cache(): void { // clear the cache. wp_delete_file( $this->get_cache_file() ); + + // delete the marker. + delete_post_meta( $this->get_id(), 'eml_proxied' ); } /** @@ -607,7 +618,7 @@ public function switch_to_local(): bool { $protocol_handler_obj = $this->get_protocol_handler_obj(); // bail if no protocol handler could be loaded. - if( ! $protocol_handler_obj ) { + if ( ! $protocol_handler_obj ) { return false; } @@ -656,7 +667,7 @@ public function switch_to_local(): bool { $tmp_file = $protocol_handler_obj->get_temp_file( $this->get_url() ); // bail if no temp file could be loaded. - if( ! $tmp_file ) { + if ( ! $tmp_file ) { return false; } @@ -675,7 +686,7 @@ public function switch_to_local(): bool { $meta_data = wp_get_attachment_metadata( $attachment_id ); // create array for meta-data if it is not one. - if( ! is_array( $meta_data ) ) { + if ( ! is_array( $meta_data ) ) { $meta_data = array(); } @@ -815,10 +826,13 @@ public function delete_thumbs(): void { return; } + // get proxy-object. + $proxy_obj = Proxy::get_instance(); + // loop through the sizes. foreach ( $image_meta_data['sizes'] as $size_data ) { // get file path. - $file = Proxy::get_instance()->get_cache_directory() . Helper::generate_sizes_filename( basename( $this->get_cache_file() ), $size_data['width'], $size_data['height'], $this->get_file_extension() ); + $file = $proxy_obj->get_cache_directory() . Helper::generate_sizes_filename( basename( $this->get_cache_file() ), $size_data['width'], $size_data['height'], $this->get_file_extension() ); // bail if file does not exist. if ( ! $wp_filesystem->exists( $file ) ) { diff --git a/app/ExternalFiles/File_Types.php b/app/ExternalFiles/File_Types.php index 031ceec..37610f7 100644 --- a/app/ExternalFiles/File_Types.php +++ b/app/ExternalFiles/File_Types.php @@ -148,4 +148,38 @@ public function get_type_object_for_file_obj( File $external_file_obj ): File_Ty // return the default file object if nothing matches. return $file_type_obj; } + + /** + * Return true if any proxy for any file is enabled. + * + * @return bool + */ + public function is_any_proxy_enabled(): bool { + // check each supported file type. + foreach ( $this->get_file_types() as $file_type ) { + // bail if file type is not a string. + if ( ! is_string( $file_type ) ) { + continue; + } + + // bail if object does not exist. + if ( ! class_exists( $file_type ) ) { + continue; + } + + // get the object. + $file_type_obj = new $file_type( false ); + + // bail if proxy for this file type is not enabled. + if ( ! $file_type_obj->is_proxy_enabled() ) { + continue; + } + + // return true if proxy is enabled. + return true; + } + + // return false if no proxy is enabled. + return false; + } } diff --git a/app/ExternalFiles/File_Types/Audio.php b/app/ExternalFiles/File_Types/Audio.php index d55d62a..361249d 100644 --- a/app/ExternalFiles/File_Types/Audio.php +++ b/app/ExternalFiles/File_Types/Audio.php @@ -42,6 +42,11 @@ class Audio extends File_Types_Base { * @noinspection PhpNoReturnAttributeCanBeAddedInspection */ public function get_proxied_file(): void { + // bail if no file is set. + if ( ! $this->get_file() ) { + exit; + } + // get the file object. $external_file_obj = $this->get_file(); @@ -88,6 +93,11 @@ public function is_proxy_enabled(): bool { * @return bool */ public function is_cache_expired(): bool { + // bail if no file is set. + if ( ! $this->get_file() ) { + return true; + } + // bail if no proxy age is set. if ( absint( get_option( 'eml_audio_proxy_max_age' ) ) <= 0 ) { return false; diff --git a/app/ExternalFiles/File_Types/File.php b/app/ExternalFiles/File_Types/File.php index acf815d..51529c2 100644 --- a/app/ExternalFiles/File_Types/File.php +++ b/app/ExternalFiles/File_Types/File.php @@ -30,6 +30,11 @@ class File extends File_Types_Base { * @noinspection PhpNoReturnAttributeCanBeAddedInspection */ public function get_proxied_file(): void { + // bail if no file is set. + if ( ! $this->get_file() ) { + exit; + } + // get the file object. $external_file_obj = $this->get_file(); diff --git a/app/ExternalFiles/File_Types/Image.php b/app/ExternalFiles/File_Types/Image.php index e20e102..e0b42c5 100644 --- a/app/ExternalFiles/File_Types/Image.php +++ b/app/ExternalFiles/File_Types/Image.php @@ -45,6 +45,11 @@ class Image extends File_Types_Base { * @noinspection PhpNoReturnAttributeCanBeAddedInspection */ public function get_proxied_file(): void { + // bail if no file is set. + if ( ! $this->get_file() ) { + exit; + } + // get the file object. $external_file_obj = $this->get_file(); @@ -72,16 +77,21 @@ public function get_proxied_file(): void { * @return void */ public function set_metadata(): void { + // bail if no file is set. + if ( ! $this->get_file() ) { + return; + } + // get the file object. $external_file_obj = $this->get_file(); // bail if file should be saved locally (then WP will handle this for us). - if( $external_file_obj->is_locally_saved() ) { + if ( $external_file_obj->is_locally_saved() ) { return; } // bail if proxy is not enabled for images. - if( ! $this->is_proxy_enabled() ) { + if ( ! $this->is_proxy_enabled() ) { return; } @@ -89,7 +99,7 @@ public function set_metadata(): void { $protocol_handler = $external_file_obj->get_protocol_handler_obj(); // bail if no handler found. - if( ! $protocol_handler ) { + if ( ! $protocol_handler ) { return; } @@ -97,7 +107,7 @@ public function set_metadata(): void { $tmp_file = $protocol_handler->get_temp_file( $external_file_obj->get_url( true ) ); // bail if no tmp file returned. - if( ! $tmp_file ) { + if ( ! $tmp_file ) { return; } @@ -133,6 +143,11 @@ public function is_proxy_enabled(): bool { * @return bool */ public function is_cache_expired(): bool { + // bail if no file is set. + if ( ! $this->get_file() ) { + return false; + } + // bail if no proxy age is set. if ( absint( get_option( 'eml_proxy_max_age' ) ) <= 0 ) { return false; diff --git a/app/ExternalFiles/File_Types/Video.php b/app/ExternalFiles/File_Types/Video.php index 7b78a95..9aa4bc8 100644 --- a/app/ExternalFiles/File_Types/Video.php +++ b/app/ExternalFiles/File_Types/Video.php @@ -44,6 +44,11 @@ class Video extends File_Types_Base { * @noinspection PhpNoReturnAttributeCanBeAddedInspection */ public function get_proxied_file(): void { + // bail if no file is set. + if ( ! $this->get_file() ) { + exit; + } + // get the file object. $external_file_obj = $this->get_file(); @@ -90,6 +95,11 @@ public function is_proxy_enabled(): bool { * @return bool */ public function is_cache_expired(): bool { + // bail if no file is set. + if ( ! $this->get_file() ) { + return true; + } + // bail if no proxy age is set. if ( absint( get_option( 'eml_video_proxy_max_age' ) ) <= 0 ) { return false; diff --git a/app/ExternalFiles/File_Types_Base.php b/app/ExternalFiles/File_Types_Base.php index de14ed0..70313f7 100644 --- a/app/ExternalFiles/File_Types_Base.php +++ b/app/ExternalFiles/File_Types_Base.php @@ -38,17 +38,19 @@ class File_Types_Base { /** * The external file object which is handled here. * - * @var File + * @var File|false */ - protected File $external_file_obj; + protected File|false $external_file_obj = false; /** * The contructor for this object. * - * @param File $external_file_obj The external file as object. + * @param File|false $external_file_obj The external file as object or false. */ - public function __construct( File $external_file_obj ) { - $this->external_file_obj = $external_file_obj; + public function __construct( File|false $external_file_obj ) { + if ( $external_file_obj instanceof File ) { + $this->external_file_obj = $external_file_obj; + } } /** @@ -57,6 +59,11 @@ public function __construct( File $external_file_obj ) { * @return bool */ public function is_file_compatible(): bool { + // bail if no file is set. + if ( ! $this->get_file() ) { + return false; + } + // bail if list is empty. if ( empty( $this->get_mime_types() ) ) { return false; @@ -88,9 +95,9 @@ public function get_proxied_file(): void {} /** * Return the external file object. * - * @return File + * @return File|false */ - protected function get_file(): File { + protected function get_file(): File|false { return $this->external_file_obj; } @@ -100,6 +107,11 @@ protected function get_file(): File { * @return array|string[] */ private function get_mime_types(): array { + // bail if no file is set. + if ( ! $this->get_file() ) { + return array(); + } + $mime_type = $this->mime_types; $external_file_obj = $this->get_file(); diff --git a/app/ExternalFiles/Files.php b/app/ExternalFiles/Files.php index 5ff4a6a..facb465 100644 --- a/app/ExternalFiles/Files.php +++ b/app/ExternalFiles/Files.php @@ -235,7 +235,7 @@ public function get_files(): array { $external_file_obj = $this->get_file( $attachment_id ); // bail if object could not be loaded. - if ( ! $external_file_obj ) { + if ( ! $external_file_obj || ! $external_file_obj->is_valid() ) { continue; } @@ -658,7 +658,7 @@ public function get_imported_external_files(): array { $external_file_obj = $this->get_file( $attachment_id ); // bail if object could not be loaded. - if ( ! $external_file_obj ) { + if ( ! $external_file_obj || false === $external_file_obj->is_valid() ) { continue; } @@ -833,13 +833,8 @@ public function add_media_box( WP_Post $post ): void { // get file by its ID. $external_file_obj = $this->get_file( $post->ID ); - // bail if the file is not an external file-URL. - if ( ! $external_file_obj ) { - return; - } - - // bail if file is not valid. - if ( ! $external_file_obj->is_valid() ) { + // bail if this is not an external file. + if ( ! ( false !== $external_file_obj && false !== $external_file_obj->is_valid() ) ) { return; } @@ -929,7 +924,7 @@ public function add_media_box_with_file_info( WP_Post $post ): void { ?> get_file_type_obj()->is_proxy_enabled() && get_option( 'eml_proxy' ) ) { + if ( $external_file_obj->get_file_type_obj()->is_proxy_enabled() ) { ?>
  • get_file( $attachment_id ); - // bail if file could not be loaded. - if ( ! $external_file_obj ) { + // bail if this is not an external file. + if ( ! ( false !== $external_file_obj && false !== $external_file_obj->is_valid() ) ) { // send response as JSON. wp_send_json( $result ); } @@ -1085,8 +1080,8 @@ public function switch_hosting_via_ajax(): void { // get the file. $external_file_obj = $this->get_file( $attachment_id ); - // bail if object could not be loaded. - if ( ! $external_file_obj ) { + // bail if this is not an external file. + if ( ! ( false !== $external_file_obj && false !== $external_file_obj->is_valid() ) ) { wp_send_json( $result ); } @@ -1155,8 +1150,8 @@ public function change_media_row_actions( array $actions, WP_Post $post ): array // get the external file object. $external_file_obj = $this->get_file( $post->ID ); - // bail if file is not an external file. - if ( ! $external_file_obj ) { + // bail if this is not an external file. + if ( ! ( false !== $external_file_obj && false !== $external_file_obj->is_valid() ) ) { return $actions; } @@ -1192,13 +1187,8 @@ public function get_attached_file( string $file, int $post_id ): string { // get the external file object. $external_file_obj = $this->get_file( $post_id ); - // bail if file is not an external file. - if ( ! $external_file_obj ) { - return $file; - } - - // bail if file is not valid. - if ( ! $external_file_obj->is_valid() ) { + // bail if this is not an external file. + if ( ! ( false !== $external_file_obj && false !== $external_file_obj->is_valid() ) ) { return $file; } @@ -1224,102 +1214,72 @@ public function image_downsize( array|bool $result, int|string $attachment_id, a // get the external file object. $external_file_obj = $this->get_file( absint( $attachment_id ) ); - // bail if file is not an external file. - if ( ! $external_file_obj ) { + // bail if this is not an external file. + if ( ! ( false !== $external_file_obj && false !== $external_file_obj->is_valid() ) ) { return $result; } - // bail if file is not valid. - if ( ! $external_file_obj->is_valid() ) { + // bail if file type has no thumb support. + if ( ! $external_file_obj->get_file_type_obj()->has_thumbs() ) { return $result; } - // check if the file is an external file, is supporting thumbs and if it is really external hosted. - if ( - false === $external_file_obj->is_locally_saved() - && $external_file_obj->get_file_type_obj()->has_thumbs() - ) { - // if requested size is a string, get its sizes. - if ( is_string( $size ) ) { - $size = array( - absint( get_option( $size . '_size_w' ) ), - absint( get_option( $size . '_size_h' ) ), - ); - } - - // get image data. - $image_data = wp_get_attachment_metadata( $attachment_id ); - - // if image data is fall, create the array manually. - if ( ! $image_data ) { - $image_data = array( - 'sizes' => array(), - 'width' => 0, - 'height' => 0, - ); - } - - // bail if both sizes are 0. - if ( 0 === $size[0] && 0 === $size[1] ) { - // set return-array so that WP won't generate an image for it. - return array( - $external_file_obj->get_url(), - isset( $image_data['width'] ) ? $image_data['width'] : 0, - isset( $image_data['height'] ) ? $image_data['height'] : 0, - false, - ); - } - - // use already existing thumb. - if ( ! empty( $image_data['sizes'][ $size[0] . 'x' . $size[1] ] ) && file_exists( $image_data['sizes'][ $size[0] . 'x' . $size[1] ]['file'] ) ) { - // return the thumb. - return array( - trailingslashit( get_home_url() ) . Proxy::get_instance()->get_slug() . '/' . $image_data['sizes'][ $size[0] . 'x' . $size[1] ]['file'], - $size[0], - $size[1], - false, - ); - } - - // get image editor as object. - $image_editor = wp_get_image_editor( $external_file_obj->get_cache_file() ); - - // on error return the original image. - if ( is_wp_error( $image_editor ) ) { - // set return-array so that WP won't generate an image for it. - return array( - $external_file_obj->get_url(), - isset( $image_data['width'] ) ? $image_data['width'] : 0, - isset( $image_data['height'] ) ? $image_data['height'] : 0, - false, - ); - } + // if requested size is a string, get its sizes. + if ( is_string( $size ) ) { + $size = array( + absint( get_option( $size . '_size_w' ) ), + absint( get_option( $size . '_size_h' ) ), + ); + } - /** - * Generate the requested thumb and save it in metadata for the image. - */ + // if file type has proxy not enabled we just return the original URL with requested sizes. + if ( ! $external_file_obj->get_file_type_obj()->is_proxy_enabled() ) { + return array( + $external_file_obj->get_url( true ), + $size[0], + $size[1], + ); + } - // generate the filename for the thumb. - $generated_filename = Helper::generate_sizes_filename( basename( $external_file_obj->get_cache_file() ), $size[0], $size[1], $external_file_obj->get_file_extension() ); + // bail if file is locally saved. + if ( $external_file_obj->is_locally_saved() ) { + return $result; + } - // public filename. - $public_filename = Helper::generate_sizes_filename( basename( $external_file_obj->get_url() ), $size[0], $size[1], $external_file_obj->get_file_extension() ); + // get image data. + $image_data = wp_get_attachment_metadata( $attachment_id ); - // resize the image. - $image_editor->resize( $size[0], $size[1], true ); + // if image data is fall, create the array manually. + if ( ! $image_data ) { + $image_data = array( + 'sizes' => array(), + 'width' => 0, + 'height' => 0, + ); + } - // save the resized image and get its data. - $new_image_data = $image_editor->save( Proxy::get_instance()->get_cache_directory() . $generated_filename ); + // bail if both sizes are 0. + if ( 0 === $size[0] && 0 === $size[1] ) { + // set return-array so that WP won't generate an image for it. + return array( + $external_file_obj->get_url(), + isset( $image_data['width'] ) ? $image_data['width'] : 0, + isset( $image_data['height'] ) ? $image_data['height'] : 0, + false, + ); + } - // remove the path from the resized image data. - unset( $new_image_data['path'] ); + // generate the filename for the thumb. + $generated_filename = Helper::generate_sizes_filename( basename( $external_file_obj->get_cache_file() ), $size[0], $size[1], $external_file_obj->get_file_extension() ); - // replace the filename in the resized image data with the public filename we use in our proxy. - $new_image_data['file'] = $public_filename; + // public filename. + $public_filename = Helper::generate_sizes_filename( basename( $external_file_obj->get_url() ), $size[0], $size[1], $external_file_obj->get_file_extension() ); - // update the meta data. - $image_data['sizes'][ $size[0] . 'x' . $size[1] ] = $new_image_data; - wp_update_attachment_metadata( $attachment_id, $image_data ); + // use already existing thumb. + if ( ! empty( $image_data['sizes'][ $size[0] . 'x' . $size[1] ] ) && file_exists( Proxy::get_instance()->get_cache_directory() . $generated_filename ) ) { + // log the event. + /* translators: %1$s will be replaced by the image sizes. */ + Log::get_instance()->create( sprintf( __( 'Loading thumb from cache for %1$s', 'external-files-in-media-library' ), $size[0] . 'x' . $size[1] ), $external_file_obj->get_url( true ), 'info', 2 ); // return the thumb. return array( @@ -1330,8 +1290,51 @@ public function image_downsize( array|bool $result, int|string $attachment_id, a ); } - // return result. - return $result; + // get image editor as object. + $image_editor = wp_get_image_editor( $external_file_obj->get_cache_file() ); + + // on error return the original image. + if ( is_wp_error( $image_editor ) ) { + // set return-array so that WP won't generate an image for it. + return array( + $external_file_obj->get_url(), + isset( $image_data['width'] ) ? $image_data['width'] : 0, + isset( $image_data['height'] ) ? $image_data['height'] : 0, + false, + ); + } + + /** + * Generate the requested thumb and save it in metadata for the image. + */ + + // resize the image. + $image_editor->resize( $size[0], $size[1], true ); + + // save the resized image and get its data. + $new_image_data = $image_editor->save( Proxy::get_instance()->get_cache_directory() . $generated_filename ); + + // remove the path from the resized image data. + unset( $new_image_data['path'] ); + + // replace the filename in the resized image data with the public filename we use in our proxy. + $new_image_data['file'] = $public_filename; + + // update the meta data. + $image_data['sizes'][ $size[0] . 'x' . $size[1] ] = $new_image_data; + wp_update_attachment_metadata( $attachment_id, $image_data ); + + // log the event. + /* translators: %1$s will be replaced by the image sizes. */ + Log::get_instance()->create( sprintf( __( 'Generated new thumb for %1$s', 'external-files-in-media-library' ), $size[0] . 'x' . $size[1] ), $external_file_obj->get_url( true ), 'info', 2 ); + + // return the thumb. + return array( + trailingslashit( get_home_url() ) . Proxy::get_instance()->get_slug() . '/' . $public_filename, + $size[0], + $size[1], + false, + ); } /** @@ -1392,13 +1395,8 @@ public function disable_attachment_page( string $redirect_url ): string { // get the external files. $external_file_obj = $this->get_file( get_the_ID() ); - // bail if file could not be loaded. - if ( ! $external_file_obj ) { - return $redirect_url; - } - - // bail if file is not valid. - if ( ! $external_file_obj->is_valid() ) { + // bail if this is not an external file. + if ( ! ( false !== $external_file_obj && false !== $external_file_obj->is_valid() ) ) { return $redirect_url; } @@ -1427,7 +1425,7 @@ public function wp_calculate_image_srcset( array $sources, array $size_array, st $external_file_obj = $this->get_file( $attachment_id ); // bail if this is not an external file. - if ( ! $external_file_obj || ! $external_file_obj->is_valid() ) { + if ( ! ( false !== $external_file_obj && false !== $external_file_obj->is_valid() ) ) { return $sources; } @@ -1457,13 +1455,8 @@ public function wp_get_attachment_metadata( array $data, int $attachment_id ): a // get the external file object. $external_file_obj = $this->get_file( $attachment_id ); - // bail if file could not be loaded. - if ( ! $external_file_obj ) { - return $data; - } - - // bail if file is not valid. - if ( ! $external_file_obj->is_valid() ) { + // bail if this is not an external file. + if ( ! ( false !== $external_file_obj && false !== $external_file_obj->is_valid() ) ) { return $data; } @@ -1576,8 +1569,8 @@ public function reset_thumbnails_by_request(): void { // get the external file object. $external_file_obj = $this->get_file( $post_id ); - // bail if object could not be loaded. - if ( ! $external_file_obj ) { + // bail if this is not an external file. + if ( ! ( false !== $external_file_obj && false !== $external_file_obj->is_valid() ) ) { wp_safe_redirect( wp_get_referer() ); exit; } @@ -1724,7 +1717,7 @@ public function check_srcset_meta( array $image_meta, array $size_array, string $external_file_obj = $this->get_file( $attachment_id ); // bail if this is not an external file. - if ( ! $external_file_obj ) { + if ( ! ( false !== $external_file_obj && false !== $external_file_obj->is_valid() ) ) { return $image_meta; } diff --git a/app/ExternalFiles/Protocol_Base.php b/app/ExternalFiles/Protocol_Base.php index 2824c44..54651fb 100644 --- a/app/ExternalFiles/Protocol_Base.php +++ b/app/ExternalFiles/Protocol_Base.php @@ -70,7 +70,7 @@ public function get_url(): string { return $this->url; } - /** + /** * Return the tcp protocols of this protocol object. * * @return array @@ -332,7 +332,7 @@ public function set_queue_mode( bool $add_to_queue ): void { */ public function get_temp_file( string $url ): false|string { // bail if url is empty. - if( empty( $url ) ) { + if ( empty( $url ) ) { return false; } diff --git a/app/ExternalFiles/Proxy.php b/app/ExternalFiles/Proxy.php index 4358905..ce4c444 100644 --- a/app/ExternalFiles/Proxy.php +++ b/app/ExternalFiles/Proxy.php @@ -66,8 +66,8 @@ public function init(): void { // misc. add_action( 'wp_ajax_eml_reset_proxy', array( $this, 'reset_via_ajax' ) ); - // bail if proxy is not enabled, neither for images nor for videos. - if ( 0 === absint( get_option( 'eml_proxy', 0 ) ) && 0 === absint( get_option( 'eml_video_proxy', 0 ) ) ) { + // bail if no proxy is enabled. + if ( ! File_Types::get_instance()->is_any_proxy_enabled() ) { return; } diff --git a/app/Plugin/Settings.php b/app/Plugin/Settings.php index f8ce17b..2f9cc92 100644 --- a/app/Plugin/Settings.php +++ b/app/Plugin/Settings.php @@ -16,6 +16,7 @@ use ExternalFilesInMediaLibrary\Plugin\Settings\Fields\Number; use ExternalFilesInMediaLibrary\Plugin\Settings\Fields\Select; use ExternalFilesInMediaLibrary\Plugin\Settings\Fields\Text; +use ExternalFilesInMediaLibrary\Plugin\Settings\Fields\Value; use ExternalFilesInMediaLibrary\Plugin\Settings\Setting; use ExternalFilesInMediaLibrary\Plugin\Tables\Logs; @@ -424,6 +425,7 @@ public function add_settings(): void { $setting->set_section( $images_tab_images ); $setting->set_type( 'integer' ); $setting->set_default( 1 ); + $setting->set_save_callback( array( $this, 'update_proxy_setting' ) ); $field = new Checkbox(); $field->set_title( __( 'Enable proxy for images', 'external-files-in-media-library' ) ); $field->set_description( __( 'This option is only available if images are hosted external. If this option is disabled, external images will be embedded with their external URL. To prevent privacy protection issue you could enable this option to load the images locally.', 'external-files-in-media-library' ) ); @@ -548,29 +550,9 @@ public function add_settings(): void { $proxy_path_setting->set_save_callback( array( $this, 'save_proxy_path' ) ); $field = new Text(); $field->set_title( __( 'Proxy path', 'external-files-in-media-library' ) ); - $field->set_description( __( 'This is the path on the filesystem of your WordPress relativ to the wp-content directory. If you change it, the new directory should not exist. All cached files will be copied.', 'external-files-in-media-library' ) ); + $field->set_description( __( 'This is the path on the filesystem of your WordPress relativ to the wp-content directory. If you change it, the new directory should not exist. All cached files will be copied to the new path.', 'external-files-in-media-library' ) ); $proxy_path_setting->set_field( $field ); - // create proxy reset dialog. - $dialog = array( - 'title' => __( 'Reset proxy cache', 'external-files-in-media-library' ), - 'texts' => array( - '

    ' . __( 'Click on the following button to reset the proxy cache.', 'external-files-in-media-library' ) . '

    ', - ), - 'buttons' => array( - array( - 'action' => 'efml_reset_proxy();', - 'variant' => 'primary', - 'text' => __( 'Reset now', 'external-files-in-media-library' ), - ), - array( - 'action' => 'closeDialog();', - 'variant' => 'secondary', - 'text' => __( 'Cancel', 'external-files-in-media-library' ), - ), - ), - ); - // add setting. $setting = $settings_obj->add_setting( 'eml_proxy_clear' ); $setting->set_section( $proxy_tab_proxy ); @@ -580,7 +562,7 @@ public function add_settings(): void { $field->set_title( __( 'Reset proxy cache', 'external-files-in-media-library' ) ); $field->set_button_title( __( 'Reset now', 'external-files-in-media-library' ) ); $field->add_class( 'easy-dialog-for-wordpress' ); - $field->set_custom_attributes( array( 'data-dialog' => wp_json_encode( $dialog ) ) ); + $field->set_custom_attributes( array( 'data-dialog' => wp_json_encode( $this->get_proxy_reset_dialog() ) ) ); $setting->set_field( $field ); // add import/export settings. @@ -858,4 +840,59 @@ public function save_proxy_path( string $new_value, string $old_value ): string // return the new value. return $new_value; } + + /** + * Check the change of proxy-setting. + * + * @param string $new_value The old value. + * @param string $old_value The new value. + * + * @return int + */ + public function update_proxy_setting( string $new_value, string $old_value ): int { + // convert the values. + $new_value = absint( $new_value ); + $old_value = absint( $old_value ); + + // bail if value has not been changed. + if ( $new_value === $old_value ) { + return $old_value; + } + + // show hint to reset the proxy-cache. + $transient_obj = Transients::get_instance()->add(); + $transient_obj->set_name( 'eml_proxy_changed' ); + $transient_obj->set_message( '' . __( 'The proxy state has been changed.', 'external-files-in-media-library' ) . ' ' . __( 'We recommend emptying the cache of the proxy. Click on the button below to do this.', 'external-files-in-media-library' ) . '
    ' . esc_html__( 'Reset now', 'external-files-in-media-library' ) . '' ); + $transient_obj->set_type( 'success' ); + $transient_obj->save(); + + // return the new value. + return $new_value; + } + + /** + * Return the proxy reset dialog configuration. + * + * @return array + */ + private function get_proxy_reset_dialog(): array { + return array( + 'title' => __( 'Reset proxy cache', 'external-files-in-media-library' ), + 'texts' => array( + '

    ' . __( 'Click on the following button to reset the proxy cache.', 'external-files-in-media-library' ) . '

    ', + ), + 'buttons' => array( + array( + 'action' => 'efml_reset_proxy();', + 'variant' => 'primary', + 'text' => __( 'Reset now', 'external-files-in-media-library' ), + ), + array( + 'action' => 'closeDialog();', + 'variant' => 'secondary', + 'text' => __( 'Cancel', 'external-files-in-media-library' ), + ), + ), + ); + } } diff --git a/app/Plugin/Update.php b/app/Plugin/Update.php index 5562bfd..a6bcf24 100644 --- a/app/Plugin/Update.php +++ b/app/Plugin/Update.php @@ -8,6 +8,8 @@ namespace ExternalFilesInMediaLibrary\Plugin; // prevent direct access. +use ExternalFilesInMediaLibrary\ExternalFiles\File; +use ExternalFilesInMediaLibrary\ExternalFiles\Files; use ExternalFilesInMediaLibrary\ExternalFiles\Queue; defined( 'ABSPATH' ) || exit; @@ -138,5 +140,20 @@ private function version210(): void { // update database-table for queues. Queue::get_instance()->install(); + + // set proxy marker for all files where proxy is enabled. + foreach ( Files::get_instance()->get_files() as $external_file_obj ) { + if ( ! $external_file_obj instanceof File ) { + continue; + } + + // bail if proxy is not enabled for this file. + if ( ! $external_file_obj->get_file_type_obj()->is_proxy_enabled() ) { + continue; + } + + // add the post meta for proxy time. + update_post_meta( $external_file_obj->get_id(), 'eml_proxied', time() ); + } } } diff --git a/app/Services/Youtube.php b/app/Services/Youtube.php index b7a5469..9a79d5d 100644 --- a/app/Services/Youtube.php +++ b/app/Services/Youtube.php @@ -674,7 +674,7 @@ public function get_youtube_channels(): array { $channels = get_option( 'eml_youtube_channels' ); // bail if list is empty. - if ( empty( $channels ) || empty( $channels[0]) ) { + if ( empty( $channels ) || empty( $channels[0] ) ) { return array(); } diff --git a/changelog.md b/changelog.md index 9b1facc..30916c2 100644 --- a/changelog.md +++ b/changelog.md @@ -15,6 +15,7 @@ - Optimized updating or installing log- and queue-tables during plugin update - Updated dependencies - Moved changelog from readme.txt in GitHub-repository +- Reduced number of calls for external file thumbs ### Fixed @@ -22,6 +23,7 @@ - Fixed output of hint it file is not available - Fixed potential error if URL is already on media library - Fixed partially wrong saving of meta-data on external media files +- Fixed wrong check for already existing thumbs of external files ## [2.0.2] - 2024-11-23 From 2ac2406a893955f4d96d625433f7d0bac9be82a5 Mon Sep 17 00:00:00 2001 From: Thomas Zwirner Date: Sun, 8 Dec 2024 15:23:25 +0100 Subject: [PATCH 5/8] optimized upload dialog --- admin/js.js | 29 +++++++++++--- admin/style.css | 4 +- app/ExternalFiles/Forms.php | 75 ++++++++++++++++++++++--------------- app/ExternalFiles/Queue.php | 41 ++++++++++++++++++++ changelog.md | 4 ++ 5 files changed, 115 insertions(+), 38 deletions(-) diff --git a/admin/js.js b/admin/js.js index 8b13d90..ace776a 100644 --- a/admin/js.js +++ b/admin/js.js @@ -165,7 +165,7 @@ jQuery(document).ready(function($) { }); /** - * Handling for upload of URLs from textarea in dialog. + * Handling for upload of URLs from textarea or input-field in dialog. */ function efml_upload_files() { let urls = jQuery( '#external_files' ).val(); @@ -193,11 +193,28 @@ function efml_upload_files() { } // get the credentials (optional). - let login = jQuery('#eml_login').val(); - let password = jQuery('#eml_password').val(); + let login = ''; + let password = ''; + if( jQuery('#eml_use_credentials').is(':checked') ) { + login = jQuery( '#eml_login' ).val(); + password = jQuery( '#eml_password' ).val(); + } - // get queue setting. - let add_to_queue = jQuery('#add_to_queue').is(':checked') ? 1 : 0; + // collect values of additional fields. + let additional_fields = {}; + jQuery('.easy-dialog-for-wordpress-text .eml-use-for-import').each(function() { + if( 'INPUT' === jQuery(this).prop('nodeName') ) { + if( 'checkbox' === jQuery(this).attr('type') && jQuery(this).prop('checked') === true ) { + additional_fields[jQuery(this).prop('name')] = 1; + } + if( 'text' === jQuery(this).attr('type') ) { + additional_fields[jQuery(this).prop('name')] = jQuery(this).val(); + } + } + if( 'TEXTAREA' === jQuery(this).prop('nodeName') ) { + additional_fields[jQuery(this).prop('name')] = jQuery(this).val(); + } + }); // send request. jQuery.ajax({ @@ -207,7 +224,7 @@ function efml_upload_files() { urls: urls, login: login, password: password, - add_to_queue: add_to_queue, + additional_fields: additional_fields, action: 'eml_add_external_urls', nonce: efmlJsVars.urls_nonce }, diff --git a/admin/style.css b/admin/style.css index ae6819c..ce932ce 100644 --- a/admin/style.css +++ b/admin/style.css @@ -53,7 +53,7 @@ body.settings_page_eml_settings .dashicons-yes { color: green } margin-bottom: 0.5em; } -.eml .easy-dialog-for-wordpress-text input[type="url"] { +.eml .easy-dialog-for-wordpress-text input[type="url"], .easy-dialog-for-wordpress-text #youtube_channel_id { display: block; margin-bottom: 0.5em; width: 100%; @@ -148,7 +148,7 @@ body.settings_page_eml_settings .dashicons-yes { color: green } .wp-list-table.media #external_files { width: 120px } -.eml .easy-dialog-for-wordpress-text details { +.eml .easy-dialog-for-wordpress-text:last-of-type { margin-bottom: 1em; } diff --git a/app/ExternalFiles/Forms.php b/app/ExternalFiles/Forms.php index 2955e15..b56e755 100644 --- a/app/ExternalFiles/Forms.php +++ b/app/ExternalFiles/Forms.php @@ -66,7 +66,7 @@ public function init(): void { add_action( 'wp_ajax_eml_add_external_urls', array( $this, 'add_urls_via_ajax' ), 10, 0 ); add_action( 'wp_ajax_eml_get_external_urls_import_info', array( $this, 'get_external_urls_import_info' ), 10, 0 ); - // our own actions. + // use our own actions. add_action( 'eml_http_directory_import_start', array( $this, 'set_http_import_title_start' ) ); add_action( 'eml_ftp_directory_import_file_check', array( $this, 'set_import_file_check' ) ); add_action( 'eml_http_directory_import_file_check', array( $this, 'set_import_file_check' ) ); @@ -311,8 +311,19 @@ public function add_urls_via_ajax(): void { $login = filter_input( INPUT_POST, 'login', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); $password = filter_input( INPUT_POST, 'password', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); - // get the queue setting. - $add_to_queue = absint( filter_input( INPUT_POST, 'add_to_queue', FILTER_SANITIZE_NUMBER_INT ) ); + // get additional fields. + $additional_fields = isset( $_POST[ 'additional_fields' ] ) ? array_map( 'sanitize_text_field', $_POST[ 'additional_fields' ] ) : array(); + + $false = false; + /** + * Get the queue setting for the import. + * + * @since 2.1.0 Available since 2.1.0. + * @param bool $false Set to true to import the files via queue. + * + * @noinspection PhpConditionAlreadyCheckedInspection + */ + $add_to_queue = apply_filters( 'eml_import_add_to_queue', $false, $additional_fields ); // collect errors. $errors = array(); @@ -322,8 +333,9 @@ public function add_urls_via_ajax(): void { * * @since 2.0.0 Available since 2.0.0. * @param array $url_array List of URLs to import. + * @param array $additional_fields List of additional fields from form (since 2.1.0). */ - do_action( 'eml_import_ajax_start', $url_array ); + do_action( 'eml_import_ajax_start', $url_array, $additional_fields ); // if URLs are given, check them. if ( ! empty( $url_array ) ) { @@ -335,8 +347,9 @@ public function add_urls_via_ajax(): void { * * @since 2.0.0 Available since 2.0.0. * @param array $url_array The list of URLs to add. + * @param array $additional_fields List of additional fields from form (since 2.1.0). */ - $url_array = apply_filters( 'eml_import_urls', $url_array ); + $url_array = apply_filters( 'eml_import_urls', $url_array, $additional_fields ); // save count of URLs. update_option( 'eml_import_url_max', count( $url_array ) ); @@ -362,6 +375,15 @@ public function add_urls_via_ajax(): void { /* translators: %1$s will be replaced by the URL which is imported. */ update_option( 'eml_import_title', sprintf( __( 'Importing URL %1$s', 'external-files-in-media-library' ), esc_html( Helper::shorten_url( $url ) ) ) ); + /** + * Filter single URL before it will be added as external file. + * + * @since 2.1.0 Available since 2.1.0. + * @param string $url The URL. + * @param array $additional_fields List of additional fields from form. + */ + $url = apply_filters( 'eml_import_url_before', $url, $additional_fields ); + // import file in media library if enqueue option is not set. $file_added = $files_obj->add_url( $url, $add_to_queue ); @@ -375,12 +397,19 @@ public function add_urls_via_ajax(): void { // log this event. $log->create( __( 'Error occurred during check of URL. The URL has not been added.', 'external-files-in-media-library' ), $url, 'info', 1 ); } + else { + /** + * Run additional tasks for single URL after it has been successfully added as external file. + * + * @since 2.1.0 Available since 2.1.0. + * @param string $url The URL. + * @param array $additional_fields List of additional fields from form. + */ + do_action( 'eml_import_url_after', $url, $additional_fields ); + } } } - // get log instance. - $log = Log::get_instance(); - // collect the errors for response. $errors_for_response = array(); @@ -671,47 +700,33 @@ private function get_fields( bool $single = false ): array { // use single fields. if ( $single ) { // add URL field. - $fields[] = ''; - - // add queue option if it is not disabled. - if ( 'eml_disable_check' !== get_option( 'eml_queue_interval' ) ) { - $fields[] = ''; - } + $fields[] = ''; // add credentials fields. - $fields[] = '
    ' . __( 'Add credentials to access this URL', 'external-files-in-media-library' ) . '

    ' . __( 'Hint:', 'external-files-in-media-library' ) . ' ' . __( 'Files with credentials will be saved locally.', 'external-files-in-media-library' ) . '

    '; + $fields[] = '
    ' . __( 'Add credentials to access this URL', 'external-files-in-media-library' ) . '

    ' . __( 'Hint:', 'external-files-in-media-library' ) . ' ' . __( 'Files with credentials will be saved locally.', 'external-files-in-media-library' ) . '

    '; /** - * Filter the fields for the dialog. + * Filter the fields for the dialog. Additional fields must be marked with "eml-use-for-import" as class. * * @since 2.0.0 Available since 2.0.0. * @param array $fields List of fields. */ - $fields = apply_filters( 'eml_import_fields', $fields ); - - return $fields; + return apply_filters( 'eml_import_fields', $fields ); } // add URLs field. $fields[] = ''; - // add queue option if it is not disabled. - if ( 'eml_disable_check' !== get_option( 'eml_queue_interval' ) ) { - $fields[] = ''; - } - // add credentials fields. - $fields[] = '
    ' . __( 'Add credentials to access these URLs', 'external-files-in-media-library' ) . '

    ' . __( 'Hint:', 'external-files-in-media-library' ) . ' ' . __( 'files with credentials will be saved locally.', 'external-files-in-media-library' ) . '

    '; + $fields[] = '
    ' . __( 'Add credentials to access these URLs', 'external-files-in-media-library' ) . '

    ' . __( 'Hint:', 'external-files-in-media-library' ) . ' ' . __( 'files with credentials will be saved locally.', 'external-files-in-media-library' ) . '

    '; /** - * Filter the fields for the dialog. + * Filter the fields for the dialog. Additional fields must be marked with "eml-use-for-import" as class. * * @since 2.0.0 Available since 2.0.0. + * * @param array $fields List of fields. */ - $fields = apply_filters( 'eml_import_fields', $fields ); - - // return the list of fields. - return $fields; + return apply_filters( 'eml_import_fields', $fields ); } } diff --git a/app/ExternalFiles/Queue.php b/app/ExternalFiles/Queue.php index 480a5ca..9c1457c 100644 --- a/app/ExternalFiles/Queue.php +++ b/app/ExternalFiles/Queue.php @@ -71,6 +71,10 @@ public function init(): void { add_action( 'admin_action_eml_queue_clear_errors', array( $this, 'delete_errors_by_request' ) ); add_action( 'admin_action_eml_queue_delete_entry', array( $this, 'delete_entry_by_request' ) ); add_action( 'admin_action_eml_queue_process_entry', array( $this, 'process_queue_entry_by_request' ) ); + + // use our own hooks. + add_filter( 'eml_import_fields', array( $this, 'add_field_in_form' ) ); + add_filter( 'eml_import_add_to_queue', array( $this, 'add_urls_to_queue' ), 10, 2 ); } /** @@ -691,4 +695,41 @@ public function delete_entry_by_request(): void { wp_safe_redirect( wp_get_referer() ); exit; } + + /** + * Add a checkbox to mark the fields to add them to queue. + * + * @param array $fields List of fields in form. + * + * @return array + */ + public function add_field_in_form( array $fields ): array { + // bail if queue is disabled. + if( 'eml_disable_check' === get_option( 'eml_queue_interval' ) ) { + return $fields; + } + + // add the field to enable queue-upload. + $fields[] = ''; + + // return the resulting fields. + return $fields; + } + + /** + * Add URLs for queue if the config "add_to_queue" from form request is set. + * + * @param bool $return_value The return value to use (true to import queue). + * @param array $config The config from form. + * + * @return bool + */ + public function add_urls_to_queue( bool $return_value, array $config ): bool { + if( empty( $config['add_to_queue'] ) ) { + return $return_value; + } + + // return true if add to queue is set. + return 1 === absint( $config['add_to_queue'] ); + } } diff --git a/changelog.md b/changelog.md index 30916c2..5e06248 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,8 @@ - Added possibility to add YouTube- and Vimeo-videos as external files - Added possibility to import Youtube-Channel-Videos as external files via YouTube API +- Added marker for proxied files +- Added possibility to customize the handling of adding new URLs to media library with custom PHP - Added more hooks ### Changed @@ -13,6 +15,7 @@ - Introduced Services to platforms which host files (like Imgur or GoogleDrive) - Does not download files via http protocol which should not be hosted locally - Optimized updating or installing log- and queue-tables during plugin update +- Optimized upload dialog regarding the credential usage if browser used autofill-functions - Updated dependencies - Moved changelog from readme.txt in GitHub-repository - Reduced number of calls for external file thumbs @@ -24,6 +27,7 @@ - Fixed potential error if URL is already on media library - Fixed partially wrong saving of meta-data on external media files - Fixed wrong check for already existing thumbs of external files +- Fixed styling of single URL upload field ## [2.0.2] - 2024-11-23 From abeb5dc9c16a85bb8c78d89ba98d7a66f2d73338 Mon Sep 17 00:00:00 2001 From: Thomas Zwirner Date: Sun, 8 Dec 2024 15:45:23 +0100 Subject: [PATCH 6/8] fixed missing check for tmp file in http protocol --- app/ExternalFiles/Protocols/Http.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/ExternalFiles/Protocols/Http.php b/app/ExternalFiles/Protocols/Http.php index b2a6dab..a8d38ce 100644 --- a/app/ExternalFiles/Protocols/Http.php +++ b/app/ExternalFiles/Protocols/Http.php @@ -248,6 +248,11 @@ public function get_url_infos(): array { // get temp file. $tmp_file = $this->get_temp_file( $this->get_url() ); + // bail if tmp file could not be loaded. + if( ! $tmp_file ) { + return array(); + } + // get the content. $content = $wp_filesystem->get_contents( $tmp_file ); @@ -765,7 +770,7 @@ public function get_temp_file( string $url ): false|string { if ( is_wp_error( $tmp_file ) ) { // file is available. /* translators: %1$s by the error in JSON-format. */ - Log::get_instance()->create( sprintf( __( 'Temp file could not be created because of the following error: %1$s', 'external-files-in-media-library' ), '' . wp_strip_all_tags( wp_json_encode( $tmp_file ) ) . '' ), esc_url( $this->get_url() ), 'error', 0 ); + Log::get_instance()->create( sprintf( __( 'Temp file could not be created because of the following error: %1$s', 'external-files-in-media-library' ), '' . wp_strip_all_tags( wp_json_encode( $tmp_file) ) . '' ), esc_url( $this->get_url() ), 'error', 0 ); // return empty array as we got not the file. return false; From 0b9e5a82a636ed8e803ba7d64acc971f032ea4d6 Mon Sep 17 00:00:00 2001 From: Thomas Zwirner Date: Sun, 8 Dec 2024 21:42:12 +0100 Subject: [PATCH 7/8] small woocommerce optimizations --- app/ThirdParty/WooCommerce.php | 35 ++++++++++++++++++++++++++++++++-- changelog.md | 1 + readme.txt | 2 +- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/app/ThirdParty/WooCommerce.php b/app/ThirdParty/WooCommerce.php index d25d604..fb92f8e 100644 --- a/app/ThirdParty/WooCommerce.php +++ b/app/ThirdParty/WooCommerce.php @@ -12,6 +12,7 @@ use ExternalFilesInMediaLibrary\ExternalFiles\Files; use ExternalFilesInMediaLibrary\Plugin\Helper; +use ExternalFilesInMediaLibrary\Plugin\Log; use ExternalFilesInMediaLibrary\Plugin\Settings\Settings; use WC_Product; @@ -84,11 +85,18 @@ public function init(): void { * @return void */ public function init_woocommerce(): void { + // get settings object. $settings_obj = Settings::get_instance(); + + // add settings tab for WooCommerce. $woocommerce_settings_tab = $settings_obj->add_tab( 'woocommerce' ); $woocommerce_settings_tab->set_title( __( 'WooCommerce', 'external-files-in-media-library' ) ); + + // add section for WooCommerce settings. $woocommerce_settings_section = $woocommerce_settings_tab->add_section( 'eml_woocommerce_settings' ); $woocommerce_settings_section->set_title( __( 'WooCommerce', 'external-files-in-media-library' ) ); + + // add setting to enable the WooCommerce-support. $woocommerce_settings_setting = $settings_obj->add_setting( 'eml_woocommerce' ); $woocommerce_settings_setting->set_section( $woocommerce_settings_section ); $woocommerce_settings_setting->set_type( 'integer' ); @@ -115,19 +123,28 @@ public function import_product_image( array $data ): array { return $data; } + // log event. + Log::get_instance()->create( __( 'Trying to import main image of WooCommerce product as external image.', 'external-files-in-media-library' ), $data['raw_image_id'], 'info', 2 ); + + // get the files object. + $external_files_obj = Files::get_instance(); + // add the image and bail if it was not successfully. - if ( ! Files::get_instance()->add_url( $data['raw_image_id'] ) ) { + if ( ! $external_files_obj->add_url( $data['raw_image_id'] ) ) { return $data; } // get the external file object for the given main image. - $external_file_obj = Files::get_instance()->get_file_by_url( $data['raw_image_id'] ); + $external_file_obj = $external_files_obj->get_file_by_url( $data['raw_image_id'] ); // bail if file for the URL does not exist. if ( ! $external_file_obj ) { return $data; } + // log event. + Log::get_instance()->create( __( 'WooCommerce Product main image has been imported as external file.', 'external-files-in-media-library' ), $data['raw_image_id'], 'info', 2 ); + // remove raw_image_id to prevent usage through WooCommerce. unset( $data['raw_image_id'] ); @@ -152,6 +169,9 @@ public function add_product_image( WC_Product $product, array $data ): void { return; } + // log event. + Log::get_instance()->create( __( 'Save external image file as WooCommerce Product main image.', 'external-files-in-media-library' ), '', 'info', 2 ); + // set the given main image on product. wc_product_attach_featured_image( $data['eml_file'], $product ); } @@ -174,6 +194,9 @@ public function import_product_gallery_images( array $data ): array { return $data; } + // log event. + Log::get_instance()->create( __( 'Trying to save WooCommerce product gallery images as external files.', 'external-files-in-media-library' ), '', 'info', 2 ); + // collect all images. $gallery_images = array(); @@ -204,6 +227,9 @@ public function import_product_gallery_images( array $data ): array { return $data; } + // log event. + Log::get_instance()->create( __( 'WooCommerce product gallery images has been saved as external files.', 'external-files-in-media-library' ), '', 'info', 2 ); + // add custom column which we use later to assign the media files to the product. $data['eml_files'] = $gallery_images; @@ -220,10 +246,15 @@ public function import_product_gallery_images( array $data ): array { * @return void */ public function add_product_gallery_images( WC_Product $product, array $data ): void { + // bail if no gallery images are given. if ( empty( $data['eml_files'] ) ) { return; } + // log event. + Log::get_instance()->create( __( 'WooCommerce product gallery images will be saved as external files on the product.', 'external-files-in-media-library' ), '', 'info', 2 ); + + // add them to the product as gallery. $product->set_gallery_image_ids( $data['eml_files'] ); $product->save(); } diff --git a/changelog.md b/changelog.md index 5e06248..88aeb40 100644 --- a/changelog.md +++ b/changelog.md @@ -19,6 +19,7 @@ - Updated dependencies - Moved changelog from readme.txt in GitHub-repository - Reduced number of calls for external file thumbs +- Small optimizations on WooCommerce support during import for products via CSV ### Fixed diff --git a/readme.txt b/readme.txt index 5e1440f..549b474 100644 --- a/readme.txt +++ b/readme.txt @@ -38,7 +38,7 @@ The plugin checks for you automatically on a regular basis whether the external == Settings == -In the settings you can define whether image files are hosted locally in your hosting or externally. +In the settings you can define whether your files are hosted locally in your hosting or externally. == Repository and documentation == From 925f7879e9ba6641a798b88ba1dee4876497fdfa Mon Sep 17 00:00:00 2001 From: Thomas Zwirner Date: Sun, 15 Dec 2024 10:51:02 +0100 Subject: [PATCH 8/8] add GitHub action to build releases --- .github/workflows/build-zip.yml | 74 +++++++++++++++++++++++++++++++++ changelog.md | 1 + readme.md | 7 ++++ 3 files changed, 82 insertions(+) create mode 100644 .github/workflows/build-zip.yml diff --git a/.github/workflows/build-zip.yml b/.github/workflows/build-zip.yml new file mode 100644 index 0000000..215e855 --- /dev/null +++ b/.github/workflows/build-zip.yml @@ -0,0 +1,74 @@ +name: Build release zip + +on: + push: + tags: + - '*' + +jobs: + build: + name: Build release zip + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup WP-CLI + uses: godaddy-wordpress/setup-wp-cli@1 + + - name: Run package installs and builds + run: | + composer install + composer update + npm i + npm i concurrently + + - name: Generate autoloader + run: composer dump-autoload -oa --no-dev + + - name: Run WordPress Coding Standard fixes + run: vendor/bin/phpcbf --extensions=php --ignore=*/vendor/*,*/svn/* --standard=ruleset.xml . + + - name: Run WordPress Coding Standard checks + run: vendor/bin/phpcs --extensions=php --ignore=*/vendor/*,*/svn/* --standard=ruleset.xml . + + - name: Generate hook documentation + run: vendor/bin/wp-documentor parse app --format=markdown --output=docs/hooks.md --prefix=eml_ + + - name: Set version number 1 + uses: richardrigutins/replace-in-files@v2 + with: + files: 'external-files-in-media-library.php' + search-text: '@@VersionNumber@@' + replacement-text: ${{ github.ref_name }} + + - name: Set version number 3 + uses: richardrigutins/replace-in-files@v2 + with: + files: 'readme.txt' + search-text: '@@VersionNumber@@' + replacement-text: ${{ github.ref_name }} + + - name: Create ZIP release + run: | + rm -fr build + rm -fr releases + rm -fr svn + rm -fr languages + rm changelog.md + rm readme.md + rm ruleset.xml + cd .. + zip -r -q ${{ github.event.repository.name }}_${{ github.ref_name }}.zip ${{ github.event.repository.name }}/* -x "*/.git/*" "*/.github/*" "*/blocks/*/src/*" "*/doc/*" "*/legacy-classes/Divi/.yarn/*" "*/phpcs.xml" "*/composer.json" "*/composer.lock" "*/package.json" "*/package-lock.json" "*/ruleset.xml" "*/.gitignore" "*/vendor/*" "*/node_modules/*" "/.editorconfig" + zip -ur ${{ github.event.repository.name }}_${{ github.ref_name }}.zip ${{ github.event.repository.name }}/vendor/autoload.php + zip -ur ${{ github.event.repository.name }}_${{ github.ref_name }}.zip ${{ github.event.repository.name }}/vendor/composer/* + zip -ur ${{ github.event.repository.name }}_${{ github.ref_name }}.zip ${{ github.event.repository.name }}/vendor/threadi/*/build/* + cp ${{ github.event.repository.name }}_${{ github.ref_name }}.zip ${{ github.event.repository.name }}/ + + - name: Create Release + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + files: ${{ github.event.repository.name }}_${{ github.ref_name }}.zip diff --git a/changelog.md b/changelog.md index 88aeb40..3347a50 100644 --- a/changelog.md +++ b/changelog.md @@ -9,6 +9,7 @@ - Added marker for proxied files - Added possibility to customize the handling of adding new URLs to media library with custom PHP - Added more hooks +- Added GitHub action to build plugin releases ### Changed diff --git a/readme.md b/readme.md index 19ea07a..8c62e26 100644 --- a/readme.md +++ b/readme.md @@ -18,10 +18,17 @@ After checkout go through the following steps: ## Release +### from local environment + 1. increase the version number in _build/build.properties_. 2. execute the following command in _build/_: `ant build` 3. after that you will finde in the release directory a zip file which could be used in WordPress to install it. +### on GitHub + +1. Create a new tag with the new version number. +2. The release zip will be created by GitHub action. + ## Translations I recommend to use [PoEdit](https://poedit.net/) to translate texts for this plugin.