From e39839284621ba03c30a76bbd1911a09024af96b Mon Sep 17 00:00:00 2001 From: Hardeep Asrani Date: Fri, 13 Dec 2024 03:43:52 +0530 Subject: [PATCH 01/15] [wip] Import Conditions --- css/settings.css | 92 ++++- .../feedzy-rss-feeds-admin-abstract.php | 183 ++-------- includes/admin/feedzy-rss-feeds-admin.php | 21 ++ includes/admin/feedzy-rss-feeds-import.php | 49 ++- includes/feedzy-rss-feeds.php | 5 +- includes/util/feedzy-rss-feeds-conditions.php | 331 ++++++++++++++++++ includes/views/import-metabox-edit.php | 146 +------- js/Conditions/ConditionsControl.js | 204 +++++++++++ js/Conditions/DateTimeControl.js | 53 +++ js/Conditions/PanelTab.js | 47 +++ js/Conditions/conditions.js | 60 ++++ 11 files changed, 879 insertions(+), 312 deletions(-) create mode 100644 includes/util/feedzy-rss-feeds-conditions.php create mode 100644 js/Conditions/ConditionsControl.js create mode 100644 js/Conditions/DateTimeControl.js create mode 100644 js/Conditions/PanelTab.js create mode 100644 js/Conditions/conditions.js diff --git a/css/settings.css b/css/settings.css index faa136c4..22589b51 100644 --- a/css/settings.css +++ b/css/settings.css @@ -89,6 +89,7 @@ .mb-20{margin-bottom: 20px;} .mb-30{margin-bottom: 30px;} .mb-24{margin-bottom: 24px;} +.mt-24{margin-top: 24px;} .mx-320{ max-width: 320px; } @@ -2358,4 +2359,93 @@ li.draggable-item .components-panel__body-toggle.components-button{ .feedzy-optimole-upsell .pro-label.free-label { color: #4268CF; background: rgba(66, 104, 207, 0.20); -} \ No newline at end of file +} + +.fz-condition-control { + padding: 24px 0; +} + +.fz-conditions .components-disabled { + opacity: 0.5; +} + +.fz-condition-control .components-button { + width: 100%; + margin: 0; + padding: 6px 12px; + justify-content: center; +} + +.fz-panel-tab { + z-index: 999999; + margin: 24px 0; +} + +.fz-panel-tab .fz-panel-tab__header { + display: flex; + background: #fff; + border: 1px solid #d5dadf; +} + +.fz-panel-tab .fz-panel-tab__header .fz-panel-tab__header__label { + cursor: pointer; + flex-basis: 90%; + display: flex; + align-items: center; + padding-left: 15px; +} + +.fz-panel-tab .fz-panel-tab__header .fz-panel-tab__header__label::selection { + background: none; +} + +.fz-panel-tab .fz-panel-tab__header .components-button { + height: auto; + flex-basis: 10%; + justify-content: center; + padding: 10px 5px; + border-left: 1px solid #d5dadf; + border-radius: 0; +} + +.fz-panel-tab .fz-panel-tab__header .components-button .dashicon { + margin: 2px; +} + +.fz-panel-tab .fz-panel-tab__header:hover { + background: #fafafb; +} + +.fz-panel-tab .fz-panel-tab__content { + background: #fff; + border: 1px solid #d5dadf; + border-top: none; + padding: 10px 15px; +} + +.fz-panel-tab .fz-panel-tab__content .components-select-control label { + overflow: visible; + white-space: normal; +} + +.fz-panel-tab .fz-panel-tab__content .components-base-control { + margin: 12px 0; +} + +.fz-panel-tab .fz-panel-tab__content .components-base-control .components-dropdown { + width: 100%; +} + +.fz-panel-tab .fz-panel-tab__content .components-base-control .components-dropdown .components-button { + display: flex; + justify-content: center; + width: 100%; +} + +.fz-panel-tab .fz-panel-tab__content .components-base-control .components-datetime__time-field-hours-input { + min-width: 60px; +} + +.fz-panel-tab .fz-panel-tab__content .components-base-control .components-datetime__timezone { + display: inline-block; +} diff --git a/includes/abstract/feedzy-rss-feeds-admin-abstract.php b/includes/abstract/feedzy-rss-feeds-admin-abstract.php index a67338f7..fc285757 100644 --- a/includes/abstract/feedzy-rss-feeds-admin-abstract.php +++ b/includes/abstract/feedzy-rss-feeds-admin-abstract.php @@ -301,78 +301,6 @@ public function feedzy_summary_input_filter( $description, $content, $feed_url ) return $description; } - /** - * Check title for keywords - * - * @since 3.0.0 - * @access public - * - * @param boolean $continue A boolean to stop the script. - * @param array $sc The shortcode attributes. - * @param object $item The feed item. - * @param string $feed_url The feed URL. - * - * @return boolean - */ - public function feedzy_feed_item_keywords_title( $continue, $sc, $item, $feed_url ) { - if ( feedzy_is_new() && ! feedzy_is_pro() ) { - return true; - } - - $inc_on = ! empty( $sc['keywords_inc_on'] ) ? $sc['keywords_inc_on'] : 'title'; - $exc_on = ! empty( $sc['keywords_exc_on'] ) ? $sc['keywords_exc_on'] : 'title'; - - if ( isset( $sc['keywords_inc'] ) && ! empty( $sc['keywords_inc'] ) ) { - $keywords = $sc['keywords_inc']; - if ( ! empty( $keywords ) ) { - $continue = false; - if ( ! empty( $inc_on ) ) { - $continue = $this->feedzy_feed_item_keywords_by( $item, $inc_on, $keywords, $sc ); - } elseif ( preg_match( "/^$keywords.*$/i", $item->get_title() ) || preg_match( "/^$keywords.*$/i", $item->get_description() ) ) { - $continue = true; - } - } - } elseif ( isset( $sc['keywords_title'] ) && ! empty( $sc['keywords_title'] ) ) { - $keywords = $sc['keywords_title']; - if ( ! empty( $keywords ) ) { - $continue = false; - if ( ! empty( $inc_on ) ) { - $continue = $this->feedzy_feed_item_keywords_by( $item, $inc_on, $keywords, $sc ); - } elseif ( preg_match( "/^$keywords.*$/i", $item->get_title() ) ) { - $continue = true; - } - } - } - - if ( isset( $sc['keywords_exc'] ) && ! empty( $sc['keywords_exc'] ) ) { - $keywords = $sc['keywords_exc']; - if ( ! empty( $keywords ) ) { - if ( ! empty( $exc_on ) ) { - $exc_item = $this->feedzy_feed_item_keywords_by( $item, $exc_on, $keywords, $sc ); - if ( $exc_item ) { - $continue = false; - } - } elseif ( ! preg_match( "/^$keywords.*$/i", $item->get_title() ) || ! preg_match( "/^$keywords.*$/i", $item->get_description() ) ) { - $continue = false; - } - } - } elseif ( isset( $sc['keywords_ban'] ) && ! empty( $sc['keywords_ban'] ) ) { - $keywords = $sc['keywords_ban']; - if ( ! empty( $keywords ) ) { - if ( ! empty( $exc_on ) ) { - $keywords_ban = $this->feedzy_feed_item_keywords_by( $item, $exc_on, $keywords, $sc ); - if ( $keywords_ban ) { - $continue = false; - } - } elseif ( preg_match( "/^$keywords.*$/i", $item->get_title() ) ) { - $continue = false; - } - } - } - - return $continue; - } - /** * Include cover picture (medium) to rss feed enclosure * and media:content @@ -514,6 +442,22 @@ public function feedzy_rss( $atts, $content = '' ) { } } + $sc['filters'] = apply_filters( 'feedzy_filter_conditions_migration', $sc ); + + $sc = array_diff_key( + $sc, + array( + 'keywords_title' => '', + 'keywords_inc' => '', + 'keywords_inc_on' => '', + 'keywords_exc' => '', + 'keywords_exc_on' => '', + 'keywords_ban' => '', + 'from_datetime' => '', + 'to_datetime' => '', + ) + ); + $feed = $this->fetch_feed( $feed_url, $cache, $sc ); if ( is_string( $feed ) ) { return $feed; @@ -560,6 +504,23 @@ public function feedzy_lazy_load( $data ) { $atts = $data['args']; $sc = $this->get_short_code_attributes( $atts ); $feed_url = $this->normalize_urls( $sc['feeds'] ); + + $sc['filters'] = apply_filters( 'feedzy_filter_conditions_migration', $sc ); + + $sc = array_diff_key( + $sc, + array( + 'keywords_title' => '', + 'keywords_inc' => '', + 'keywords_inc_on' => '', + 'keywords_exc' => '', + 'keywords_exc_on' => '', + 'keywords_ban' => '', + 'from_datetime' => '', + 'to_datetime' => '', + ) + ); + $feed = $this->fetch_feed( $feed_url, $sc['refresh'], $sc ); if ( is_string( $feed ) ) { return $feed; @@ -1087,30 +1048,6 @@ public function sanitize_attr( $sc, $feed_url ) { if ( empty( $sc['size'] ) || ! ctype_digit( (string) $sc['size'] ) ) { $sc['size'] = '150'; } - if ( ! empty( $sc['keywords_title'] ) ) { - if ( is_array( $sc['keywords_title'] ) ) { - $sc['keywords_title'] = implode( ',', $sc['keywords_title'] ); - } - $sc['keywords_title'] = feedzy_filter_custom_pattern( $sc['keywords_title'] ); - } - if ( ! empty( $sc['keywords_inc'] ) ) { - if ( is_array( $sc['keywords_inc'] ) ) { - $sc['keywords_inc'] = implode( ',', $sc['keywords_inc'] ); - } - $sc['keywords_inc'] = feedzy_filter_custom_pattern( $sc['keywords_inc'] ); - } - if ( ! empty( $sc['keywords_ban'] ) ) { - if ( is_array( $sc['keywords_ban'] ) ) { - $sc['keywords_ban'] = implode( ',', $sc['keywords_ban'] ); - } - $sc['keywords_ban'] = feedzy_filter_custom_pattern( $sc['keywords_ban'] ); - } - if ( ! empty( $sc['keywords_exc'] ) ) { - if ( is_array( $sc['keywords_exc'] ) ) { - $sc['keywords_exc'] = implode( ',', $sc['keywords_exc'] ); - } - $sc['keywords_exc'] = feedzy_filter_custom_pattern( $sc['keywords_exc'] ); - } if ( empty( $sc['summarylength'] ) || ! is_numeric( $sc['summarylength'] ) ) { $sc['summarylength'] = ''; } @@ -1937,60 +1874,6 @@ protected function array_insert_before( $key, &$array, $new_key, $new_value ) { return false; } - /** - * Keyword filter in multiple fields. - * - * @param object $item The feed item. - * @param string $filter_by Filter by. - * @param string $keywords Keywords. - * - * @return bool - */ - public function feedzy_feed_item_keywords_by( $item, $filter_by = '', $keywords = '', $sc = array() ) { - $is_valid = false; - - if ( empty( $filter_by ) ) { - return $is_valid; - } - - if ( 'title' === $filter_by ) { - $item_title = wp_strip_all_tags( $item->get_title(), true ); - if ( ! empty( $item_title ) && preg_match( "/^$keywords.*$/i", $item_title ) ) { - $is_valid = true; - } - } elseif ( 'description' === $filter_by ) { - $description = wp_strip_all_tags( $item->get_content(), true ); - if ( ! empty( $description ) && preg_match( "/^$keywords.*$/i", $description ) ) { - $is_valid = true; - } - } elseif ( 'author' === $filter_by ) { - $author = $item->get_author(); - $author_name = ''; - if ( $author ) { - $author_name = $author->get_name(); - } - if ( ! empty( $author_name ) && preg_match( "/^$keywords.*$/i", $author_name ) ) { - $is_valid = true; - } - } elseif ( 'fullcontent' === $filter_by ) { - $content = $item->get_item_tags( SIMPLEPIE_NAMESPACE_ATOM_10, 'full-content' ); - $content = ! empty( $content[0]['data'] ) ? $content[0]['data'] : ''; - $content = wp_strip_all_tags( $content, true ); - if ( ! empty( $content ) && preg_match( "/^$keywords.*$/i", $content ) ) { - $is_valid = true; - } - } - - // Date filter. - if ( $is_valid && ( ! empty( $sc['from_datetime'] ) && ! empty( $sc['to_datetime'] ) ) ) { - $from_datetime = strtotime( $sc['from_datetime'] ); - $to_datetime = strtotime( $sc['to_datetime'] ); - $item_date = strtotime( $item->get_date() ); - $is_valid = ( ( $from_datetime <= $item_date ) && ( $item_date <= $to_datetime ) ); - } - return $is_valid; - } - /** * Init amazon API. * diff --git a/includes/admin/feedzy-rss-feeds-admin.php b/includes/admin/feedzy-rss-feeds-admin.php index c6f7ed23..808dbea8 100644 --- a/includes/admin/feedzy-rss-feeds-admin.php +++ b/includes/admin/feedzy-rss-feeds-admin.php @@ -212,6 +212,27 @@ public function enqueue_styles_admin() { 'languageList' => $this->get_lang_list(), ) ); + + $asset_file = include FEEDZY_ABSPATH . '/js/build/conditions.asset.php'; + wp_enqueue_script( $this->plugin_name . '_conditions', FEEDZY_ABSURL . 'js/build/conditions.js', array_merge( $asset_file['dependencies'], array( 'wp-editor', 'wp-api' ) ), $asset_file['version'], true ); + + // Add wp_localize_script to pass variables to the JS file with a filter over the data. + wp_localize_script( + $this->plugin_name . '_conditions', + 'feedzyConditionsData', + apply_filters( + 'feedzy_conditions_data', + array( + 'isPro' => feedzy_is_pro(), + 'isBusinessPlan' => apply_filters( 'feedzy_is_license_of_type', false, 'business' ), + 'isAgencyPlan' => apply_filters( 'feedzy_is_license_of_type', false, 'agency' ), + 'apiLicenseStatus' => $this->api_license_status(), + 'isHighPrivileges' => current_user_can( 'manage_options' ), + 'operators' => Feedzy_Rss_Feeds_Conditions::get_operators(), + ) + ) + ); + wp_enqueue_style( 'wp-block-editor' ); $this->register_survey(); diff --git a/includes/admin/feedzy-rss-feeds-import.php b/includes/admin/feedzy-rss-feeds-import.php index 2464ff3a..9bd04357 100644 --- a/includes/admin/feedzy-rss-feeds-import.php +++ b/includes/admin/feedzy-rss-feeds-import.php @@ -326,16 +326,6 @@ public function feedzy_import_feed_options() { $post_types = get_post_types( '', 'names' ); $post_types = array_diff( $post_types, array( 'feedzy_imports', 'feedzy_categories' ) ); $published_status = array( 'publish', 'draft' ); - $keyword_filter_fields = array( __( 'Title', 'feedzy-rss-feeds' ) ); - if ( feedzy_is_pro() ) { - $keyword_filter_fields = array_merge( - $keyword_filter_fields, array( - __( 'Description', 'feedzy-rss-feeds' ), - __( 'Author', 'feedzy-rss-feeds' ), - __( 'Full Content', 'feedzy-rss-feeds' ), - ) - ); - } $import_post_type = get_post_meta( $post->ID, 'import_post_type', true ); $import_post_term = get_post_meta( $post->ID, 'import_post_term', true ); if ( metadata_exists( $import_post_type, $post->ID, 'import_post_status' ) ) { @@ -364,6 +354,22 @@ public function feedzy_import_feed_options() { $import_auto_translation = get_post_meta( $post->ID, 'import_auto_translation', true ); $import_auto_translation = 'yes' === $import_auto_translation ? 'checked' : ''; $import_translation_lang = get_post_meta( $post->ID, 'import_auto_translation_lang', true ); + $filter_conditions = get_post_meta( $post->ID, 'filter_conditions', true ); + + if ( empty( $filter_conditions ) ) { + $filter_conditions = apply_filters( + 'feedzy_filter_conditions_migration', + array( + 'keywords_inc' => $inc_key, + 'keywords_exc' => $exc_key, + 'keywords_inc_on' => $inc_on, + 'keywords_exc_on' => $exc_on, + 'from_datetime' => $from_datetime, + 'to_datetime' => $to_datetime, + ) + ); + } + // default values so that post is not created empty. if ( empty( $import_title ) ) { $import_title = '[[{"value":"%5B%7B%22id%22%3A%22%22%2C%22tag%22%3A%22item_title%22%2C%22data%22%3A%7B%7D%7D%5D"}]]'; @@ -1344,8 +1350,23 @@ private function run_job( $job, $max ) { $import_auto_translation = get_post_meta( $job->ID, 'import_auto_translation', true ); $import_auto_translation = $this->feedzy_is_agency() && 'yes' === $import_auto_translation ? true : false; $import_translation_lang = get_post_meta( $job->ID, 'import_auto_translation_lang', true ); + $filter_conditions = get_post_meta( $job->ID, 'filter_conditions', true ); $max = $import_feed_limit; + if ( empty( $filter_conditions ) ) { + $filter_conditions = apply_filters( + 'feedzy_filter_conditions_migration', + array( + 'keywords_inc' => $inc_key, + 'keywords_exc' => $exc_key, + 'keywords_inc_on' => $inc_on, + 'keywords_exc_on' => $exc_on, + 'from_datetime' => $from_datetime, + 'to_datetime' => $to_datetime, + ) + ); + } + if ( metadata_exists( 'post', $job->ID, 'import_post_status' ) ) { $import_post_status = get_post_meta( $job->ID, 'import_post_status', true ); } else { @@ -1397,17 +1418,11 @@ private function run_job( $job, $max ) { 'thumb' => 'auto', 'default' => '', 'size' => '250', - 'keywords_inc' => $inc_key, // this is not keywords_title - 'keywords_ban' => $exc_key, // to support old pro that does not support keywords_exc - 'keywords_exc' => $exc_key, // this is not keywords_ban - 'keywords_inc_on' => $inc_on, - 'keywords_exc_on' => $exc_on, 'columns' => 1, 'offset' => 0, 'multiple_meta' => 'no', 'refresh' => '55_mins', - 'from_datetime' => $from_datetime, - 'to_datetime' => $to_datetime, + 'filters' => $filter_conditions, ), $job ); diff --git a/includes/feedzy-rss-feeds.php b/includes/feedzy-rss-feeds.php index 9369c298..7ede8bcb 100644 --- a/includes/feedzy-rss-feeds.php +++ b/includes/feedzy-rss-feeds.php @@ -190,7 +190,6 @@ private function define_admin_hooks() { self::$instance->loader->add_filter( 'feedzy_item_attributes', self::$instance->admin, 'feedzy_classes_item', 99, 5 ); self::$instance->loader->add_filter( 'feedzy_register_options', self::$instance->admin, 'register_options' ); self::$instance->loader->add_filter( 'feedzy_summary_input', self::$instance->admin, 'feedzy_summary_input_filter', 9, 3 ); - self::$instance->loader->add_filter( 'feedzy_item_keyword', self::$instance->admin, 'feedzy_feed_item_keywords_title', 9, 4 ); self::$instance->loader->add_filter( 'feedzy_get_feed_array', self::$instance->admin, 'get_feed_array', 10, 5 ); self::$instance->loader->add_filter( 'feedzy_process_feed_source', self::$instance->admin, 'process_feed_source', 10, 1 ); self::$instance->loader->add_filter( 'feedzy_get_feed_url', self::$instance->admin, 'get_feed_url', 10, 1 ); @@ -266,6 +265,10 @@ function () { $this->loader->add_action( 'elementor/widgets/register', $plugin_elementor_widget, 'feedzy_elementor_widgets_registered' ); $this->loader->add_action( 'elementor/controls/register', $plugin_elementor_widget, 'feedzy_elementor_register_datetime_local_control' ); $this->loader->add_action( 'elementor/frontend/before_enqueue_styles', $plugin_elementor_widget, 'feedzy_elementor_before_enqueue_scripts' ); + + $plugin_conditions = new Feedzy_Rss_Feeds_Conditions(); + $this->loader->add_action( 'feedzy_filter_conditions_migration', $plugin_conditions, 'migrate_conditions' ); + $this->loader->add_action( 'feedzy_item_keyword', $plugin_conditions, 'evaluate_conditions', 10, 5 ); } $plugin_slug = FEEDZY_DIRNAME . '/' . basename( FEEDZY_BASEFILE ); diff --git a/includes/util/feedzy-rss-feeds-conditions.php b/includes/util/feedzy-rss-feeds-conditions.php new file mode 100644 index 00000000..c73c2c94 --- /dev/null +++ b/includes/util/feedzy-rss-feeds-conditions.php @@ -0,0 +1,331 @@ + The supported operators. + */ + public static function get_operators(): array { + return array( + self::OPERATOR_HAS_VALUE => __( 'Has Any Value', 'feedzy-rss-feeds' ), + self::OPERATOR_EQUALS => __( 'Equals', 'feedzy-rss-feeds' ), + self::OPERATOR_NOT_EQUALS => __( 'Not Equals', 'feedzy-rss-feeds' ), + self::OPERATOR_EMPTY => __( 'Is Empty', 'feedzy-rss-feeds' ), + self::OPERATOR_CONTAINS => __( 'Contains', 'feedzy-rss-feeds' ), + self::OPERATOR_NOT_CONTAINS => __( 'Not Contains', 'feedzy-rss-feeds' ), + self::OPERATOR_GREATER_THAN => __( 'Greater Than', 'feedzy-rss-feeds' ), + self::OPERATOR_GREATER_THAN_EQUALS => __( 'Greater Than or Equals', 'feedzy-rss-feeds' ), + self::OPERATOR_LESS_THAN => __( 'Less Than', 'feedzy-rss-feeds' ), + self::OPERATOR_LESS_THAN_EQUALS => __( 'Less Than or Equals', 'feedzy-rss-feeds' ), + self::OPERATOR_REGEX => __( 'Matches Regular Expression', 'feedzy-rss-feeds' ), + ); + } + + /** + * Migrate old conditions to a new format. + * + * This function takes an array of old conditions and converts them into a new format + * that includes logical operators and condition mappings. + * + * @param array $conditions The old conditions array. + * + * @return string The new conditions in JSON format. + */ + public function migrate_conditions( $conditions ): string { + if ( ! is_array( $conditions ) ) { + return ''; + } + + foreach ( array( 'keywords_title' => 'keywords_inc', 'keywords_ban' => 'keywords_exc' ) as $old_key => $new_key ) { + if ( isset( $conditions[ $old_key ] ) ) { + $conditions[ $new_key ] = $conditions[ $old_key ]; + unset( $conditions[ $old_key ] ); + } + } + + $new_conditions = array( + 'match' => self::LOGIC_AND, + 'conditions' => array(), + ); + + $mapping = array( + 'keywords_inc' => self::OPERATOR_CONTAINS, + 'keywords_exc' => self::OPERATOR_NOT_CONTAINS, + 'from_datetime' => self::OPERATOR_GREATER_THAN, + 'to_datetime' => self::OPERATOR_LESS_THAN, + ); + + foreach ( $mapping as $key => $operator ) { + if ( isset( $conditions[ $key ] ) && ! empty( $conditions[ $key ] ) ) { + $field = $key === 'from_datetime' || $key === 'to_datetime' ? 'date' : $conditions[ $key . '_on' ]; + if ( ! empty( $field ) ) { + array_push( + $new_conditions['conditions'], array( + 'field' => $field, + 'operator' => $operator, + 'value' => $conditions[ $key ], + ) + ); + } + } + } + + return wp_json_encode( $new_conditions ); + } + + /** + * Check if a condition is met. + * + * This function takes a condition and checks if it is met by the given value. + * + * @param array $condition The condition to check. + * @param string $value The value to check against. + * + * @return bool True if the condition is met, false otherwise. + */ + public function is_condition_met( $condition, $value ): bool { + $operator = $condition['operator']; + $condition_value = trim( $condition['value'] ); + $value = trim( $value ); + + switch ( $operator ) { + case self::OPERATOR_HAS_VALUE: + return ! empty( $value ); + case self::OPERATOR_EQUALS: + return strtolower( $value ) === strtolower( $condition_value ); + case self::OPERATOR_NOT_EQUALS: + return strtolower( $value ) !== strtolower( $condition_value ); + case self::OPERATOR_EMPTY: + return empty( $value ); + case self::OPERATOR_CONTAINS: + return $this->check_contains( strtolower( $value ), strtolower( $condition_value ) ); + case self::OPERATOR_NOT_CONTAINS: + return ! $this->check_contains( strtolower( $value ), strtolower( $condition_value ) ); + case self::OPERATOR_GREATER_THAN: + case self::OPERATOR_GREATER_THAN_EQUALS: + case self::OPERATOR_LESS_THAN: + case self::OPERATOR_LESS_THAN_EQUALS: + // Check if the field type is date. + if ( isset( $condition['field'] ) && $condition['field'] === 'date' ) { + $condition_value = new DateTime( $condition_value, new DateTimeZone( 'UTC' ) ); + $condition_value = $condition_value->getTimestamp(); + } elseif ( isset( $condition['field'] ) && in_array( $condition['field'], array( 'title', 'description', 'fullcontent' ), true ) ) { + // Check if the field type is title, description or fullcontent, we compare the length of the string. + $value = strlen( $value ); + $condition_value = (int) $condition_value; + } + + switch ( $operator ) { + case self::OPERATOR_GREATER_THAN: + return $value > $condition_value; + case self::OPERATOR_GREATER_THAN_EQUALS: + return $value >= $condition_value; + case self::OPERATOR_LESS_THAN: + return $value < $condition_value; + case self::OPERATOR_LESS_THAN_EQUALS: + return $value <= $condition_value; + } + break; + case self::OPERATOR_REGEX: + $regex_pattern = $condition_value; + if ( ! preg_match( '/^\/.*\/[imsxuADU]*$/', $condition_value ) ) { + $regex_pattern = '/' . $condition_value . '/i'; + } + return preg_match( $regex_pattern, $value ) === 1; + default: + // Default is self::OPERATOR_HAS_VALUE + return ! empty( $value ); + } + } + + /** + * Evaluate conditions. + * + * This function evaluates a set of conditions against an item and returns whether they are met. + * + * @param bool $continue The current return value. + * @param array $attrs The attributes of the feed. + * @param array $item The item to evaluate. + * @param string $feed_url The URL of the feed. + * @param int $index The index of the item. + * + * @return bool True if the conditions are met, false otherwise. + */ + public function evaluate_conditions( $continue, $attrs, $item, $feed_url, $index ): bool { + if ( feedzy_is_new() && ! feedzy_is_pro() ) { + return $continue; + } + + $filters = json_decode( $attrs['filters'], true ); + + if ( ! is_array( $filters ) ) { + return $continue; + } + + $conditions = $filters['conditions'] ?? array(); + $logic = $filters['match'] ?? self::LOGIC_AND; + + if ( ! is_array( $conditions ) ) { + return $continue; + } + + $continue = $logic === self::LOGIC_AND; + + foreach ( $conditions as $condition ) { + $field = $condition['field'] ?? ''; + $value = ''; + + switch ( $field ) { + case 'title': + $value = wp_strip_all_tags( $item->get_title(), true ); + break; + case 'description': + $value = wp_strip_all_tags( $item->get_content(), true ); + break; + case 'fullcontent': + $content = $item->get_item_tags( SIMPLEPIE_NAMESPACE_ATOM_10, 'full-content' ); + $content = ! empty( $content[0]['data'] ) ? $content[0]['data'] : ''; + $value = wp_strip_all_tags( $content, true ); + break; + case 'author': + $author = $item->get_author(); + $value = $author ? $author->get_name() : ''; + break; + case 'date': + $value = strtotime( $item->get_date() ); + break; + case 'featured_image': + $instance = Feedzy_Rss_Feeds::instance(); + $admin = $instance->get_admin(); + $image = $admin->feedzy_retrieve_image( $item ); + $value = $image; + break; + default: + $value = ''; + break; + } + + $condition_met = $this->is_condition_met( $condition, $value ); + + if ( $logic === self::LOGIC_AND && ! $condition_met ) { + $continue = false; + break; + } + + if ( $logic === self::LOGIC_OR && $condition_met ) { + $continue = true; + break; + } + } + + return $continue; + } + + /** + * Check if a value contains a condition value. + * + * This function checks if a value contains a condition value. + * + * @param string $value The value to check. + * @param string $condition_value The condition value to check for. + * + * @return bool True if the value contains the condition value, false otherwise. + */ + private function check_contains( $value, $condition_value ): bool { + $or_conditions = preg_split( '/\s*,\s*/', $condition_value ); + foreach ( $or_conditions as $or_condition ) { + $and_conditions = preg_split( '/\s*\+\s*/', $or_condition ); + $all_and_conditions_match = true; + foreach ( $and_conditions as $and_condition ) { + if ( strpos( $value, trim( $and_condition ) ) === false ) { + $all_and_conditions_match = false; + break; + } + } + if ( $all_and_conditions_match ) { + return true; + } + } + return false; + } +} diff --git a/includes/views/import-metabox-edit.php b/includes/views/import-metabox-edit.php index c4661a60..e7a5d02e 100644 --- a/includes/views/import-metabox-edit.php +++ b/includes/views/import-metabox-edit.php @@ -130,149 +130,9 @@ class="dashicons dashicons-arrow-down-alt2">
-
- -
-

PRO' : ''; ?>

-
- -
- - -
-
-
-
- -
-
-
-
- -
- -
-
-
-
- ', - '' - ) - ) - ?> -
-
-
- -
-
-
- -
-
-
-
- -
- -
-

PRO' : ''; ?>

-
-
-
- -
-
-
-
- -
- -
-
-
-
- ', - '' - ) - ); - ?> -
-
-
- -
-
-
- -
-
-
-
- -
- -
-

PRO' : ''; ?>

-
-
-
-
- - -
-
-
- - -
-
-
- ', '' ) ); ?> -
-
-
+ + +
diff --git a/js/Conditions/ConditionsControl.js b/js/Conditions/ConditionsControl.js new file mode 100644 index 00000000..914dc0ed --- /dev/null +++ b/js/Conditions/ConditionsControl.js @@ -0,0 +1,204 @@ +/** + * WordPress dependencies. + */ +import { __ } from '@wordpress/i18n'; + +import { + Button, + SelectControl, + TextControl +} from '@wordpress/components'; + +import { + Icon, + plus +} from '@wordpress/icons'; + +/** + * Internal dependencies. + */ +import PanelTab from './PanelTab'; +import DateTimeControl from './DateTimeControl'; + +const SUPPORTED_FIELDS = [ + { + label: __( 'Title', 'feedzy-rss-feeds' ), + value: 'title' + }, + { + label: __( 'Description', 'feedzy-rss-feeds' ), + value: 'description' + }, + { + label: __( 'Full Content', 'feedzy-rss-feeds' ), + value: 'fullcontent' + }, + { + label: __( 'Author', 'feedzy-rss-feeds' ), + value: 'author', + unsupportedOperators: [ + 'greater_than', + 'gte', + 'less_than', + 'lte' + ] + }, + { + label: __( 'Date', 'feedzy-rss-feeds' ), + value: 'date', + unsupportedOperators: [ + 'has_value', + 'equals', + 'not_equals', + 'empty', + 'contains', + 'not_contains' + ] + }, + { + label: __( 'Featured Image', 'feedzy-rss-feeds' ), + value: 'featured_image', + unsupportedOperators: [ + 'greater_than', + 'gte', + 'less_than', + 'lte' + ] + } +]; + +const ConditionsControl = ({ + conditions, + setConditions +}) => { + const onChangeMatch = ( value ) => { + setConditions( { + ...conditions, + match: value + } ); + }; + + const addCondition = () => { + const conditionsCopy = [ ...conditions.conditions ]; + + conditionsCopy.push({ + field: SUPPORTED_FIELDS[0].value, + operator: 'contains' + }); + + setConditions( { + ...conditions, + conditions: conditionsCopy + } ); + }; + + const removeCondition = ( index ) => { + const conditionsCopy = [ ...conditions.conditions ]; + conditionsCopy.splice( index, 1 ); + + setConditions( { + ...conditions, + conditions: conditionsCopy + } ); + }; + + const onChangeCondtion = ( index, value, key ) => { + const conditionsCopy = [ ...conditions.conditions ]; + + conditionsCopy[index][key] = value; + + // We need to make sure we don't have unsupported operators for the selected field. + if ( key === 'field' ) { + const field = SUPPORTED_FIELDS.find( field => field.value === value ); + if ( field.unsupportedOperators?.includes( conditionsCopy[index].operator ) ) { + conditionsCopy[index].operator = Object.keys( window?.feedzyConditionsData?.operators ).filter( key => ! field.unsupportedOperators?.includes( key ) )[0]; + } + } + + setConditions( { + ...conditions, + conditions: conditionsCopy + } ); + }; + + return ( +
+ + + { conditions.conditions.map( ( condition, index ) => { + const field = SUPPORTED_FIELDS.find( field => field.value === condition.field ); + const operators = Object.keys( window?.feedzyConditionsData?.operators ).filter( key => ! field.unsupportedOperators?.includes( key ) ); + + return ( + removeCondition( index ) } + > + onChangeCondtion( index, value, 'field' ) } + /> + + ( { + label: window.feedzyConditionsData.operators[key], + value: key + } ) ) } + help={ [ 'contains', 'not_contains' ].includes( condition?.operator ) ? __( 'You can use comma(,) and plus(+) keyword.', 'feedzy-rss-feeds' ) : '' } + value={ condition?.operator } + onChange={ ( value ) => onChangeCondtion( index, value, 'operator' ) } + /> + + { ! [ 'has_value', 'empty' ].includes( condition?.operator ) && ( + <> + { condition?.field === 'date' ? ( + onChangeCondtion( index, value, 'value' ) } + /> + ) : ( + onChangeCondtion( index, value, 'value' ) } + /> + ) } + + ) } + + ); + } ) } + +
+ +
+
+ ); +}; + +export default ConditionsControl; diff --git a/js/Conditions/DateTimeControl.js b/js/Conditions/DateTimeControl.js new file mode 100644 index 00000000..28619216 --- /dev/null +++ b/js/Conditions/DateTimeControl.js @@ -0,0 +1,53 @@ +/** + * WordPress dependencies. + */ +import { __ } from '@wordpress/i18n'; + +import { + BaseControl, + Button, + DateTimePicker, + Dropdown +} from '@wordpress/components'; + +import { + format, + __experimentalGetSettings +} from '@wordpress/date'; + +const DateTimeControl = ({ + label, + value, + onChange +}) => { + const settings = __experimentalGetSettings(); + + return ( + + ( + <> + + + ) } + renderContent={ () => ( + + ) } + /> + + ); +}; + +export default DateTimeControl; diff --git a/js/Conditions/PanelTab.js b/js/Conditions/PanelTab.js new file mode 100644 index 00000000..c2eb4189 --- /dev/null +++ b/js/Conditions/PanelTab.js @@ -0,0 +1,47 @@ +/** + * WordPress dependencies. + */ +import { __ } from '@wordpress/i18n'; + +import { Button } from '@wordpress/components'; + +import { useState } from '@wordpress/element'; + +const PanelTab = ({ + label, + onDelete, + children +}) => { + const [ isOpen, setOpen ] = useState( false ); + + return ( +
+
+
setOpen( ! isOpen ) } + > + { label } +
+ +
+ + { isOpen &&
{ children }
} +
+ ); +}; + +export default PanelTab; diff --git a/js/Conditions/conditions.js b/js/Conditions/conditions.js new file mode 100644 index 00000000..d84c3168 --- /dev/null +++ b/js/Conditions/conditions.js @@ -0,0 +1,60 @@ +/** + * WordPress dependencies. + */ +import { Disabled } from '@wordpress/components'; + +import domReady from '@wordpress/dom-ready'; + +import { + createRoot, + useEffect, + useState +} from '@wordpress/element'; + +/** + * Internal dependencies. + */ +import ConditionsControl from './ConditionsControl'; + +const App = () => { + const [ conditions, setConditions ] = useState( { + conditions: [], + match: 'all' + } ); + + useEffect( () => { + const field = document.getElementById( 'feed-post-filters-conditions' ); + if ( field && field.value ) { + const parsedConditions = JSON.parse( field.value ); + console.log( parsedConditions && parsedConditions.conditions ? parsedConditions : { conditions: [], match: 'all' } ) + setConditions( parsedConditions && parsedConditions.conditions ? parsedConditions : { conditions: [], match: 'all' } ); + } + }, [] ); + + useEffect( () => { + document.getElementById( 'feed-post-filters-conditions' ).value = JSON.stringify( conditions ); + }, [ conditions ] ); + + if ( ! feedzyData.isPro ) { + return ( + + + + ); + } + + return ( + + ); +}; + +domReady( () => { + const root = createRoot( document.getElementById( 'fz-conditions' ) ); + root.render( ); +}); From 8c1711e54d51e9fbc8b371a40000ba3c65bacf15 Mon Sep 17 00:00:00 2001 From: Hardeep Asrani Date: Fri, 13 Dec 2024 04:15:19 +0530 Subject: [PATCH 02/15] fix: e2e test failing --- includes/util/feedzy-rss-feeds-conditions.php | 6 +++--- tests/e2e/specs/upsell.spec.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/includes/util/feedzy-rss-feeds-conditions.php b/includes/util/feedzy-rss-feeds-conditions.php index c73c2c94..38f05876 100644 --- a/includes/util/feedzy-rss-feeds-conditions.php +++ b/includes/util/feedzy-rss-feeds-conditions.php @@ -191,7 +191,7 @@ public function is_condition_met( $condition, $value ): bool { $condition_value = $condition_value->getTimestamp(); } elseif ( isset( $condition['field'] ) && in_array( $condition['field'], array( 'title', 'description', 'fullcontent' ), true ) ) { // Check if the field type is title, description or fullcontent, we compare the length of the string. - $value = strlen( $value ); + $value = strlen( $value ); $condition_value = (int) $condition_value; } @@ -265,11 +265,11 @@ public function evaluate_conditions( $continue, $attrs, $item, $feed_url, $index case 'fullcontent': $content = $item->get_item_tags( SIMPLEPIE_NAMESPACE_ATOM_10, 'full-content' ); $content = ! empty( $content[0]['data'] ) ? $content[0]['data'] : ''; - $value = wp_strip_all_tags( $content, true ); + $value = wp_strip_all_tags( $content, true ); break; case 'author': $author = $item->get_author(); - $value = $author ? $author->get_name() : ''; + $value = $author ? $author->get_name() : ''; break; case 'date': $value = strtotime( $item->get_date() ); diff --git a/tests/e2e/specs/upsell.spec.js b/tests/e2e/specs/upsell.spec.js index 6d7ceca7..dd69b8c9 100644 --- a/tests/e2e/specs/upsell.spec.js +++ b/tests/e2e/specs/upsell.spec.js @@ -30,8 +30,8 @@ test.describe( 'Upsell', () => { // Hover over text named Filter by Keyword const filtersTab = page.locator('#feedzy-import-form > div.feedzy-accordion > div:nth-child(2)'); - // It should have 3 elements with .only-pro-content class. - await expect( filtersTab.locator('.only-pro-content').count() ).resolves.toBe(3); + // It should have 1 elements with .only-pro-content class. + await expect( filtersTab.locator('.only-pro-content').count() ).resolves.toBe(1); const filterByKeywordAlert = await filtersTab.locator('.upgrade-alert').first(); let upgradeLink = new URL( await filterByKeywordAlert.locator('a').first().getAttribute('href') ); From 6e82359afc84aeccddd3fa1b5e753231496dc7f1 Mon Sep 17 00:00:00 2001 From: Hardeep Asrani Date: Fri, 13 Dec 2024 04:23:18 +0530 Subject: [PATCH 03/15] fix: unit tests --- includes/util/feedzy-rss-feeds-conditions.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/includes/util/feedzy-rss-feeds-conditions.php b/includes/util/feedzy-rss-feeds-conditions.php index 38f05876..29467435 100644 --- a/includes/util/feedzy-rss-feeds-conditions.php +++ b/includes/util/feedzy-rss-feeds-conditions.php @@ -236,6 +236,10 @@ public function evaluate_conditions( $continue, $attrs, $item, $feed_url, $index return $continue; } + if ( ! isset( $attrs['filters'] ) || empty( $attrs['filters'] ) ) { + return $continue; + } + $filters = json_decode( $attrs['filters'], true ); if ( ! is_array( $filters ) ) { From 9fcba74ce60ad6dc91d5602e31aa11825c7ebde5 Mon Sep 17 00:00:00 2001 From: Hardeep Asrani Date: Fri, 13 Dec 2024 04:59:38 +0530 Subject: [PATCH 04/15] test: adding phpunit tests --- composer.json | 6 +- composer.lock | 1648 ++++++++++++++++- includes/util/feedzy-rss-feeds-conditions.php | 2 +- tests/bootstrap.php | 5 + tests/test-conditions.php | 149 ++ tests/test-image-import.php | 2 +- 6 files changed, 1726 insertions(+), 86 deletions(-) create mode 100644 tests/test-conditions.php diff --git a/composer.json b/composer.json index 34dbd758..d3bae119 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,8 @@ }, "scripts": { "format": "phpcbf --standard=phpcs.xml --report-summary --report-source", - "lint": "phpcs --standard=phpcs.xml" + "lint": "phpcs --standard=phpcs.xml", + "test": "phpunit" }, "minimum-stability": "dev", "prefer-stable": true, @@ -46,6 +47,7 @@ "require-dev": { "wp-coding-standards/wpcs": "^3.1", "dealerdirect/phpcodesniffer-composer-installer": "^1.0.0", - "phpcompatibility/phpcompatibility-wp": "^2.1" + "phpcompatibility/phpcompatibility-wp": "^2.1", + "yoast/phpunit-polyfills": "^3.0" } } diff --git a/composer.lock b/composer.lock index 8a6edf78..bea710a5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f9dd3949923501eedc2e9f9f8c140f2b", + "content-hash": "c8131a107d5dc757269228991b688709", "packages": [ { "name": "codeinwp/themeisle-sdk", @@ -127,6 +127,254 @@ }, "time": "2023-01-05T11:28:13+00:00" }, + { + "name": "doctrine/instantiator", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.30 || ^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.5.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:15:36+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.12.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845", + "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2024-11-08T17:47:46+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, { "name": "phpcompatibility/php-compatibility", "version": "9.3.5", @@ -498,150 +746,1386 @@ "time": "2024-04-24T11:47:18+00:00" }, { - "name": "squizlabs/php_codesniffer", - "version": "3.9.2", + "name": "phpunit/php-code-coverage", + "version": "7.0.17", "source": { "type": "git", - "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "aac1f6f347a5c5ac6bc98ad395007df00990f480" + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "40a4ed114a4aea5afd6df8d0f0c9cd3033097f66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/aac1f6f347a5c5ac6bc98ad395007df00990f480", - "reference": "aac1f6f347a5c5ac6bc98ad395007df00990f480", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/40a4ed114a4aea5afd6df8d0f0c9cd3033097f66", + "reference": "40a4ed114a4aea5afd6df8d0f0c9cd3033097f66", "shasum": "" }, "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", + "ext-dom": "*", "ext-xmlwriter": "*", - "php": ">=5.4.0" + "php": ">=7.2", + "phpunit/php-file-iterator": "^2.0.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^3.1.3 || ^4.0", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^4.2.2", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1.3" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + "phpunit/phpunit": "^8.2.2" + }, + "suggest": { + "ext-xdebug": "^2.7.2" }, - "bin": [ - "bin/phpcbf", - "bin/phpcs" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "3.x-dev" + "dev-master": "7.0-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { - "name": "Greg Sherwood", - "role": "Former lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "Current lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", "keywords": [ - "phpcs", - "standards", - "static analysis" + "coverage", + "testing", + "xunit" ], "support": { - "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", - "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", - "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/7.0.17" }, "funding": [ { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", + "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" } ], - "time": "2024-04-23T20:25:34+00:00" + "time": "2024-03-02T06:09:37+00:00" }, { - "name": "wp-coding-standards/wpcs", - "version": "3.1.0", + "name": "phpunit/php-file-iterator", + "version": "2.0.6", "source": { "type": "git", - "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", - "reference": "9333efcbff231f10dfd9c56bb7b65818b4733ca7" + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "69deeb8664f611f156a924154985fbd4911eb36b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/9333efcbff231f10dfd9c56bb7b65818b4733ca7", - "reference": "9333efcbff231f10dfd9c56bb7b65818b4733ca7", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/69deeb8664f611f156a924154985fbd4911eb36b", + "reference": "69deeb8664f611f156a924154985fbd4911eb36b", "shasum": "" }, "require": { - "ext-filter": "*", - "ext-libxml": "*", - "ext-tokenizer": "*", - "ext-xmlreader": "*", - "php": ">=5.4", - "phpcsstandards/phpcsextra": "^1.2.1", - "phpcsstandards/phpcsutils": "^1.0.10", - "squizlabs/php_codesniffer": "^3.9.0" + "php": ">=7.1" }, "require-dev": { - "php-parallel-lint/php-console-highlighter": "^1.0.0", - "php-parallel-lint/php-parallel-lint": "^1.3.2", - "phpcompatibility/php-compatibility": "^9.0", - "phpcsstandards/phpcsdevtools": "^1.2.0", - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^8.5" }, - "suggest": { - "ext-iconv": "For improved results", - "ext-mbstring": "For improved results" + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] }, - "type": "phpcodesniffer-standard", "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Contributors", - "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", "keywords": [ - "phpcs", - "standards", - "static analysis", - "wordpress" + "filesystem", + "iterator" ], "support": { - "issues": "https://github.com/WordPress/WordPress-Coding-Standards/issues", - "source": "https://github.com/WordPress/WordPress-Coding-Standards", - "wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki" + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0.6" }, "funding": [ { - "url": "https://opencollective.com/php_codesniffer", - "type": "custom" + "url": "https://github.com/sebastianbergmann", + "type": "github" } ], - "time": "2024-03-25T16:39:00+00:00" + "time": "2024-03-01T13:39:50+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" + }, + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "2.1.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "a691211e94ff39a34811abd521c31bd5b305b0bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/a691211e94ff39a34811abd521c31bd5b305b0bb", + "reference": "a691211e94ff39a34811abd521c31bd5b305b0bb", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/2.1.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-01T13:42:41+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "3.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "9c1da83261628cb24b6a6df371b6e312b3954768" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/9c1da83261628cb24b6a6df371b6e312b3954768", + "reference": "9c1da83261628cb24b6a6df371b6e312b3954768", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", + "source": "https://github.com/sebastianbergmann/php-token-stream/tree/3.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "abandoned": true, + "time": "2021-07-26T12:15:06+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "8.5.41", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "d843cb5bcf0bf9ae3484016444fe0c5b6ec7e4fa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d843cb5bcf0bf9ae3484016444fe0c5b6ec7e4fa", + "reference": "d843cb5bcf0bf9ae3484016444fe0c5b6ec7e4fa", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.5.0", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.12.1", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=7.2", + "phpunit/php-code-coverage": "^7.0.17", + "phpunit/php-file-iterator": "^2.0.6", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^2.1.4", + "sebastian/comparator": "^3.0.5", + "sebastian/diff": "^3.0.6", + "sebastian/environment": "^4.2.5", + "sebastian/exporter": "^3.1.6", + "sebastian/global-state": "^3.0.5", + "sebastian/object-enumerator": "^3.0.5", + "sebastian/resource-operations": "^2.0.3", + "sebastian/type": "^1.1.5", + "sebastian/version": "^2.0.1" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage", + "phpunit/php-invoker": "To allow enforcing time limits" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.5-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/8.5.41" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2024-12-05T13:44:26+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "92a1a52e86d34cde6caa54f1b5ffa9fda18e5d54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/92a1a52e86d34cde6caa54f1b5ffa9fda18e5d54", + "reference": "92a1a52e86d34cde6caa54f1b5ffa9fda18e5d54", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-01T13:45:45+00:00" + }, + { + "name": "sebastian/comparator", + "version": "3.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "1dc7ceb4a24aede938c7af2a9ed1de09609ca770" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dc7ceb4a24aede938c7af2a9ed1de09609ca770", + "reference": "1dc7ceb4a24aede938c7af2a9ed1de09609ca770", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "sebastian/diff": "^3.0", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/3.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:31:48+00:00" + }, + { + "name": "sebastian/diff", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "98ff311ca519c3aa73ccd3de053bdb377171d7b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/98ff311ca519c3aa73ccd3de053bdb377171d7b6", + "reference": "98ff311ca519c3aa73ccd3de053bdb377171d7b6", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:16:36+00:00" + }, + { + "name": "sebastian/environment", + "version": "4.2.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "56932f6049a0482853056ffd617c91ffcc754205" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/56932f6049a0482853056ffd617c91ffcc754205", + "reference": "56932f6049a0482853056ffd617c91ffcc754205", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.5" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/4.2.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-01T13:49:59+00:00" + }, + { + "name": "sebastian/exporter", + "version": "3.1.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "1939bc8fd1d39adcfa88c5b35335910869214c56" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/1939bc8fd1d39adcfa88c5b35335910869214c56", + "reference": "1939bc8fd1d39adcfa88c5b35335910869214c56", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/3.1.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:21:38+00:00" + }, + { + "name": "sebastian/global-state", + "version": "3.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "91c7c47047a971f02de57ed6f040087ef110c5d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/91c7c47047a971f02de57ed6f040087ef110c5d9", + "reference": "91c7c47047a971f02de57ed6f040087ef110c5d9", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^8.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/3.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:13:16+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "3.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "ac5b293dba925751b808e02923399fb44ff0d541" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/ac5b293dba925751b808e02923399fb44ff0d541", + "reference": "ac5b293dba925751b808e02923399fb44ff0d541", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-01T13:54:02+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "1d439c229e61f244ff1f211e5c99737f90c67def" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/1d439c229e61f244ff1f211e5c99737f90c67def", + "reference": "1d439c229e61f244ff1f211e5c99737f90c67def", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-01T13:56:04+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "9bfd3c6f1f08c026f542032dfb42813544f7d64c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/9bfd3c6f1f08c026f542032dfb42813544f7d64c", + "reference": "9bfd3c6f1f08c026f542032dfb42813544f7d64c", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-01T14:07:30+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "72a7f7674d053d548003b16ff5a106e7e0e06eee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/72a7f7674d053d548003b16ff5a106e7e0e06eee", + "reference": "72a7f7674d053d548003b16ff5a106e7e0e06eee", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "source": "https://github.com/sebastianbergmann/resource-operations/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-01T13:59:09+00:00" + }, + { + "name": "sebastian/type", + "version": "1.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "18f071c3a29892b037d35e6b20ddf3ea39b42874" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/18f071c3a29892b037d35e6b20ddf3ea39b42874", + "reference": "18f071c3a29892b037d35e6b20ddf3ea39b42874", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/1.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-01T14:04:07+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/master" + }, + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.9.2", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "aac1f6f347a5c5ac6bc98ad395007df00990f480" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/aac1f6f347a5c5ac6bc98ad395007df00990f480", + "reference": "aac1f6f347a5c5ac6bc98ad395007df00990f480", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2024-04-23T20:25:34+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" + }, + { + "name": "wp-coding-standards/wpcs", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", + "reference": "9333efcbff231f10dfd9c56bb7b65818b4733ca7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/9333efcbff231f10dfd9c56bb7b65818b4733ca7", + "reference": "9333efcbff231f10dfd9c56bb7b65818b4733ca7", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "ext-libxml": "*", + "ext-tokenizer": "*", + "ext-xmlreader": "*", + "php": ">=5.4", + "phpcsstandards/phpcsextra": "^1.2.1", + "phpcsstandards/phpcsutils": "^1.0.10", + "squizlabs/php_codesniffer": "^3.9.0" + }, + "require-dev": { + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcompatibility/php-compatibility": "^9.0", + "phpcsstandards/phpcsdevtools": "^1.2.0", + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + }, + "suggest": { + "ext-iconv": "For improved results", + "ext-mbstring": "For improved results" + }, + "type": "phpcodesniffer-standard", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Contributors", + "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", + "keywords": [ + "phpcs", + "standards", + "static analysis", + "wordpress" + ], + "support": { + "issues": "https://github.com/WordPress/WordPress-Coding-Standards/issues", + "source": "https://github.com/WordPress/WordPress-Coding-Standards", + "wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki" + }, + "funding": [ + { + "url": "https://opencollective.com/php_codesniffer", + "type": "custom" + } + ], + "time": "2024-03-25T16:39:00+00:00" + }, + { + "name": "yoast/phpunit-polyfills", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/Yoast/PHPUnit-Polyfills.git", + "reference": "19e6d5fb8aad31f731f774f9646a10c64a8843d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/19e6d5fb8aad31f731f774f9646a10c64a8843d2", + "reference": "19e6d5fb8aad31f731f774f9646a10c64a8843d2", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "phpunit/phpunit": "^6.4.4 || ^7.0 || ^8.0 || ^9.0 || ^11.0" + }, + "require-dev": { + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "yoast/yoastcs": "^3.1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "files": [ + "phpunitpolyfills-autoload.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Team Yoast", + "email": "support@yoast.com", + "homepage": "https://yoast.com" + }, + { + "name": "Contributors", + "homepage": "https://github.com/Yoast/PHPUnit-Polyfills/graphs/contributors" + } + ], + "description": "Set of polyfills for changed PHPUnit functionality to allow for creating PHPUnit cross-version compatible tests", + "homepage": "https://github.com/Yoast/PHPUnit-Polyfills", + "keywords": [ + "phpunit", + "polyfill", + "testing" + ], + "support": { + "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues", + "security": "https://github.com/Yoast/PHPUnit-Polyfills/security/policy", + "source": "https://github.com/Yoast/PHPUnit-Polyfills" + }, + "time": "2024-09-07T00:24:25+00:00" } ], "aliases": [], diff --git a/includes/util/feedzy-rss-feeds-conditions.php b/includes/util/feedzy-rss-feeds-conditions.php index 29467435..c5f46654 100644 --- a/includes/util/feedzy-rss-feeds-conditions.php +++ b/includes/util/feedzy-rss-feeds-conditions.php @@ -137,7 +137,7 @@ public function migrate_conditions( $conditions ): string { foreach ( $mapping as $key => $operator ) { if ( isset( $conditions[ $key ] ) && ! empty( $conditions[ $key ] ) ) { - $field = $key === 'from_datetime' || $key === 'to_datetime' ? 'date' : $conditions[ $key . '_on' ]; + $field = $key === 'from_datetime' || $key === 'to_datetime' ? 'date' : ( isset( $conditions[ $key . '_on' ] ) ? $conditions[ $key . '_on' ] : '' ); if ( ! empty( $field ) ) { array_push( $new_conditions['conditions'], array( diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 6dec5e67..87285714 100755 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -5,6 +5,11 @@ * @package Visualizer */ $_tests_dir = getenv( 'WP_TESTS_DIR' ); + +if ( class_exists( '\Yoast\PHPUnitPolyfills\Autoload' ) === false ) { + require_once dirname( dirname( __FILE__ ) ) . '/vendor/yoast/phpunit-polyfills/phpunitpolyfills-autoload.php'; +} + if ( ! $_tests_dir ) { $_tests_dir = '/tmp/wordpress-tests-lib'; } diff --git a/tests/test-conditions.php b/tests/test-conditions.php new file mode 100644 index 00000000..7fba60b4 --- /dev/null +++ b/tests/test-conditions.php @@ -0,0 +1,149 @@ +conditions = new Feedzy_Rss_Feeds_Conditions(); + } + + public function test_migration() { + $conditions = array( + 'keywords_inc' => 'test', + 'keywords_exc' => 'ban', + 'keywords_inc_on' => 'title', + 'keywords_exc_on' => 'title', + 'from_datetime' => '2023-01-01', + 'to_datetime' => '2023-12-31', + ); + + $expected = json_encode(array( + 'match' => 'all', + 'conditions' => array( + array( + 'field' => 'title', + 'operator' => 'contains', + 'value' => 'test', + ), + array( + 'field' => 'title', + 'operator' => 'not_contains', + 'value' => 'ban', + ), + array( + 'field' => 'date', + 'operator' => 'greater_than', + 'value' => '2023-01-01', + ), + array( + 'field' => 'date', + 'operator' => 'less_than', + 'value' => '2023-12-31', + ), + ), + )); + + $result = $this->conditions->migrate_conditions( $conditions ); + $this->assertJsonStringEqualsJsonString( $expected, $result ); + } + + public function test_is_condition_met_equals() { + $condition = array( + 'operator' => 'equals', + 'value' => 'test', + ); + $this->assertTrue( $this->conditions->is_condition_met( $condition, 'test' ) ); + } + + public function test_is_condition_met_not_equals() { + $condition = array( + 'operator' => 'not_equals', + 'value' => 'test', + ); + $this->assertFalse( $this->conditions->is_condition_met( $condition, 'test' ) ); + } + + public function test_is_condition_met_contains_single() { + $condition = array( + 'operator' => 'contains', + 'value' => 'test', + ); + $this->assertTrue( $this->conditions->is_condition_met( $condition, 'this is a test' ) ); + } + + public function test_is_condition_met_contains_multiple() { + $condition = array( + 'operator' => 'contains', + 'value' => 'test, this', + ); + $this->assertTrue( $this->conditions->is_condition_met( $condition, 'it is a test' ) ); + } + + public function test_is_condition_met_contains_plus() { + $condition = array( + 'operator' => 'contains', + 'value' => 'this+this', + ); + $this->assertTrue( $this->conditions->is_condition_met( $condition, 'this is a test' ) ); + } + + public function test_is_condition_met_contains_plus_false() { + $condition = array( + 'operator' => 'contains', + 'value' => 'it+this', + ); + $this->assertFalse( $this->conditions->is_condition_met( $condition, 'this is a test' ) ); + } + + public function test_is_condition_met_not_contains() { + $condition = array( + 'operator' => 'not_contains', + 'value' => 'test', + ); + $this->assertFalse( $this->conditions->is_condition_met( $condition, 'this is a test' ) ); + } + + public function test_is_condition_met_greater_than() { + $condition = array( + 'operator' => 'greater_than', + 'value' => '5', + ); + $this->assertTrue( $this->conditions->is_condition_met( $condition, '10' ) ); + } + + public function test_is_condition_met_less_than() { + $condition = array( + 'operator' => 'less_than', + 'value' => '10', + ); + $this->assertTrue( $this->conditions->is_condition_met( $condition, '5' ) ); + } + + public function test_is_condition_met_regex() { + $condition = array( + 'operator' => 'regex', + 'value' => '/test/', + ); + $this->assertTrue( $this->conditions->is_condition_met( $condition, 'this is a test' ) ); + } +} diff --git a/tests/test-image-import.php b/tests/test-image-import.php index 85e3ee93..bf589bd7 100644 --- a/tests/test-image-import.php +++ b/tests/test-image-import.php @@ -2,7 +2,7 @@ /** * WordPress unit test plugin. * - * @package feedzy-rss-feeds-pro + * @package feedzy-rss-feeds * @subpackage Tests * @copyright Copyright (c) 2024, Bogdan Preda * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License From 0a911a91fffd27882039b6f340b2e46f9df40bce Mon Sep 17 00:00:00 2001 From: Hardeep Asrani Date: Fri, 13 Dec 2024 05:41:53 +0530 Subject: [PATCH 05/15] fix: e2e test failing --- tests/e2e/specs/upsell.spec.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/tests/e2e/specs/upsell.spec.js b/tests/e2e/specs/upsell.spec.js index dd69b8c9..585bd7f5 100644 --- a/tests/e2e/specs/upsell.spec.js +++ b/tests/e2e/specs/upsell.spec.js @@ -35,15 +35,7 @@ test.describe( 'Upsell', () => { const filterByKeywordAlert = await filtersTab.locator('.upgrade-alert').first(); let upgradeLink = new URL( await filterByKeywordAlert.locator('a').first().getAttribute('href') ); - expect( upgradeLink.searchParams.get( 'utm_campaign' ) ).toBe('filter-keyword'); - - const excludeItemsAlert = await filtersTab.locator('.upgrade-alert').nth(1); - upgradeLink = new URL( await excludeItemsAlert.locator('a').first().getAttribute('href') ); - expect( upgradeLink.searchParams.get( 'utm_campaign' ) ).toBe('exclude-items'); - - const filterByTimeRangeAlert = await filtersTab.locator('.upgrade-alert').nth(2); - upgradeLink = new URL( await filterByTimeRangeAlert.locator('a').first().getAttribute('href') ); - expect( upgradeLink.searchParams.get( 'utm_campaign' ) ).toBe('filter-time-range'); + expect( upgradeLink.searchParams.get( 'utm_campaign' ) ).toBe('filters'); } ); test( 'map content', async({ editor, page }) => { From 25aa7a26dd4de81ffb31690ecc126db048f2f11d Mon Sep 17 00:00:00 2001 From: Hardeep Asrani Date: Fri, 13 Dec 2024 07:48:59 +0530 Subject: [PATCH 06/15] fix: backward compat --- includes/util/feedzy-rss-feeds-conditions.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/includes/util/feedzy-rss-feeds-conditions.php b/includes/util/feedzy-rss-feeds-conditions.php index c5f46654..7c7ca542 100644 --- a/includes/util/feedzy-rss-feeds-conditions.php +++ b/includes/util/feedzy-rss-feeds-conditions.php @@ -116,6 +116,18 @@ public function migrate_conditions( $conditions ): string { return ''; } + // In shortcodes and blocks, sometimes only the keywords are set, and the fields are not set. + $default_field_mappings = array( + 'keywords_title' => 'keywords_inc_on', + 'keywords_ban' => 'keywords_exc_on', + ); + + foreach ( $default_field_mappings as $old_key => $new_key ) { + if ( isset( $conditions[ $old_key ] ) && ( ! isset( $conditions[ $new_key ] ) || empty( $conditions[ $new_key ] ) ) ) { + $conditions[ $new_key ] = 'title'; + } + } + foreach ( array( 'keywords_title' => 'keywords_inc', 'keywords_ban' => 'keywords_exc' ) as $old_key => $new_key ) { if ( isset( $conditions[ $old_key ] ) ) { $conditions[ $new_key ] = $conditions[ $old_key ]; From 11ee73a64da41aa626a1994c430dd54e6621dfb0 Mon Sep 17 00:00:00 2001 From: Hardeep Asrani Date: Sat, 14 Dec 2024 02:20:49 +0530 Subject: [PATCH 07/15] Update ConditionsControl.js --- js/Conditions/ConditionsControl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/Conditions/ConditionsControl.js b/js/Conditions/ConditionsControl.js index 914dc0ed..fa642f70 100644 --- a/js/Conditions/ConditionsControl.js +++ b/js/Conditions/ConditionsControl.js @@ -124,7 +124,7 @@ const ConditionsControl = ({ return (
Date: Tue, 17 Dec 2024 10:15:40 +0530 Subject: [PATCH 08/15] chore: add dummy conditions for upsell --- js/Conditions/ConditionsControl.js | 7 +++++-- js/Conditions/PanelTab.js | 3 ++- js/Conditions/conditions.js | 13 ++++++++++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/js/Conditions/ConditionsControl.js b/js/Conditions/ConditionsControl.js index fa642f70..45307030 100644 --- a/js/Conditions/ConditionsControl.js +++ b/js/Conditions/ConditionsControl.js @@ -113,6 +113,8 @@ const ConditionsControl = ({ if ( field.unsupportedOperators?.includes( conditionsCopy[index].operator ) ) { conditionsCopy[index].operator = Object.keys( window?.feedzyConditionsData?.operators ).filter( key => ! field.unsupportedOperators?.includes( key ) )[0]; } + + conditionsCopy[index].value = ''; } setConditions( { @@ -128,11 +130,11 @@ const ConditionsControl = ({ value={ conditions.match } options={ [ { - label: __( 'All', 'feedzy-rss-feeds' ), + label: __( 'All conditions are true', 'feedzy-rss-feeds' ), value: 'all' }, { - label: __( 'Any', 'feedzy-rss-feeds' ), + label: __( 'Any condition is true', 'feedzy-rss-feeds' ), value: 'any' } ] } @@ -148,6 +150,7 @@ const ConditionsControl = ({ key={ index } label={ `${ field?.label } ${ window.feedzyConditionsData.operators[condition.operator] } ${ condition?.value || '' }` } onDelete={ () => removeCondition( index ) } + initialOpen={ index === 0 } > { - const [ isOpen, setOpen ] = useState( false ); + const [ isOpen, setOpen ] = useState( initialOpen ); return (
diff --git a/js/Conditions/conditions.js b/js/Conditions/conditions.js index d84c3168..71195610 100644 --- a/js/Conditions/conditions.js +++ b/js/Conditions/conditions.js @@ -16,6 +16,17 @@ import { */ import ConditionsControl from './ConditionsControl'; +const dummyConditions = { + match: 'all', + conditions: [ + { + field: 'title', + operator: 'contains', + value: 'Sports' + } + ] +}; + const App = () => { const [ conditions, setConditions ] = useState( { conditions: [], @@ -39,7 +50,7 @@ const App = () => { return ( From ad167d89db1f469aef6bc2cdcbe1f9f74a996a87 Mon Sep 17 00:00:00 2001 From: Hardeep Asrani Date: Tue, 17 Dec 2024 13:44:48 +0530 Subject: [PATCH 09/15] chore: allow editing of conditions without saving in free --- css/settings.css | 4 ---- js/Conditions/conditions.js | 23 +++++++++-------------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/css/settings.css b/css/settings.css index 22589b51..f9aed047 100644 --- a/css/settings.css +++ b/css/settings.css @@ -2365,10 +2365,6 @@ li.draggable-item .components-panel__body-toggle.components-button{ padding: 24px 0; } -.fz-conditions .components-disabled { - opacity: 0.5; -} - .fz-condition-control .components-button { width: 100%; margin: 0; diff --git a/js/Conditions/conditions.js b/js/Conditions/conditions.js index 71195610..1aa75fd6 100644 --- a/js/Conditions/conditions.js +++ b/js/Conditions/conditions.js @@ -1,8 +1,6 @@ /** * WordPress dependencies. */ -import { Disabled } from '@wordpress/components'; - import domReady from '@wordpress/dom-ready'; import { @@ -34,29 +32,26 @@ const App = () => { } ); useEffect( () => { + if ( ! feedzyData.isPro ) { + setConditions( dummyConditions ); + return + } + const field = document.getElementById( 'feed-post-filters-conditions' ); if ( field && field.value ) { const parsedConditions = JSON.parse( field.value ); - console.log( parsedConditions && parsedConditions.conditions ? parsedConditions : { conditions: [], match: 'all' } ) setConditions( parsedConditions && parsedConditions.conditions ? parsedConditions : { conditions: [], match: 'all' } ); } }, [] ); useEffect( () => { + if ( ! feedzyData.isPro ) { + return + } + document.getElementById( 'feed-post-filters-conditions' ).value = JSON.stringify( conditions ); }, [ conditions ] ); - if ( ! feedzyData.isPro ) { - return ( - - - - ); - } - return ( Date: Wed, 18 Dec 2024 11:06:30 +0530 Subject: [PATCH 10/15] feat: add filters support to shortcode --- .../feedzy-rss-feeds-admin-abstract.php | 14 +++++- includes/feedzy-rss-feeds.php | 1 + includes/util/feedzy-rss-feeds-conditions.php | 48 +++++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/includes/abstract/feedzy-rss-feeds-admin-abstract.php b/includes/abstract/feedzy-rss-feeds-admin-abstract.php index fc285757..e46518f5 100644 --- a/includes/abstract/feedzy-rss-feeds-admin-abstract.php +++ b/includes/abstract/feedzy-rss-feeds-admin-abstract.php @@ -442,7 +442,12 @@ public function feedzy_rss( $atts, $content = '' ) { } } - $sc['filters'] = apply_filters( 'feedzy_filter_conditions_migration', $sc ); + // If the user is explicitly using filters attribute, then use it and ignore old filters. + if ( isset( $sc['filters'] ) && ! empty( $sc['filters'] ) && feedzy_is_pro() ) { + $sc['filters'] = apply_filters( 'feedzy_filter_conditions_attribute', $sc['filters'] ); + } else { + $sc['filters'] = apply_filters( 'feedzy_filter_conditions_migration', $sc ); + } $sc = array_diff_key( $sc, @@ -505,7 +510,11 @@ public function feedzy_lazy_load( $data ) { $sc = $this->get_short_code_attributes( $atts ); $feed_url = $this->normalize_urls( $sc['feeds'] ); - $sc['filters'] = apply_filters( 'feedzy_filter_conditions_migration', $sc ); + if ( isset( $sc['filters'] ) && ! empty( $sc['filters'] ) && feedzy_is_pro() ) { + $sc['filters'] = apply_filters( 'feedzy_filter_conditions_attribute', $sc['filters'] ); + } else { + $sc['filters'] = apply_filters( 'feedzy_filter_conditions_migration', $sc ); + } $sc = array_diff_key( $sc, @@ -614,6 +623,7 @@ public function get_short_code_attributes( $atts ) { 'to_datetime' => '', // Disable default style. 'disable_default_style' => 'no', + 'filters' => '', ), $atts, 'feedzy_default' diff --git a/includes/feedzy-rss-feeds.php b/includes/feedzy-rss-feeds.php index 7ede8bcb..730d583b 100644 --- a/includes/feedzy-rss-feeds.php +++ b/includes/feedzy-rss-feeds.php @@ -268,6 +268,7 @@ function () { $plugin_conditions = new Feedzy_Rss_Feeds_Conditions(); $this->loader->add_action( 'feedzy_filter_conditions_migration', $plugin_conditions, 'migrate_conditions' ); + $this->loader->add_action( 'feedzy_filter_conditions_attribute', $plugin_conditions, 'convert_filter_string_to_json' ); $this->loader->add_action( 'feedzy_item_keyword', $plugin_conditions, 'evaluate_conditions', 10, 5 ); } diff --git a/includes/util/feedzy-rss-feeds-conditions.php b/includes/util/feedzy-rss-feeds-conditions.php index 7c7ca542..9f3441a8 100644 --- a/includes/util/feedzy-rss-feeds-conditions.php +++ b/includes/util/feedzy-rss-feeds-conditions.php @@ -344,4 +344,52 @@ private function check_contains( $value, $condition_value ): bool { } return false; } + + /** + * Convert a filter string to JSON. + * + * This function converts a filter string to a JSON object. + * + * @param string $filter_str The filter string to convert. + * + * @return string The JSON object. + */ + public function convert_filter_string_to_json( $filter_str ) { + // Split into segments by semicolon. + $segments = explode( ';', $filter_str ); + $filter_array = array( 'conditions' => array() ); + + foreach ( $segments as $segment ) { + $segment = trim( $segment ); + + // Check if this segment defines 'match'. + if ( strpos( $segment, 'match=' ) === 0 ) { + // Extract match value. + list( , $match_val ) = explode( '=', $segment, 2 ); + $filter_array['match'] = trim( $match_val ); + } elseif ( strpos( $segment, 'condition=' ) === 0 ) { + // Check if this segment defines a 'condition'. + // Remove "condition=" prefix. + $condition_str = substr( $segment, strlen( 'condition=' ) ); + $pairs = explode( ',', $condition_str ); + $condition = array(); + + // Each pair is in the form key:value. + foreach ( $pairs as $pair ) { + $pair = trim( $pair ); + if ( strpos( $pair, ':' ) !== false ) { + list( $key, $val ) = explode( ':', $pair, 2 ); + $condition[ trim( $key ) ] = trim( $val ); + } + } + + if ( ! empty( $condition ) ) { + $filter_array['conditions'][] = $condition; + } + } + } + + // Encode the final array as JSON. + return json_encode( $filter_array ); + } } From 1f06de3a960031ae447eb715ee5e77bc6b12c6e1 Mon Sep 17 00:00:00 2001 From: Hardeep Asrani Date: Wed, 18 Dec 2024 11:17:01 +0530 Subject: [PATCH 11/15] chore: improve upsell --- css/settings.css | 4 ++++ js/Conditions/ConditionsControl.js | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/css/settings.css b/css/settings.css index f9aed047..9aaa9f95 100644 --- a/css/settings.css +++ b/css/settings.css @@ -2365,6 +2365,10 @@ li.draggable-item .components-panel__body-toggle.components-button{ padding: 24px 0; } +.fz-condition-control.is-upsell { + opacity: 0.6; +} + .fz-condition-control .components-button { width: 100%; margin: 0; diff --git a/js/Conditions/ConditionsControl.js b/js/Conditions/ConditionsControl.js index 45307030..cf8a8a4c 100644 --- a/js/Conditions/ConditionsControl.js +++ b/js/Conditions/ConditionsControl.js @@ -1,3 +1,8 @@ +/** + * External dependencies. + */ +import classNames from 'classnames'; + /** * WordPress dependencies. */ @@ -124,7 +129,7 @@ const ConditionsControl = ({ }; return ( -
+
Date: Thu, 19 Dec 2024 17:38:24 +0530 Subject: [PATCH 12/15] fix: display of regex strings as special chars --- js/Conditions/conditions.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/js/Conditions/conditions.js b/js/Conditions/conditions.js index 1aa75fd6..c714ceef 100644 --- a/js/Conditions/conditions.js +++ b/js/Conditions/conditions.js @@ -40,7 +40,25 @@ const App = () => { const field = document.getElementById( 'feed-post-filters-conditions' ); if ( field && field.value ) { const parsedConditions = JSON.parse( field.value ); - setConditions( parsedConditions && parsedConditions.conditions ? parsedConditions : { conditions: [], match: 'all' } ); + if ( parsedConditions && parsedConditions.conditions ) { + parsedConditions.conditions = parsedConditions.conditions.map( condition => { + // We do all these schananigans to make sure we JS doesn't confuse regex for special characters. + if ( typeof condition.value === 'string' ) { + condition.value = condition.value + .replace( /\u0008/g, '\\b' ) + .replace( /\u000C/g, '\\f' ) + .replace( /\n/g, '\\n' ) + .replace( /\r/g, '\\r' ) + .replace( /\t/g, '\\t' ); + } + return condition; + } ); + setConditions( parsedConditions ); + } else { + setConditions( { conditions: [], match: 'all' } ); + } + } else { + setConditions( { conditions: [], match: 'all' } ); } }, [] ); From b8b3d0a4909261f39d61ffedada51d6dbb2613cc Mon Sep 17 00:00:00 2001 From: Hardeep Asrani Date: Fri, 20 Dec 2024 15:08:58 +0530 Subject: [PATCH 13/15] chore: fix eslint error --- .distignore | 1 + includes/admin/feedzy-rss-feeds-admin.php | 4 +- js/Conditions/ConditionsControl.js | 404 ++++++++++++---------- js/Conditions/DateTimeControl.js | 39 +-- js/Conditions/PanelTab.js | 39 +-- js/Conditions/conditions.js | 84 ----- js/Conditions/index.js | 83 +++++ package.json | 2 + 8 files changed, 338 insertions(+), 318 deletions(-) delete mode 100644 js/Conditions/conditions.js create mode 100644 js/Conditions/index.js diff --git a/.distignore b/.distignore index 2f996a02..c700c69f 100755 --- a/.distignore +++ b/.distignore @@ -18,6 +18,7 @@ composer.lock package-lock.json key.enc js/FeedzyBlock +js/Conditions/ js/Onboarding/ js/ActionPopup/ js/FeedBack/ diff --git a/includes/admin/feedzy-rss-feeds-admin.php b/includes/admin/feedzy-rss-feeds-admin.php index 808dbea8..46415706 100644 --- a/includes/admin/feedzy-rss-feeds-admin.php +++ b/includes/admin/feedzy-rss-feeds-admin.php @@ -213,8 +213,8 @@ public function enqueue_styles_admin() { ) ); - $asset_file = include FEEDZY_ABSPATH . '/js/build/conditions.asset.php'; - wp_enqueue_script( $this->plugin_name . '_conditions', FEEDZY_ABSURL . 'js/build/conditions.js', array_merge( $asset_file['dependencies'], array( 'wp-editor', 'wp-api' ) ), $asset_file['version'], true ); + $asset_file = include FEEDZY_ABSPATH . '/build/conditions/index.asset.php'; + wp_enqueue_script( $this->plugin_name . '_conditions', FEEDZY_ABSURL . 'build/conditions/index.js', array_merge( $asset_file['dependencies'], array( 'wp-editor', 'wp-api' ) ), $asset_file['version'], true ); // Add wp_localize_script to pass variables to the JS file with a filter over the data. wp_localize_script( diff --git a/js/Conditions/ConditionsControl.js b/js/Conditions/ConditionsControl.js index cf8a8a4c..f5271b90 100644 --- a/js/Conditions/ConditionsControl.js +++ b/js/Conditions/ConditionsControl.js @@ -8,16 +8,9 @@ import classNames from 'classnames'; */ import { __ } from '@wordpress/i18n'; -import { - Button, - SelectControl, - TextControl -} from '@wordpress/components'; +import { Button, SelectControl, TextControl } from '@wordpress/components'; -import { - Icon, - plus -} from '@wordpress/icons'; +import { Icon, plus } from '@wordpress/icons'; /** * Internal dependencies. @@ -26,187 +19,222 @@ import PanelTab from './PanelTab'; import DateTimeControl from './DateTimeControl'; const SUPPORTED_FIELDS = [ - { - label: __( 'Title', 'feedzy-rss-feeds' ), - value: 'title' - }, - { - label: __( 'Description', 'feedzy-rss-feeds' ), - value: 'description' - }, - { - label: __( 'Full Content', 'feedzy-rss-feeds' ), - value: 'fullcontent' - }, - { - label: __( 'Author', 'feedzy-rss-feeds' ), - value: 'author', - unsupportedOperators: [ - 'greater_than', - 'gte', - 'less_than', - 'lte' - ] - }, - { - label: __( 'Date', 'feedzy-rss-feeds' ), - value: 'date', - unsupportedOperators: [ - 'has_value', - 'equals', - 'not_equals', - 'empty', - 'contains', - 'not_contains' - ] - }, - { - label: __( 'Featured Image', 'feedzy-rss-feeds' ), - value: 'featured_image', - unsupportedOperators: [ - 'greater_than', - 'gte', - 'less_than', - 'lte' - ] - } + { + label: __('Title', 'feedzy-rss-feeds'), + value: 'title', + }, + { + label: __('Description', 'feedzy-rss-feeds'), + value: 'description', + }, + { + label: __('Full Content', 'feedzy-rss-feeds'), + value: 'fullcontent', + }, + { + label: __('Author', 'feedzy-rss-feeds'), + value: 'author', + unsupportedOperators: ['greater_than', 'gte', 'less_than', 'lte'], + }, + { + label: __('Date', 'feedzy-rss-feeds'), + value: 'date', + unsupportedOperators: [ + 'has_value', + 'equals', + 'not_equals', + 'empty', + 'contains', + 'not_contains', + ], + }, + { + label: __('Featured Image', 'feedzy-rss-feeds'), + value: 'featured_image', + unsupportedOperators: ['greater_than', 'gte', 'less_than', 'lte'], + }, ]; -const ConditionsControl = ({ - conditions, - setConditions -}) => { - const onChangeMatch = ( value ) => { - setConditions( { - ...conditions, - match: value - } ); - }; - - const addCondition = () => { - const conditionsCopy = [ ...conditions.conditions ]; - - conditionsCopy.push({ - field: SUPPORTED_FIELDS[0].value, - operator: 'contains' - }); - - setConditions( { - ...conditions, - conditions: conditionsCopy - } ); - }; - - const removeCondition = ( index ) => { - const conditionsCopy = [ ...conditions.conditions ]; - conditionsCopy.splice( index, 1 ); - - setConditions( { - ...conditions, - conditions: conditionsCopy - } ); - }; - - const onChangeCondtion = ( index, value, key ) => { - const conditionsCopy = [ ...conditions.conditions ]; - - conditionsCopy[index][key] = value; - - // We need to make sure we don't have unsupported operators for the selected field. - if ( key === 'field' ) { - const field = SUPPORTED_FIELDS.find( field => field.value === value ); - if ( field.unsupportedOperators?.includes( conditionsCopy[index].operator ) ) { - conditionsCopy[index].operator = Object.keys( window?.feedzyConditionsData?.operators ).filter( key => ! field.unsupportedOperators?.includes( key ) )[0]; - } - - conditionsCopy[index].value = ''; - } - - setConditions( { - ...conditions, - conditions: conditionsCopy - } ); - }; - - return ( -
- - - { conditions.conditions.map( ( condition, index ) => { - const field = SUPPORTED_FIELDS.find( field => field.value === condition.field ); - const operators = Object.keys( window?.feedzyConditionsData?.operators ).filter( key => ! field.unsupportedOperators?.includes( key ) ); - - return ( - removeCondition( index ) } - initialOpen={ index === 0 } - > - onChangeCondtion( index, value, 'field' ) } - /> - - ( { - label: window.feedzyConditionsData.operators[key], - value: key - } ) ) } - help={ [ 'contains', 'not_contains' ].includes( condition?.operator ) ? __( 'You can use comma(,) and plus(+) keyword.', 'feedzy-rss-feeds' ) : '' } - value={ condition?.operator } - onChange={ ( value ) => onChangeCondtion( index, value, 'operator' ) } - /> - - { ! [ 'has_value', 'empty' ].includes( condition?.operator ) && ( - <> - { condition?.field === 'date' ? ( - onChangeCondtion( index, value, 'value' ) } - /> - ) : ( - onChangeCondtion( index, value, 'value' ) } - /> - ) } - - ) } - - ); - } ) } - -
- -
-
- ); +const ConditionsControl = ({ conditions, setConditions }) => { + const onChangeMatch = (value) => { + setConditions({ + ...conditions, + match: value, + }); + }; + + const addCondition = () => { + const conditionsCopy = [...conditions.conditions]; + + conditionsCopy.push({ + field: SUPPORTED_FIELDS[0].value, + operator: 'contains', + }); + + setConditions({ + ...conditions, + conditions: conditionsCopy, + }); + }; + + const removeCondition = (index) => { + const conditionsCopy = [...conditions.conditions]; + conditionsCopy.splice(index, 1); + + setConditions({ + ...conditions, + conditions: conditionsCopy, + }); + }; + + const onChangeCondtion = (index, value, key) => { + const conditionsCopy = [...conditions.conditions]; + + conditionsCopy[index][key] = value; + + // We need to make sure we don't have unsupported operators for the selected field. + if (key === 'field') { + const field = SUPPORTED_FIELDS.find((i) => i.value === value); + if ( + field.unsupportedOperators?.includes( + conditionsCopy[index].operator + ) + ) { + conditionsCopy[index].operator = Object.keys( + window?.feedzyConditionsData?.operators + ).filter((i) => !field.unsupportedOperators?.includes(i))[0]; + } + + conditionsCopy[index].value = ''; + } + + setConditions({ + ...conditions, + conditions: conditionsCopy, + }); + }; + + return ( +
+ + + {conditions.conditions.map((condition, index) => { + const field = SUPPORTED_FIELDS.find( + (i) => i.value === condition.field + ); + const operators = Object.keys( + window?.feedzyConditionsData?.operators + ).filter((key) => !field.unsupportedOperators?.includes(key)); + + return ( + removeCondition(index)} + initialOpen={index === 0} + > + + onChangeCondtion(index, value, 'field') + } + /> + + ({ + label: window.feedzyConditionsData.operators[ + key + ], + value: key, + }))} + help={ + ['contains', 'not_contains'].includes( + condition?.operator + ) + ? __( + 'You can use comma(,) and plus(+) keyword.', + 'feedzy-rss-feeds' + ) + : '' + } + value={condition?.operator} + onChange={(value) => + onChangeCondtion(index, value, 'operator') + } + /> + + {!['has_value', 'empty'].includes( + condition?.operator + ) && ( + <> + {condition?.field === 'date' ? ( + + onChangeCondtion( + index, + value, + 'value' + ) + } + /> + ) : ( + + onChangeCondtion( + index, + value, + 'value' + ) + } + /> + )} + + )} + + ); + })} + +
+ +
+
+ ); }; export default ConditionsControl; diff --git a/js/Conditions/DateTimeControl.js b/js/Conditions/DateTimeControl.js index 28619216..317cfd92 100644 --- a/js/Conditions/DateTimeControl.js +++ b/js/Conditions/DateTimeControl.js @@ -7,44 +7,35 @@ import { BaseControl, Button, DateTimePicker, - Dropdown + Dropdown, } from '@wordpress/components'; -import { - format, - __experimentalGetSettings -} from '@wordpress/date'; +// eslint-disable-next-line @wordpress/no-unsafe-wp-apis +import { format, __experimentalGetSettings } from '@wordpress/date'; -const DateTimeControl = ({ - label, - value, - onChange -}) => { +const DateTimeControl = ({ index, label, value, onChange }) => { const settings = __experimentalGetSettings(); return ( - + ( + renderToggle={({ onToggle, isOpen }) => ( <> - ) } - renderContent={ () => ( - - ) } + )} + renderContent={() => ( + + )} /> ); diff --git a/js/Conditions/PanelTab.js b/js/Conditions/PanelTab.js index 1c612ac1..04d66ad9 100644 --- a/js/Conditions/PanelTab.js +++ b/js/Conditions/PanelTab.js @@ -7,40 +7,39 @@ import { Button } from '@wordpress/components'; import { useState } from '@wordpress/element'; -const PanelTab = ({ - label, - onDelete, - initialOpen = false, - children -}) => { - const [ isOpen, setOpen ] = useState( initialOpen ); +const PanelTab = ({ label, onDelete, initialOpen = false, children }) => { + const [isOpen, setOpen] = useState(initialOpen); return (
setOpen( ! isOpen ) } - > - { label } -
+ className="fz-panel-tab__header__label" + onClick={() => setOpen(!isOpen)} + > + {label} +
- { isOpen &&
{ children }
} + {isOpen &&
{children}
}
); }; diff --git a/js/Conditions/conditions.js b/js/Conditions/conditions.js deleted file mode 100644 index c714ceef..00000000 --- a/js/Conditions/conditions.js +++ /dev/null @@ -1,84 +0,0 @@ -/** - * WordPress dependencies. - */ -import domReady from '@wordpress/dom-ready'; - -import { - createRoot, - useEffect, - useState -} from '@wordpress/element'; - -/** - * Internal dependencies. - */ -import ConditionsControl from './ConditionsControl'; - -const dummyConditions = { - match: 'all', - conditions: [ - { - field: 'title', - operator: 'contains', - value: 'Sports' - } - ] -}; - -const App = () => { - const [ conditions, setConditions ] = useState( { - conditions: [], - match: 'all' - } ); - - useEffect( () => { - if ( ! feedzyData.isPro ) { - setConditions( dummyConditions ); - return - } - - const field = document.getElementById( 'feed-post-filters-conditions' ); - if ( field && field.value ) { - const parsedConditions = JSON.parse( field.value ); - if ( parsedConditions && parsedConditions.conditions ) { - parsedConditions.conditions = parsedConditions.conditions.map( condition => { - // We do all these schananigans to make sure we JS doesn't confuse regex for special characters. - if ( typeof condition.value === 'string' ) { - condition.value = condition.value - .replace( /\u0008/g, '\\b' ) - .replace( /\u000C/g, '\\f' ) - .replace( /\n/g, '\\n' ) - .replace( /\r/g, '\\r' ) - .replace( /\t/g, '\\t' ); - } - return condition; - } ); - setConditions( parsedConditions ); - } else { - setConditions( { conditions: [], match: 'all' } ); - } - } else { - setConditions( { conditions: [], match: 'all' } ); - } - }, [] ); - - useEffect( () => { - if ( ! feedzyData.isPro ) { - return - } - - document.getElementById( 'feed-post-filters-conditions' ).value = JSON.stringify( conditions ); - }, [ conditions ] ); - - return ( - - ); -}; - -domReady( () => { - const root = createRoot( document.getElementById( 'fz-conditions' ) ); - root.render( ); -}); diff --git a/js/Conditions/index.js b/js/Conditions/index.js new file mode 100644 index 00000000..90e3d099 --- /dev/null +++ b/js/Conditions/index.js @@ -0,0 +1,83 @@ +/** + * WordPress dependencies. + */ +import domReady from '@wordpress/dom-ready'; + +import { createRoot, useEffect, useState } from '@wordpress/element'; + +/** + * Internal dependencies. + */ +import ConditionsControl from './ConditionsControl'; + +const dummyConditions = { + match: 'all', + conditions: [ + { + field: 'title', + operator: 'contains', + value: 'Sports', + }, + ], +}; + +const App = () => { + const [conditions, setConditions] = useState({ + conditions: [], + match: 'all', + }); + + useEffect(() => { + if (!feedzyData.isPro) { + setConditions(dummyConditions); + return; + } + + const field = document.getElementById('feed-post-filters-conditions'); + if (field && field.value) { + const parsedConditions = JSON.parse(field.value); + if (parsedConditions && parsedConditions.conditions) { + parsedConditions.conditions = parsedConditions.conditions.map( + (condition) => { + // We do all these schananigans to make sure we JS doesn't confuse regex for special characters. + if (typeof condition.value === 'string') { + condition.value = condition.value + .replace(/\u0008/g, '\\b') + .replace(/\u000C/g, '\\f') + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/\t/g, '\\t'); + } + return condition; + } + ); + setConditions(parsedConditions); + } else { + setConditions({ conditions: [], match: 'all' }); + } + } else { + setConditions({ conditions: [], match: 'all' }); + } + }, []); + + useEffect(() => { + if (!feedzyData.isPro) { + return; + } + + document.getElementById('feed-post-filters-conditions').value = + JSON.stringify(conditions); + }, [conditions]); + + return ( + + ); +}; + +domReady(() => { + const root = createRoot(document.getElementById('fz-conditions')); + root.render(); +}); diff --git a/package.json b/package.json index 894d8314..b2822395 100755 --- a/package.json +++ b/package.json @@ -22,11 +22,13 @@ "build:onboarding": "wp-scripts build --webpack-src-dir=js/Onboarding --output-path=build/onboarding --output-filename=index.js", "build:feedback": "wp-scripts build --webpack-src-dir=js/FeedBack --output-path=build/feedback --output-filename=index.js", "build:actions": "wp-scripts build --webpack-src-dir=js/ActionPopup --output-path=build/action-popup --output-filename=index.js", + "build:conditions": "wp-scripts build --webpack-src-dir=js/Conditions --output-path=build/conditions --output-filename=index.js", "dev": "npm-run-all --parallel dev:*", "dev:block": "wp-scripts start --webpack-src-dir=js/FeedzyBlock --output-path=build/block --output-filename=index.js", "dev:onboarding": "wp-scripts start --webpack-src-dir=js/Onboarding --output-path=build/onboarding --output-filename=index.js", "dev:feedback": "wp-scripts start --webpack-src-dir=js/FeedBack --output-path=build/feedback --output-filename=index.js", "dev:actions": "wp-scripts start --webpack-src-dir=js/ActionPopup --output-path=build/action-popup --output-filename=index.js", + "dev:conditions": "wp-scripts start --webpack-src-dir=js/Conditions --output-path=build/conditions --output-filename=index.js", "lint:js": "wp-scripts lint-js ./js", "release": "semantic-release --debug", "dist": "bash bin/dist.sh", From 64ddc9b9458a80a7eba0d7eb204b39ce5ab90970 Mon Sep 17 00:00:00 2001 From: Hardeep Asrani Date: Fri, 20 Dec 2024 18:25:57 +0530 Subject: [PATCH 14/15] chore: fix broken code --- includes/admin/feedzy-rss-feeds-import.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/includes/admin/feedzy-rss-feeds-import.php b/includes/admin/feedzy-rss-feeds-import.php index 97ecf80c..a2c0b352 100644 --- a/includes/admin/feedzy-rss-feeds-import.php +++ b/includes/admin/feedzy-rss-feeds-import.php @@ -328,7 +328,7 @@ public function feedzy_import_feed_options() { $post_types = array_diff( $post_types, array( 'feedzy_imports', 'feedzy_categories' ) ); $published_status = array( 'publish', 'draft' ); - $authors = get_users( array( 'number' => 100 ) ); + $authors = get_users( array( 'number' => 100 ) ); $authors_array = array(); foreach ( $authors as $author ) { $authors_array[] = $author->user_login; @@ -377,6 +377,7 @@ public function feedzy_import_feed_options() { 'to_datetime' => $to_datetime, ) ); + } /** * This code snippet retrieves the post author for backward compatibility for existing imports as well as for any new imports. @@ -1297,7 +1298,6 @@ function ( $errors, $feed, $url ) { wp_send_json_success( array( 'output' => do_shortcode( $shortcode ) ) ); } - /** * The Cron Job. * @@ -2520,7 +2520,6 @@ public function feedzy_is_license_of_type( $default, $type ) { return $default; } - /** * Method for updating settings page via AJAX. * From c0c7cb7d60e26de5b2b0b49bf7f6327703a3f20a Mon Sep 17 00:00:00 2001 From: Hardeep Asrani Date: Fri, 20 Dec 2024 21:08:52 +0530 Subject: [PATCH 15/15] fix: the mess with escape and unescaping --- includes/admin/feedzy-rss-feeds-import.php | 4 +++ includes/util/feedzy-rss-feeds-conditions.php | 5 ++-- js/Conditions/index.js | 26 ++++--------------- tests/test-conditions.php | 7 +++++ 4 files changed, 18 insertions(+), 24 deletions(-) diff --git a/includes/admin/feedzy-rss-feeds-import.php b/includes/admin/feedzy-rss-feeds-import.php index a2c0b352..1bdf94cb 100644 --- a/includes/admin/feedzy-rss-feeds-import.php +++ b/includes/admin/feedzy-rss-feeds-import.php @@ -565,6 +565,10 @@ public function save_feedzy_import_feed_meta( $post_id, $post ) { $data_meta['import_auto_translation'] = isset( $data_meta['import_auto_translation'] ) ? $data_meta['import_auto_translation'] : 'no'; // Check feeds external image URL checkbox checked OR not. $data_meta['import_use_external_image'] = isset( $data_meta['import_use_external_image'] ) ? $data_meta['import_use_external_image'] : 'no'; + // If it is filter_conditions we want to escape it. + if ( isset( $data_meta['filter_conditions'] ) ) { + $data_meta['filter_conditions'] = wp_slash( $data_meta['filter_conditions'] ); + } // $data_meta['feedzy_post_author'] should be the author username. We convert it to the author ID. if ( ! empty( $data_meta['import_post_author'] ) ) { diff --git a/includes/util/feedzy-rss-feeds-conditions.php b/includes/util/feedzy-rss-feeds-conditions.php index 9f3441a8..1801fc24 100644 --- a/includes/util/feedzy-rss-feeds-conditions.php +++ b/includes/util/feedzy-rss-feeds-conditions.php @@ -219,11 +219,10 @@ public function is_condition_met( $condition, $value ): bool { } break; case self::OPERATOR_REGEX: - $regex_pattern = $condition_value; if ( ! preg_match( '/^\/.*\/[imsxuADU]*$/', $condition_value ) ) { - $regex_pattern = '/' . $condition_value . '/i'; + $condition_value = '/' . $condition_value . '/i'; } - return preg_match( $regex_pattern, $value ) === 1; + return preg_match( $condition_value, $value ) === 1; default: // Default is self::OPERATOR_HAS_VALUE return ! empty( $value ); diff --git a/js/Conditions/index.js b/js/Conditions/index.js index 90e3d099..db5b5c97 100644 --- a/js/Conditions/index.js +++ b/js/Conditions/index.js @@ -36,27 +36,11 @@ const App = () => { const field = document.getElementById('feed-post-filters-conditions'); if (field && field.value) { const parsedConditions = JSON.parse(field.value); - if (parsedConditions && parsedConditions.conditions) { - parsedConditions.conditions = parsedConditions.conditions.map( - (condition) => { - // We do all these schananigans to make sure we JS doesn't confuse regex for special characters. - if (typeof condition.value === 'string') { - condition.value = condition.value - .replace(/\u0008/g, '\\b') - .replace(/\u000C/g, '\\f') - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') - .replace(/\t/g, '\\t'); - } - return condition; - } - ); - setConditions(parsedConditions); - } else { - setConditions({ conditions: [], match: 'all' }); - } - } else { - setConditions({ conditions: [], match: 'all' }); + setConditions( + parsedConditions && parsedConditions.conditions + ? parsedConditions + : { conditions: [], match: 'all' } + ); } }, []); diff --git a/tests/test-conditions.php b/tests/test-conditions.php index 7fba60b4..f00a3caf 100644 --- a/tests/test-conditions.php +++ b/tests/test-conditions.php @@ -145,5 +145,12 @@ public function test_is_condition_met_regex() { 'value' => '/test/', ); $this->assertTrue( $this->conditions->is_condition_met( $condition, 'this is a test' ) ); + + + $condition = array( + 'operator' => 'regex', + 'value' => '\band\b', + ); + $this->assertTrue( $this->conditions->is_condition_met( $condition, 'matt and tommy' ) ); } }