Plugin Directory

Changeset 3743356


Ignore:
Timestamp:
10/13/2026 09:15:26 AM (11 days ago)
Author:
surf7net
Message:

Release 1.64.3

Location:
surf7-simple-catalog/trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • surf7-simple-catalog/trunk/readme.txt

    r3743323 r3743356  
    55Tested up to: 7.1
    66Requires PHP: 8.1
    7 Stable tag: 1.64.2
     7Stable tag: 1.64.3
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    127127== Changelog ==
    128128
     129= 1.64.3 =
     130
     131Security release. Updating is recommended.
     132
     133**Security**
     134
     135* When the email channel opens the enquiry form, the address enquiries are sent to and the Email Bcc address are no longer included in the product page's source.
     136* A product's own enquiry contact details (set in its Enquiry Settings box) are no longer included in the post meta returned by WordPress's REST API for products. People who can edit the product still see them in the editor.
     137
     138Contact details that the page already shows on its enquiry buttons are unchanged. No database changes.
     139
    129140= 1.64.2 =
    130141
    … …  
    249260== Upgrade Notice ==
    250261
     262= 1.64.3 =
     263Security release: keeps the enquiry form's recipient and Bcc addresses, and per-product enquiry contact overrides, out of the page source and public API responses. No database changes.
     264
    251265= 1.64.2 =
    252266Security release, recommended if you use Hide price or Price on request: those prices are now also kept out of public API responses, option selectors and price filtering. No database changes.
  • surf7-simple-catalog/trunk/simple-catalog.php

    r3743323 r3743356  
    33 * Plugin Name:       Surf7 Simple Catalog
    44 * Description:       A lightweight product catalog / showcase plugin. Visitors browse products and contact you via WhatsApp, email, phone, or enquiry form — no cart, no checkout.
    5  * Version:           1.64.2
     5 * Version:           1.64.3
    66 * Requires at least: 6.4
    77 * Requires PHP:      8.1
    … …  
    1818defined( 'ABSPATH' ) || exit;
    1919
    20 define( 'SCAT_VERSION', '1.64.2' );
     20define( 'SCAT_VERSION', '1.64.3' );
    2121define( 'SCAT_DB_VERSION', '103' );
    2222define( 'SCAT_PLUGIN_FILE', __FILE__ );
  • surf7-simple-catalog/trunk/src/Frontend/Assets.php

    r3664599 r3743356  
    127127                        'loadMoreNonce'   => wp_create_nonce( 'scat_load_more' ),
    128128                        'productId'       => $post_id,
    129                         'channels'        => $channels->get_enabled( $post_id ),
     129                        'channels'        => self::script_channels( $channels->get_enabled( $post_id ) ),
    130130                        'defaultTemplate' => $builder->default_whatsapp_template(),
    131131                        // The resolved template per channel, plus the static placeholder
    … …  
    327327                return $tag;
    328328        }
     329
     330        /**
     331         * Channel configs as the front-end script receives them.
     332         *
     333         * In form mode the email channel's addresses never appear on the page: the
     334         * button opens the inline form and the server mails the enquiry. They were
     335         * still passed to the script with the rest of the config, which put the
     336         * form's recipient and its Bcc copy in every product page's source. The
     337         * script reads only the message template from that entry, so the addresses
     338         * go out blank, in the same keys.
     339         *
     340         * Mailto mode is unchanged: its link carries the address by design.
     341         *
     342         * @param array<string,array<string,mixed>> $channels Enabled channels from ChannelRegistry.
     343         * @return array<string,array<string,mixed>>
     344         */
     345        public static function script_channels( array $channels ): array {
     346                if ( isset( $channels['email'] ) && 'form' === (string) ( $channels['email']['mode'] ?? 'form' ) ) {
     347                        foreach ( [ 'to', 'bcc' ] as $key ) {
     348                                if ( array_key_exists( $key, $channels['email'] ) ) {
     349                                        $channels['email'][ $key ] = '';
     350                                }
     351                        }
     352                }
     353                return $channels;
     354        }
    329355}
  • surf7-simple-catalog/trunk/src/Meta/MetaRegistry.php

    r3743323 r3743356  
    5151                add_filter( 'wp_save_post_revision_post_has_changed', [ self::class, 'revision_has_changed' ], 10, 3 );
    5252                add_action( 'wp_restore_post_revision', [ self::class, 'restore_revision_meta' ], 10, 2 );
    53                 add_filter( 'rest_prepare_' . ProductPostType::SLUG, [ self::class, 'hide_private_price_meta' ], 10, 2 );
     53                add_filter( 'rest_prepare_' . ProductPostType::SLUG, [ self::class, 'hide_private_meta' ], 10, 2 );
    5454        }
    5555
    5656        /**
    57          * Keep a hidden price out of the core posts endpoint's `meta` field.
    58          *
    59          * The price keys are registered with show_in_rest so the block editor can
    60          * read and write them, and core exposes registered meta to every reader of
    61          * a published post: auth_callback only governs writes. So the stored figure
    62          * was readable whatever the product's price mode.
     57         * Keep private product meta out of the core posts endpoint's `meta` field.
     58         *
     59         * Every key in Schema is registered with show_in_rest so the block editor
     60         * can read and write it, and core serves registered meta to every reader of
     61         * a published post: auth_callback only governs writes. Two kinds of value
     62         * were readable that should not be:
     63         *
     64         * - a price whose mode is not "show" (the figures, and option prices);
     65         * - the per-product enquiry override, whose `email_to` is the form's
     66         *   recipient and is printed nowhere when the email channel is in form
     67         *   mode. Its other fields are public only while their channel is enabled.
     68         *   Schema has always declared this key `'auth' => 'edit_posts'`, which
     69         *   was the intent, but that too only governs writes.
    6370         *
    6471         * Done here rather than with a prepare_callback in show_in_rest, because
    6572         * core calls that with the value and the request but not the post, and
    66          * the mode is per product.
    67          *
    68          * Values are blanked, not removed, so the response keeps its shape. An
    69          * empty string is each key's registered default, i.e. what an unpriced
    70          * product already returns.
     73         * both decisions are per product.
     74         *
     75         * Values are blanked, not removed, so the response keeps its shape: each
     76         * blank is what a product without that meta already returns.
    7177         *
    7278         * @param \WP_REST_Response $response Prepared response.
    … …  
    7480         * @return \WP_REST_Response
    7581         */
    76         public static function hide_private_price_meta( $response, $post ) {
     82        public static function hide_private_meta( $response, $post ) {
    7783                if ( ! $response instanceof \WP_REST_Response || ! $post instanceof \WP_Post ) {
    7884                        return $response;
    7985                }
    80                 if ( PriceVisibility::current_user_can_see( $post->ID ) ) {
     86                if ( current_user_can( 'edit_scat_product', $post->ID ) ) {
    8187                        return $response;
    8288                }
    … …  
    8793                }
    8894
    89                 foreach ( [ '_scat_price', '_scat_price_min', '_scat_price_max' ] as $key ) {
    90                         if ( array_key_exists( $key, $data['meta'] ) ) {
    91                                 $data['meta'][ $key ] = '';
    92                         }
    93                 }
    94                 // Core returns `_scat_options` as null today: its schema declares objects
    95                 // with no properties, and additionalProperties defaults to false, so every
    96                 // stored value fails validation. Blanked anyway, so that giving the schema
    97                 // real properties cannot quietly expose option prices.
    98                 if ( isset( $data['meta']['_scat_options'] ) && is_array( $data['meta']['_scat_options'] ) ) {
    99                         $data['meta']['_scat_options'] = PriceVisibility::strip_option_prices( $data['meta']['_scat_options'] );
     95                if ( array_key_exists( '_scat_enquiry_override', $data['meta'] ) ) {
     96                        $data['meta']['_scat_enquiry_override'] = [];
     97                }
     98
     99                if ( ! PriceVisibility::is_public( $post->ID ) ) {
     100                        foreach ( [ '_scat_price', '_scat_price_min', '_scat_price_max' ] as $key ) {
     101                                if ( array_key_exists( $key, $data['meta'] ) ) {
     102                                        $data['meta'][ $key ] = '';
     103                                }
     104                        }
     105                        // Core returns `_scat_options` as null today: its schema declares objects
     106                        // with no properties, and additionalProperties defaults to false, so every
     107                        // stored value fails validation. Blanked anyway, so that giving the schema
     108                        // real properties cannot quietly expose option prices.
     109                        if ( isset( $data['meta']['_scat_options'] ) && is_array( $data['meta']['_scat_options'] ) ) {
     110                                $data['meta']['_scat_options'] = PriceVisibility::strip_option_prices( $data['meta']['_scat_options'] );
     111                        }
    100112                }
    101113
Note: See TracChangeset for help on using the changeset viewer.