Changeset 3482456
- Timestamp:
- 03/14/2026 09:55:02 AM (3 weeks ago)
- Location:
- feed-kuantokusta-for-woocommerce
- Files:
-
- 6 edited
- 1 copied
-
tags/5.2 (copied) (copied from feed-kuantokusta-for-woocommerce/trunk)
-
tags/5.2/feed-kuantokusta-for-woocommerce.php (modified) (3 diffs)
-
tags/5.2/includes/class-wc-feed-kuantokusta.php (modified) (30 diffs)
-
tags/5.2/readme.txt (modified) (2 diffs)
-
trunk/feed-kuantokusta-for-woocommerce.php (modified) (3 diffs)
-
trunk/includes/class-wc-feed-kuantokusta.php (modified) (30 diffs)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
feed-kuantokusta-for-woocommerce/tags/5.2/feed-kuantokusta-for-woocommerce.php
r3444190 r3482456 4 4 * Plugin URI: https://www.webdados.pt/wordpress/plugins/feed-kuantokusta-para-woocommerce/ 5 5 * Description: This plugin allows you to generate a WooCommerce product feed to submit to KuantoKusta, a portuguese price comparison website and marketplace. 6 * Version: 5. 16 * Version: 5.2 7 7 * Author: Naked Cat Plugins (by Webdados) 8 8 * Author URI: https://nakedcatplugins.com … … 10 10 * Domain Path: /languages 11 11 * Requires at least: 6.2 12 * Tested up to: 6.912 * Tested up to: 7.0 13 13 * Requires PHP: 7.2 14 14 * WC requires at least: 8.0 15 * WC tested up to: 10. 515 * WC tested up to: 10.6 16 16 * Requires Plugins: woocommerce 17 17 **/ … … 91 91 } 92 92 93 93 /** 94 * Incompatible version of KuantoKusta PRO notice 95 * 96 * @return void 97 */ 94 98 function fkkwc_admin_notices_pro_incompatible() { 95 99 ?> -
feed-kuantokusta-for-woocommerce/tags/5.2/includes/class-wc-feed-kuantokusta.php
r3394301 r3482456 97 97 $this->out_link_utm = '?utm_source=' . rawurlencode( esc_url( home_url( '/' ) ) ) . '&utm_medium=link&utm_campaign=kk_woocommerce_plugin'; 98 98 // Mode 99 $this->mode = get_option( $this->id . '_plugin_mode' ) != '' ? get_option( $this->id . '_plugin_mode' ) : 'comparison';99 $this->mode = get_option( $this->id . '_plugin_mode' ) !== '' ? get_option( $this->id . '_plugin_mode' ) : 'comparison'; 100 100 // Settings 101 101 $temp = $this->get_settings(); 102 102 foreach ( $temp as $key => $value ) { 103 if ( isset( $value['id_'] ) && $value['id_'] != '' ) {103 if ( isset( $value['id_'] ) && $value['id_'] !== '' ) { 104 104 $this->settings[ $value['id_'] ] = get_option( $value['id'] ); 105 105 } … … 234 234 ); 235 235 236 if ( $this->mode == 'marketplace' ) {236 if ( $this->mode === 'marketplace' ) { 237 237 // Product stock 238 238 $settings = array_merge( … … 280 280 ) 281 281 ); 282 if ( $this->mode == 'marketplace' ) {282 if ( $this->mode === 'marketplace' ) { 283 283 $settings = array_merge( 284 284 $settings, … … 318 318 319 319 foreach ( $settings as $key => $value ) { 320 if ( isset( $value['id_'] ) && $value['id_'] != '' ) {320 if ( isset( $value['id_'] ) && $value['id_'] !== '' ) { 321 321 $settings[ $key ]['id'] = $this->id . '_' . $value['id_']; 322 322 } … … 467 467 ) 468 468 ); 469 if ( $this->mode== 'marketplace' ) {470 // Preparation days471 woocommerce_wp_text_input(472 array(473 'id' => '_kuantokusta_preparation_days_max',474 'label' => __( 'Maximum preparation time', 'feed-kuantokusta-for-woocommerce' ) . ' (' . __( 'days', 'feed-kuantokusta-for-woocommerce' ) . ')',475 'placeholder' => sprintf(476 /* translators: 1: default preparation days. */477 __( 'Blank for default (%s)', 'feed-kuantokusta-for-woocommerce' ),478 $this->get_setting( 'preparation_days_max_default' )479 ),480 'type' => 'number',481 'custom_attributes' => array(482 'min' => 0,483 ),484 )485 );486 // Delivery days487 woocommerce_wp_text_input(488 array(489 'id' => '_kuantokusta_delivery_days_max',490 'label' => __( 'Maximum delivery time', 'feed-kuantokusta-for-woocommerce' ) . ' (' . __( 'days', 'feed-kuantokusta-for-woocommerce' ) . ')',491 'placeholder' => sprintf(492 /* translators: 1: default delivery days. */493 __( 'Blank for default (%s)', 'feed-kuantokusta-for-woocommerce' ),494 $this->get_setting( 'delivery_days_max_default' )495 ),496 'type' => 'number',497 'custom_attributes' => array(498 'min' => 0,499 ),500 )501 );502 }469 if ( $this->mode === 'marketplace' ) { 470 // Preparation days 471 woocommerce_wp_text_input( 472 array( 473 'id' => '_kuantokusta_preparation_days_max', 474 'label' => __( 'Maximum preparation time', 'feed-kuantokusta-for-woocommerce' ) . ' (' . __( 'days', 'feed-kuantokusta-for-woocommerce' ) . ')', 475 'placeholder' => sprintf( 476 /* translators: 1: default preparation days. */ 477 __( 'Blank for default (%s)', 'feed-kuantokusta-for-woocommerce' ), 478 $this->get_setting( 'preparation_days_max_default' ) 479 ), 480 'type' => 'number', 481 'custom_attributes' => array( 482 'min' => 0, 483 ), 484 ) 485 ); 486 // Delivery days 487 woocommerce_wp_text_input( 488 array( 489 'id' => '_kuantokusta_delivery_days_max', 490 'label' => __( 'Maximum delivery time', 'feed-kuantokusta-for-woocommerce' ) . ' (' . __( 'days', 'feed-kuantokusta-for-woocommerce' ) . ')', 491 'placeholder' => sprintf( 492 /* translators: 1: default delivery days. */ 493 __( 'Blank for default (%s)', 'feed-kuantokusta-for-woocommerce' ), 494 $this->get_setting( 'delivery_days_max_default' ) 495 ), 496 'type' => 'number', 497 'custom_attributes' => array( 498 'min' => 0, 499 ), 500 ) 501 ); 502 } 503 503 // Action for integration... 504 504 do_action( 'kuantokusta_product_data_panel_end' ); 505 ?>505 ?> 506 506 </div> 507 507 <script type="text/javascript"> 508 508 jQuery( function( $ ) { 509 509 function kk_hide_fields() { 510 if ( $( '#_kuantokusta_hide' ).is( ":checked") ) {510 if ( $( '#_kuantokusta_hide' ).is( ':checked' ) ) { 511 511 $( '#kuantokusta p.form-field' ).hide(); 512 512 $( '#kuantokusta p.kuantokusta-title' ).hide(); … … 542 542 */ 543 543 public function woocommerce_process_product_meta( $post_id ) { 544 // WooCommerce took care of nonces 545 // phpcs:disable WordPress.Security.NonceVerification.Missing 544 546 $meta = array(); 545 547 $product = wc_get_product( $post_id ); 546 548 // Hide 547 $meta['_kuantokusta_hide'] = ! empty( $_POST['_kuantokusta_hide'] ) ? wc_clean( $_POST['_kuantokusta_hide']) : '';549 $meta['_kuantokusta_hide'] = ! empty( $_POST['_kuantokusta_hide'] ) ? sanitize_text_field( wp_unslash( $_POST['_kuantokusta_hide'] ) ) : ''; 548 550 // EAN 549 $meta['_kuantokusta_ean'] = isset( $_POST['_kuantokusta_ean'] ) && ! empty( $_POST['_kuantokusta_ean'] ) ? wc_clean( $_POST['_kuantokusta_ean']) : '';551 $meta['_kuantokusta_ean'] = ! empty( $_POST['_kuantokusta_ean'] ) ? sanitize_text_field( wp_unslash( $_POST['_kuantokusta_ean'] ) ) : ''; 550 552 if ( version_compare( WC_VERSION, '9.2', '>=' ) && ! empty( $_POST['_global_unique_id'] ) ) { 551 553 // If the core field is filled in, remove ours from the database … … 554 556 } 555 557 // Shipping 556 $meta['_kuantokusta_shipping'] = trim( $_POST['_kuantokusta_shipping'] ) != '' ? wc_clean( $_POST['_kuantokusta_shipping']) : '';558 $meta['_kuantokusta_shipping'] = ! empty( $_POST['_kuantokusta_shipping'] ) ? sanitize_text_field( wp_unslash( $_POST['_kuantokusta_shipping'] ) ) : ''; 557 559 // Shipping 558 $meta['_kuantokusta_preparation_days_max'] = ! empty( $_POST['_kuantokusta_preparation_days_max'] ) ? wc_clean( $_POST['_kuantokusta_preparation_days_max']) : '';560 $meta['_kuantokusta_preparation_days_max'] = ! empty( $_POST['_kuantokusta_preparation_days_max'] ) ? sanitize_text_field( wp_unslash( $_POST['_kuantokusta_preparation_days_max'] ) ) : ''; 559 561 // Shipping 560 $meta['_kuantokusta_delivery_days_max'] = ! empty( $_POST['_kuantokusta_delivery_days_max'] ) ? wc_clean( $_POST['_kuantokusta_delivery_days_max']) : '';562 $meta['_kuantokusta_delivery_days_max'] = ! empty( $_POST['_kuantokusta_delivery_days_max'] ) ? sanitize_text_field( wp_unslash( $_POST['_kuantokusta_delivery_days_max'] ) ) : ''; 561 563 // Filter for integration ( Use this filter to add to $meta the keys/values of the fields added by the `kuantokusta_product_data_panel_end` action ) 562 564 $meta = apply_filters( 'kuantokusta_process_product_meta', $meta ); … … 568 570 // Action for integration - ONLY if the filter above was not used 569 571 do_action( 'kuantokusta_process_product_meta_end', $post_id ); 572 // phpcs:enable 570 573 } 571 574 … … 583 586 public function render_products_feed() { 584 587 define( 'KK_IS_FEED', true ); 585 @define( 'DONOTCACHEPAGE', true ); // Cache plugins 588 if ( ! defined( 'DONOTCACHEPAGE' ) ) { 589 define( 'DONOTCACHEPAGE', true ); // Cache plugins 590 } 586 591 header( 'Content-Type: application/rss+xml; charset=utf-8' ); 587 592 header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() - 86400 ) . ' GMT' ); // Yesterday … … 589 594 header( 'Cache-Control: post-check=0, pre-check=0', false ); 590 595 header( 'Pragma: no-cache' ); 591 $offset = intval( isset( $_GET['LIMIT'] ) ? $_GET['LIMIT'] : 0 ); 592 $posts_per_page = intval( isset( $_GET['TOTAL_PRODUTOS'] ) ? $_GET['TOTAL_PRODUTOS'] : -1 ); 596 // phpcs:disable WordPress.Security.NonceVerification.Recommended 597 $offset = isset( $_GET['LIMIT'] ) ? intval( $_GET['LIMIT'] ) : 0; 598 $posts_per_page = isset( $_GET['TOTAL_PRODUTOS'] ) ? intval( $_GET['TOTAL_PRODUTOS'] ) : -1; 599 // phpcs:enable 600 ob_start(); 593 601 do_action( 'kuantokusta_render_products_feed_start' ); 594 echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset') . '"?' . '>602 echo '<?xml version="1.0" encoding="' . esc_attr( get_option( 'blog_charset' ) ) . '"?' . '> 595 603 '; 596 604 ?> … … 602 610 $sql_exclude = "SELECT DISTINCT post_id FROM $wpdb->postmeta WHERE ( meta_key = '_kuantokusta_hide' AND meta_value = 'yes' )"; 603 611 // Debug and only include specific SKU 604 if ( isset( $_GET['sku'] ) && trim( $_GET['sku'] ) != '' ) { 605 $sql_exclude .= " || ( meta_key = '_sku' AND meta_value NOT LIKE '%" . sanitize_text_field( trim( $_GET['sku'] ) ) . "%' )"; 606 } 607 $results = $wpdb->get_results( $sql_exclude, ARRAY_A ); 612 // phpcs:disable WordPress.Security.NonceVerification.Recommended 613 if ( isset( $_GET['sku'] ) && trim( sanitize_text_field( wp_unslash( $_GET['sku'] ) ) ) !== '' ) { 614 $sql_exclude .= " || ( meta_key = '_sku' AND meta_value NOT LIKE '%" . trim( sanitize_text_field( wp_unslash( $_GET['sku'] ) ) ) . "%' )"; 615 } 616 // phpcs:enable 617 $results = $wpdb->get_results( $sql_exclude, ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared 608 618 if ( ! empty( $results ) ) { 609 619 if ( count( $results ) > 0 ) { … … 639 649 if ( apply_filters( 'kuantokusta_variation_node_show', true, $product, $variation ) ) { 640 650 $product_node = $this->render_product_feed_variation( $product, $variation ); 641 echo apply_filters( 'kuantokusta_product_node_variation', $product_node, $product, $variation ); 651 // This is XML, so we cannot escape it 652 echo apply_filters( 'kuantokusta_product_node_variation', $product_node, $product, $variation ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 642 653 } 643 654 } … … 647 658 // Just like simple products 648 659 $product_node = $this->render_product_feed_default( $product, $product_type ); 649 echo apply_filters( 'kuantokusta_product_node_default', $product_node, $product, $product_type ); 660 // This is XML, so we cannot escape it 661 echo apply_filters( 'kuantokusta_product_node_default', $product_node, $product, $product_type ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 650 662 break; 651 663 } … … 653 665 default: // Including 'simple' 654 666 $product_node = $this->render_product_feed_default( $product, $product_type ); 655 echo apply_filters( 'kuantokusta_product_node_default', $product_node, $product, $product_type ); 667 // This is XML, so we cannot escape it 668 echo apply_filters( 'kuantokusta_product_node_default', $product_node, $product, $product_type ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 656 669 break; 657 670 } … … 663 676 </products> 664 677 <?php 678 // This is XML, so we cannot escape it 679 // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped 680 $xml_string = ob_get_clean(); 681 if ( apply_filters( 'kuantokusta_prettify_xml', true ) && class_exists( 'DOMDocument' ) ) { 682 libxml_use_internal_errors( true ); 683 $dom = new DOMDocument( '1.0', 'UTF-8' ); 684 $dom->preserveWhiteSpace = false; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase 685 $dom->formatOutput = true; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase 686 $ok = $dom->loadXML( $xml_string, LIBXML_NOBLANKS | LIBXML_NOERROR | LIBXML_NOWARNING ); 687 if ( ! $ok ) { 688 // If it fails, output the non-formatted XML and log the error 689 error_log( 'KuantoKusta feed XML parsing errors:' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log 690 foreach ( libxml_get_errors() as $error ) { 691 error_log( $error->message ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log 692 error_log( 'Line: ' . $error->line . ' Column: ' . $error->column ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log 693 } 694 libxml_clear_errors(); 695 echo $xml_string; 696 } 697 libxml_clear_errors(); 698 // Keep empty tags instead of self-closing tags, as we don't know if KuantoKusta accepts self-closing tags 699 echo preg_replace( '/<(\w+)\/>/', '<$1></$1>', $dom->saveXML() ); 700 } else { 701 echo $xml_string; 702 } 703 // phpcs:enable 665 704 } 666 705 … … 685 724 $image = apply_filters( 'kuantokusta_product_node_default_image', $this->get_product_image( $product ), $product, $product_type ); 686 725 $description = apply_filters( 'kuantokusta_product_node_default_description', $this->get_product_description( $product ), $product, $product_type ); 687 // $brand = apply_filters( 'kuantokusta_product_node_default_brand', $this->get_product_brand( $product ), $product, $product_type );688 726 $ean = apply_filters( 'kuantokusta_product_node_default_ean', $this->get_product_ean( $product ), $product, $product_type ); 689 727 $reference = apply_filters( 'kuantokusta_product_node_default_reference', $product->get_sku(), $product, $product_type ); … … 743 781 'cdata' => true, 744 782 ), 745 // 'brand' => array(746 // 'value' => trim( $brand ),747 // 'cdata' => true,748 // ),749 783 'upc_ean' => array( 750 784 'value' => trim( $ean ), … … 761 795 ), 762 796 'shipping_cost' => array( 763 'value' => ( trim( $shipping_cost ) != '' && floatval( $shipping_cost ) >= 0 ) ? round( floatval( $shipping_cost ), wc_get_price_decimals() ) : '',797 'value' => ( trim( $shipping_cost ) !== '' && floatval( $shipping_cost ) >= 0 ) ? round( floatval( $shipping_cost ), wc_get_price_decimals() ) : '', 764 798 'cdata' => false, 765 799 'alias_key' => 'shipping', 766 800 ), 767 801 ); 768 if ( $this->mode == 'marketplace' ) {802 if ( $this->mode === 'marketplace' ) { 769 803 // Marketplace 770 804 unset( $xml_fields['stock'] ); … … 805 839 foreach ( $xml_fields as $key => $value ) { 806 840 ?> 807 <<?php echo $key; ?>><?php echo $value['cdata'] ? '<![CDATA[' . $value['value'] . ']]>' : $value['value']; ?></<?php echo $key; ?>>841 <<?php echo esc_attr( $key ); ?>><?php echo $value['cdata'] ? '<![CDATA[' . wp_kses_post( $value['value'] ) . ']]>' : esc_html( $value['value'] ); ?></<?php echo esc_attr( $key ); ?>> 808 842 <?php 809 843 } … … 827 861 $url = $variation->get_permalink(); 828 862 $title = trim( apply_filters( 'kuantokusta_product_node_pre_variation_title', $variation->get_name(), $product, $variation ) ); 829 if ( trim( $title ) == '' ) {863 if ( trim( $title ) === '' ) { 830 864 $title = trim( $product->get_title() ); 831 865 } 832 866 $reference = $variation->get_sku(); 833 867 if ( apply_filters( 'kuantokusta_product_node_variation_title_append_description', true, $product, $variation ) ) { 834 if ( trim( $variation->get_description() ) != '' ) {868 if ( trim( $variation->get_description() ) !== '' ) { 835 869 // Variation description 836 870 $title .= apply_filters( 'woocommerce_product_variation_title_attributes_separator', ' - ', $variation ) . trim( $variation->get_description() ); 837 871 } elseif ( apply_filters( 'kuantokusta_product_node_variation_title_append_sku_or_id', true, $product, $variation ) ) { 838 if ( trim( $reference ) != '' ) {872 if ( trim( $reference ) !== '' ) { 839 873 // Variation sku 840 874 $title .= ' (' . trim( $reference ) . ')'; … … 855 889 $image = apply_filters( 'kuantokusta_product_node_variation_image', $this->get_product_variation_image( $product, $variation ), $product, $variation ); 856 890 $description = apply_filters( 'kuantokusta_product_node_variation_description', $this->get_product_variation_description( $product, $variation ), $product, $variation ); 857 // $brand = apply_filters( 'kuantokusta_product_node_variation_brand', $this->get_product_brand( $product ), $product, $variation );858 891 $ean = apply_filters( 'kuantokusta_product_node_variation_ean', $this->get_product_ean( $product ), $product, $variation ); // On the free version we only read EAN from the main product 859 if ( trim( $reference ) == '' ) {892 if ( trim( $reference ) === '' ) { 860 893 $reference = $product->get_sku(); 861 894 } 862 895 $reference = apply_filters( 'kuantokusta_product_node_variation_reference', $reference, $product, $variation ); 863 896 $weight = $variation->get_weight(); 864 if ( floatval( $weight ) == 0 ) {897 if ( floatval( $weight ) === 0 ) { 865 898 $weight = $product->get_weight(); 866 899 } … … 920 953 'cdata' => true, 921 954 ), 922 // 'brand' => array(923 // 'value' => trim( $brand ),924 // 'cdata' => true,925 // ),926 955 'upc_ean' => array( 927 956 'value' => trim( $ean ), … … 938 967 ), 939 968 'shipping_cost' => array( 940 'value' => ( trim( $shipping_cost ) != '' && floatval( $shipping_cost ) >= 0 ) ? round( floatval( $shipping_cost ), wc_get_price_decimals() ) : '',969 'value' => ( trim( $shipping_cost ) !== '' && floatval( $shipping_cost ) >= 0 ) ? round( floatval( $shipping_cost ), wc_get_price_decimals() ) : '', 941 970 'cdata' => false, 942 971 'alias_key' => 'shipping', … … 982 1011 foreach ( $xml_fields as $key => $value ) { 983 1012 ?> 984 <<?php echo $key; ?>><?php echo $value['cdata'] ? '<![CDATA[' . $value['value'] . ']]>' : $value['value']; ?></<?php echo $key; ?>>1013 <<?php echo esc_attr( $key ); ?>><?php echo $value['cdata'] ? '<![CDATA[' . wp_kses_post( $value['value'] ) . ']]>' : esc_html( $value['value'] ); ?></<?php echo esc_attr( $key ); ?>> 985 1014 <?php 986 1015 } … … 1030 1059 */ 1031 1060 public function get_product_description( $product ) { 1032 if ( $this->get_setting( 'description_type' ) == 'full' ) {1061 if ( $this->get_setting( 'description_type' ) === 'full' ) { 1033 1062 $description = trim( $product->get_description() ); 1034 if ( trim( $description ) == '' ) {1063 if ( trim( $description ) === '' ) { 1035 1064 $description = trim( $product->get_short_description() ); 1036 1065 } … … 1038 1067 $description = trim( $product->get_short_description() ); 1039 1068 } 1040 if ( trim( $description ) == '' ) {1069 if ( trim( $description ) === '' ) { 1041 1070 $description = trim( $product->get_title() ); 1042 1071 } … … 1044 1073 return wpautop( $description ); 1045 1074 } 1075 1076 /** 1077 * Get the product variation description 1078 * 1079 * @param WC_Product $product The product object. 1080 * @param WC_Product_Variation $variation The variation object. 1081 * @return string The product variation description. 1082 */ 1046 1083 public function get_product_variation_description( $product, $variation ) { 1047 1084 $product_description = $this->get_product_description( $product ); … … 1131 1168 case 'parent': 1132 1169 return $this->get_comparison_product_stock( $product ); 1133 break;1134 1170 default: // ??? 1135 1171 return ''; 1136 break;1137 1172 } 1138 1173 } … … 1163 1198 case 'parent': 1164 1199 return $this->get_marketplace_product_stock( $product ); 1165 break;1166 1200 default: // ??? 1167 1201 return ''; 1168 break;1169 1202 } 1170 1203 } … … 1181 1214 $shipping_cost = $product->get_meta( '_kuantokusta_shipping' ); 1182 1215 // We do not use empty() because the shop owner might want to offer free shipping 1183 if ( trim( $shipping_cost ) == '' ) {1216 if ( trim( $shipping_cost ) === '' ) { 1184 1217 $shipping_cost = $this->get_setting( 'shipping_cost_default' ); 1185 1218 } -
feed-kuantokusta-for-woocommerce/tags/5.2/readme.txt
r3444190 r3482456 3 3 Tags: marketplace, feed, comparison, e-commerce, Portugal 4 4 Requires at least: 6.2 5 Tested up to: 6.85 Tested up to: 7.0 6 6 Requires PHP: 7.2 7 Stable tag: 5. 17 Stable tag: 5.2 8 8 License: GPLv3 9 9 License URI: https://www.gnu.org/licenses/gpl-3.0.html … … 121 121 == Changelog == 122 122 123 = 5.2 - 2026-03-14 = 124 125 * [TWEAK] XML output is now prettified (can be disabled by returning `false` to the `kuantokusta_prettify_xml` filter) 126 * [DEV] New updater v13.1I [Pro add-on](https://nakedcatplugins.com/product/feed-kuantokusta-for-woocommerce-pro/?utm_source=wordpress.org&utm_medium=link&utm_campaign=kk_woocommerce_plugin) 127 * [DEV] Enforce hooks to be initialized only if the license is activeI [Pro add-on](https://nakedcatplugins.com/product/feed-kuantokusta-for-woocommerce-pro/?utm_source=wordpress.org&utm_medium=link&utm_campaign=kk_woocommerce_plugin) 128 * [DEV] Enforce WordPress Coding Standards on all the codebase 129 * [DEV] Update GitHub actions 130 * [DEV] Tested with WordPress 7.0-beta5-61992 and WooCommerce 10.6.1 131 123 132 = 5.1 - 2026-01-21 = 124 133 * [FIX] Plugin license validation when running in WP CLI [Pro add-on](https://nakedcatplugins.com/product/feed-kuantokusta-for-woocommerce-pro/?utm_source=wordpress.org&utm_medium=link&utm_campaign=kk_woocommerce_plugin) -
feed-kuantokusta-for-woocommerce/trunk/feed-kuantokusta-for-woocommerce.php
r3444190 r3482456 4 4 * Plugin URI: https://www.webdados.pt/wordpress/plugins/feed-kuantokusta-para-woocommerce/ 5 5 * Description: This plugin allows you to generate a WooCommerce product feed to submit to KuantoKusta, a portuguese price comparison website and marketplace. 6 * Version: 5. 16 * Version: 5.2 7 7 * Author: Naked Cat Plugins (by Webdados) 8 8 * Author URI: https://nakedcatplugins.com … … 10 10 * Domain Path: /languages 11 11 * Requires at least: 6.2 12 * Tested up to: 6.912 * Tested up to: 7.0 13 13 * Requires PHP: 7.2 14 14 * WC requires at least: 8.0 15 * WC tested up to: 10. 515 * WC tested up to: 10.6 16 16 * Requires Plugins: woocommerce 17 17 **/ … … 91 91 } 92 92 93 93 /** 94 * Incompatible version of KuantoKusta PRO notice 95 * 96 * @return void 97 */ 94 98 function fkkwc_admin_notices_pro_incompatible() { 95 99 ?> -
feed-kuantokusta-for-woocommerce/trunk/includes/class-wc-feed-kuantokusta.php
r3394301 r3482456 97 97 $this->out_link_utm = '?utm_source=' . rawurlencode( esc_url( home_url( '/' ) ) ) . '&utm_medium=link&utm_campaign=kk_woocommerce_plugin'; 98 98 // Mode 99 $this->mode = get_option( $this->id . '_plugin_mode' ) != '' ? get_option( $this->id . '_plugin_mode' ) : 'comparison';99 $this->mode = get_option( $this->id . '_plugin_mode' ) !== '' ? get_option( $this->id . '_plugin_mode' ) : 'comparison'; 100 100 // Settings 101 101 $temp = $this->get_settings(); 102 102 foreach ( $temp as $key => $value ) { 103 if ( isset( $value['id_'] ) && $value['id_'] != '' ) {103 if ( isset( $value['id_'] ) && $value['id_'] !== '' ) { 104 104 $this->settings[ $value['id_'] ] = get_option( $value['id'] ); 105 105 } … … 234 234 ); 235 235 236 if ( $this->mode == 'marketplace' ) {236 if ( $this->mode === 'marketplace' ) { 237 237 // Product stock 238 238 $settings = array_merge( … … 280 280 ) 281 281 ); 282 if ( $this->mode == 'marketplace' ) {282 if ( $this->mode === 'marketplace' ) { 283 283 $settings = array_merge( 284 284 $settings, … … 318 318 319 319 foreach ( $settings as $key => $value ) { 320 if ( isset( $value['id_'] ) && $value['id_'] != '' ) {320 if ( isset( $value['id_'] ) && $value['id_'] !== '' ) { 321 321 $settings[ $key ]['id'] = $this->id . '_' . $value['id_']; 322 322 } … … 467 467 ) 468 468 ); 469 if ( $this->mode== 'marketplace' ) {470 // Preparation days471 woocommerce_wp_text_input(472 array(473 'id' => '_kuantokusta_preparation_days_max',474 'label' => __( 'Maximum preparation time', 'feed-kuantokusta-for-woocommerce' ) . ' (' . __( 'days', 'feed-kuantokusta-for-woocommerce' ) . ')',475 'placeholder' => sprintf(476 /* translators: 1: default preparation days. */477 __( 'Blank for default (%s)', 'feed-kuantokusta-for-woocommerce' ),478 $this->get_setting( 'preparation_days_max_default' )479 ),480 'type' => 'number',481 'custom_attributes' => array(482 'min' => 0,483 ),484 )485 );486 // Delivery days487 woocommerce_wp_text_input(488 array(489 'id' => '_kuantokusta_delivery_days_max',490 'label' => __( 'Maximum delivery time', 'feed-kuantokusta-for-woocommerce' ) . ' (' . __( 'days', 'feed-kuantokusta-for-woocommerce' ) . ')',491 'placeholder' => sprintf(492 /* translators: 1: default delivery days. */493 __( 'Blank for default (%s)', 'feed-kuantokusta-for-woocommerce' ),494 $this->get_setting( 'delivery_days_max_default' )495 ),496 'type' => 'number',497 'custom_attributes' => array(498 'min' => 0,499 ),500 )501 );502 }469 if ( $this->mode === 'marketplace' ) { 470 // Preparation days 471 woocommerce_wp_text_input( 472 array( 473 'id' => '_kuantokusta_preparation_days_max', 474 'label' => __( 'Maximum preparation time', 'feed-kuantokusta-for-woocommerce' ) . ' (' . __( 'days', 'feed-kuantokusta-for-woocommerce' ) . ')', 475 'placeholder' => sprintf( 476 /* translators: 1: default preparation days. */ 477 __( 'Blank for default (%s)', 'feed-kuantokusta-for-woocommerce' ), 478 $this->get_setting( 'preparation_days_max_default' ) 479 ), 480 'type' => 'number', 481 'custom_attributes' => array( 482 'min' => 0, 483 ), 484 ) 485 ); 486 // Delivery days 487 woocommerce_wp_text_input( 488 array( 489 'id' => '_kuantokusta_delivery_days_max', 490 'label' => __( 'Maximum delivery time', 'feed-kuantokusta-for-woocommerce' ) . ' (' . __( 'days', 'feed-kuantokusta-for-woocommerce' ) . ')', 491 'placeholder' => sprintf( 492 /* translators: 1: default delivery days. */ 493 __( 'Blank for default (%s)', 'feed-kuantokusta-for-woocommerce' ), 494 $this->get_setting( 'delivery_days_max_default' ) 495 ), 496 'type' => 'number', 497 'custom_attributes' => array( 498 'min' => 0, 499 ), 500 ) 501 ); 502 } 503 503 // Action for integration... 504 504 do_action( 'kuantokusta_product_data_panel_end' ); 505 ?>505 ?> 506 506 </div> 507 507 <script type="text/javascript"> 508 508 jQuery( function( $ ) { 509 509 function kk_hide_fields() { 510 if ( $( '#_kuantokusta_hide' ).is( ":checked") ) {510 if ( $( '#_kuantokusta_hide' ).is( ':checked' ) ) { 511 511 $( '#kuantokusta p.form-field' ).hide(); 512 512 $( '#kuantokusta p.kuantokusta-title' ).hide(); … … 542 542 */ 543 543 public function woocommerce_process_product_meta( $post_id ) { 544 // WooCommerce took care of nonces 545 // phpcs:disable WordPress.Security.NonceVerification.Missing 544 546 $meta = array(); 545 547 $product = wc_get_product( $post_id ); 546 548 // Hide 547 $meta['_kuantokusta_hide'] = ! empty( $_POST['_kuantokusta_hide'] ) ? wc_clean( $_POST['_kuantokusta_hide']) : '';549 $meta['_kuantokusta_hide'] = ! empty( $_POST['_kuantokusta_hide'] ) ? sanitize_text_field( wp_unslash( $_POST['_kuantokusta_hide'] ) ) : ''; 548 550 // EAN 549 $meta['_kuantokusta_ean'] = isset( $_POST['_kuantokusta_ean'] ) && ! empty( $_POST['_kuantokusta_ean'] ) ? wc_clean( $_POST['_kuantokusta_ean']) : '';551 $meta['_kuantokusta_ean'] = ! empty( $_POST['_kuantokusta_ean'] ) ? sanitize_text_field( wp_unslash( $_POST['_kuantokusta_ean'] ) ) : ''; 550 552 if ( version_compare( WC_VERSION, '9.2', '>=' ) && ! empty( $_POST['_global_unique_id'] ) ) { 551 553 // If the core field is filled in, remove ours from the database … … 554 556 } 555 557 // Shipping 556 $meta['_kuantokusta_shipping'] = trim( $_POST['_kuantokusta_shipping'] ) != '' ? wc_clean( $_POST['_kuantokusta_shipping']) : '';558 $meta['_kuantokusta_shipping'] = ! empty( $_POST['_kuantokusta_shipping'] ) ? sanitize_text_field( wp_unslash( $_POST['_kuantokusta_shipping'] ) ) : ''; 557 559 // Shipping 558 $meta['_kuantokusta_preparation_days_max'] = ! empty( $_POST['_kuantokusta_preparation_days_max'] ) ? wc_clean( $_POST['_kuantokusta_preparation_days_max']) : '';560 $meta['_kuantokusta_preparation_days_max'] = ! empty( $_POST['_kuantokusta_preparation_days_max'] ) ? sanitize_text_field( wp_unslash( $_POST['_kuantokusta_preparation_days_max'] ) ) : ''; 559 561 // Shipping 560 $meta['_kuantokusta_delivery_days_max'] = ! empty( $_POST['_kuantokusta_delivery_days_max'] ) ? wc_clean( $_POST['_kuantokusta_delivery_days_max']) : '';562 $meta['_kuantokusta_delivery_days_max'] = ! empty( $_POST['_kuantokusta_delivery_days_max'] ) ? sanitize_text_field( wp_unslash( $_POST['_kuantokusta_delivery_days_max'] ) ) : ''; 561 563 // Filter for integration ( Use this filter to add to $meta the keys/values of the fields added by the `kuantokusta_product_data_panel_end` action ) 562 564 $meta = apply_filters( 'kuantokusta_process_product_meta', $meta ); … … 568 570 // Action for integration - ONLY if the filter above was not used 569 571 do_action( 'kuantokusta_process_product_meta_end', $post_id ); 572 // phpcs:enable 570 573 } 571 574 … … 583 586 public function render_products_feed() { 584 587 define( 'KK_IS_FEED', true ); 585 @define( 'DONOTCACHEPAGE', true ); // Cache plugins 588 if ( ! defined( 'DONOTCACHEPAGE' ) ) { 589 define( 'DONOTCACHEPAGE', true ); // Cache plugins 590 } 586 591 header( 'Content-Type: application/rss+xml; charset=utf-8' ); 587 592 header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() - 86400 ) . ' GMT' ); // Yesterday … … 589 594 header( 'Cache-Control: post-check=0, pre-check=0', false ); 590 595 header( 'Pragma: no-cache' ); 591 $offset = intval( isset( $_GET['LIMIT'] ) ? $_GET['LIMIT'] : 0 ); 592 $posts_per_page = intval( isset( $_GET['TOTAL_PRODUTOS'] ) ? $_GET['TOTAL_PRODUTOS'] : -1 ); 596 // phpcs:disable WordPress.Security.NonceVerification.Recommended 597 $offset = isset( $_GET['LIMIT'] ) ? intval( $_GET['LIMIT'] ) : 0; 598 $posts_per_page = isset( $_GET['TOTAL_PRODUTOS'] ) ? intval( $_GET['TOTAL_PRODUTOS'] ) : -1; 599 // phpcs:enable 600 ob_start(); 593 601 do_action( 'kuantokusta_render_products_feed_start' ); 594 echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset') . '"?' . '>602 echo '<?xml version="1.0" encoding="' . esc_attr( get_option( 'blog_charset' ) ) . '"?' . '> 595 603 '; 596 604 ?> … … 602 610 $sql_exclude = "SELECT DISTINCT post_id FROM $wpdb->postmeta WHERE ( meta_key = '_kuantokusta_hide' AND meta_value = 'yes' )"; 603 611 // Debug and only include specific SKU 604 if ( isset( $_GET['sku'] ) && trim( $_GET['sku'] ) != '' ) { 605 $sql_exclude .= " || ( meta_key = '_sku' AND meta_value NOT LIKE '%" . sanitize_text_field( trim( $_GET['sku'] ) ) . "%' )"; 606 } 607 $results = $wpdb->get_results( $sql_exclude, ARRAY_A ); 612 // phpcs:disable WordPress.Security.NonceVerification.Recommended 613 if ( isset( $_GET['sku'] ) && trim( sanitize_text_field( wp_unslash( $_GET['sku'] ) ) ) !== '' ) { 614 $sql_exclude .= " || ( meta_key = '_sku' AND meta_value NOT LIKE '%" . trim( sanitize_text_field( wp_unslash( $_GET['sku'] ) ) ) . "%' )"; 615 } 616 // phpcs:enable 617 $results = $wpdb->get_results( $sql_exclude, ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared 608 618 if ( ! empty( $results ) ) { 609 619 if ( count( $results ) > 0 ) { … … 639 649 if ( apply_filters( 'kuantokusta_variation_node_show', true, $product, $variation ) ) { 640 650 $product_node = $this->render_product_feed_variation( $product, $variation ); 641 echo apply_filters( 'kuantokusta_product_node_variation', $product_node, $product, $variation ); 651 // This is XML, so we cannot escape it 652 echo apply_filters( 'kuantokusta_product_node_variation', $product_node, $product, $variation ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 642 653 } 643 654 } … … 647 658 // Just like simple products 648 659 $product_node = $this->render_product_feed_default( $product, $product_type ); 649 echo apply_filters( 'kuantokusta_product_node_default', $product_node, $product, $product_type ); 660 // This is XML, so we cannot escape it 661 echo apply_filters( 'kuantokusta_product_node_default', $product_node, $product, $product_type ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 650 662 break; 651 663 } … … 653 665 default: // Including 'simple' 654 666 $product_node = $this->render_product_feed_default( $product, $product_type ); 655 echo apply_filters( 'kuantokusta_product_node_default', $product_node, $product, $product_type ); 667 // This is XML, so we cannot escape it 668 echo apply_filters( 'kuantokusta_product_node_default', $product_node, $product, $product_type ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 656 669 break; 657 670 } … … 663 676 </products> 664 677 <?php 678 // This is XML, so we cannot escape it 679 // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped 680 $xml_string = ob_get_clean(); 681 if ( apply_filters( 'kuantokusta_prettify_xml', true ) && class_exists( 'DOMDocument' ) ) { 682 libxml_use_internal_errors( true ); 683 $dom = new DOMDocument( '1.0', 'UTF-8' ); 684 $dom->preserveWhiteSpace = false; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase 685 $dom->formatOutput = true; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase 686 $ok = $dom->loadXML( $xml_string, LIBXML_NOBLANKS | LIBXML_NOERROR | LIBXML_NOWARNING ); 687 if ( ! $ok ) { 688 // If it fails, output the non-formatted XML and log the error 689 error_log( 'KuantoKusta feed XML parsing errors:' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log 690 foreach ( libxml_get_errors() as $error ) { 691 error_log( $error->message ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log 692 error_log( 'Line: ' . $error->line . ' Column: ' . $error->column ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log 693 } 694 libxml_clear_errors(); 695 echo $xml_string; 696 } 697 libxml_clear_errors(); 698 // Keep empty tags instead of self-closing tags, as we don't know if KuantoKusta accepts self-closing tags 699 echo preg_replace( '/<(\w+)\/>/', '<$1></$1>', $dom->saveXML() ); 700 } else { 701 echo $xml_string; 702 } 703 // phpcs:enable 665 704 } 666 705 … … 685 724 $image = apply_filters( 'kuantokusta_product_node_default_image', $this->get_product_image( $product ), $product, $product_type ); 686 725 $description = apply_filters( 'kuantokusta_product_node_default_description', $this->get_product_description( $product ), $product, $product_type ); 687 // $brand = apply_filters( 'kuantokusta_product_node_default_brand', $this->get_product_brand( $product ), $product, $product_type );688 726 $ean = apply_filters( 'kuantokusta_product_node_default_ean', $this->get_product_ean( $product ), $product, $product_type ); 689 727 $reference = apply_filters( 'kuantokusta_product_node_default_reference', $product->get_sku(), $product, $product_type ); … … 743 781 'cdata' => true, 744 782 ), 745 // 'brand' => array(746 // 'value' => trim( $brand ),747 // 'cdata' => true,748 // ),749 783 'upc_ean' => array( 750 784 'value' => trim( $ean ), … … 761 795 ), 762 796 'shipping_cost' => array( 763 'value' => ( trim( $shipping_cost ) != '' && floatval( $shipping_cost ) >= 0 ) ? round( floatval( $shipping_cost ), wc_get_price_decimals() ) : '',797 'value' => ( trim( $shipping_cost ) !== '' && floatval( $shipping_cost ) >= 0 ) ? round( floatval( $shipping_cost ), wc_get_price_decimals() ) : '', 764 798 'cdata' => false, 765 799 'alias_key' => 'shipping', 766 800 ), 767 801 ); 768 if ( $this->mode == 'marketplace' ) {802 if ( $this->mode === 'marketplace' ) { 769 803 // Marketplace 770 804 unset( $xml_fields['stock'] ); … … 805 839 foreach ( $xml_fields as $key => $value ) { 806 840 ?> 807 <<?php echo $key; ?>><?php echo $value['cdata'] ? '<![CDATA[' . $value['value'] . ']]>' : $value['value']; ?></<?php echo $key; ?>>841 <<?php echo esc_attr( $key ); ?>><?php echo $value['cdata'] ? '<![CDATA[' . wp_kses_post( $value['value'] ) . ']]>' : esc_html( $value['value'] ); ?></<?php echo esc_attr( $key ); ?>> 808 842 <?php 809 843 } … … 827 861 $url = $variation->get_permalink(); 828 862 $title = trim( apply_filters( 'kuantokusta_product_node_pre_variation_title', $variation->get_name(), $product, $variation ) ); 829 if ( trim( $title ) == '' ) {863 if ( trim( $title ) === '' ) { 830 864 $title = trim( $product->get_title() ); 831 865 } 832 866 $reference = $variation->get_sku(); 833 867 if ( apply_filters( 'kuantokusta_product_node_variation_title_append_description', true, $product, $variation ) ) { 834 if ( trim( $variation->get_description() ) != '' ) {868 if ( trim( $variation->get_description() ) !== '' ) { 835 869 // Variation description 836 870 $title .= apply_filters( 'woocommerce_product_variation_title_attributes_separator', ' - ', $variation ) . trim( $variation->get_description() ); 837 871 } elseif ( apply_filters( 'kuantokusta_product_node_variation_title_append_sku_or_id', true, $product, $variation ) ) { 838 if ( trim( $reference ) != '' ) {872 if ( trim( $reference ) !== '' ) { 839 873 // Variation sku 840 874 $title .= ' (' . trim( $reference ) . ')'; … … 855 889 $image = apply_filters( 'kuantokusta_product_node_variation_image', $this->get_product_variation_image( $product, $variation ), $product, $variation ); 856 890 $description = apply_filters( 'kuantokusta_product_node_variation_description', $this->get_product_variation_description( $product, $variation ), $product, $variation ); 857 // $brand = apply_filters( 'kuantokusta_product_node_variation_brand', $this->get_product_brand( $product ), $product, $variation );858 891 $ean = apply_filters( 'kuantokusta_product_node_variation_ean', $this->get_product_ean( $product ), $product, $variation ); // On the free version we only read EAN from the main product 859 if ( trim( $reference ) == '' ) {892 if ( trim( $reference ) === '' ) { 860 893 $reference = $product->get_sku(); 861 894 } 862 895 $reference = apply_filters( 'kuantokusta_product_node_variation_reference', $reference, $product, $variation ); 863 896 $weight = $variation->get_weight(); 864 if ( floatval( $weight ) == 0 ) {897 if ( floatval( $weight ) === 0 ) { 865 898 $weight = $product->get_weight(); 866 899 } … … 920 953 'cdata' => true, 921 954 ), 922 // 'brand' => array(923 // 'value' => trim( $brand ),924 // 'cdata' => true,925 // ),926 955 'upc_ean' => array( 927 956 'value' => trim( $ean ), … … 938 967 ), 939 968 'shipping_cost' => array( 940 'value' => ( trim( $shipping_cost ) != '' && floatval( $shipping_cost ) >= 0 ) ? round( floatval( $shipping_cost ), wc_get_price_decimals() ) : '',969 'value' => ( trim( $shipping_cost ) !== '' && floatval( $shipping_cost ) >= 0 ) ? round( floatval( $shipping_cost ), wc_get_price_decimals() ) : '', 941 970 'cdata' => false, 942 971 'alias_key' => 'shipping', … … 982 1011 foreach ( $xml_fields as $key => $value ) { 983 1012 ?> 984 <<?php echo $key; ?>><?php echo $value['cdata'] ? '<![CDATA[' . $value['value'] . ']]>' : $value['value']; ?></<?php echo $key; ?>>1013 <<?php echo esc_attr( $key ); ?>><?php echo $value['cdata'] ? '<![CDATA[' . wp_kses_post( $value['value'] ) . ']]>' : esc_html( $value['value'] ); ?></<?php echo esc_attr( $key ); ?>> 985 1014 <?php 986 1015 } … … 1030 1059 */ 1031 1060 public function get_product_description( $product ) { 1032 if ( $this->get_setting( 'description_type' ) == 'full' ) {1061 if ( $this->get_setting( 'description_type' ) === 'full' ) { 1033 1062 $description = trim( $product->get_description() ); 1034 if ( trim( $description ) == '' ) {1063 if ( trim( $description ) === '' ) { 1035 1064 $description = trim( $product->get_short_description() ); 1036 1065 } … … 1038 1067 $description = trim( $product->get_short_description() ); 1039 1068 } 1040 if ( trim( $description ) == '' ) {1069 if ( trim( $description ) === '' ) { 1041 1070 $description = trim( $product->get_title() ); 1042 1071 } … … 1044 1073 return wpautop( $description ); 1045 1074 } 1075 1076 /** 1077 * Get the product variation description 1078 * 1079 * @param WC_Product $product The product object. 1080 * @param WC_Product_Variation $variation The variation object. 1081 * @return string The product variation description. 1082 */ 1046 1083 public function get_product_variation_description( $product, $variation ) { 1047 1084 $product_description = $this->get_product_description( $product ); … … 1131 1168 case 'parent': 1132 1169 return $this->get_comparison_product_stock( $product ); 1133 break;1134 1170 default: // ??? 1135 1171 return ''; 1136 break;1137 1172 } 1138 1173 } … … 1163 1198 case 'parent': 1164 1199 return $this->get_marketplace_product_stock( $product ); 1165 break;1166 1200 default: // ??? 1167 1201 return ''; 1168 break;1169 1202 } 1170 1203 } … … 1181 1214 $shipping_cost = $product->get_meta( '_kuantokusta_shipping' ); 1182 1215 // We do not use empty() because the shop owner might want to offer free shipping 1183 if ( trim( $shipping_cost ) == '' ) {1216 if ( trim( $shipping_cost ) === '' ) { 1184 1217 $shipping_cost = $this->get_setting( 'shipping_cost_default' ); 1185 1218 } -
feed-kuantokusta-for-woocommerce/trunk/readme.txt
r3444190 r3482456 3 3 Tags: marketplace, feed, comparison, e-commerce, Portugal 4 4 Requires at least: 6.2 5 Tested up to: 6.85 Tested up to: 7.0 6 6 Requires PHP: 7.2 7 Stable tag: 5. 17 Stable tag: 5.2 8 8 License: GPLv3 9 9 License URI: https://www.gnu.org/licenses/gpl-3.0.html … … 121 121 == Changelog == 122 122 123 = 5.2 - 2026-03-14 = 124 125 * [TWEAK] XML output is now prettified (can be disabled by returning `false` to the `kuantokusta_prettify_xml` filter) 126 * [DEV] New updater v13.1I [Pro add-on](https://nakedcatplugins.com/product/feed-kuantokusta-for-woocommerce-pro/?utm_source=wordpress.org&utm_medium=link&utm_campaign=kk_woocommerce_plugin) 127 * [DEV] Enforce hooks to be initialized only if the license is activeI [Pro add-on](https://nakedcatplugins.com/product/feed-kuantokusta-for-woocommerce-pro/?utm_source=wordpress.org&utm_medium=link&utm_campaign=kk_woocommerce_plugin) 128 * [DEV] Enforce WordPress Coding Standards on all the codebase 129 * [DEV] Update GitHub actions 130 * [DEV] Tested with WordPress 7.0-beta5-61992 and WooCommerce 10.6.1 131 123 132 = 5.1 - 2026-01-21 = 124 133 * [FIX] Plugin license validation when running in WP CLI [Pro add-on](https://nakedcatplugins.com/product/feed-kuantokusta-for-woocommerce-pro/?utm_source=wordpress.org&utm_medium=link&utm_campaign=kk_woocommerce_plugin)
Note: See TracChangeset
for help on using the changeset viewer.