Changeset 3743356
- Timestamp:
- 10/13/2026 09:15:26 AM (11 days ago)
- Location:
- surf7-simple-catalog/trunk
- Files:
-
- 4 edited
-
readme.txt (modified) (3 diffs)
-
simple-catalog.php (modified) (2 diffs)
-
src/Frontend/Assets.php (modified) (2 diffs)
-
src/Meta/MetaRegistry.php (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
surf7-simple-catalog/trunk/readme.txt
r3743323 r3743356 5 5 Tested up to: 7.1 6 6 Requires PHP: 8.1 7 Stable tag: 1.64. 27 Stable tag: 1.64.3 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 127 127 == Changelog == 128 128 129 = 1.64.3 = 130 131 Security 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 138 Contact details that the page already shows on its enquiry buttons are unchanged. No database changes. 139 129 140 = 1.64.2 = 130 141 … … 249 260 == Upgrade Notice == 250 261 262 = 1.64.3 = 263 Security 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 251 265 = 1.64.2 = 252 266 Security 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 3 3 * Plugin Name: Surf7 Simple Catalog 4 4 * 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. 25 * Version: 1.64.3 6 6 * Requires at least: 6.4 7 7 * Requires PHP: 8.1 … … 18 18 defined( 'ABSPATH' ) || exit; 19 19 20 define( 'SCAT_VERSION', '1.64. 2' );20 define( 'SCAT_VERSION', '1.64.3' ); 21 21 define( 'SCAT_DB_VERSION', '103' ); 22 22 define( 'SCAT_PLUGIN_FILE', __FILE__ ); -
surf7-simple-catalog/trunk/src/Frontend/Assets.php
r3664599 r3743356 127 127 'loadMoreNonce' => wp_create_nonce( 'scat_load_more' ), 128 128 'productId' => $post_id, 129 'channels' => $channels->get_enabled( $post_id),129 'channels' => self::script_channels( $channels->get_enabled( $post_id ) ), 130 130 'defaultTemplate' => $builder->default_whatsapp_template(), 131 131 // The resolved template per channel, plus the static placeholder … … 327 327 return $tag; 328 328 } 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 } 329 355 } -
surf7-simple-catalog/trunk/src/Meta/MetaRegistry.php
r3743323 r3743356 51 51 add_filter( 'wp_save_post_revision_post_has_changed', [ self::class, 'revision_has_changed' ], 10, 3 ); 52 52 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 ); 54 54 } 55 55 56 56 /** 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. 63 70 * 64 71 * Done here rather than with a prepare_callback in show_in_rest, because 65 72 * 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. 71 77 * 72 78 * @param \WP_REST_Response $response Prepared response. … … 74 80 * @return \WP_REST_Response 75 81 */ 76 public static function hide_private_ price_meta( $response, $post ) {82 public static function hide_private_meta( $response, $post ) { 77 83 if ( ! $response instanceof \WP_REST_Response || ! $post instanceof \WP_Post ) { 78 84 return $response; 79 85 } 80 if ( PriceVisibility::current_user_can_see($post->ID ) ) {86 if ( current_user_can( 'edit_scat_product', $post->ID ) ) { 81 87 return $response; 82 88 } … … 87 93 } 88 94 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 } 100 112 } 101 113
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)