diff --git a/.github/workflows/pr_verify_linked_issue.yml b/.github/workflows/pr_verify_linked_issue.yml index 2c0514c2..861ecff7 100755 --- a/.github/workflows/pr_verify_linked_issue.yml +++ b/.github/workflows/pr_verify_linked_issue.yml @@ -2,7 +2,7 @@ name: Verify PR on: pull_request: - types: [ edited, synchronize, opened, reopened ] + types: [edited, synchronize, opened, reopened] branches: - development check_run: @@ -19,13 +19,13 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.BOT_TOKEN }} with: - quiet: 'true' + quiet: "true" - name: Find Comment uses: peter-evans/find-comment@v1 id: find_coomment with: issue-number: ${{ github.event.pull_request.number }} - comment-author: 'pirate-bot' + comment-author: "pirate-bot" body-includes: No Linked Issue found - name: Create or update comment uses: peter-evans/create-or-update-comment@v1 @@ -41,9 +41,9 @@ jobs: if: steps.verify_linked_issues.outputs.has_linked_issues == 'false' run: exit 1; - name: Delete comment - uses: jungwinter/comment@v1 + uses: winterjung/comment@v1 if: steps.verify_linked_issues.outputs.has_linked_issues == 'true' && steps.find_coomment.outputs.comment-id != '' with: type: delete comment_id: ${{ steps.find_coomment.outputs.comment-id }} - token: ${{ secrets.BOT_TOKEN }} \ No newline at end of file + token: ${{ secrets.BOT_TOKEN }} diff --git a/composer.json b/composer.json index 848f1c06..2827678a 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "source": "https://github.com/Codeinwp/feedzy-rss-feeds" }, "require": { - "codeinwp/themeisle-sdk": "^3.2" + "codeinwp/themeisle-sdk": "^3.3" }, "autoload": { "files": [ diff --git a/composer.lock b/composer.lock index 0f974c16..65c5246f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "97eb2251fdc012f5c1c5894605a1a338", + "content-hash": "24aa0794184be44173a59d590a9e6fa8", "packages": [ { "name": "codeinwp/themeisle-sdk", - "version": "3.3.14", + "version": "3.3.16", "source": { "type": "git", "url": "https://github.com/Codeinwp/themeisle-sdk.git", - "reference": "662952078c57b12e4d3af9bc98ef847ea3500206" + "reference": "94e9274d32bda46fe675be4160be8bfceb034278" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeinwp/themeisle-sdk/zipball/662952078c57b12e4d3af9bc98ef847ea3500206", - "reference": "662952078c57b12e4d3af9bc98ef847ea3500206", + "url": "https://api.github.com/repos/Codeinwp/themeisle-sdk/zipball/94e9274d32bda46fe675be4160be8bfceb034278", + "reference": "94e9274d32bda46fe675be4160be8bfceb034278", "shasum": "" }, "require-dev": { @@ -42,9 +42,9 @@ ], "support": { "issues": "https://github.com/Codeinwp/themeisle-sdk/issues", - "source": "https://github.com/Codeinwp/themeisle-sdk/tree/v3.3.14" + "source": "https://github.com/Codeinwp/themeisle-sdk/tree/v3.3.16" }, - "time": "2024-02-27T17:30:04+00:00" + "time": "2024-03-29T10:39:36+00:00" } ], "packages-dev": [ diff --git a/css/metabox-settings.css b/css/metabox-settings.css index dfec6926..fae7c4c5 100644 --- a/css/metabox-settings.css +++ b/css/metabox-settings.css @@ -42,16 +42,16 @@ .fz-input-group{flex-wrap: wrap;} .fz-input-group .fz-input-group-right{width: 100%; padding-left: 0; padding-top: 8px;} .fz-input-group .fz-input-group-right .btn.dropdown-toggle{width: 100%;} - .fz-form-wrap .form-block.form-block-two-column .left{width: 100%; padding-right: 0; padding-bottom: 24px;} - .fz-form-wrap .form-block.form-block-two-column .right{width: 100%;} - .fz-form-action .left{width: 100%; padding-bottom: 16px;} - .fz-form-action .left .btn{width: 100%; display: block; text-align: center;} - .fz-form-action .right{width: 100%; flex-direction: column;} - .fz-form-action .right .btn + .btn{margin-left: 0; margin-top: 8px;} + .fz-form-wrap .form-block.form-block-two-column .fz-left{width: 100%; padding-right: 0; padding-bottom: 24px;} + .fz-form-wrap .form-block.form-block-two-column .fz-right{width: 100%;} + .fz-form-action .fz-left{width: 100%; padding-bottom: 16px;} + .fz-form-action .fz-left .btn{width: 100%; display: block; text-align: center;} + .fz-form-action .fz-right{width: 100%; flex-direction: column;} + .fz-form-action .fz-right .btn + .btn{margin-left: 0; margin-top: 8px;} .fz-form-row .fz-form-col-6, .fz-form-row .fz-form-col-4, .fz-form-row .fz-form-col-8{width: 100%;} .fz-document-list > ul > li{width: 100%;} - .fz-help-improve-box .left{width: 100%;} - .fz-help-improve-box .right{width: 100%;} + .fz-help-improve-box .fz-left{width: 100%;} + .fz-help-improve-box .fz-right{width: 100%;} .fz-tabs-menu ul {flex-wrap: wrap;} .fz-tabs-menu ul li{flex-shrink: 0; width: 50%;} .fz-tabs-menu ul li a{padding: 0px; border: 1px solid transparent;} diff --git a/css/settings.css b/css/settings.css index 15c775ee..98304e62 100644 --- a/css/settings.css +++ b/css/settings.css @@ -350,14 +350,15 @@ fieldset[disabled] .form-control { display: flex; flex-wrap: wrap; } -.fz-form-wrap .form-block.form-block-two-column .left{ +.fz-form-wrap .form-block.form-block-two-column .fz-left{ width: 285px; padding-right: 24px; } -.fz-form-wrap .form-block.form-block-two-column .right{ +.fz-form-wrap .form-block.form-block-two-column .fz-right{ width: calc(100% - 285px); + text-align: left; } -.fz-form-wrap .form-block.form-block-two-column .right .upgrade-alert{ +.fz-form-wrap .form-block.form-block-two-column .fz-right .upgrade-alert{ margin-top: 20px; } .fz-form-wrap .form-block .only-pro-content{ @@ -666,14 +667,14 @@ input.fz-switch-toggle[type=checkbox]:checked:before{ flex-wrap: wrap; justify-content: space-between; } -.fz-form-action .right{ +.fz-form-action .fz-right{ display: flex; flex-wrap: wrap; } -.fz-form-action .right .btn{ +.fz-form-action .fz-right .btn{ margin-bottom: 8px; } -.fz-form-action .right .btn + .btn{ +.fz-form-action .fz-right .btn + .btn{ margin-left: 16px; } @@ -901,9 +902,9 @@ input.fz-switch-toggle[type=checkbox]:checked:before{ } .fz-form-wrap .tagify__tag{ position: relative; - margin-left: 0; - margin-right: 16px; - margin-bottom: 16px; + margin-left: 2px; + margin-right: 2px; + margin-bottom: 2px; vertical-align: top; } .fz-form-wrap .tagify__tag>div{ @@ -1310,18 +1311,18 @@ input.fz-switch-toggle[type=checkbox]:checked:before{ flex-direction: row-reverse; border: 1px solid #D9D9D9; } -.fz-help-improve-box .left{ +.fz-help-improve-box .fz-left{ width: calc(100% - 320px); padding: 30px; } -.fz-help-improve-box .left p{ +.fz-help-improve-box .fz-left p{ font-size: 16px; line-height: 24px; color: #050505; margin-bottom: 24px; max-width: 710px; } -.fz-help-improve-box .right{ +.fz-help-improve-box .fz-right{ width: 320px; padding: 18px; background-color: #F5F7F9; diff --git a/feedzy-rss-feed.php b/feedzy-rss-feed.php index 9a5c362e..e079f18a 100644 --- a/feedzy-rss-feed.php +++ b/feedzy-rss-feed.php @@ -129,6 +129,7 @@ function run_feedzy_rss_feeds() { define( 'FEEDZY_REST_VERSION', '1' ); // to redirect all themeisle_log_event to error log. define( 'FEEDZY_LOCAL_DEBUG', false ); + define( 'FEEDZY_FEED_CUSTOM_TAG_NAMESPACE', 'http://feedzy.themeisle.com' ); // always make this true before testing // also used in gutenberg. diff --git a/includes/abstract/feedzy-rss-feeds-admin-abstract.php b/includes/abstract/feedzy-rss-feeds-admin-abstract.php index 32770a68..1e7c78e9 100644 --- a/includes/abstract/feedzy-rss-feeds-admin-abstract.php +++ b/includes/abstract/feedzy-rss-feeds-admin-abstract.php @@ -679,7 +679,7 @@ public function get_short_code_attributes( $atts ) { * * @param string $raw Url or list of urls. * - * @return mixed|void Urls of the feeds. + * @return string|array Urls of the feeds. */ public function normalize_urls( $raw ) { $feeds = apply_filters( 'feedzy_process_feed_source', $raw ); @@ -1412,12 +1412,12 @@ public function get_feed_array( $feed_items, $sc, $feed, $feed_url, $sizes ) { * @since 3.0.0 * @access private * - * @param array $sc The shorcode attributes array. - * @param array $sizes The sizes array. - * @param object $item The feed item object. - * @param string $feed_url The feed url. - * @param int $index The item number (may not be the same as the item_index). - * @param int $item_index The real index of this items in the feed (maybe be different from $index if filters are used). + * @param array $sc The shorcode attributes array. + * @param array $sizes The sizes array. + * @param \SimplePie_Item $item The feed item object. + * @param string $feed_url The feed url. + * @param int $index The item number (may not be the same as the item_index). + * @param int $item_index The real index of this items in the feed (maybe be different from $index if filters are used). * * @return array */ @@ -1515,8 +1515,14 @@ private function get_feed_item_filter( $sc, $sizes, $item, $feed_url, $index, $i // multiple sources? $is_multiple = is_array( $feed_url ); - $feed_source = $item->get_feed()->get_title(); + $feed_source = ''; + $feed_source_tags = $item->get_item_tags( FEEDZY_FEED_CUSTOM_TAG_NAMESPACE, 'parent-source' ); + if ( ! empty( $feed_source_tags ) && ! empty( $feed_source_tags[0]['data'] ) ) { + $feed_source = $feed_source_tags[0]['data']; + } else { + $feed_source = $item->get_feed()->get_title(); + } // author. if ( $item->get_author() && $meta_args['author'] ) { $author = $item->get_author(); diff --git a/includes/admin/feedzy-rss-feeds-actions.php b/includes/admin/feedzy-rss-feeds-actions.php index a8f94c68..d981edfa 100644 --- a/includes/admin/feedzy-rss-feeds-actions.php +++ b/includes/admin/feedzy-rss-feeds-actions.php @@ -453,21 +453,25 @@ private function summarize_content() { } /** - * Generate item image. + * Generate item image using OpenAI. + * Return default value if OpenAI is not available or `Generate only for missing images` option is enabled and feed has image. * - * @return string + * @return string Image URL to download. */ private function generate_image() { - $content = call_user_func( array( $this, 'item_title' ) ); + if ( ! class_exists( '\Feedzy_Rss_Feeds_Pro_Openai' ) ) { return isset( $this->default_value ) ? $this->default_value : ''; } - if ( $this->current_job->data->generateImgWithChatGPT && empty( $this->default_value ) ) { + + $feed_has_image = false !== filter_var( $this->default_value, FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED ); + if ( ( ! isset( $this->current_job->data->generateOnlyMissingImages ) || ! empty( $this->current_job->data->generateOnlyMissingImages ) ) && $feed_has_image ) { return isset( $this->default_value ) ? $this->default_value : ''; } - $openai = new \Feedzy_Rss_Feeds_Pro_Openai(); - $content = $openai->call_api( $this->settings, $content, 'image', array() ); - return $content; + + $prompt = call_user_func( array( $this, 'item_title' ) ); + $openai = new \Feedzy_Rss_Feeds_Pro_Openai(); + return $openai->call_api( $this->settings, $prompt, 'image', array() ); } } } diff --git a/includes/admin/feedzy-rss-feeds-import.php b/includes/admin/feedzy-rss-feeds-import.php index 8d63c40b..cc4a9f78 100644 --- a/includes/admin/feedzy-rss-feeds-import.php +++ b/includes/admin/feedzy-rss-feeds-import.php @@ -1187,13 +1187,20 @@ public function run_cron( $max = 100 ) { 'post_status' => 'publish', 'numberposts' => 99, ); + $feedzy_imports = get_posts( $args ); foreach ( $feedzy_imports as $job ) { - $result = $this->run_job( $job, $max ); - if ( empty( $result ) ) { - $this->run_job( $job, $max ); + try { + $result = $this->run_job( $job, $max ); + if ( empty( $result ) ) { + $this->run_job( $job, $max ); + } + do_action( 'feedzy_run_cron_extra', $job ); + } catch ( Exception $e ) { + if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { + error_log( '[Feedzy Run Cron][Post title: ' . ( ! empty( $job->post_title ) ? $job->post_title : '' ) . '] Error: ' . $e->getMessage() ); + } } - do_action( 'feedzy_run_cron_extra', $job ); } } @@ -1409,6 +1416,9 @@ private function run_job( $job, $max ) { $item_date = date( get_option( 'date_format' ) . ' at ' . get_option( 'time_format' ), $item['item_date'] ); $item_date = $item['item_date_formatted']; + // Transform any structure like [[{"value":"[#item_title]"}]] to [#item_title]. + $import_title = preg_replace( '/\[\[\{"value":"(\[#[^]]+\])"\}\]\]/', '$1', $import_title ); + // Get translated item title. $translated_title = ''; if ( $import_auto_translation && ( false !== strpos( $import_title, '[#translated_title]' ) || false !== strpos( $post_excerpt, '[#translated_title]' ) ) ) { @@ -1639,16 +1649,16 @@ private function run_job( $job, $max ) { } if ( 'attachment' === $import_post_type ) { - $image_url = ''; - $img_success = true; - $new_post_id = 0; - $default_img_tag = ! empty( $import_featured_img ) ? '[#item_image]' : ''; + $image_source_url = ''; + $img_success = true; + $new_post_id = 0; + $default_img_tag = ! empty( $import_featured_img ) ? '[#item_image]' : ''; // image tag if ( strpos( $default_img_tag, '[#item_image]' ) !== false ) { // image exists in item if ( ! empty( $item['item_img_path'] ) ) { - $image_url = str_replace( '[#item_image]', $item['item_img_path'], $default_img_tag ); + $image_source_url = str_replace( '[#item_image]', $item['item_img_path'], $default_img_tag ); } else { $img_success = false; } @@ -1659,16 +1669,16 @@ private function run_job( $job, $max ) { } if ( ! empty( $value ) && strpos( $value, '[#item_custom' ) === false ) { - $image_url = $value; + $image_source_url = $value; } else { $img_success = false; } } else { - $image_url = $default_img_tag; + $image_source_url = $default_img_tag; } - if ( ! empty( $image_url ) ) { - $img_success = $this->generate_featured_image( $image_url, 0, $item['item_title'], $import_errors, $import_info, $new_post ); + if ( ! empty( $image_source_url ) ) { + $img_success = $this->try_save_featured_image( $image_source_url, 0, $item['item_title'], $import_errors, $import_info, $new_post ); $new_post_id = $img_success; } @@ -1751,14 +1761,14 @@ function( $term ) { $default_img_tag = ! empty( $import_featured_img ) ? '[#item_image]' : ''; if ( ! empty( $default_img_tag ) && 'attachment' !== $import_post_type ) { - $image_url = ''; + $image_source_url = ''; $img_success = true; // image tag if ( strpos( $default_img_tag, '[#item_image]' ) !== false ) { // image exists in item if ( ! empty( $item['item_img_path'] ) ) { - $image_url = str_replace( '[#item_image]', $item['item_img_path'], $default_img_tag ); + $image_source_url = str_replace( '[#item_image]', $item['item_img_path'], $default_img_tag ); } else { $img_success = false; } @@ -1768,14 +1778,14 @@ function( $term ) { $value = apply_filters( 'feedzy_parse_custom_tags', $default_img_tag, $item_obj ); } if ( ! empty( $value ) && strpos( $value, '[#item_custom' ) === false ) { - $image_url = $value; + $image_source_url = $value; } else { $img_success = false; } } // Fetch image from graby. - if ( empty( $image_url ) && ( wp_doing_cron() || defined( 'FEEDZY_PRO_FETCH_ITEM_IMG_URL' ) ) ) { + if ( empty( $image_source_url ) && ( wp_doing_cron() && defined( 'FEEDZY_PRO_FETCH_ITEM_IMG_URL' ) ) ) { // if license does not exist, use the site url // this should obviously never happen unless on dev instances. $license = apply_filters( 'product_feedzy_license_key', sprintf( 'n/a - %s', get_site_url() ) ); @@ -1806,7 +1816,7 @@ function( $term ) { if ( ! is_wp_error( $body ) ) { $response_data = json_decode( $body, true ); if ( isset( $response_data['url'] ) ) { - $image_url = $response_data['url']; + $image_source_url = $response_data['url']; } } else { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r @@ -1824,15 +1834,15 @@ function( $term ) { $import_featured_img = trim( $import_featured_img ); $img_action = $this->handle_content_actions( $import_featured_img, 'item_image' ); // Item image action process. - $image_url = $img_action->run_action_job( $import_featured_img, $import_translation_lang, $job, $language_code, $item, $image_url ); + $image_source_url = $img_action->run_action_job( $import_featured_img, $import_translation_lang, $job, $language_code, $item, $image_source_url ); - if ( ! empty( $image_url ) ) { + if ( ! empty( $image_source_url ) ) { if ( 'yes' === $import_item_img_url ) { // Set external image URL. - update_post_meta( $new_post_id, 'feedzy_item_external_url', $image_url ); + update_post_meta( $new_post_id, 'feedzy_item_external_url', $image_source_url ); } else { // if import_featured_img is a tag. - $img_success = $this->generate_featured_image( $image_url, $new_post_id, $item['item_title'], $import_errors, $import_info ); + $img_success = $this->try_save_featured_image( $image_source_url, $new_post_id, $item['item_title'], $import_errors, $import_info ); } } } @@ -1970,33 +1980,39 @@ public function tryReuseExistingFeaturedImage( &$result, $title_feed, $post_id = /** * Downloads and sets a post featured image if possible. * - * @param string $file The file URL. + * @param string $img_source_url The download source URL for the image. * @param integer $post_id The post ID. - * @param string $desc Description. + * @param string $post_title Post title. Used to check if an attachment with the same title exists. * @param array $import_errors Array of import error messages. * @param array $import_info Array of import information messages. * - * @return bool + * @return bool|int Return the attachment ID if the image was successfully attached to the post, false otherwise. * @since 1.2.0 * @access private */ - private function generate_featured_image( $file, $post_id, $desc, &$import_errors, &$import_info, $post_data = array() ) { + private function try_save_featured_image( $img_source_url, $post_id, $post_title, &$import_errors, &$import_info, $post_data = array() ) { if ( ! function_exists( 'post_exists' ) ) { require_once ABSPATH . 'wp-admin/includes/post.php'; } // Find existing attachment by item title. - $id = post_exists( $desc, '', '', 'attachment' ); + $id = post_exists( $post_title, '', '', 'attachment' ); if ( ! $id ) { - do_action( 'themeisle_log_event', FEEDZY_NAME, sprintf( 'Trying to generate featured image for %s and postID %d', $file, $post_id ), 'debug', __FILE__, __LINE__ ); + + if ( filter_var( $img_source_url, FILTER_VALIDATE_URL ) === false ) { + $import_errors[] = 'Invalid Featured Image URL: ' . $img_source_url; + return false; + } + + do_action( 'themeisle_log_event', FEEDZY_NAME, sprintf( 'Trying to save the featured image for %s and postID %d', $img_source_url, $post_id ), 'debug', __FILE__, __LINE__ ); require_once ABSPATH . 'wp-admin' . '/includes/image.php'; require_once ABSPATH . 'wp-admin' . '/includes/file.php'; require_once ABSPATH . 'wp-admin' . '/includes/media.php'; - $file_array = array(); - $file = trim( $file, chr( 0xC2 ) . chr( 0xA0 ) ); - $local_file = download_url( $file ); + $file_array = array(); + $img_source_url = trim( $img_source_url, chr( 0xC2 ) . chr( 0xA0 ) ); + $local_file = download_url( $img_source_url ); if ( is_wp_error( $local_file ) ) { do_action( 'themeisle_log_event', FEEDZY_NAME, sprintf( 'Unable to download file = %s and postID %d', print_r( $local_file, true ), $post_id ), 'error', __FILE__, __LINE__ ); @@ -2023,7 +2039,7 @@ private function generate_featured_image( $file, $post_id, $desc, &$import_error $file_array['tmp_name'] = $local_file; $file_array['name'] = basename( $local_file ); - $id = media_handle_sideload( $file_array, $post_id, $desc, $post_data ); + $id = media_handle_sideload( $file_array, $post_id, $post_title, $post_data ); if ( is_wp_error( $id ) ) { do_action( 'themeisle_log_event', FEEDZY_NAME, sprintf( 'Unable to attach file for postID %d = %s', $post_id, print_r( $id, true ) ), 'error', __FILE__, __LINE__ ); unlink( $file_array['tmp_name'] ); @@ -2031,7 +2047,7 @@ private function generate_featured_image( $file, $post_id, $desc, &$import_error return false; } } else { - do_action( 'themeisle_log_event', FEEDZY_NAME, sprintf( 'Found an existing attachment(ID: %d) image for %s and postID %d', $id, $file, $post_id ), 'debug', __FILE__, __LINE__ ); + do_action( 'themeisle_log_event', FEEDZY_NAME, sprintf( 'Found an existing attachment(ID: %d) image for %s and postID %d', $id, $img_source_url, $post_id ), 'debug', __FILE__, __LINE__ ); } if ( ! empty( $post_data ) ) { @@ -2914,7 +2930,7 @@ private function wizard_import_feed() { * * @param string $actions Item content actions. * @param string $type Action type. - * @return object `Feedzy_Rss_Feeds_Actions` class instance. + * @return Feedzy_Rss_Feeds_Actions Instance of Feedzy_Rss_Feeds_Actions. */ public function handle_content_actions( $actions = '', $type = '' ) { $action_instance = Feedzy_Rss_Feeds_Actions::instance(); diff --git a/includes/layouts/feedzy-improve.php b/includes/layouts/feedzy-improve.php index f90a4cf2..97468f48 100644 --- a/includes/layouts/feedzy-improve.php +++ b/includes/layouts/feedzy-improve.php @@ -1,10 +1,10 @@
-
+
-
+

Answer a few questions to help us improve Feedzy

We're always looking for suggestions to further improve Feedzy. diff --git a/includes/views/import-metabox-edit.php b/includes/views/import-metabox-edit.php index f9c946c2..ecf69cc4 100644 --- a/includes/views/import-metabox-edit.php +++ b/includes/views/import-metabox-edit.php @@ -126,7 +126,7 @@ class="dashicons dashicons-arrow-down-alt2">

-
+

PRO' : ''; ?>

-
+
@@ -180,10 +180,10 @@ class="dashicons dashicons-arrow-down-alt2">
-
+

PRO' : ''; ?>

-
+
@@ -223,10 +223,10 @@ class="dashicons dashicons-arrow-down-alt2">
-
+

PRO' : ''; ?>

-
+