Changeset 3441297
- Timestamp:
- 01/16/2026 10:30:41 PM (4 weeks ago)
- Location:
- wp-commerce7/trunk
- Files:
-
- 18 added
- 35 edited
-
README.txt (modified) (4 diffs)
-
admin/template.options.page.php (modified) (2 diffs)
-
assets/public/css/commerce7-for-wordpress.css (modified) (3 diffs)
-
commerce7-for-wordpress.php (modified) (9 diffs)
-
includes/class-c7wp-validation.php (added)
-
includes/class-c7wp.php (modified) (35 diffs)
-
includes/elementor/elementor-buyslug.php (modified) (3 diffs)
-
includes/elementor/elementor-clubselector.php (added)
-
includes/elementor/elementor-form.php (modified) (2 diffs)
-
includes/elementor/elementor-joinnow.php (modified) (2 diffs)
-
includes/elementor/elementor-loginform.php (modified) (2 diffs)
-
includes/elementor/elementor-reservation.php (modified) (2 diffs)
-
includes/elementor/elementor-subscribe.php (modified) (3 diffs)
-
includes/elementor/load.php (modified) (4 diffs)
-
includes/gutenberg/blocks-v2/buyslug/c7wp-buyslug.css (modified) (1 diff)
-
includes/gutenberg/blocks-v2/buyslug/c7wp-buyslug.js (modified) (5 diffs)
-
includes/gutenberg/blocks-v2/buyslug/frontend.css (added)
-
includes/gutenberg/blocks-v2/clubselector/c7wp-clubselector.css (modified) (1 diff)
-
includes/gutenberg/blocks-v2/clubselector/c7wp-clubselector.js (modified) (3 diffs)
-
includes/gutenberg/blocks-v2/clubselector/frontend.js (modified) (1 diff)
-
includes/gutenberg/blocks-v2/collection/block.json (added)
-
includes/gutenberg/blocks-v2/collection/c7wp-collection.css (modified) (2 diffs)
-
includes/gutenberg/blocks-v2/collection/c7wp-collection.js (modified) (7 diffs)
-
includes/gutenberg/blocks-v2/collectionlist/c7wp-collectionlist.css (modified) (1 diff)
-
includes/gutenberg/blocks-v2/collectionlist/c7wp-collectionlist.js (modified) (1 diff)
-
includes/gutenberg/blocks-v2/default/block.json (added)
-
includes/gutenberg/blocks-v2/default/c7wp-default.css (modified) (2 diffs)
-
includes/gutenberg/blocks-v2/default/c7wp-default.js (modified) (1 diff)
-
includes/gutenberg/blocks-v2/form/c7wp-form.css (modified) (1 diff)
-
includes/gutenberg/blocks-v2/form/c7wp-form.js (modified) (8 diffs)
-
includes/gutenberg/blocks-v2/form/frontend.css (added)
-
includes/gutenberg/blocks-v2/joinnow/c7wp-joinnow.css (modified) (1 diff)
-
includes/gutenberg/blocks-v2/loginform/c7wp-loginform.css (modified) (1 diff)
-
includes/gutenberg/blocks-v2/personalization/block.json (added)
-
includes/gutenberg/blocks-v2/personalization/c7wp-personalization.css (modified) (2 diffs)
-
includes/gutenberg/blocks-v2/personalization/c7wp-personalization.js (modified) (7 diffs)
-
includes/gutenberg/blocks-v2/reservation/c7wp-reservation.css (modified) (1 diff)
-
includes/gutenberg/blocks-v2/reservation/c7wp-reservation.js (modified) (5 diffs)
-
includes/gutenberg/blocks-v2/reservation/frontend.css (added)
-
includes/gutenberg/blocks-v2/subscribe/c7wp-subscribe.css (modified) (1 diff)
-
includes/gutenberg/blocks-v2/subscribe/c7wp-subscribe.js (modified) (4 diffs)
-
includes/gutenberg/blocks-v2/subscribe/frontend.css (added)
-
includes/gutenberg/load.php (modified) (2 diffs)
-
includes/health-check.php (added)
-
includes/rankmath/load.php (modified) (3 diffs)
-
includes/themeco/legacy (added)
-
includes/themeco/legacy/cornerstone (added)
-
includes/themeco/legacy/cornerstone/controls.php (added)
-
includes/themeco/legacy/cornerstone/defaults.php (added)
-
includes/themeco/legacy/cornerstone/definition.php (added)
-
includes/themeco/legacy/cornerstone/shortcode.php (added)
-
includes/themeco/legacy/load.php (added)
-
uninstall.php (added)
Legend:
- Unmodified
- Added
- Removed
-
wp-commerce7/trunk/README.txt
r3410240 r3441297 5 5 Requires at least: 6.0 6 6 Tested up to: 6.9 7 Stable tag: 1. 5.47 Stable tag: 1.6.1 8 8 License: GPLv3 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-3.0.en.html … … 60 60 == Plugin Removal == 61 61 62 Removing this plugin will render your widgets inactive, but will not remove them or the pages created.62 Removing this plugin will render your widgets and/or blocks inactive, but will not remove them or the pages created. Be sure to clean out all pages of Commerce7 content if removing. 63 63 64 64 … … 73 73 == Changelog == 74 74 75 = 1.5.4 = 75 = 1.6.1 - January 16, 2026 = 76 * Added: alignment controls form blocks 77 78 = 1.6 - December 15, 2025 = 79 * Large plugin changes, please backup site before updating 80 * Improved: Elementor blocks, adding static previews to some block types for inline styles and visual verifications 81 * Improved: Themeco Cornerstone blocks, adding static previews to some block types for inline styles and visual verifications 82 * Improved: Settings sanitization 83 * Improved: C7WP notices 84 * Improved: Page creation on initial plugin activation 85 * Improved: Plugin settings cache speed 86 * Improved: Pages post state text on dynamic routes 87 * Added: WP Health Check screen 88 * Fixed: RankMath canonical tag 89 * Added: Uninstall handler to remove plugin data 90 91 92 93 = 1.5.4 - August 11, 2025 = 76 94 * Fix: Gutenberg block settings for old beta frontend 77 95 * Fix: Login widget redirect path on V2 frontend … … 226 244 == Upgrade Notice == 227 245 246 = 1.6.1 = 247 Large plugin update, create a backup before proceeding, and test all widgets on all pages afterwards. 248 228 249 = 1.5.1 = 229 250 You may need to resave existing Club Selector blocks if you've used them already. -
wp-commerce7/trunk/admin/template.options.page.php
r3292177 r3441297 11 11 12 12 if ( ! defined( 'ABSPATH' ) ) { 13 return;13 return; 14 14 } 15 15 … … 17 17 ?> 18 18 <div class="c7wp-reset c7wp-wrap c7wp-wrap-about"> 19 <div class="c7wp-content">20 <div class="c7wp-main">19 <div class="c7wp-content"> 20 <div class="c7wp-main"> 21 21 22 <div class="c7wp-row">23 <div class="c7wp-column">22 <div class="c7wp-row"> 23 <div class="c7wp-column"> 24 24 25 <div class="c7wp-box gradient header">25 <div class="c7wp-box gradient header"> 26 26 27 <div class="c7wp-box-content cols-2">28 <div class="c7wp-box-content-left">29 <h1 class="c7wp-box-title"><?php esc_html_e( 'Commerce7 for WordPress', 'wp-commerce7' ); ?></h1>30 <p class="c7wp-box-content-text"><?php esc_html_e( 'Built for wineries that want more control, better performance, and smarter marketing.', 'wp-commerce7' ); ?></p>31 </div>27 <div class="c7wp-box-content cols-2"> 28 <div class="c7wp-box-content-left"> 29 <h1 class="c7wp-box-title"><?php esc_html_e( 'Commerce7 for WordPress', 'wp-commerce7' ); ?></h1> 30 <p class="c7wp-box-content-text"><?php esc_html_e( 'Built for wineries that want more control, better performance, and smarter marketing.', 'wp-commerce7' ); ?></p> 31 </div> 32 32 33 <div class="c7wp-box-content-right">34 <a href="https://c7wp.com/documentation/" target="_blank" class="c7wp-btn c7wp-btn-primary c7wp-btn-large">35 <svg width="800px" height="800px" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path fill="currentColor" d="M512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896zm23.744 191.488c-52.096 0-92.928 14.784-123.2 44.352-30.976 29.568-45.76 70.4-45.76 122.496h80.256c0-29.568 5.632-52.8 17.6-68.992 13.376-19.712 35.2-28.864 66.176-28.864 23.936 0 42.944 6.336 56.32 19.712 12.672 13.376 19.712 31.68 19.712 54.912 0 17.6-6.336 34.496-19.008 49.984l-8.448 9.856c-45.76 40.832-73.216 70.4-82.368 89.408-9.856 19.008-14.08 42.24-14.08 68.992v9.856h80.96v-9.856c0-16.896 3.52-31.68 10.56-45.76 6.336-12.672 15.488-24.64 28.16-35.2 33.792-29.568 54.208-48.576 60.544-55.616 16.896-22.528 26.048-51.392 26.048-86.592 0-42.944-14.08-76.736-42.24-101.376-28.16-25.344-65.472-37.312-111.232-37.312zm-12.672 406.208a54.272 54.272 0 0 0-38.72 14.784 49.408 49.408 0 0 0-15.488 38.016c0 15.488 4.928 28.16 15.488 38.016A54.848 54.848 0 0 0 523.072 768c15.488 0 28.16-4.928 38.72-14.784a51.52 51.52 0 0 0 16.192-38.72 51.968 51.968 0 0 0-15.488-38.016 55.936 55.936 0 0 0-39.424-14.784z"/></svg>36 <?php esc_html_e( 'Documentation', 'wp-commerce7' ); ?>37 </a>38 </div>33 <div class="c7wp-box-content-right"> 34 <a href="https://c7wp.com/documentation/" target="_blank" class="c7wp-btn c7wp-btn-primary c7wp-btn-large"> 35 <svg width="800px" height="800px" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path fill="currentColor" d="M512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896zm23.744 191.488c-52.096 0-92.928 14.784-123.2 44.352-30.976 29.568-45.76 70.4-45.76 122.496h80.256c0-29.568 5.632-52.8 17.6-68.992 13.376-19.712 35.2-28.864 66.176-28.864 23.936 0 42.944 6.336 56.32 19.712 12.672 13.376 19.712 31.68 19.712 54.912 0 17.6-6.336 34.496-19.008 49.984l-8.448 9.856c-45.76 40.832-73.216 70.4-82.368 89.408-9.856 19.008-14.08 42.24-14.08 68.992v9.856h80.96v-9.856c0-16.896 3.52-31.68 10.56-45.76 6.336-12.672 15.488-24.64 28.16-35.2 33.792-29.568 54.208-48.576 60.544-55.616 16.896-22.528 26.048-51.392 26.048-86.592 0-42.944-14.08-76.736-42.24-101.376-28.16-25.344-65.472-37.312-111.232-37.312zm-12.672 406.208a54.272 54.272 0 0 0-38.72 14.784 49.408 49.408 0 0 0-15.488 38.016c0 15.488 4.928 28.16 15.488 38.016A54.848 54.848 0 0 0 523.072 768c15.488 0 28.16-4.928 38.72-14.784a51.52 51.52 0 0 0 16.192-38.72 51.968 51.968 0 0 0-15.488-38.016 55.936 55.936 0 0 0-39.424-14.784z"/></svg> 36 <?php esc_html_e( 'Documentation', 'wp-commerce7' ); ?> 37 </a> 38 </div> 39 39 40 </div>40 </div> 41 41 42 </div>42 </div> 43 43 44 <div class="c7wp-box">44 <div class="c7wp-box"> 45 45 46 <div class="c7wp-box-content"> 47 <form method="post" action="options.php"> 48 <?php 49 settings_fields( 'commerce7' ); 50 do_settings_sections( 'commerce7' ); 51 submit_button(); 52 ?> 53 </form> 54 </div> 46 <div class="c7wp-box-content"> 47 <form method="post" action="options.php"> 48 <?php 49 settings_fields( 'commerce7' ); 50 do_settings_sections( 'commerce7' ); 51 submit_button(); 52 ?> 53 </form> 54 </div> 55 56 </div> 57 58 </div> 59 </div> 60 61 </div> 55 62 56 63 57 </div> 58 </div> 59 </div> 64 <div class="c7wp-sidebar"> 60 65 61 </div> 66 <?php 62 67 68 /** 69 * Filter: `c7wp_show_sidebar` 70 * 71 * Filter for hiding the sidebar in our plugin settings, which might include promotions for 72 * our services. This is a whitelabel as you're going to get. 73 * 74 * @param bool Should the sidebar be shown? Default: true 75 */ 76 if ( apply_filters( 'c7wp_show_sidebar', true ) ) : 63 77 64 <div class="c7wp-sidebar"> 78 $gists = array( 79 '95be9529b9ba6f9cc96336e085a4b122', 80 '902913bb4b5623f945c9ebe30dfbc0b6', 81 'fb980c8d769a96f169250a79ca278f74', 82 ); 65 83 66 <?php 84 $allowed_html = wp_kses_allowed_html( 'post' ); 85 $allowed_protocols = array( 86 'https', 87 'data', 88 ); 67 89 68 /** 69 * Filter: `c7wp_show_sidebar` 70 * 71 * Filter for hiding the sidebar in our plugin settings, which might include promotions for 72 * our services. This is a whitelabel as you're going to get. 73 * 74 * @param bool Should the sidebar be shown? Default: true 75 */ 76 if ( apply_filters( 'c7wp_show_sidebar', true ) ) : 90 $args = array( 91 'headers' => array( 'Content-Type' => 'application/json; charset=utf-8' ), 92 ); 77 93 78 $gists = [ 79 '95be9529b9ba6f9cc96336e085a4b122', 80 '902913bb4b5623f945c9ebe30dfbc0b6', 81 'fb980c8d769a96f169250a79ca278f74', 82 ]; 94 foreach ( $gists as $gist ) { 95 $callout = get_transient( 'c7wp_' . $gist ); 83 96 84 $allowed_html = wp_kses_allowed_html( 'post' ); 85 $allowed_protocols = [ 86 'https', 87 'data', 88 ]; 97 if ( empty( $callout ) ) { 98 $response = wp_remote_get( 'https://api.github.com/gists/' . $gist, $args ); 89 99 90 $args = [ 91 'headers' => [ 'Content-Type' => 'application/json; charset=utf-8' ], 92 ]; 100 if ( is_array( $response ) && ! is_wp_error( $response ) && '200' === wp_remote_retrieve_response_code( $response ) ) { 101 $headers = $response['headers']; // array of http header lines 102 $body = json_decode( $response['body'], true ); // use the content 93 103 94 foreach ( $gists as $gist ) { 95 $callout = get_transient( 'c7wp_' . $gist ); 104 if ( isset( $body['files']['index.html']['content'] ) ) { 105 $callout = stripslashes( $body['files']['index.html']['content'] ); 106 set_transient( 'c7wp_' . $gist, $callout, WEEK_IN_SECONDS ); 107 } else { 108 // Log error if WP_DEBUG is enabled 109 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { 110 error_log( 'Commerce7: Invalid response structure from GitHub API for gist ' . $gist ); 111 } 112 continue; 113 } 114 } else { 115 // Log error if WP_DEBUG is enabled 116 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { 117 $error_message = is_wp_error( $response ) ? $response->get_error_message() : 'HTTP ' . wp_remote_retrieve_response_code( $response ); 118 error_log( 'Commerce7: Failed to fetch gist ' . $gist . ': ' . $error_message ); 119 } 120 continue; 121 } 122 } 96 123 97 if ( empty( $callout ) ) { 98 $response = wp_remote_get( 'https://api.github.com/gists/' . $gist, $args ); 124 if ( ! empty( $callout ) ) { 125 echo wp_kses( $callout, $allowed_html, $allowed_protocols ); 126 } 127 } 99 128 100 if ( is_array( $response ) && ! is_wp_error( $response ) && '200' == wp_remote_retrieve_response_code( $response ) ) { 101 $headers = $response['headers']; // array of http header lines 102 $body = json_decode( $response['body'], true ); // use the content 129 endif; 130 ?> 103 131 104 $callout = stripslashes( $body['files']['index.html']['content'] ); 105 106 $trans = set_transient( 'c7wp_' . $gist, $callout, WEEK_IN_SECONDS ); 107 } else { 108 continue; 109 } 110 } 111 112 echo wp_kses( $callout, $allowed_html, $allowed_protocols ); 113 } 114 115 endif; 116 ?> 117 118 <div class="c7wp-cta"> 119 <p class="c7wp-cta-note">Plugin created by URSA6 & 5forests. Provided free to Commerce7 customers and agencies around the world.</p> 120 <hr class="c7wp-cta-spacing"> 121 <p class="c7wp-cta-note">We offer unbeatable <a href="https://5forests.com/services/technology/website-care-plans/" target="_blank">sustainble hosting and care plans</a> to our WordPress clients.</p> 122 </div> 123 </div> 132 <div class="c7wp-cta"> 133 <p class="c7wp-cta-note">Plugin created by URSA6 & 5forests. Provided free to Commerce7 customers and agencies around the world.</p> 134 <hr class="c7wp-cta-spacing"> 135 <p class="c7wp-cta-note">We offer unbeatable <a href="https://5forests.com/services/technology/website-care-plans/" target="_blank">sustainable hosting and care plans</a> to our WordPress clients.</p> 136 </div> 137 </div> 124 138 125 139 126 140 127 </div>141 </div> 128 142 </div> -
wp-commerce7/trunk/assets/public/css/commerce7-for-wordpress.css
r2768084 r3441297 10 10 flex-direction: row; 11 11 align-items: center; 12 } 13 #c7wp-cart-box.top-left { 14 top: 0; 15 right: auto; 16 left: 0; 17 bottom: auto; 18 } 19 #c7wp-cart-box.bottom-left { 20 top: auto; 21 right: auto; 22 left: 0; 23 bottom: 0; 24 position: fixed; 25 } 26 #c7wp-cart-box.bottom-right { 27 top: auto; 28 right: 0; 29 left: auto; 30 bottom: 0; 31 position: fixed; 32 } 33 #c7wp-cart-box.c7dark > div > a { 34 color: #fff; 35 } 36 #c7wp-cart-box.c7light > div > a { 37 color: #333; 12 13 &.top-left { 14 top: 0; 15 right: auto; 16 left: 0; 17 bottom: auto; 18 } 19 20 &.bottom-left { 21 top: auto; 22 right: auto; 23 left: 0; 24 bottom: 0; 25 position: fixed; 26 } 27 28 &.bottom-right { 29 top: auto; 30 right: 0; 31 left: auto; 32 bottom: 0; 33 position: fixed; 34 } 35 36 &.c7dark > div > a { 37 color: #fff; 38 } 39 40 &.c7light > div > a { 41 color: #333; 42 } 38 43 } 39 44 .c7-dark { … … 44 49 padding: 0 1rem 0 0; 45 50 } 46 .c7-checkout__content__title a { 47 font-size: 0.95rem; 51 .c7-checkout__content__title { 52 a { 53 font-size: 0.95rem; 54 } 48 55 } 49 56 .c7-cart__count { … … 51 58 } 52 59 @media screen and (min-width: 46rem) { 53 .c7-form__group div div.date-picker, .c7-form__group div div.rdtPicker, .c7-form__group div div.rdtDays { 54 width: auto; 55 margin: 0; 60 .c7-form__group { 61 div div { 62 &.date-picker, 63 &.rdtPicker, 64 &.rdtDays { 65 width: auto; 66 margin: 0; 67 } 68 } 56 69 } 57 70 } -
wp-commerce7/trunk/commerce7-for-wordpress.php
r3343231 r3441297 12 12 * Plugin Name: Commerce7 for WordPress 13 13 * Description: Integrate Commerce7 functionality into your WordPress site easily 14 * Version: 1. 5.414 * Version: 1.6.1 15 15 * Author: URSA6 & 5forests 16 16 * Author URI: https://5forests.com 17 17 * Plugin URI: https://c7wp.com 18 18 * Requires at least: 6.0 19 * Tested up to: 6. 820 * Stable tag: 1. 5.419 * Tested up to: 6.9 20 * Stable tag: 1.6.1 21 21 * Requires PHP: 7.4 22 22 * License: GPL3 … … 28 28 * Author: Michael Bourne 29 29 * ----- 30 * Last Modified: Tuesday, August 5th 2025, 9:23:42 pm30 * Last Modified: Wednesday, January 7th 2026, 3:14:12 pm 31 31 * Modified By: Michael Bourne 32 32 * ----- … … 48 48 defined( 'C7WP_ROOT' ) || define( 'C7WP_ROOT', __DIR__ ); 49 49 defined( 'C7WP_URI' ) || define( 'C7WP_URI', plugin_dir_url( __FILE__ ) ); 50 defined( 'C7WP_VERSION' ) || define( 'C7WP_VERSION', '1. 5.4' );50 defined( 'C7WP_VERSION' ) || define( 'C7WP_VERSION', '1.6.1' ); 51 51 if ( ! defined( 'C7WP_NOTICES_URL' ) || C7WP_NOTICES_URL !== 'https://c7wp.com/notices.json' ) { 52 define( 'C7WP_NOTICES_URL', 'https://c7wp.com/notices.json' );52 define( 'C7WP_NOTICES_URL', 'https://c7wp.com/notices.json' ); 53 53 } 54 54 … … 61 61 */ 62 62 function c7wp_activate_plugin() { 63 add_option( 'c7wp_activation', true ); 64 65 $pages = array( 'profile', 'collection', 'product', 'club', 'checkout', 'cart', 'reservation' ); 66 $fail = array(); 67 68 foreach ( $pages as $page ) { 69 if ( get_page_by_path( $page, 'ARRAY_N', 'page' ) ) { 70 $fail[] = $page; 71 continue; 72 } 73 74 $c7_post = array( 75 'post_title' => wp_strip_all_tags( ucfirst( $page ) ), 76 'post_content' => '<!-- wp:c7wp/default --><div class="wp-block-c7wp-default"><div id="c7-content"></div></div><!-- /wp:c7wp/default -->', 77 'post_status' => 'publish', 78 'post_author' => 1, 79 'post_type' => 'page', 80 ); 81 82 $pageid = wp_insert_post( $c7_post ); 83 } 84 85 if ( ! empty( $fail ) ) { 86 set_transient( 'c7wp-admin-notice-pages', $fail, 5 ); 87 } 88 89 $c7options = array( 90 'c7wp_tenant' => '', 91 'c7wp_display_cart' => 'no', 92 'c7wp_display_cart_location' => 'tr', 93 'c7wp_display_cart_color' => 'light', 94 'c7wp_widget_version' => 'v2', 95 'c7wp_enable_custom_routes' => 'no', 96 'c7wp_frontend_routes' => array( 97 'profile' => 'profile', 98 'collection' => 'collection', 99 'product' => 'product', 100 'club' => 'club', 101 'checkout' => 'checkout', 102 'cart' => 'cart', 103 'reservation' => 'reservation', 104 ), 105 ); 106 107 update_option( 'c7wp_settings', $c7options, true ); 108 109 // set a default permalink structure if the installation has not yet done this 110 require_once ABSPATH . 'wp-admin/includes/upgrade.php'; 111 if ( function_exists( 'wp_install_maybe_enable_pretty_permalinks' ) ) { 112 wp_install_maybe_enable_pretty_permalinks(); 113 } 63 add_option( 'c7wp_activation', true ); 64 65 // Schedule remote notices cron job 66 c7wp_schedule_notices_cron(); 67 68 $pages = array( 'profile', 'collection', 'product', 'club', 'checkout', 'cart', 'reservation' ); 69 $fail = array(); 70 71 foreach ( $pages as $page ) { 72 if ( get_page_by_path( $page, 'ARRAY_N', 'page' ) ) { 73 $fail[] = $page; 74 continue; 75 } 76 77 $c7_post = array( 78 'post_title' => wp_strip_all_tags( ucfirst( $page ) ), 79 'post_content' => '<!-- wp:c7wp/default --><div class="wp-block-c7wp-default"><div id="c7-content"></div></div><!-- /wp:c7wp/default -->', 80 'post_status' => 'publish', 81 'post_author' => 1, 82 'post_type' => 'page', 83 ); 84 85 $pageid = wp_insert_post( $c7_post ); 86 87 // Check if page creation was successful 88 if ( is_wp_error( $pageid ) ) { 89 // Log error if WP_DEBUG is enabled 90 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { 91 error_log( 'Commerce7: Failed to create page "' . $page . '": ' . $pageid->get_error_message() ); 92 } 93 $fail[] = $page; 94 } elseif ( ! $pageid ) { 95 // Log error if WP_DEBUG is enabled 96 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { 97 error_log( 'Commerce7: Failed to create page "' . $page . '": Unknown error' ); 98 } 99 $fail[] = $page; 100 } 101 } 102 103 if ( ! empty( $fail ) ) { 104 set_transient( 'c7wp-admin-notice-pages', $fail, 5 ); 105 } 106 107 $c7options = array( 108 'c7wp_tenant' => '', 109 'c7wp_display_cart' => 'no', 110 'c7wp_display_cart_location' => 'tr', 111 'c7wp_display_cart_color' => 'light', 112 'c7wp_widget_version' => 'v2', 113 'c7wp_enable_custom_routes' => 'no', 114 'c7wp_frontend_routes' => array( 115 'profile' => 'profile', 116 'collection' => 'collection', 117 'product' => 'product', 118 'club' => 'club', 119 'checkout' => 'checkout', 120 'cart' => 'cart', 121 'reservation' => 'reservation', 122 ), 123 ); 124 125 update_option( 'c7wp_settings', $c7options, true ); 126 127 // set a default permalink structure if the installation has not yet done this 128 require_once ABSPATH . 'wp-admin/includes/upgrade.php'; 129 if ( function_exists( 'wp_install_maybe_enable_pretty_permalinks' ) ) { 130 wp_install_maybe_enable_pretty_permalinks(); 131 } 114 132 } 115 133 register_activation_hook( __FILE__, 'c7wp_activate_plugin' ); … … 130 148 */ 131 149 function c7wp_upgrade_function( $upgrader_object, $options ) { 132 $current_plugin_path_name = plugin_basename( __FILE__ );133 134 // If a plugin is being updated.135 if ( 'update' === $options['action'] && 'plugin' === $options['type'] && isset( $options['plugins'] ) ) {136 foreach ( $options['plugins'] as $each_plugin ) {137 // If the plugin being updated is this plugin.150 $current_plugin_path_name = plugin_basename( __FILE__ ); 151 152 // If a plugin is being updated. 153 if ( 'update' === $options['action'] && 'plugin' === $options['type'] && isset( $options['plugins'] ) ) { 154 foreach ( $options['plugins'] as $each_plugin ) { 155 // If the plugin being updated is this plugin. 138 156 if ( $each_plugin == $current_plugin_path_name ) { // phpcs:ignore 139 157 140 $options = get_option( 'c7wp_settings' ); 141 142 if ( isset( $options['c7wp_widget_version'] ) && 'v2' === $options['c7wp_widget_version'] 143 && isset( $options['c7wp_enable_custom_routes'] ) && 'yes' === $options['c7wp_enable_custom_routes'] 144 && isset( $options['c7wp_frontend_routes'] ) && is_array( $options['c7wp_frontend_routes'] ) ) { 145 $pages = $options['c7wp_frontend_routes']; 146 } else { 147 $pages = array( 148 'profile' => 'profile', 149 'collection' => 'collection', 150 'product' => 'product', 151 'club' => 'club', 152 'checkout' => 'checkout', 153 'cart' => 'cart', 154 'reservation' => 'reservation', 155 ); 156 } 157 158 $fail = array(); 159 // Loop through required paged for C7. 160 foreach ( $pages as $page => $slug ) { 161 // if the page is missing, add it to the notice 162 if ( ! get_page_by_path( $slug, 'ARRAY_N', 'page' ) ) { 163 $fail[] = wp_strip_all_tags( ucfirst( $page ) ); 164 continue; 165 } 166 } 167 168 // If we have missing pages, let's set a transient to display a notice. 169 if ( ! empty( $fail ) ) { 170 set_transient( 'c7wp-admin-notice-pages-missing', $fail, 0 ); 171 } 172 173 $c7options = array( 174 'c7wp_tenant' => '', 175 'c7wp_display_cart' => 'no', 176 'c7wp_display_cart_location' => 'tr', 177 'c7wp_display_cart_color' => 'light', 178 'c7wp_widget_version' => 'v2', 179 'c7wp_enable_custom_routes' => 'no', 180 'c7wp_frontend_routes' => array( 181 'profile' => 'profile', 182 'collection' => 'collection', 183 'product' => 'product', 184 'club' => 'club', 185 'checkout' => 'checkout', 186 'cart' => 'cart', 187 'reservation' => 'reservation', 188 ), 189 ); 190 191 // Merge client set options with default options to fix any unset array keys. 192 $normalized_options = array_merge( $c7options, $options ); 193 update_option( 'c7wp_settings', $normalized_options, true ); 194 195 // flush rewrite rules. 196 if ( function_exists( 'flush_rewrite_rules' ) ) { 197 flush_rewrite_rules(); 198 } 199 } 200 } 201 } 158 $options = get_option( 'c7wp_settings' ); 159 160 if ( isset( $options['c7wp_widget_version'] ) && 'v2' === $options['c7wp_widget_version'] 161 && isset( $options['c7wp_enable_custom_routes'] ) && 'yes' === $options['c7wp_enable_custom_routes'] 162 && isset( $options['c7wp_frontend_routes'] ) && is_array( $options['c7wp_frontend_routes'] ) ) { 163 $pages = $options['c7wp_frontend_routes']; 164 } else { 165 $pages = array( 166 'profile' => 'profile', 167 'collection' => 'collection', 168 'product' => 'product', 169 'club' => 'club', 170 'checkout' => 'checkout', 171 'cart' => 'cart', 172 'reservation' => 'reservation', 173 ); 174 } 175 176 $fail = array(); 177 // Loop through required paged for C7. 178 foreach ( $pages as $page => $slug ) { 179 // if the page is missing, add it to the notice 180 if ( ! get_page_by_path( $slug, 'ARRAY_N', 'page' ) ) { 181 $fail[] = wp_strip_all_tags( ucfirst( $page ) ); 182 continue; 183 } 184 } 185 186 // If we have missing pages, let's set a transient to display a notice. 187 if ( ! empty( $fail ) ) { 188 set_transient( 'c7wp-admin-notice-pages-missing', $fail, 0 ); 189 } 190 191 $c7options = array( 192 'c7wp_tenant' => '', 193 'c7wp_display_cart' => 'no', 194 'c7wp_display_cart_location' => 'tr', 195 'c7wp_display_cart_color' => 'light', 196 'c7wp_widget_version' => 'v2', 197 'c7wp_enable_custom_routes' => 'no', 198 'c7wp_frontend_routes' => array( 199 'profile' => 'profile', 200 'collection' => 'collection', 201 'product' => 'product', 202 'club' => 'club', 203 'checkout' => 'checkout', 204 'cart' => 'cart', 205 'reservation' => 'reservation', 206 ), 207 ); 208 209 // Merge client set options with default options to fix any unset array keys. 210 $normalized_options = array_merge( $c7options, $options ); 211 update_option( 'c7wp_settings', $normalized_options, true ); 212 213 // Only flush rewrite rules if route settings have changed 214 $old_routes = isset( $options['c7wp_frontend_routes'] ) ? $options['c7wp_frontend_routes'] : array(); 215 $new_routes = $normalized_options['c7wp_frontend_routes']; 216 217 if ( $old_routes !== $new_routes ) { 218 if ( function_exists( 'flush_rewrite_rules' ) ) { 219 flush_rewrite_rules(); 220 } 221 } 222 } 223 } 224 } 202 225 } 203 226 … … 209 232 210 233 if ( $data = get_transient( 'c7wp-admin-notice-pages' ) ) { // phpcs:ignore 211 $pages = implode( ', ', $data ); 212 echo '<div class="notice notice-warning is-dismissible"><p>'; 213 printf( 214 /* translators: 1: List of missing pages 2: List of missing pages */ 215 esc_html__( 'Commerce7 requires specific pages exist in order for integration to work properly. The following pages are needed but were not created, as they already exist: %1$s. 216 Please ensure these pages contain the proper content.', 'wp-commerce7' ), 217 '<strong>' . esc_html( $pages ) . '</strong>' 218 ); 219 echo '</p></div>'; 220 221 /* Delete transient, only display this notice once. */ 222 delete_transient( 'c7wp-admin-notice-pages' ); 223 } 234 $pages = implode( ', ', $data ); 235 echo '<div class="notice notice-warning is-dismissible"><p>'; 236 printf( 237 /* translators: 1: List of missing pages 2: List of missing pages */ 238 esc_html__( 239 'Commerce7 requires specific pages exist in order for integration to work properly. The following pages are needed but were not created, as they already exist: %1$s. 240 Please ensure these pages contain the proper content.', 241 'wp-commerce7' 242 ), 243 '<strong>' . esc_html( $pages ) . '</strong>' 244 ); 245 echo '</p></div>'; 246 247 /* Delete transient, only display this notice once. */ 248 delete_transient( 'c7wp-admin-notice-pages' ); 249 } 224 250 225 251 if ( $data = get_transient( 'c7wp-admin-notice-pages-missing' ) ) { // phpcs:ignore 226 $pages = implode( ', ', $data ); 227 echo '<div class="notice notice-warning is-dismissible"><p>'; 228 printf( 229 /* translators: %s: List of missing pages */ 230 esc_html__( 'Commerce7 requires specific pages exist in order for integration to work properly. The following pages were missing: %s. 231 These pages were not recreated in case you have removed them on purpose. Please review and crate these pages if needed.', 'wp-commerce7' ), 232 '<strong>' . esc_html( $pages ) . '</strong>' 233 ); 234 echo '</p></div>'; 235 236 /* Delete transient, only display this notice once. */ 237 delete_transient( 'c7wp-admin-notice-pages-missing' ); 238 } 252 $pages = implode( ', ', $data ); 253 echo '<div class="notice notice-warning is-dismissible"><p>'; 254 printf( 255 /* translators: %s: List of missing pages */ 256 esc_html__( 257 'Commerce7 requires specific pages exist in order for integration to work properly. The following pages were missing: %s. 258 These pages were not recreated in case you have removed them on purpose. Please review and crate these pages if needed.', 259 'wp-commerce7' 260 ), 261 '<strong>' . esc_html( $pages ) . '</strong>' 262 ); 263 echo '</p></div>'; 264 265 /* Delete transient, only display this notice once. */ 266 delete_transient( 'c7wp-admin-notice-pages-missing' ); 267 } 239 268 } 240 269 add_action( 'admin_notices', 'c7wp_admin_notice_pages' ); … … 246 275 */ 247 276 function c7wp_deactivate_plugin() { 248 flush_rewrite_rules();277 flush_rewrite_rules(); 249 278 } 250 279 … … 262 291 263 292 /** 264 * Fetch and display remote admin notices 265 */ 266 function c7wp_remote_notices() { 267 $transient_key = 'c7wp_remote_notices'; 268 $notices = get_transient( $transient_key ); 269 270 if ( false === $notices ) { 271 $response = wp_remote_get( C7WP_NOTICES_URL ); 272 273 if ( ! is_wp_error( $response ) && 200 === wp_remote_retrieve_response_code( $response ) ) { 274 $notices = json_decode( wp_remote_retrieve_body( $response ), true ); 275 set_transient( $transient_key, $notices, 12 * HOUR_IN_SECONDS ); 276 } 277 } 278 279 if ( ! empty( $notices ) && is_array( $notices ) ) { 280 foreach ( $notices as $notice ) { 281 if ( ! empty( $notice['message'] ) && ! get_user_meta( get_current_user_id(), 'c7wp_notice_dismissed_' . md5( $notice['message'] ), true ) ) { 282 add_action('admin_notices', function() use ( $notice ) { 283 $dismiss_url = add_query_arg(array( 284 'c7wp_dismiss_notice' => md5( $notice['message'] ), 285 '_wpnonce' => wp_create_nonce( 'c7wp_dismiss_notice' ), 286 )); 287 ?> 288 <div class="notice notice-<?php echo esc_attr( $notice['type'] ?? 'info' ); ?> is-dismissible"> 289 <?php if ( ! empty( $notice['format'] ) && 'html' === $notice['format'] ) : ?> 290 <?php echo wp_kses_post( $notice['message'] ); ?> 291 <?php else : ?> 292 <p><?php echo wp_kses_post( $notice['message'] ); ?></p> 293 <?php endif; ?> 294 <a href="<?php echo esc_url( $dismiss_url ); ?>" class="notice-dismiss"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-commerce7' ); ?></span></a> 295 </div> 296 <?php 297 }); 298 } 299 } 300 } 301 } 302 add_action( 'admin_init', 'c7wp_remote_notices' ); 293 * Fetch remote admin notices via cron job 294 */ 295 function c7wp_fetch_remote_notices() { 296 $response = wp_remote_get( 297 C7WP_NOTICES_URL, 298 array( 299 'timeout' => 10, 300 'headers' => array( 301 'User-Agent' => 'Commerce7-WordPress-Plugin/' . C7WP_VERSION, 302 ), 303 ) 304 ); 305 306 if ( is_wp_error( $response ) ) { 307 // Log error if WP_DEBUG is enabled 308 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { 309 error_log( 'Commerce7: Failed to fetch remote notices: ' . $response->get_error_message() ); 310 } 311 return; 312 } 313 314 $response_code = wp_remote_retrieve_response_code( $response ); 315 if ( 200 !== $response_code ) { 316 // Log error if WP_DEBUG is enabled 317 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { 318 error_log( 'Commerce7: Remote notices API returned HTTP ' . $response_code ); 319 } 320 return; 321 } 322 323 $notices = json_decode( wp_remote_retrieve_body( $response ), true ); 324 if ( json_last_error() !== JSON_ERROR_NONE ) { 325 // Log error if WP_DEBUG is enabled 326 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { 327 error_log( 'Commerce7: Failed to parse remote notices JSON: ' . json_last_error_msg() ); 328 } 329 return; 330 } 331 332 if ( is_array( $notices ) ) { 333 set_transient( 'c7wp_remote_notices', $notices, 12 * HOUR_IN_SECONDS ); 334 } 335 } 336 337 /** 338 * Schedule remote notices cron job 339 */ 340 function c7wp_schedule_notices_cron() { 341 if ( ! wp_next_scheduled( 'c7wp_fetch_remote_notices' ) ) { 342 wp_schedule_event( time(), 'twicedaily', 'c7wp_fetch_remote_notices' ); 343 } 344 } 345 346 /** 347 * Display remote admin notices 348 */ 349 function c7wp_display_remote_notices() { 350 $notices = get_transient( 'c7wp_remote_notices' ); 351 352 if ( ! empty( $notices ) && is_array( $notices ) ) { 353 foreach ( $notices as $notice ) { 354 if ( ! empty( $notice['message'] ) && ! get_user_meta( get_current_user_id(), 'c7wp_notice_dismissed_' . md5( $notice['message'] ), true ) ) { 355 add_action( 356 'admin_notices', 357 function() use ( $notice ) { 358 $dismiss_url = add_query_arg( 359 array( 360 'c7wp_dismiss_notice' => md5( $notice['message'] ), 361 '_wpnonce' => wp_create_nonce( 'c7wp_dismiss_notice' ), 362 ) 363 ); 364 ?> 365 <div class="notice notice-<?php echo esc_attr( $notice['type'] ?? 'info' ); ?> is-dismissible"> 366 <?php if ( ! empty( $notice['format'] ) && 'html' === $notice['format'] ) : ?> 367 <?php echo wp_kses_post( $notice['message'] ); ?> 368 <?php else : ?> 369 <p><?php echo wp_kses_post( $notice['message'] ); ?></p> 370 <?php endif; ?> 371 <a href="<?php echo esc_url( $dismiss_url ); ?>" class="notice-dismiss"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-commerce7' ); ?></span></a> 372 </div> 373 <?php 374 } 375 ); 376 } 377 } 378 } 379 } 380 381 382 // Clean up cron job on deactivation 383 register_deactivation_hook( 384 __FILE__, 385 function() { 386 wp_clear_scheduled_hook( 'c7wp_fetch_remote_notices' ); 387 } 388 ); 389 390 // Hook the cron job 391 add_action( 'c7wp_fetch_remote_notices', 'c7wp_fetch_remote_notices' ); 392 393 // Display notices on admin pages 394 add_action( 'admin_init', 'c7wp_display_remote_notices' ); 303 395 304 396 /** … … 306 398 */ 307 399 function c7wp_handle_notice_dismissal() { 308 if ( isset( $_GET['c7wp_dismiss_notice'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), 'c7wp_dismiss_notice' ) ) { 309 $notice_id = sanitize_text_field( wp_unslash( $_GET['c7wp_dismiss_notice'] ) ); 310 update_user_meta( get_current_user_id(), 'c7wp_notice_dismissed_' . $notice_id, true ); 311 wp_safe_redirect( remove_query_arg( array( 'c7wp_dismiss_notice', '_wpnonce' ) ) ); 312 exit; 313 } 400 // Check user capabilities first 401 if ( ! current_user_can( 'manage_options' ) ) { 402 return; 403 } 404 405 if ( isset( $_GET['c7wp_dismiss_notice'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'c7wp_dismiss_notice' ) ) { 406 $notice_id = sanitize_text_field( wp_unslash( $_GET['c7wp_dismiss_notice'] ) ); 407 update_user_meta( get_current_user_id(), 'c7wp_notice_dismissed_' . $notice_id, true ); 408 wp_safe_redirect( remove_query_arg( array( 'c7wp_dismiss_notice', '_wpnonce' ) ) ); 409 exit; 410 } 314 411 } 315 412 add_action( 'admin_init', 'c7wp_handle_notice_dismissal' ); -
wp-commerce7/trunk/includes/class-c7wp.php
r3313519 r3441297 47 47 private $seoplugin; 48 48 49 /** 50 * Cached plugin settings 51 * 52 * @var array 53 */ 54 private $settings; 55 49 56 50 57 /** … … 75 82 add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); 76 83 add_action( 'elementor/editor/before_enqueue_scripts', array( $this, 'elementor_editor_enqueue_scripts' ) ); 84 add_action( 'elementor/frontend/after_enqueue_scripts', array( $this, 'elementor_frontend_assets_fallback' ) ); 77 85 add_action( 'after_setup_theme', array( $this, 'load_c7_css' ), 9 ); 78 86 add_filter( 'body_class', array( $this, 'add_body_class' ) ); … … 91 99 $this->seoplugin = false; 92 100 93 $options = get_option( 'c7wp_settings' ); 94 if ( isset( $options['c7wp_widget_version'] ) && ! empty( $options['c7wp_widget_version'] ) ) { 95 $this->widgetsver = esc_attr( $options['c7wp_widget_version'] ); 101 // Cache settings to avoid multiple database calls 102 $this->settings = get_option( 'c7wp_settings', array() ); 103 if ( isset( $this->settings['c7wp_widget_version'] ) && ! empty( $this->settings['c7wp_widget_version'] ) ) { 104 $this->widgetsver = esc_attr( $this->settings['c7wp_widget_version'] ); 96 105 } else { 97 106 $this->widgetsver = 'v2'; 98 107 } 99 108 100 // load translations101 add_action( 'plugins_loaded', array( $this, 'c7wp_load_textdomain' ) );109 // load health check integration 110 require_once C7WP_ROOT . '/includes/health-check.php'; 102 111 103 112 // c7 div output for certain pagebuilders … … 119 128 120 129 /** 130 * Get plugin settings with caching 131 * 132 * @return array Plugin settings 133 */ 134 public function get_settings() { 135 return $this->settings; 136 } 137 138 /** 139 * Refresh cached settings 140 */ 141 public function refresh_settings() { 142 $this->settings = get_option( 'c7wp_settings', array() ); 143 } 144 145 /** 121 146 * @param mixed $instance Singleton instance. 122 147 */ … … 130 155 public function admin_init() { 131 156 132 $options = get_option( 'c7wp_settings' ); 133 if ( ! isset( $options['c7wp_frontend_routes'] ) || ! is_array( $options['c7wp_frontend_routes'] ) ) { 134 $options['c7wp_frontend_routes'] = array( 157 if ( ! isset( $this->settings['c7wp_frontend_routes'] ) || ! is_array( $this->settings['c7wp_frontend_routes'] ) ) { 158 $this->settings['c7wp_frontend_routes'] = array( 135 159 'profile' => 'profile', 136 160 'collection' => 'collection', … … 143 167 'reservation' => 'reservation', 144 168 ); 145 update_option( 'c7wp_settings', $options, true ); 169 update_option( 'c7wp_settings', $this->settings, true ); 170 $this->refresh_settings(); 146 171 } 147 172 … … 271 296 */ 272 297 public function load_cs_elements() { 273 // Cornerstone Support 298 // Cornerstone Support for older versions 274 299 if ( class_exists( 'Cornerstone_Plugin' ) || function_exists( 'cornerstone_boot' ) ) { 275 require_once C7WP_ROOT . '/includes/themeco/l oad.php';300 require_once C7WP_ROOT . '/includes/themeco/legacy/load.php'; 276 301 } 277 302 } … … 298 323 \Elementor\Plugin::instance()->widgets_manager->register( new \C7WP_Elementor() ); 299 324 } 300 }301 302 /**303 * Internationalization304 */305 public function c7wp_load_textdomain() {306 load_plugin_textdomain( 'wp-commerce7', false, C7WP_ROOT . '/languages/' );307 325 } 308 326 … … 336 354 } 337 355 356 // phpcs:ignore WordPress.Security.NonceVerification.Recommended 338 357 if ( isset( $_GET['settings-updated'] ) && empty( get_settings_errors( 'c7wp_settings' ) ) ) { // phpcs:ignore 339 358 add_settings_error( 'c7wp_settings', 'c7wp_settings_saved', __( 'Settings Saved', 'wp-commerce7' ), 'updated' ); … … 351 370 protected function settings_init() { 352 371 353 register_setting( 'commerce7', 'c7wp_settings', 'c7wp_settings_callback' ); 372 register_setting( 373 'commerce7', 374 'c7wp_settings', 375 array( 376 'sanitize_callback' => array( $this, 'c7wp_settings_callback' ), 377 'default' => array(), 378 ) 379 ); 354 380 355 381 add_settings_section( … … 446 472 if ( is_array( $value ) ) { 447 473 foreach ( $value as $subkey => $subvalue ) { 448 $output[ $key ][ $subkey ] = sanitize_title($subvalue );474 $output[ $key ][ $subkey ] = $this->sanitize_setting_field( $key, $subkey, $subvalue ); 449 475 } 450 476 } else { 451 $output[ $key ] = sanitize_title($value );477 $output[ $key ] = $this->sanitize_setting_field( $key, null, $value ); 452 478 } 453 479 } 454 480 } 455 481 482 $this->settings = $output; 483 456 484 return apply_filters( 'c7wp_settings_post_validation', $output, $input ); 457 485 } 458 486 487 /** 488 * Sanitize individual setting fields based on field type 489 * 490 * @param string $key The setting key. 491 * @param string|null $subkey The subkey for array values. 492 * @param mixed $value The value to sanitize. 493 * @return mixed The sanitized value. 494 */ 495 private function sanitize_setting_field( $key, $subkey, $value ) { 496 // Handle tenant ID specifically 497 if ( 'c7wp_tenant' === $key ) { 498 // Tenant ID should be alphanumeric with possible hyphens/underscores 499 return trim( sanitize_text_field( $value ) ); 500 } 501 502 // Handle frontend routes (page slugs) 503 if ( 'c7wp_frontend_routes' === $key && ! is_null( $subkey ) ) { 504 // Page slugs should be valid WordPress slugs 505 $sanitized = sanitize_title( $value ); 506 // Ensure it's not empty and doesn't conflict with WordPress reserved terms 507 $reserved_terms = array( 'admin', 'api', 'wp-admin', 'wp-content', 'wp-includes' ); 508 if ( empty( $sanitized ) || in_array( $sanitized, $reserved_terms, true ) ) { 509 // Return default value if invalid 510 $defaults = array( 511 'profile' => 'profile', 512 'collection' => 'collection', 513 'product' => 'product', 514 'club' => 'club', 515 'checkout' => 'checkout', 516 'cart' => 'cart', 517 'reservation' => 'reservation', 518 ); 519 return isset( $defaults[ $subkey ] ) ? $defaults[ $subkey ] : sanitize_title( $value ); 520 } 521 return $sanitized; 522 } 523 524 // Handle select fields (these should be from predefined options) 525 $select_fields = array( 526 'c7wp_display_cart' => array( 'yes', 'no' ), 527 'c7wp_display_cart_location' => array( 'tl', 'tr', 'br', 'bl' ), 528 'c7wp_display_cart_color' => array( 'light', 'dark' ), 529 'c7wp_widget_version' => array( 'v2', 'v2-compat', 'beta' ), 530 'c7wp_enable_custom_routes' => array( 'yes', 'no' ), 531 ); 532 533 if ( isset( $select_fields[ $key ] ) ) { 534 $allowed_values = $select_fields[ $key ]; 535 if ( in_array( $value, $allowed_values, true ) ) { 536 return $value; 537 } 538 // Return default value if invalid 539 $defaults = array( 540 'c7wp_display_cart' => 'no', 541 'c7wp_display_cart_location' => 'tr', 542 'c7wp_display_cart_color' => 'light', 543 'c7wp_widget_version' => 'v2', 544 'c7wp_enable_custom_routes' => 'no', 545 ); 546 return isset( $defaults[ $key ] ) ? $defaults[ $key ] : ''; 547 } 548 549 // Default sanitization for other fields 550 return sanitize_text_field( $value ); 551 } 552 459 553 public function c7wp_tenant_render() { 460 554 461 $options = get_option( 'c7wp_settings' );555 $options = $this->settings; 462 556 ?> 463 557 <input type='text' name='c7wp_settings[c7wp_tenant]' value='<?php echo esc_attr( $options['c7wp_tenant'] ); ?>'> … … 467 561 public function c7wp_display_cart_render() { 468 562 469 $options = get_option( 'c7wp_settings' );563 $options = $this->settings; 470 564 ?> 471 565 <select name='c7wp_settings[c7wp_display_cart]' class='c7displaycart'> … … 475 569 <p><small> 476 570 <?php 477 echo wp_kses( __( 'If set to <strong>yes</strong>, this plugin will add a floating login cart box to the front end of your website. If set to <strong>no</strong>, you will need to add the <code>[c7wp type=\'login\']</code> and <code>[c7wp type=\'cart\']</code> shortcodes (or Commerce7\'s HTML) to your header manually. We recommend setting this to no and placing your cart manually.', 'wp-commerce7' ), 478 array( 'strong' => array(), 'code' => array() ) ); 479 ?> 480 </small></p> 571 echo wp_kses( 572 __( 573 'If set to <strong>yes</strong>, this plugin will add a floating login cart box to the front end of your website. If set to <strong>no</strong>, you will need to add the <code>[c7wp type=\'login\']</code> and <code>[c7wp type=\'cart\']</code> shortcodes (or Commerce7\'s HTML) to your header manually. We recommend setting this to no and placing your cart manually.', 574 'wp-commerce7' 575 ), 576 array( 577 'strong' => array(), 578 'code' => array(), 579 ) 580 ); 581 ?> 582 </small></p> 481 583 <?php 482 584 } … … 484 586 public function c7wp_display_cart_location_render() { 485 587 486 $options = get_option( 'c7wp_settings' );588 $options = $this->settings; 487 589 $disabled = ( 'no' === $options['c7wp_display_cart'] ) ? 'disabled' : ''; 488 590 if ( ! isset( $options['c7wp_display_cart_location'] ) ) { … … 502 604 public function c7wp_display_cart_color_render() { 503 605 504 $options = get_option( 'c7wp_settings' );606 $options = $this->settings; 505 607 $disabled = ( 'no' === $options['c7wp_display_cart'] ) ? 'disabled' : ''; 506 608 if ( ! isset( $options['c7wp_display_cart_color'] ) ) { … … 522 624 public function c7wp_widget_version_render() { 523 625 524 $options = get_option( 'c7wp_settings' );626 $options = $this->settings; 525 627 ?> 526 628 <select name='c7wp_settings[c7wp_widget_version]' class='c7widgetversion'> … … 531 633 <p><small> 532 634 <?php 533 echo wp_kses( '<strong>V2:</strong> The standard front-end widgets version used by most wineries. Most users should select this option. 534 <br> 535 <strong>V2 (Compatibility Mode):</strong> Use this if you are having issues with the standard V2 widgets, such as widgets not displaying correctly or displaying multiple times. This will load the V2 widgets in a way that is compatible with more themes. 536 <br> 537 <strong>V1:</strong> Only a select few legacy sites are still using the old beta/V1 widgets.', array( 'strong' => array(), 'br' => array() ) ); 635 echo wp_kses( 636 __( 637 '<strong>V2:</strong> The standard front-end widgets version used by most wineries. 638 <br> 639 <strong>V2 (Compatibility Mode):</strong> This will load the V2 widgets in a way that is compatible with more themes and plugins, with safer javascript invocation. Safe for all websites, and the recommended option for everyone. 640 <br> 641 <strong>V1:</strong> Only a select few legacy sites are still using the old beta/V1 widgets.', 642 'wp-commerce7', 643 ), 644 array( 645 'strong' => array(), 646 'br' => array(), 647 ) 648 ); 538 649 ?> 539 650 </small></p> 540 </small></p>541 651 <?php 542 652 } … … 544 654 public function c7wp_enable_custom_routes_render() { 545 655 546 $options = get_option( 'c7wp_settings' );656 $options = $this->settings; 547 657 $disabled = ( 'beta' === $options['c7wp_widget_version'] ) ? 'disabled' : ''; 548 658 ?> 549 659 <select name='c7wp_settings[c7wp_enable_custom_routes]' <?php echo esc_attr( $disabled ); ?> > 550 660 <option value='no' 551 <?php if ( isset( $options['c7wp_enable_custom_routes'] ) ) { selected( $options['c7wp_enable_custom_routes'], 'no' ); } ?> 661 <?php 662 if ( isset( $options['c7wp_enable_custom_routes'] ) ) { 663 selected( 664 $options['c7wp_enable_custom_routes'], 665 'no' 666 ); 667 } 668 ?> 552 669 ><?php esc_html_e( 'No', 'wp-commerce7' ); ?></option> 553 670 <option value='yes' 554 <?php if ( isset( $options['c7wp_enable_custom_routes'] ) ) { selected( $options['c7wp_enable_custom_routes'], 'yes' ); } ?> 671 <?php 672 if ( isset( $options['c7wp_enable_custom_routes'] ) ) { 673 selected( 674 $options['c7wp_enable_custom_routes'], 675 'yes' 676 ); 677 } 678 ?> 555 679 ><?php esc_html_e( 'Yes', 'wp-commerce7' ); ?></option> 556 680 </select> … … 565 689 public function c7wp_frontend_routes_render() { 566 690 567 $options = get_option( 'c7wp_settings' );691 $options = $this->settings; 568 692 $disabled = ( 'yes' === $options['c7wp_enable_custom_routes'] ) ? '' : 'disabled'; 569 693 ?> … … 607 731 // Define the allowed HTML tags and attributes 608 732 $allowed_html = array( 609 'a' => array(610 'href'=> array(),611 'target' => array(),612 ),613 'strong' => array(),614 'br'=> array(),733 'a' => array( 734 'href' => array(), 735 'target' => array(), 736 ), 737 'strong' => array(), 738 'br' => array(), 615 739 ); 616 740 … … 621 745 /* translators: %1$s: URL to the routing settings in Commerce7 %2$s: URL to the permalinks settings in WordPress */ 622 746 $string = __( 623 'These routes <strong>must</strong> match your <a href="%1$s" target="_blank">routing settings in Commerce7</a>.624 <br>625 Make sure you edit the slugs of any existing pages if you are changing these values.626 <br>627 You <strong>must</strong> <a href="%2$s">resave your permalinks in WordPress</a> after changing these settings.',628 'wp-commerce7',747 'These routes <strong>must</strong> match your <a href="%1$s" target="_blank">routing settings in Commerce7</a>. 748 <br> 749 Make sure you edit the slugs of any existing pages if you are changing these values. 750 <br> 751 You <strong>must</strong> <a href="%2$s">resave your permalinks in WordPress</a> after changing these settings.', 752 'wp-commerce7', 629 753 ); 630 754 … … 652 776 public function enqueue_scripts() { 653 777 654 $options = get_option( 'c7wp_settings' );778 $options = $this->settings; 655 779 656 780 /** … … 689 813 wp_enqueue_script( 'c7js' ); 690 814 } 815 816 // Enqueue block-specific assets only when needed 817 $this->enqueue_block_assets(); 691 818 692 819 /** … … 743 870 744 871 /** 872 * Enqueue block-specific assets only when blocks are present 873 */ 874 private function enqueue_block_assets() { 875 global $post; 876 877 if ( ! $post ) { 878 return; 879 } 880 881 $post_content = $post->post_content; 882 883 // Check for Gutenberg blocks 884 if ( has_blocks( $post_content ) ) { 885 $blocks = parse_blocks( $post_content ); 886 $this->enqueue_blocks_assets( $blocks ); 887 } 888 889 // Check for shortcodes 890 if ( has_shortcode( $post_content, 'c7wp' ) ) { 891 $this->enqueue_shortcode_assets(); 892 } 893 } 894 895 /** 896 * Recursively enqueue assets for blocks 897 * 898 * @param array $blocks Array of blocks to check. 899 */ 900 private function enqueue_blocks_assets( $blocks ) { 901 foreach ( $blocks as $block ) { 902 // Check if this is a Commerce7 block 903 if ( isset( $block['blockName'] ) && strpos( $block['blockName'], 'c7wp/' ) === 0 ) { 904 $block_type = str_replace( 'c7wp/', '', $block['blockName'] ); 905 $this->enqueue_specific_block_assets( $block_type ); 906 } 907 908 // Check inner blocks 909 if ( isset( $block['innerBlocks'] ) && ! empty( $block['innerBlocks'] ) ) { 910 $this->enqueue_blocks_assets( $block['innerBlocks'] ); 911 } 912 } 913 } 914 915 /** 916 * Enqueue assets for a specific block type 917 * 918 * @param string $block_type The block type to enqueue assets for. 919 */ 920 private function enqueue_specific_block_assets( $block_type ) { 921 $options = $this->settings; 922 $widgetsver = $options['c7wp_widget_version']; 923 924 // Determine the correct directory 925 $dir = in_array( $widgetsver, array( 'v2', 'v2-compat' ), true ) ? 'blocks-v2' : 'blocks'; 926 927 // Enqueue frontend styles 928 $frontend_css_path = $dir . '/' . $block_type . '/frontend.css'; 929 if ( file_exists( C7WP_ROOT . '/includes/gutenberg/' . $frontend_css_path ) ) { 930 wp_enqueue_style( 931 'c7wp-' . $block_type . '-frontend', 932 C7WP_URI . 'includes/gutenberg/' . $frontend_css_path, 933 array(), 934 C7WP_VERSION 935 ); 936 } 937 938 // Enqueue frontend scripts 939 $frontend_js_path = $dir . '/' . $block_type . '/frontend.js'; 940 if ( file_exists( C7WP_ROOT . '/includes/gutenberg/' . $frontend_js_path ) ) { 941 wp_enqueue_script( 942 'c7wp-' . $block_type . '-frontend', 943 C7WP_URI . 'includes/gutenberg/' . $frontend_js_path, 944 array(), 945 C7WP_VERSION, 946 true 947 ); 948 949 // Localize settings for specific blocks 950 if ( 'clubselector' === $block_type ) { 951 $options = $this->settings; 952 wp_localize_script( 953 'c7wp-' . $block_type . '-frontend', 954 'c7wp_settings', 955 array( 956 'c7wp_frontend_routes' => isset( $options['c7wp_frontend_routes'] ) ? $options['c7wp_frontend_routes'] : array( 'club' => 'club' ), 957 ) 958 ); 959 } 960 } 961 } 962 963 /** 964 * Enqueue assets for shortcode usage 965 */ 966 private function enqueue_shortcode_assets() { 967 // Enqueue general Commerce7 styles 968 wp_enqueue_style( 969 'c7wp-shortcode', 970 C7WP_URI . 'assets/public/css/commerce7-for-wordpress.css', 971 array(), 972 C7WP_VERSION 973 ); 974 } 975 976 /** 745 977 * Elementor specific styles 746 978 * … … 750 982 wp_enqueue_style( 'wp-commerce7-icons', C7WP_URI . 'assets/admin/css/c7wpicons.css', array(), C7WP_VERSION ); 751 983 } 984 985 /** 986 * Ensure clubselector frontend assets are loaded for Elementor when Gutenberg is disabled 987 * 988 * @return void 989 */ 990 public function elementor_frontend_assets_fallback() { 991 // Only run if Gutenberg is not available (Classic Editor scenario) 992 if ( ! function_exists( 'register_block_type' ) ) { 993 // Check if we're on v2 widgets and clubselector frontend assets exist 994 if ( in_array( $this->widgetsver, array( 'v2', 'v2-compat' ), true ) ) { 995 $frontend_js_path = 'blocks-v2/clubselector/frontend.js'; 996 $frontend_css_path = 'blocks-v2/clubselector/frontend.css'; 997 998 // Register and enqueue frontend script if it exists 999 if ( file_exists( C7WP_ROOT . '/includes/gutenberg/' . $frontend_js_path ) && empty( $_GET['ct_builder'] ) ) { 1000 $frontend_script_handle = 'c7wp-clubselector-frontend'; 1001 wp_register_script( 1002 $frontend_script_handle, 1003 plugins_url( $frontend_js_path, C7WP_ROOT . '/includes/gutenberg/load.php' ), 1004 array(), 1005 C7WP_VERSION, 1006 true 1007 ); 1008 1009 // Localize settings 1010 $options = get_option( 'c7wp_settings' ); 1011 wp_localize_script( 1012 $frontend_script_handle, 1013 'c7wp_settings', 1014 array( 1015 'c7wp_frontend_routes' => isset( $options['c7wp_frontend_routes'] ) ? $options['c7wp_frontend_routes'] : array( 'club' => 'club' ), 1016 ) 1017 ); 1018 1019 wp_enqueue_script( $frontend_script_handle ); 1020 } 1021 1022 // Register and enqueue frontend styles if they exist 1023 if ( file_exists( C7WP_ROOT . '/includes/gutenberg/' . $frontend_css_path ) ) { 1024 wp_register_style( 1025 'c7wp-clubselector-frontend', 1026 plugins_url( $frontend_css_path, C7WP_ROOT . '/includes/gutenberg/load.php' ), 1027 array(), 1028 C7WP_VERSION 1029 ); 1030 wp_enqueue_style( 'c7wp-clubselector-frontend' ); 1031 } 1032 } 1033 } 1034 } 1035 752 1036 753 1037 … … 763 1047 public function add_data_to_c7_script( $tag, $handle, $src ) { 764 1048 if ( 'c7js' === $handle ) { 765 $options = get_option( 'c7wp_settings' );1049 $options = $this->settings; 766 1050 $tag = '<script data-cfasync="false" type="text/javascript" src="' . esc_url( $src ) . '" id="c7-javascript" data-tenant="' . esc_attr( $options['c7wp_tenant'] ) . '"></script>'; // phpcs:ignore 767 1051 } … … 780 1064 public function add_c7_rewrites() { 781 1065 782 if ( in_array( $this->widgetsver, [ 'v2', 'v2-compat' ]) ) {783 784 $options = get_option( 'c7wp_settings' );1066 if ( in_array( $this->widgetsver, array( 'v2', 'v2-compat' ), true ) ) { 1067 1068 $options = $this->settings; 785 1069 786 1070 if ( isset( $options['c7wp_frontend_routes'] ) && 'yes' === $options['c7wp_enable_custom_routes'] ) { … … 815 1099 public function footer_inject() { 816 1100 817 $options = get_option( 'c7wp_settings' );1101 $options = $this->settings; 818 1102 if ( 'yes' === $options['c7wp_display_cart'] ) { 819 1103 … … 842 1126 } 843 1127 844 $login = ( in_array( $this->widgetsver, [ 'v2', 'v2-compat' ]) ) ? 'c7-account' : 'c7-login';1128 $login = ( in_array( $this->widgetsver, array( 'v2', 'v2-compat' ) ) ) ? 'c7-account' : 'c7-login'; 845 1129 846 1130 echo '<div id="c7wp-cart-box" class="' . esc_attr( $class ) . esc_attr( $color ) . '"><div id="' . esc_attr( $login ) . '"></div><div id="c7-cart"></div></div>'; … … 895 1179 $output = '<div class="c7wp-wrap" data-c7-type="' . $atts['type'] . '">'; 896 1180 897 if ( in_array( $this->widgetsver, [ 'v2', 'v2-compat' ] ) ) { 898 899 switch ( $atts['type'] ) { 900 case 'default': 901 $output .= '<div id="c7-content"></div>'; 902 break; 903 904 case 'personalization': 905 $output .= '<div class="c7-personalization" data-block-code="' . esc_attr( $atts['data'] ) . '"></div>'; 906 break; 907 908 case 'subscribe': 909 $output .= ( 'true' === $atts['data'] ) ? '<div class="c7-subscribe" data-has-name-field="true"></div>' : '<div class="c7-subscribe"></div>'; 910 break; 911 912 case 'collection': 913 $output .= '<div class="c7-product-collection" data-collection-slug="' . esc_attr( $atts['data'] ) . '"></div>'; 914 break; 915 916 case 'login': 917 $output .= '<div id="c7-account"></div>'; 918 break; 919 920 case 'cart': 921 $output .= '<div id="c7-cart"></div>'; 922 break; 923 924 case 'reservation': 925 $output .= '<div class="c7-reservation-availability" data-reservation-type-slug="' . esc_attr( $atts['data'] ) . '"></div>'; 926 break; 927 928 case 'form': 929 $output .= '<div class="c7-custom-form" data-form-code="' . esc_attr( $atts['data'] ) . '"></div>'; 930 break; 931 932 case 'joinnow': 933 $output .= '<div class="c7-club-join-button" 934 data-club-slug="' . esc_attr( $atts['data'] ) . '" 935 data-join-text="' . esc_attr( $atts['join-text'] ) . '" 936 data-edit-text="' . esc_attr( $atts['edit-text'] ) . '" 937 ></div>'; 938 break; 939 940 case 'buyslug': 941 $output .= '<div class="c7-buy-product" data-product-slug="' . esc_attr( $atts['data'] ) . '"></div>'; 942 break; 943 944 case 'loginform': 945 $output .= '<div id="c7-login-form" data-redirect-to="' . esc_attr( $atts['data'] ) . '"></div>'; 946 break; 947 948 case 'collectionlist': 949 $output .= '<div id="c7-collection-list"></div>'; 950 break; 951 952 default: 953 $output .= '<div id="c7-content"></div>'; 954 break; 955 } 1181 if ( in_array( $this->widgetsver, array( 'v2', 'v2-compat' ), true ) ) { 1182 $output .= $this->render_v2_widget( $atts ); 956 1183 } else { 957 958 switch ( $atts['type'] ) { 959 case 'default': 960 $output .= '<div id="c7-content"></div>'; 961 break; 962 963 case 'personalization': 964 $output .= '<div class="c7-personalization" data-block-code="' . esc_attr( $atts['data'] ) . '"></div>'; 965 break; 966 967 case 'buy': 968 $output .= '<div class="c7-buy-variant" data-sku="' . esc_attr( $atts['data'] ) . '"></div>'; 969 break; 970 971 case 'buyslug': 972 $output .= '<div class="c7-buy-variant" data-product-slug="' . esc_attr( $atts['data'] ) . '"></div>'; 973 break; 974 975 case 'subscribe': 976 $output .= ( 'true' === $atts['data'] ) ? '<div class="c7-subscribe" data-has-name-fields="true"></div>' : '<div class="c7-subscribe"></div>'; 977 break; 978 979 case 'collection': 980 $output .= '<div class="c7-product-collection" data-collection-slug="' . esc_attr( $atts['data'] ) . '"></div>'; 981 break; 982 983 case 'login': 984 $output .= '<div id="c7-login"></div>'; 985 break; 986 987 case 'cart': 988 $output .= '<div id="c7-cart"></div>'; 989 break; 990 991 case 'reservation': 992 $output .= '<div class="c7-reservation-availability" data-reservation-type-slug="' . esc_attr( $atts['data'] ) . '"></div>'; 993 break; 994 995 case 'form': 996 $output .= '<div class="c7-form-wrapper" data-form-code="' . esc_attr( $atts['data'] ) . '"></div>'; 997 break; 998 999 case 'joinnow': 1000 $output .= '<div class="c7-club-join-button" data-club-slug="' . esc_attr( $atts['data'] ) . '"></div>'; 1001 break; 1002 1003 case 'quickshop': 1004 $output .= '<div id="c7-quick-shop" data-collection-slug="' . esc_attr( $atts['data'] ) . '"></div>'; 1005 break; 1006 1007 case 'loginform': 1008 $output .= '<div id="c7-login-form" data-redirect-to="' . esc_attr( $atts['data'] ) . '"></div>'; 1009 break; 1010 1011 case 'createaccount': 1012 $output .= '<div id="c7-create-account" data-redirect-to="' . esc_attr( $atts['data'] ) . '"></div>'; 1013 break; 1014 1015 default: 1016 $output .= '<div id="c7-content"></div>'; 1017 break; 1018 } 1184 $output .= $this->render_v1_widget( $atts ); 1019 1185 } 1020 1186 … … 1022 1188 1023 1189 return $output; 1190 } 1191 1192 /** 1193 * Render V2 widget output 1194 * 1195 * @param array $atts Shortcode attributes. 1196 * @return string Widget HTML. 1197 */ 1198 private function render_v2_widget( $atts ) { 1199 switch ( $atts['type'] ) { 1200 case 'default': 1201 return '<div id="c7-content"></div>'; 1202 1203 case 'personalization': 1204 return '<div class="c7-personalization" data-block-code="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1205 1206 case 'subscribe': 1207 return ( 'true' === $atts['data'] ) ? '<div class="c7-subscribe" data-has-name-field="true"></div>' : '<div class="c7-subscribe"></div>'; 1208 1209 case 'collection': 1210 return '<div class="c7-product-collection" data-collection-slug="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1211 1212 case 'login': 1213 return '<div id="c7-account"></div>'; 1214 1215 case 'cart': 1216 return '<div id="c7-cart"></div>'; 1217 1218 case 'reservation': 1219 return '<div class="c7-reservation-availability" data-reservation-type-slug="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1220 1221 case 'form': 1222 return '<div class="c7-custom-form" data-form-code="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1223 1224 case 'joinnow': 1225 return '<div class="c7-club-join-button" 1226 data-club-slug="' . trim( esc_attr( $atts['data'] ) ) . '" 1227 data-join-text="' . trim( esc_attr( $atts['join-text'] ) ) . '" 1228 data-edit-text="' . trim( esc_attr( $atts['edit-text'] ) ) . '" 1229 ></div>'; 1230 1231 case 'buyslug': 1232 return '<div class="c7-buy-product" data-product-slug="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1233 1234 case 'loginform': 1235 return '<div id="c7-login-form" data-redirect-to="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1236 1237 case 'collectionlist': 1238 return '<div id="c7-collection-list"></div>'; 1239 1240 default: 1241 return '<div id="c7-content"></div>'; 1242 } 1243 } 1244 1245 /** 1246 * Render V1 widget output 1247 * 1248 * @param array $atts Shortcode attributes. 1249 * @return string Widget HTML. 1250 */ 1251 private function render_v1_widget( $atts ) { 1252 switch ( $atts['type'] ) { 1253 case 'default': 1254 return '<div id="c7-content"></div>'; 1255 1256 case 'personalization': 1257 return '<div class="c7-personalization" data-block-code="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1258 1259 case 'buy': 1260 return '<div class="c7-buy-variant" data-sku="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1261 1262 case 'buyslug': 1263 return '<div class="c7-buy-variant" data-product-slug="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1264 1265 case 'subscribe': 1266 return ( 'true' === $atts['data'] ) ? '<div class="c7-subscribe" data-has-name-fields="true"></div>' : '<div class="c7-subscribe"></div>'; 1267 1268 case 'collection': 1269 return '<div class="c7-product-collection" data-collection-slug="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1270 1271 case 'login': 1272 return '<div id="c7-login"></div>'; 1273 1274 case 'cart': 1275 return '<div id="c7-cart"></div>'; 1276 1277 case 'reservation': 1278 return '<div class="c7-reservation-availability" data-reservation-type-slug="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1279 1280 case 'form': 1281 return '<div class="c7-form-wrapper" data-form-code="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1282 1283 case 'joinnow': 1284 return '<div class="c7-club-join-button" data-club-slug="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1285 1286 case 'quickshop': 1287 return '<div id="c7-quick-shop" data-collection-slug="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1288 1289 case 'loginform': 1290 return '<div id="c7-login-form" data-redirect-to="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1291 1292 case 'createaccount': 1293 return '<div id="c7-create-account" data-redirect-to="' . trim( esc_attr( $atts['data'] ) ) . '"></div>'; 1294 1295 default: 1296 return '<div id="c7-content"></div>'; 1297 } 1024 1298 } 1025 1299 … … 1033 1307 public function add_display_post_states( $post_states, $post ) { 1034 1308 1035 $options = get_option( 'c7wp_settings' );1309 $options = $this->settings; 1036 1310 if ( isset( $options['c7wp_widget_version'] ) && 'v2' === $options['c7wp_widget_version'] 1037 1311 && isset( $options['c7wp_frontend_routes'] ) && 'yes' === $options['c7wp_enable_custom_routes'] ) { … … 1045 1319 'checkout', 1046 1320 'cart', 1047 'privacy',1048 'terms',1049 1321 'reservation', 1050 1322 ); … … 1052 1324 1053 1325 if ( in_array( $post->post_name, $pages, true ) ) { 1054 $post_states['c7wp'] = esc_html__( 'Commerce7 Required Page', 'wp-commerce7' ); 1326 $post_states['c7wp'] = esc_html__( 'Commerce7 Dynamic Route', 'wp-commerce7' ); 1327 } 1328 1329 $static_pages = array( 1330 'privacy', 1331 'terms', 1332 ); 1333 1334 if ( in_array( $post->post_name, $static_pages, true ) ) { 1335 $post_states['c7wp-static'] = esc_html__( 'Commerce7 Required Page', 'wp-commerce7' ); 1055 1336 } 1056 1337 … … 1066 1347 return $classes; 1067 1348 } 1349 1350 /** 1351 * Check if a page has proper Commerce7 content 1352 * 1353 * @param int|WP_Post $page Page ID or WP_Post object. 1354 * @return bool True if page has proper C7 content. 1355 */ 1356 public function page_has_c7_content( $page ) { 1357 if ( is_numeric( $page ) ) { 1358 $page = get_post( $page ); 1359 } 1360 1361 if ( ! $page || 'page' !== $page->post_type ) { 1362 return false; 1363 } 1364 1365 $content = $page->post_content; 1366 1367 // Check for various C7 content patterns 1368 $patterns = array( 1369 '/c7-content/', // Basic C7 div 1370 '/wp:c7wp/', // Gutenberg blocks 1371 '/<!-- wp:c7wp/', // Gutenberg block comments 1372 '/\[c7wp/', // Shortcodes 1373 '/class="c7wp-/', // C7WP wrapper classes 1374 ); 1375 1376 foreach ( $patterns as $pattern ) { 1377 if ( preg_match( $pattern, $content ) ) { 1378 return true; 1379 } 1380 } 1381 1382 return false; 1383 } 1384 1385 /** 1386 * Get pages that need Commerce7 content 1387 * 1388 * @return array Array of page objects that need C7 content. 1389 */ 1390 public function get_pages_needing_c7_content() { 1391 $options = $this->settings; 1392 1393 if ( isset( $options['c7wp_frontend_routes'] ) && 'yes' === $options['c7wp_enable_custom_routes'] ) { 1394 $required_pages = array_values( $options['c7wp_frontend_routes'] ); 1395 } else { 1396 $required_pages = array( 'profile', 'collection', 'product', 'club', 'checkout', 'cart', 'reservation' ); 1397 } 1398 1399 $pages_needing_content = array(); 1400 1401 foreach ( $required_pages as $page_slug ) { 1402 $page = get_page_by_path( $page_slug, 'ARRAY_N', 'page' ); 1403 if ( $page && ! $this->page_has_c7_content( $page[0] ) ) { 1404 $pages_needing_content[] = get_post( $page[0] ); 1405 } 1406 } 1407 1408 return $pages_needing_content; 1409 } 1410 1068 1411 } -
wp-commerce7/trunk/includes/elementor/elementor-buyslug.php
r3292177 r3441297 6 6 * Author: Michael Bourne 7 7 * ----- 8 * Last Modified: T hursday, January 9th 2025, 1:51:21 pm8 * Last Modified: Tuesday, September 16th 2025, 10:24:41 pm 9 9 * Modified By: Michael Bourne 10 10 * ----- … … 115 115 116 116 $this->add_control( 117 'preview_notice', 118 [ 119 'type' => \Elementor\Controls_Manager::RAW_HTML, 120 'raw' => '<div style="background: #fff3cd; border: 1px solid #ffeaa7; padding: 10px; border-radius: 4px; margin-bottom: 15px;"><strong>Preview Notice:</strong> The preview shown in your editor is for example purposes only, it does not reflect the slug you provide nor is it interactive.</div>', 121 'content_classes' => 'elementor-panel-alert elementor-panel-alert-warning', 122 ] 123 ); 124 125 $this->add_control( 117 126 'data', 118 127 [ … … 141 150 $data = esc_attr( $settings['data'] ); 142 151 143 echo do_shortcode( '[c7wp type="buyslug" data="' . $data . '"]' ); 144 145 } 146 147 protected function content_template() {} //phpcs:ignore 152 // Show preview in Elementor editor, shortcode on frontend 153 if ( \Elementor\Plugin::$instance->editor->is_edit_mode() || \Elementor\Plugin::$instance->preview->is_preview_mode() ) { 154 $slugProvided = !empty( $data ); 155 ?> 156 <div class="c7-buy-product-placeholder" data-product-slug="<?php echo esc_attr( $data ); ?>"> 157 <?php if ( $slugProvided ) : ?> 158 <form action="#" class="c7-form c7-product__add-to-cart"> 159 <div class="c7-product__add-to-cart__price"> 160 <span class="c7-sr-only">Item Price</span> 161 <span class="c7-price--original">$45<span>.00</span></span> 162 <span class="c7-price--discounted">$38<span>.00</span></span> 163 <span class="c7-product__add-to-cart__price__variant"> 164 <span class="c7-product__variant__price__title">bottle</span> 165 </span> 166 </div> 167 <div class="c7-product__add-to-cart__form"> 168 <div class="c7-product__add-to-cart__form__quantity"> 169 <div class="c7-form__field"> 170 <input name="quantity" type="text" inputmode="numeric" value="1" class="c7-product__quantity-input" tabindex="-1" disabled> 171 </div> 172 </div> 173 <button type="submit" class="c7-btn c7-btn--primary" tabindex="-1" disabled> 174 <span>Add to Cart</span> 175 </button> 176 </div> 177 </form> 178 <?php else : ?> 179 <div class="c7-message c7-message--alert-error" role="presentation"> 180 <svg aria-hidden="true" focusable="false" role="presentation" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> 181 <circle cx="12" cy="12" r="10"></circle> 182 <line x1="12" y1="8" x2="12" y2="12"></line> 183 <line x1="12" y1="16" x2="12.01" y2="16"></line> 184 </svg> 185 Please enter a product slug in the widget settings 186 </div> 187 <?php endif; ?> 188 </div> 189 <?php 190 } else { 191 // Frontend - show actual shortcode 192 echo do_shortcode( '[c7wp type="buyslug" data="' . $data . '"]' ); 193 } 194 195 } 196 197 /** 198 * Render widget output in the editor. 199 * 200 * Written as a Backbone JavaScript template and used to generate the live preview. 201 * 202 * @since 1.0.0 203 * @access protected 204 */ 205 protected function content_template() { 206 ?> 207 <# 208 var slugProvided = settings.data && settings.data.length > 0; 209 #> 210 <div class="c7-buy-product-placeholder" data-product-slug="{{{ settings.data }}}"> 211 <# if (slugProvided) { #> 212 <form action="#" class="c7-form c7-product__add-to-cart"> 213 <div class="c7-product__add-to-cart__price"> 214 <span class="c7-sr-only">Item Price</span> 215 <span class="c7-price--original">$45<span>.00</span></span> 216 <span class="c7-price--discounted">$38<span>.00</span></span> 217 <span class="c7-product__add-to-cart__price__variant"> 218 <span class="c7-product__variant__price__title">bottle</span> 219 </span> 220 </div> 221 <div class="c7-product__add-to-cart__form"> 222 <div class="c7-product__add-to-cart__form__quantity"> 223 <div class="c7-form__field"> 224 <input name="quantity" type="text" inputmode="numeric" value="1" class="c7-product__quantity-input" tabindex="-1" disabled> 225 </div> 226 </div> 227 <button type="submit" class="c7-btn c7-btn--primary" tabindex="-1" disabled> 228 <span>Add to Cart</span> 229 </button> 230 </div> 231 </form> 232 <# } else { #> 233 <div class="c7-message c7-message--alert-error" role="presentation"> 234 <svg aria-hidden="true" focusable="false" role="presentation" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> 235 <circle cx="12" cy="12" r="10"></circle> 236 <line x1="12" y1="8" x2="12" y2="12"></line> 237 <line x1="12" y1="16" x2="12.01" y2="16"></line> 238 </svg> 239 Please enter a product slug in the widget settings 240 </div> 241 <# } #> 242 </div> 243 <?php 244 } 148 245 public function render_plain_content( $instance = [] ) {} 149 246 -
wp-commerce7/trunk/includes/elementor/elementor-form.php
r3292177 r3441297 116 116 117 117 $this->add_control( 118 'preview_notice', 119 [ 120 'type' => \Elementor\Controls_Manager::RAW_HTML, 121 'raw' => '<div style="background: #fff3cd; border: 1px solid #ffeaa7; padding: 10px; border-radius: 4px; margin-bottom: 15px;"><strong>Preview Notice:</strong> The preview shown in your editor is for example purposes only, it does not reflect the form you provide nor is it interactive.</div>', 122 'content_classes' => 'elementor-panel-alert elementor-panel-alert-warning', 123 ] 124 ); 125 126 $this->add_control( 118 127 'data', 119 128 [ … … 142 151 $data = esc_attr( $settings['data'] ); 143 152 144 echo do_shortcode( '[c7wp type="form" data="' . $data . '"]' ); 145 146 } 147 148 protected function content_template() {} //phpcs:ignore 153 // Show preview in Elementor editor, shortcode on frontend 154 if ( \Elementor\Plugin::$instance->editor->is_edit_mode() || \Elementor\Plugin::$instance->preview->is_preview_mode() ) { 155 $slugProvided = !empty( $data ); 156 ?> 157 <div class="c7-custom-form-placeholder" data-form-code="<?php echo esc_attr( $data ); ?>"> 158 <?php if ( $slugProvided ) : ?> 159 <form class="c7-form"> 160 <fieldset> 161 <legend class="c7-sr-only">Contact Us</legend> 162 <div class="c7-form__field"> 163 <label class="c7-required">First & Last Name</label> 164 <input name="fullName" type="text" value="" disabled tabindex="-1"> 165 </div> 166 <div class="c7-form__field"> 167 <label class="c7-required">Country</label> 168 <select name="countryCode" disabled tabindex="-1"> 169 <option value="CA">Canada</option> 170 <option value="US">United States</option> 171 </select> 172 </div> 173 <div class="c7-form__field"> 174 <label>Phone</label> 175 <input name="phone" type="tel" value="" disabled tabindex="-1"> 176 </div> 177 <div class="c7-form__field"> 178 <label class="c7-required">Email</label> 179 <input name="email" type="email" value="" disabled tabindex="-1"> 180 </div> 181 <div class="c7-form__field"> 182 <label class="c7-required">Questions/Comments</label> 183 <textarea name="questions-comments" rows="3" disabled tabindex="-1"></textarea> 184 </div> 185 </fieldset> 186 <div class="c7-form__buttons"> 187 <button type="submit" class="c7-btn c7-btn--primary" disabled tabindex="-1"> 188 <span>Submit</span> 189 </button> 190 </div> 191 </form> 192 <?php else : ?> 193 <div class="c7-message c7-message--alert-error" role="presentation"> 194 <svg aria-hidden="true" focusable="false" role="presentation" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> 195 <circle cx="12" cy="12" r="10"></circle> 196 <line x1="12" y1="8" x2="12" y2="12"></line> 197 <line x1="12" y1="16" x2="12.01" y2="16"></line> 198 </svg> 199 Please enter a form slug in the widget settings 200 </div> 201 <?php endif; ?> 202 </div> 203 <?php 204 } else { 205 // Frontend - show actual shortcode 206 echo do_shortcode( '[c7wp type="form" data="' . $data . '"]' ); 207 } 208 209 } 210 211 /** 212 * Render widget output in the editor. 213 * 214 * Written as a Backbone JavaScript template and used to generate the live preview. 215 * 216 * @since 1.0.0 217 * @access protected 218 */ 219 protected function content_template() { 220 ?> 221 <# 222 var slugProvided = settings.data && settings.data.length > 0; 223 #> 224 <div class="c7-custom-form-placeholder" data-form-code="{{{ settings.data }}}"> 225 <# if (slugProvided) { #> 226 <form class="c7-form"> 227 <fieldset> 228 <legend class="c7-sr-only">Contact Us</legend> 229 <div class="c7-form__field"> 230 <label class="c7-required">First & Last Name</label> 231 <input name="fullName" type="text" value="" disabled tabindex="-1"> 232 </div> 233 <div class="c7-form__field"> 234 <label class="c7-required">Country</label> 235 <select name="countryCode" disabled tabindex="-1"> 236 <option value="CA">Canada</option> 237 <option value="US">United States</option> 238 </select> 239 </div> 240 <div class="c7-form__field"> 241 <label>Phone</label> 242 <input name="phone" type="tel" value="" disabled tabindex="-1"> 243 </div> 244 <div class="c7-form__field"> 245 <label class="c7-required">Email</label> 246 <input name="email" type="email" value="" disabled tabindex="-1"> 247 </div> 248 <div class="c7-form__field"> 249 <label class="c7-required">Questions/Comments</label> 250 <textarea name="questions-comments" rows="3" disabled tabindex="-1"></textarea> 251 </div> 252 </fieldset> 253 <div class="c7-form__buttons"> 254 <button type="submit" class="c7-btn c7-btn--primary" disabled tabindex="-1"> 255 <span>Submit</span> 256 </button> 257 </div> 258 </form> 259 <# } else { #> 260 <div class="c7-message c7-message--alert-error" role="presentation"> 261 <svg aria-hidden="true" focusable="false" role="presentation" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> 262 <circle cx="12" cy="12" r="10"></circle> 263 <line x1="12" y1="8" x2="12" y2="12"></line> 264 <line x1="12" y1="16" x2="12.01" y2="16"></line> 265 </svg> 266 Please enter a form slug in the widget settings 267 </div> 268 <# } #> 269 </div> 270 <?php 271 } 149 272 public function render_plain_content( $instance = [] ) {} 150 273 -
wp-commerce7/trunk/includes/elementor/elementor-joinnow.php
r3292177 r3441297 116 116 117 117 $this->add_control( 118 'preview_notice', 119 [ 120 'type' => \Elementor\Controls_Manager::RAW_HTML, 121 'raw' => '<div style="background: #fff3cd; border: 1px solid #ffeaa7; padding: 10px; border-radius: 4px; margin-bottom: 15px;"><strong>Preview Notice:</strong> The preview shown in your editor is for example purposes only, it does not reflect the club slug you provide nor is it interactive.</div>', 122 'content_classes' => 'elementor-panel-alert elementor-panel-alert-warning', 123 ] 124 ); 125 126 $this->add_control( 118 127 'data', 119 128 [ … … 160 169 $data = esc_attr( $settings['data'] ); 161 170 162 $extras = ''; 163 164 if ( ! empty( $settings['join-text'] ) ) { 165 $extras .= ' join-text="' . esc_attr( $settings['join-text'] ) . '"'; 171 // Show preview in Elementor editor, shortcode on frontend 172 if ( \Elementor\Plugin::$instance->editor->is_edit_mode() || \Elementor\Plugin::$instance->preview->is_preview_mode() ) { 173 $slugProvided = !empty( $data ); 174 $joinText = !empty( $settings['join-text'] ) ? $settings['join-text'] : 'Join Now'; 175 $editText = !empty( $settings['edit-text'] ) ? $settings['edit-text'] : 'Edit Membership'; 176 ?> 177 <div class="c7-club-join-button-placeholder" data-club-slug="<?php echo esc_attr( $data ); ?>" data-join-text="<?php echo esc_attr( $joinText ); ?>" data-edit-text="<?php echo esc_attr( $editText ); ?>"> 178 <?php if ( $slugProvided ) : ?> 179 <a class="c7-btn c7-btn--primary" role="link" tabindex="-1" disabled> 180 <?php echo esc_html( $joinText ); ?> 181 </a> 182 <?php else : ?> 183 <div class="c7-message c7-message--alert-error" role="presentation"> 184 <svg aria-hidden="true" focusable="false" role="presentation" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> 185 <circle cx="12" cy="12" r="10"></circle> 186 <line x1="12" y1="8" x2="12" y2="12"></line> 187 <line x1="12" y1="16" x2="12.01" y2="16"></line> 188 </svg> 189 Please enter a club slug in the widget settings 190 </div> 191 <?php endif; ?> 192 </div> 193 <?php 194 } else { 195 // Frontend - show actual shortcode 196 $extras = ''; 197 if ( ! empty( $settings['join-text'] ) ) { 198 $extras .= ' join-text="' . esc_attr( $settings['join-text'] ) . '"'; 199 } 200 if ( ! empty( $settings['edit-text'] ) ) { 201 $extras .= ' edit-text="' . esc_attr( $settings['edit-text'] ) . '"'; 202 } 203 echo do_shortcode( '[c7wp type="joinnow" data="' . $data . '"' . $extras . ']' ); 166 204 } 167 if ( ! empty( $settings['edit-text'] ) ) { 168 $extras .= ' edit-text="' . esc_attr( $settings['edit-text'] ) . '"'; 169 } 170 171 echo do_shortcode( '[c7wp type="joinnow" data="' . $data . '"' . $extras . ']' ); 172 } 173 174 protected function content_template() {} //phpcs:ignore 205 } 206 207 /** 208 * Render widget output in the editor. 209 * 210 * Written as a Backbone JavaScript template and used to generate the live preview. 211 * 212 * @since 1.0.0 213 * @access protected 214 */ 215 protected function content_template() { 216 ?> 217 <# 218 var slugProvided = settings.data && settings.data.length > 0; 219 var joinText = settings['join-text'] || 'Join Now'; 220 var editText = settings['edit-text'] || 'Edit Membership'; 221 #> 222 <div class="c7-club-join-button-placeholder" data-club-slug="{{{ settings.data }}}" data-join-text="{{{ joinText }}}" data-edit-text="{{{ editText }}}"> 223 <# if (slugProvided) { #> 224 <a class="c7-btn c7-btn--primary" role="link" tabindex="-1" disabled> 225 {{{ joinText }}} 226 </a> 227 <# } else { #> 228 <div class="c7-message c7-message--alert-error" role="presentation"> 229 <svg aria-hidden="true" focusable="false" role="presentation" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> 230 <circle cx="12" cy="12" r="10"></circle> 231 <line x1="12" y1="8" x2="12" y2="12"></line> 232 <line x1="12" y1="16" x2="12.01" y2="16"></line> 233 </svg> 234 Please enter a club slug in the widget settings 235 </div> 236 <# } #> 237 </div> 238 <?php 239 } 175 240 public function render_plain_content( $instance = [] ) {} 176 241 -
wp-commerce7/trunk/includes/elementor/elementor-loginform.php
r3292177 r3441297 116 116 117 117 $this->add_control( 118 'preview_notice', 119 [ 120 'type' => \Elementor\Controls_Manager::RAW_HTML, 121 'raw' => '<div style="background: #fff3cd; border: 1px solid #ffeaa7; padding: 10px; border-radius: 4px; margin-bottom: 15px;"><strong>Preview Notice:</strong> The preview shown in your editor is for example purposes only, it does not reflect the redirect path you provide nor is it interactive.</div>', 122 'content_classes' => 'elementor-panel-alert elementor-panel-alert-warning', 123 ] 124 ); 125 126 $this->add_control( 118 127 'data', 119 128 [ … … 142 151 $data = esc_attr( $settings['data'] ); 143 152 144 echo do_shortcode( '[c7wp type="loginform" data="' . $data . '"]' ); 145 146 } 147 148 protected function content_template() {} //phpcs:ignore 153 // Show preview in Elementor editor, shortcode on frontend 154 if ( \Elementor\Plugin::$instance->editor->is_edit_mode() || \Elementor\Plugin::$instance->preview->is_preview_mode() ) { 155 ?> 156 <div id="c7-login-form-placeholder" data-redirect-to="<?php echo esc_attr( $data ); ?>"> 157 <form class="c7-form c7-form--login" data-sku="<?php echo esc_attr( $data ); ?>"> 158 <div class="c7-form__field"> 159 <label class="c7-required">Email</label> 160 <input name="email" tabindex="-1" disabled type="text"> 161 </div> 162 <div class="c7-form__field"> 163 <label class="c7-required">Password</label> 164 <input name="password" tabindex="-1" disabled type="password"> 165 </div> 166 <div class="c7-form__buttons c7-form__buttons--wide"> 167 <button type="submit" tabindex="-1" disabled class="c7-btn c7-btn--primary"> 168 <span>Log in</span> 169 </button> 170 </div> 171 </form> 172 </div> 173 <?php 174 } else { 175 // Frontend - show actual shortcode 176 echo do_shortcode( '[c7wp type="loginform" data="' . $data . '"]' ); 177 } 178 179 } 180 181 /** 182 * Render widget output in the editor. 183 * 184 * Written as a Backbone JavaScript template and used to generate the live preview. 185 * 186 * @since 1.0.0 187 * @access protected 188 */ 189 protected function content_template() { 190 ?> 191 <# 192 var slugProvided = settings.data && settings.data.length > 0; 193 #> 194 <div id="c7-login-form-placeholder" data-redirect-to="{{{ settings.data }}}"> 195 <form class="c7-form c7-form--login" data-sku="{{{ settings.data }}}"> 196 <div class="c7-form__field"> 197 <label class="c7-required">Email</label> 198 <input name="email" tabindex="-1" disabled type="text"> 199 </div> 200 <div class="c7-form__field"> 201 <label class="c7-required">Password</label> 202 <input name="password" tabindex="-1" disabled type="password"> 203 </div> 204 <div class="c7-form__buttons c7-form__buttons--wide"> 205 <button type="submit" tabindex="-1" disabled class="c7-btn c7-btn--primary"> 206 <span>Log in</span> 207 </button> 208 </div> 209 </form> 210 </div> 211 <?php 212 } 149 213 public function render_plain_content( $instance = [] ) {} 150 214 -
wp-commerce7/trunk/includes/elementor/elementor-reservation.php
r3292177 r3441297 116 116 117 117 $this->add_control( 118 'preview_notice', 119 [ 120 'type' => \Elementor\Controls_Manager::RAW_HTML, 121 'raw' => '<div style="background: #fff3cd; border: 1px solid #ffeaa7; padding: 10px; border-radius: 4px; margin-bottom: 15px;"><strong>Preview Notice:</strong> The preview shown in your editor is for example purposes only, it does not reflect the experience slug you provide nor is it interactive.</div>', 122 'content_classes' => 'elementor-panel-alert elementor-panel-alert-warning', 123 ] 124 ); 125 126 $this->add_control( 118 127 'data', 119 128 [ … … 142 151 $data = esc_attr( $settings['data'] ); 143 152 144 echo do_shortcode( '[c7wp type="reservation" data="' . $data . '"]' ); 145 146 } 147 148 protected function content_template() {} //phpcs:ignore 153 // Show preview in Elementor editor, shortcode on frontend 154 if ( \Elementor\Plugin::$instance->editor->is_edit_mode() || \Elementor\Plugin::$instance->preview->is_preview_mode() ) { 155 $slugProvided = !empty( $data ); 156 ?> 157 <div class="c7-reservation-availability-placeholder" data-reservation-type-slug="<?php echo esc_attr( $data ); ?>"> 158 <?php if ( $slugProvided ) : ?> 159 <section class="c7-reservation__search"> 160 <form class="c7-form"> 161 <div class="c7-form__group"> 162 <div class="c7-form__field"> 163 <label class="c7-required">Date</label> 164 <div class="c7-date-picker-input"> 165 <input type="text" placeholder="MMM DD YYYY" value="" tabindex="-1" disabled> 166 <button type="button" class="c7-date-picker-toggle" tabindex="-1" disabled> 167 <span role="img"> 168 <img class="emoji" src="https://s.w.org/images/core/emoji/14.0.0/svg/1f4c5.svg"> 169 </span> 170 </button> 171 </div> 172 </div> 173 <div class="c7-form__field"> 174 <label class="c7-required">Time</label> 175 <select tabindex="-1" disabled> 176 <option value=""></option> 177 <option value="10:00:00">10:00 am</option> 178 <option value="10:30:00">10:30 am</option> 179 <option value="11:00:00">11:00 am</option> 180 <option value="11:30:00">11:30 am</option> 181 <option value="12:00:00">12:00 pm</option> 182 <option value="12:30:00">12:30 pm</option> 183 <option value="13:00:00">1:00 pm</option> 184 <option value="13:30:00">1:30 pm</option> 185 <option value="14:00:00">2:00 pm</option> 186 <option value="14:30:00">2:30 pm</option> 187 <option value="15:00:00">3:00 pm</option> 188 <option value="15:30:00">3:30 pm</option> 189 <option value="16:00:00">4:00 pm</option> 190 </select> 191 </div> 192 <div class="c7-form__field"> 193 <label class="c7-required">No of Guests</label> 194 <select tabindex="-1" disabled> 195 <option value=""></option> 196 <option value="1">1</option> 197 <option value="2">2</option> 198 <option value="3">3</option> 199 <option value="4">4</option> 200 <option value="5">5</option> 201 </select> 202 </div> 203 <button type="submit" class="c7-btn c7-btn--primary" tabindex="-1" disabled> 204 <span>Check Availability</span> 205 </button> 206 </div> 207 </form> 208 </section> 209 <?php else : ?> 210 <div class="c7-message c7-message--alert-error" role="presentation"> 211 <svg aria-hidden="true" focusable="false" role="presentation" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> 212 <circle cx="12" cy="12" r="10"></circle> 213 <line x1="12" y1="8" x2="12" y2="12"></line> 214 <line x1="12" y1="16" x2="12.01" y2="16"></line> 215 </svg> 216 Please enter the single experience slug in the widget settings 217 </div> 218 <?php endif; ?> 219 </div> 220 <?php 221 } else { 222 // Frontend - show actual shortcode 223 echo do_shortcode( '[c7wp type="reservation" data="' . $data . '"]' ); 224 } 225 226 } 227 228 /** 229 * Render widget output in the editor. 230 * 231 * Written as a Backbone JavaScript template and used to generate the live preview. 232 * 233 * @since 1.0.0 234 * @access protected 235 */ 236 protected function content_template() { 237 ?> 238 <# 239 var slugProvided = settings.data && settings.data.length > 0; 240 #> 241 <div class="c7-reservation-availability-placeholder" data-reservation-type-slug="{{{ settings.data }}}"> 242 <# if (slugProvided) { #> 243 <section class="c7-reservation__search"> 244 <form class="c7-form"> 245 <div class="c7-form__group"> 246 <div class="c7-form__field"> 247 <label class="c7-required">Date</label> 248 <div class="c7-date-picker-input"> 249 <input type="text" placeholder="MMM DD YYYY" value="" tabindex="-1" disabled> 250 <button type="button" class="c7-date-picker-toggle" tabindex="-1" disabled> 251 <span role="img"> 252 <img class="emoji" src="https://s.w.org/images/core/emoji/14.0.0/svg/1f4c5.svg"> 253 </span> 254 </button> 255 </div> 256 </div> 257 <div class="c7-form__field"> 258 <label class="c7-required">Time</label> 259 <select tabindex="-1" disabled> 260 <option value=""></option> 261 <option value="10:00:00">10:00 am</option> 262 <option value="10:30:00">10:30 am</option> 263 <option value="11:00:00">11:00 am</option> 264 <option value="11:30:00">11:30 am</option> 265 <option value="12:00:00">12:00 pm</option> 266 <option value="12:30:00">12:30 pm</option> 267 <option value="13:00:00">1:00 pm</option> 268 <option value="13:30:00">1:30 pm</option> 269 <option value="14:00:00">2:00 pm</option> 270 <option value="14:30:00">2:30 pm</option> 271 <option value="15:00:00">3:00 pm</option> 272 <option value="15:30:00">3:30 pm</option> 273 <option value="16:00:00">4:00 pm</option> 274 </select> 275 </div> 276 <div class="c7-form__field"> 277 <label class="c7-required">No of Guests</label> 278 <select tabindex="-1" disabled> 279 <option value=""></option> 280 <option value="1">1</option> 281 <option value="2">2</option> 282 <option value="3">3</option> 283 <option value="4">4</option> 284 <option value="5">5</option> 285 </select> 286 </div> 287 <button type="submit" class="c7-btn c7-btn--primary" tabindex="-1" disabled> 288 <span>Check Availability</span> 289 </button> 290 </div> 291 </form> 292 </section> 293 <# } else { #> 294 <div class="c7-message c7-message--alert-error" role="presentation"> 295 <svg aria-hidden="true" focusable="false" role="presentation" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> 296 <circle cx="12" cy="12" r="10"></circle> 297 <line x1="12" y1="8" x2="12" y2="12"></line> 298 <line x1="12" y1="16" x2="12.01" y2="16"></line> 299 </svg> 300 Please enter the single experience slug in the widget settings 301 </div> 302 <# } #> 303 </div> 304 <?php 305 } 149 306 public function render_plain_content( $instance = [] ) {} 150 307 -
wp-commerce7/trunk/includes/elementor/elementor-subscribe.php
r3292177 r3441297 6 6 * Author: Michael Bourne 7 7 * ----- 8 * Last Modified: T hursday, January 9th 2025, 1:51:13pm8 * Last Modified: Tuesday, September 16th 2025, 10:35:48 pm 9 9 * Modified By: Michael Bourne 10 10 * ----- … … 111 111 'label' => __( 'Settings', 'wp-commerce7' ), 112 112 'tab' => \Elementor\Controls_Manager::TAB_CONTENT, 113 ] 114 ); 115 116 $this->add_control( 117 'preview_notice', 118 [ 119 'type' => \Elementor\Controls_Manager::RAW_HTML, 120 'raw' => '<div style="background: #fff3cd; border: 1px solid #ffeaa7; padding: 10px; border-radius: 4px; margin-bottom: 15px;"><strong>Preview Notice:</strong> The preview shown in your editor is for example purposes only.</div>', 121 'content_classes' => 'elementor-panel-alert elementor-panel-alert-warning', 113 122 ] 114 123 ); … … 151 160 $data = esc_attr( $settings['data'] ); 152 161 153 echo do_shortcode( '[c7wp type="subscribe" data="' . $data . '"]' ); 154 155 } 156 157 protected function content_template() {} //phpcs:ignore 162 // Show preview in Elementor editor, shortcode on frontend 163 if ( \Elementor\Plugin::$instance->editor->is_edit_mode() || \Elementor\Plugin::$instance->preview->is_preview_mode() ) { 164 $showNameField = ( $data === 'true' ); 165 ?> 166 <div class="c7-subscribe-placeholder" data-has-name-field="<?php echo esc_attr( $data ); ?>"> 167 <form class="c7-form"> 168 <div class="c7-form__group"> 169 <?php if ( $showNameField ) : ?> 170 <div class="c7-form__field"> 171 <label class="c7-required">First & Last Name</label> 172 <input name="fullName" type="text" tabindex="-1" disabled value=""> 173 </div> 174 <?php endif; ?> 175 <div class="c7-form__field"> 176 <label class="c7-required">Email</label> 177 <input name="email" type="email" tabindex="-1" disabled value=""> 178 </div> 179 <button type="submit" tabindex="-1" disabled class="c7-btn c7-btn--primary"> 180 <span>Subscribe</span> 181 </button> 182 </div> 183 </form> 184 </div> 185 <?php 186 } else { 187 // Frontend - show actual shortcode 188 echo do_shortcode( '[c7wp type="subscribe" data="' . $data . '"]' ); 189 } 190 191 } 192 193 /** 194 * Render widget output in the editor. 195 * 196 * Written as a Backbone JavaScript template and used to generate the live preview. 197 * 198 * @since 1.0.0 199 * @access protected 200 */ 201 protected function content_template() { 202 ?> 203 <# 204 var showNameField = settings.data === 'true'; 205 #> 206 <div class="c7-subscribe-placeholder" data-has-name-field="{{{ settings.data }}}"> 207 <form class="c7-form"> 208 <div class="c7-form__group"> 209 <# if (showNameField) { #> 210 <div class="c7-form__field"> 211 <label class="c7-required">First & Last Name</label> 212 <input name="fullName" type="text" tabindex="-1" disabled value=""> 213 </div> 214 <# } #> 215 <div class="c7-form__field"> 216 <label class="c7-required">Email</label> 217 <input name="email" type="email" tabindex="-1" disabled value=""> 218 </div> 219 <button type="submit" tabindex="-1" disabled class="c7-btn c7-btn--primary"> 220 <span>Subscribe</span> 221 </button> 222 </div> 223 </form> 224 </div> 225 <?php 226 } 158 227 public function render_plain_content( $instance = [] ) {} 159 228 -
wp-commerce7/trunk/includes/elementor/load.php
r3313519 r3441297 6 6 * Author: Michael Bourne 7 7 * ----- 8 * Last Modified: T hursday, June 5th 2025, 5:11:55pm8 * Last Modified: Tuesday, September 16th 2025, 8:35:52 pm 9 9 * Modified By: Michael Bourne 10 10 * ----- … … 22 22 \Elementor\Plugin::instance()->widgets_manager->register_widget_type( new \C7WP_Elementor() ); 23 23 24 if ( in_array( $this->widgetsver, [ 'v2', 'v2-compat' ]) ) {25 $elements = [24 if ( in_array( $this->widgetsver, array( 'v2', 'v2-compat' ), true ) ) { 25 $elements = array( 26 26 'personalization', 27 27 'buyslug', … … 35 35 'default', 36 36 'collectionlist', 37 ]; 37 'clubselector', 38 ); 38 39 } else { 39 $elements = [40 $elements = array( 40 41 'personalization', 41 42 'buy', … … 51 52 'loginform', 52 53 'createaccount', 53 ]; 54 ); 55 54 56 } 55 57 -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/buyslug/c7wp-buyslug.css
r3009702 r3441297 3 3 z-index: 1; 4 4 } 5 .wp-block-c7wp-buyslug > div { 5 6 .wp-block-c7wp-buyslug>div { 6 7 max-width: 100%; 7 8 } 9 8 10 .wp-block-c7wp-buyslug .c7-product__add-to-cart { 9 11 pointer-events: none; 10 12 } 13 11 14 .wp-block-c7wp-buyslug .c7-message { 12 15 pointer-events: none; 13 16 } 17 18 19 20 .c7wp-justify-center { 21 .c7-buy-product { 22 .c7-form { 23 max-width: unset; 24 } 25 26 .c7-product__add-to-cart__form { 27 justify-content: center; 28 } 29 30 .c7-product__add-to-cart__price { 31 text-align: center; 32 } 33 } 34 } 35 36 .c7wp-justify-right { 37 .c7-buy-product { 38 .c7-form { 39 max-width: unset; 40 } 41 42 .c7-product__add-to-cart__form { 43 justify-content: flex-end; 44 } 45 46 .c7-product__add-to-cart__price { 47 text-align: right; 48 } 49 } 50 } 51 52 .c7wp-justify-left { 53 .c7-buy-product { 54 margin-left: 0; 55 56 .c7-product__add-to-cart__form { 57 justify-content: flex-start; 58 } 59 } 60 } -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/buyslug/c7wp-buyslug.js
r3167363 r3441297 3 3 const { registerBlockType } = blocks; 4 4 const { InspectorControls } = blockEditor; 5 const { TextControl, PanelBody } = components;5 const { TextControl, PanelBody, SelectControl } = components; 6 6 const { createElement } = element; 7 7 const { __ } = i18n; … … 24 24 selector: '.c7-buy-product', 25 25 attribute: 'data-product-slug', 26 }, 27 justifyContent: { 28 type: 'string', 29 default: 'center', 26 30 } 27 31 }, … … 30 34 function updateData(value) { 31 35 props.setAttributes({ data: value }); 36 } 37 38 function updateJustifyContent(value) { 39 props.setAttributes({ justifyContent: value }); 40 } 41 42 function getAlignmentClass(justifyContent) { 43 const alignmentMap = { 44 'flex-start': 'c7wp-justify-left', 45 'center': 'c7wp-justify-center', 46 'flex-end': 'c7wp-justify-right' 47 }; 48 return alignmentMap[justifyContent] || 'c7wp-justify-center'; 32 49 } 33 50 … … 52 69 value: props.attributes.data, 53 70 onChange: updateData, 71 }), 72 createElement(SelectControl, { 73 label: 'Form Alignment', 74 value: props.attributes.justifyContent || 'center', 75 options: [ 76 { label: 'Left', value: 'flex-start' }, 77 { label: 'Center', value: 'center' }, 78 { label: 'Right', value: 'flex-end' } 79 ], 80 onChange: updateJustifyContent, 54 81 }) 55 82 ), 56 83 ), 57 createElement('div', { className: props.className},84 createElement('div', { className: [props.className, getAlignmentClass(props.attributes.justifyContent)].filter(Boolean).join(' ') }, 58 85 createElement('div', { 59 86 className: 'c7-buy-product', … … 149 176 ]; 150 177 }, 178 deprecated: [ 179 { 180 attributes: { 181 data: { 182 type: 'string', 183 source: 'attribute', 184 selector: '.c7-buy-product', 185 attribute: 'data-product-slug', 186 } 187 }, 188 save: function (props) { 189 return ( 190 createElement('div', { 191 className: props.className 192 }, 193 createElement('div', { 194 className: 'c7-buy-product', 195 'data-product-slug': props.attributes.data, 196 } 197 ) 198 ) 199 ); 200 } 201 } 202 ], 151 203 save: function (props) { 204 function getAlignmentClass(justifyContent) { 205 const alignmentMap = { 206 'flex-start': 'c7wp-justify-left', 207 'center': 'c7wp-justify-center', 208 'flex-end': 'c7wp-justify-right' 209 }; 210 return alignmentMap[justifyContent] || 'c7wp-justify-center'; 211 } 212 152 213 return ( 153 214 createElement('div', { 154 className: props.className215 className: [props.className, getAlignmentClass(props.attributes.justifyContent)].filter(Boolean).join(' ') 155 216 }, 156 217 createElement('div', { -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/clubselector/c7wp-clubselector.css
r3292177 r3441297 42 42 cursor: default; 43 43 opacity: 0.8; 44 } 44 } 45 -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/clubselector/c7wp-clubselector.js
r3313519 r3441297 88 88 // Force update button text and URL whenever clubs change 89 89 useEffect(() => { 90 const buttonBlock = wp.data.select('core/block-editor').getBlock(clientId).innerBlocks[0]; 90 const block = wp.data.select('core/block-editor').getBlock(clientId); 91 if (!block || !block.innerBlocks) return; 92 93 const buttonBlock = block.innerBlocks[0]; 91 94 if (buttonBlock && clubs.length > 0) { 92 95 const firstClub = clubs[0]; … … 105 108 useEffect(() => { 106 109 const block = wp.data.select('core/block-editor').getBlock(clientId); 107 if (!block) return; 110 if (!block || !block.innerBlocks) return; 111 108 112 // Filter to only core/button blocks 109 113 const buttonBlocks = block.innerBlocks.filter(b => b.name === 'core/button'); … … 118 122 ); 119 123 } 120 const buttonBlock = wp.data.select('core/block-editor').getBlock(clientId).innerBlocks[0]; 124 125 const updatedBlock = wp.data.select('core/block-editor').getBlock(clientId); 126 if (!updatedBlock || !updatedBlock.innerBlocks) return; 127 128 const buttonBlock = updatedBlock.innerBlocks[0]; 121 129 if (buttonBlock) { 122 130 const unsubscribe = wp.data.subscribe(() => { -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/clubselector/frontend.js
r3292177 r3441297 18 18 // Iterate through each club selector element 19 19 clubSelectors.forEach((selector) => { 20 // Get the button element 21 const button = selector.querySelector('.wp-block-button__link') ;20 // Get the button element - check for both Gutenberg and Elementor buttons 21 const button = selector.querySelector('.wp-block-button__link') || selector.querySelector('.elementor-button-link'); 22 22 23 23 // Handle radio button selection -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/collection/c7wp-collection.css
r3009702 r3441297 2 2 overflow: hidden; 3 3 z-index: 1; 4 border: 1px solid currentColor; 5 padding: 1rem; 4 6 } 5 7 .wp-block-c7wp-collection > div { … … 15 17 max-height: 100%; 16 18 position: absolute; 17 top: 0;18 right: 0;19 top: 1rem; 20 right: 1rem; 19 21 background-image: url('../../../../assets/c7bg.svg'); 20 22 background-size: contain; 21 23 background-repeat: no-repeat; 22 24 background-position: center right; 23 opacity: 0.0 5;25 opacity: 0.08; 24 26 pointer-events: none; 25 27 z-index: -1; -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/collection/c7wp-collection.js
r3167363 r3441297 2 2 3 3 const { registerBlockType } = blocks; 4 const { InspectorControls } = blockEditor;4 const { InspectorControls, useBlockProps } = blockEditor; // ADD useBlockProps here 5 5 const { TextControl, PanelBody } = components; 6 6 const { createElement } = element; … … 11 11 ); 12 12 13 registerBlockType( 'c7wp/collection', {14 title: __( 'Collection Grid' ), // The title of block in editor.15 description: __( 'Displays a single Commerce7 Collection.' ),16 icon: iconEl,17 category: 'commerce7', // The category of block in editor.13 registerBlockType( 'c7wp/collection', { 14 title: __( 'Collection Grid', 'wp-commerce7' ), 15 description: __( 'Displays a single Commerce7 Collection.', 'wp-commerce7' ), 16 icon: iconEl, 17 category: 'commerce7', 18 18 keywords: [ 'commerce7', 'collection', 'shop', 'products' ], 19 19 example: {}, 20 attributes: {20 attributes: { 21 21 data: { 22 22 type: 'string', … … 26 26 } 27 27 }, 28 edit: function( props ) { 28 edit: function( props ) { 29 const blockProps = useBlockProps(); 29 30 30 31 function updateData(value) { … … 41 42 marginBottom: '5px', 42 43 } 43 }, 44 createElement('small', 45 null, 46 'The preview shown in your editor is for example purposes only, it does not reflect the collection slug you provide nor is it interactive.' 47 ) 48 ), 44 }), 49 45 createElement(PanelBody, { title: 'Settings' }, 50 46 createElement(TextControl, { … … 55 51 ), 56 52 ), 57 slugProvided && createElement( 'div', { 58 className: 'components-placeholder ' + props.className 59 }, 53 slugProvided && createElement( 'div', blockProps, 60 54 createElement( 'div', { 61 55 className: 'c7-product-collection', 62 56 'data-collection-slug': props.attributes.data, 63 57 }, 64 // todo: insert demo html here 65 createElement( 'div', { style: { 66 textAlign: 'center', 67 } }, 58 createElement( 'div', null, 68 59 createElement( 'h2', null, "Commerce7 Collection" ), 69 createElement( 'p', null, props.attributes.data )60 createElement( 'p', null, "Collection slug: " + props.attributes.data ) 70 61 ), 71 62 ) 72 63 ), 73 !slugProvided && createElement('div', { className: 'c7-message c7-message--alert-error', role: 'presentation' }, 64 !slugProvided && createElement('div', { 65 ...blockProps, 66 className: blockProps.className + ' c7-message c7-message--alert-error', 67 role: 'presentation' 68 }, 74 69 createElement('svg', { 75 70 'aria-hidden': 'true', … … 93 88 ) 94 89 ]; 95 }, 96 save: function( props ) { 90 }, 91 save: function( props ) { 92 const blockProps = useBlockProps.save(); 97 93 return ( 98 createElement( 'div', { 99 className: props.className 100 }, 94 createElement( 'div', blockProps, 101 95 createElement( 'div', { 102 96 className: 'c7-product-collection', … … 106 100 ) 107 101 ); 108 }, 109 } ); 102 }, 103 // Deprecated version to handle old blocks without proper className 104 deprecated: [ 105 { 106 attributes: { 107 data: { 108 type: 'string', 109 source: 'attribute', 110 selector: '.c7-product-collection', 111 attribute: 'data-collection-slug', 112 } 113 }, 114 save: function( props ) { 115 return ( 116 createElement( 'div', { className: props.className }, 117 createElement( 'div', { 118 className: 'c7-product-collection', 119 'data-collection-slug': props.attributes.data, 120 } 121 ) 122 ) 123 ); 124 } 125 } 126 ] 127 } ); 110 128 })(window.wp.blocks, window.wp.blockEditor, window.wp.element, window.wp.i18n, window.wp.components); -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/collectionlist/c7wp-collectionlist.css
r3313519 r3441297 2 2 3 3 } 4 5 .wp-block-c7wp-collectionlist::before { 6 content: ''; 7 width: 50px; 8 height: 50px; 9 max-width: 100%; 10 max-height: 100%; 11 position: absolute; 12 top: 1rem; 13 right: 1rem; 14 background-image: url('../../../../assets/c7bg.svg'); 15 background-size: contain; 16 background-repeat: no-repeat; 17 background-position: center right; 18 opacity: 0.08; 19 pointer-events: none; 20 } -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/collectionlist/c7wp-collectionlist.js
r3313519 r3441297 28 28 'strong', 29 29 null, 30 'This block will automatically populate with list of collections.'30 'This block will automatically populate with list of Web Available collections.' 31 31 ), 32 32 ) -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/default/c7wp-default.css
r2592286 r3441297 2 2 overflow: hidden; 3 3 z-index: 1; 4 border: 1px solid currentColor; 5 padding: 1rem; 4 6 } 5 7 .wp-block-c7wp-default > div { 6 8 max-width: 100%; 7 9 } 8 .wp-block-c7wp-default strong{10 .wp-block-c7wp-default p { 9 11 margin-bottom: 1rem; 10 12 display: block; 11 } 12 13 .wp-block-c7wp-default label { 14 display: block; 15 } 16 .wp-block-c7wp-default input { 17 max-width: 100%; 18 margin-top: 0.5rem; 19 display: block; 13 max-width: 55ch; 20 14 } 21 15 .wp-block-c7wp-default::before { … … 26 20 max-height: 100%; 27 21 position: absolute; 28 top: 0;29 right: 0;22 top: 1rem; 23 right: 1rem; 30 24 background-image: url('../../../../assets/c7bg.svg'); 31 25 background-size: contain; 32 26 background-repeat: no-repeat; 33 27 background-position: center right; 34 opacity: 0.0 5;28 opacity: 0.08; 35 29 pointer-events: none; 36 30 z-index: -1; -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/default/c7wp-default.js
r3167363 r3441297 1 ( function( blocks, editor, element ) {1 ( function( blocks, blockEditor, element ) { 2 2 3 3 var el = element.createElement; 4 var useBlockProps = blockEditor.useBlockProps; 4 5 5 6 const { __ } = wp.i18n; 6 7 const iconEl = el('svg', { preserveAspectRatio: 'xMinYMin meet', viewBox: '0 0 28 28' }, 7 el('path', { fill: '#333', d: "M12.7.8c-2.6.3-5 1.3-7 2.9S2.2 7.5 1.5 10c-.8 2.4-.8 5.1-.2 7.5.7 2.5 2.1 4.7 4 6.4.1.1.2.1.3.2h.3c.1 0 .2 0 .3-.1.1-.1.2-.1.2-.2.1-.1.1-.2.1-.3v-.3c0-.1 0-.2-.1-.3-.1-.1-.1-.2-.2-.2-1.5-1.3-2.6-2.9-3.2-4.8s-.7-3.9-.4-5.8c.3-1.9 1.1-3.7 2.3-5.3s2.8-2.7 4.6-3.5c1.8-.8 3.8-1.1 5.7-.9 1.9.2 3.8.9 5.4 2 1.6 1.1 2.9 2.6 3.8 4.4.9 1.8 1.3 3.7 1.2 5.6-.1 2.3-.9 4.5-2.3 6.3-1.3 1.8-3.2 3.3-5.3 4.1-2.1.8-4.3 1-6.5.5l8-15.1c.1-.2.2-.5.2-.8 0-.1 0-.2-.1-.3 0-.1-.1-.2-.2-.3-.1-.1-.2-.1-.3-.2-.1 0-.2-.1-.4 0h-10c-.2 0-.5.1-.7.2 0 .2 0 .3-.1.4 0 .1-.1.2 0 .3 0 .1 0 .2.1.3 0 .2 0 .3.1.4.2.2.4.2.7.2h8.5L9.6 24.7c-.7 1.1-.3 1.7 1.1 2.1 1.9.5 3.8.5 5.7.2 1.9-.4 3.7-1.1 5.3-2.3 1.6-1.1 2.9-2.6 3.8-4.3s1.5-3.6 1.6-5.5c.1-1.9-.1-3.9-.8-5.7-.7-1.8-1.8-3.4-3.1-4.8s-3-2.4-4.9-3C16.5.9 14.6.6 12.7.8z" } )8 el('path', { fill: '#333', d: "M12.7.8c-2.6.3-5 1.3-7 2.9S2.2 7.5 1.5 10c-.8 2.4-.8 5.1-.2 7.5.7 2.5 2.1 4.7 4 6.4.1.1.2.1.3.2h.3c.1 0 .2 0 .3-.1.1-.1.2-.1.2-.2.1-.1.1-.2.1-.3v-.3c0-.1 0-.2-.1-.3-.1-.1-.1-.2-.2-.2-1.5-1.3-2.6-2.9-3.2-4.8s-.7-3.9-.4-5.8c.3-1.9 1.1-3.7 2.3-5.3s2.8-2.7 4.6-3.5c1.8-.8 3.8-1.1 5.7-.9 1.9.2 3.8.9 5.4 2 1.6 1.1 2.9 2.6 3.8 4.4.9 1.8 1.3 3.7 1.2 5.6-.1 2.3-.9 4.5-2.3 6.3-1.3 1.8-3.2 3.3-5.3 4.1-2.1.8-4.3 1-6.5.5l8-15.1c.1-.2.2-.5.2-.8 0-.1 0-.2-.1-.3 0-.1-.1-.2-.2-.3-.1-.1-.2-.1-.3-.2-.1 0-.2-.1-.4 0h-10c-.2 0-.5.1-.7.2 0 .2 0 .3-.1.4 0 .1-.1.2 0 .3 0 .1 0 .2.1.3 0 .2 0 .3.1.4.2.2.4.2.7.2h8.5L9.6 24.7c-.7 1.1-.3 1.7 1.1 2.1 1.9.5 3.8.5 5.7.2 1.9-.4 3.7-1.1 5.3-2.3 1.6-1.1 2.9-2.6 3.8-4.3s1.5-3.6 1.6-5.5c.1-1.9-.1-3.9-.8-5.7-.7-1.8-1.8-3.4-3.1-4.8s-3-2.4-4.9-3C16.5.9 14.6.6 12.7.8z" } ) 8 9 ); 9 10 10 blocks.registerBlockType( 'c7wp/default', {11 title: __( 'Default Content' ), // The title of block in editor.12 description: __( 'Placeholder for dynamic Commerce7 content on base routes. Required on product, club, collection, reservation, cart, and checkout pages.' ),13 icon: iconEl,14 category: 'commerce7', // The category of block in editor.11 blocks.registerBlockType( 'c7wp/default', { 12 title: __( 'Default Content', 'wp-commerce7' ), 13 description: __( 'Placeholder for dynamic Commerce7 content on base routes. Required on product, club, collection, reservation, cart, and checkout pages.', 'wp-commerce7' ), 14 icon: iconEl, 15 category: 'commerce7', 15 16 keywords: [ 'commerce7', 'default' ], 16 17 example: {}, 17 attributes: {}, 18 edit: function( props ) { 18 attributes: {}, 19 supports: { 20 html: false, 21 customClassName: false, 22 }, 23 edit: function( props ) { 24 var blockProps = useBlockProps(); 19 25 20 return ( 21 el( 'div', { 22 className: 'components-placeholder ' + props.className 23 }, 24 el( 'div', { 25 id: 'c7-content' 26 }, 27 el( 28 'strong', 29 null, 30 'Default Content. This block will automatically populate with content on a default route.' 31 ), 26 return el( 'div', blockProps, 27 el( 'div', { 28 id: 'c7-content' 29 }, 30 el( 'h2', null, 31 __( 'Default dynamic content for Commerce7.', 'wp-commerce7' ) 32 ), 33 el( 'p', null, 34 __( 'This block will automatically populate with content on a default route such as product, club, collection, reservation, cart, or checkout.', 'wp-commerce7' ) 32 35 ) 33 36 ) 34 37 ); 35 }, 36 save: function( props ) { 37 return ( 38 }, 39 save: function( props ) { 40 var blockProps = useBlockProps.save(); 41 42 return el( 'div', blockProps, 38 43 el( 'div', { 39 className: props.className 44 id: 'c7-content' 45 }) 46 ); 47 }, 48 // Deprecated version to handle old blocks without proper className 49 deprecated: [ 50 { 51 attributes: {}, 52 save: function( props ) { 53 // Old save function that didn't use useBlockProps 54 return el( 'div', { 55 className: props.className 40 56 }, 41 el( 'div', {42 id: 'c7-content'43 } 44 ) 45 )46 );47 }, 48 } );49 } )( window.wp.blocks, window.wp. editor, window.wp.element );57 el( 'div', { 58 id: 'c7-content' 59 }) 60 ); 61 } 62 } 63 ] 64 } ); 65 } )( window.wp.blocks, window.wp.blockEditor, window.wp.element ); -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/form/c7wp-form.css
r3009702 r3441297 12 12 pointer-events: none; 13 13 } 14 15 16 17 .c7wp-justify-center { 18 .c7-custom-form { 19 .c7-form { 20 margin-left: auto; 21 margin-right: auto; 22 } 23 .c7-custom-form { 24 justify-content: center; 25 } 26 } 27 } 28 29 .c7wp-justify-right { 30 .c7-custom-form { 31 .c7-form { 32 margin-right: 0; 33 margin-left: auto; 34 } 35 .c7-custom-form { 36 justify-content: flex-end; 37 } 38 } 39 } 40 41 .c7wp-justify-left { 42 .c7-custom-form { 43 margin-left: 0; 44 .c7-form { 45 margin-right: auto; 46 margin-left: 0; 47 } 48 } 49 } -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/form/c7wp-form.js
r3343231 r3441297 3 3 const { registerBlockType } = blocks; 4 4 const { InspectorControls } = blockEditor; 5 const { TextControl, PanelBody } = components;5 const { TextControl, PanelBody, SelectControl } = components; 6 6 const { createElement } = element; 7 7 const { __ } = i18n; 8 8 9 9 const iconEl = createElement('svg', { preserveAspectRatio: 'xMinYMin meet', viewBox: '0 0 28 28' }, 10 createElement('path', { fill: '#333', d: "M12.7.8c-2.6.3-5 1.3-7 2.9S2.2 7.5 1.5 10c-.8 2.4-.8 5.1-.2 7.5.7 2.5 2.1 4.7 4 6.4.1.1.2.1.3.2h.3c.1 0 .2 0 .3-.1.1-.1.2-.1.2-.2.1-.1.1-.2.1-.3v-.3c0-.1 0-.2-.1-.3-.1-.1-.1-.2-.2-.2-1.5-1.3-2.6-2.9-3.2-4.8s-.7-3.9-.4-5.8c.3-1.9 1.1-3.7 2.3-5.3s2.8-2.7 4.6-3.5c1.8-.8 3.8-1.1 5.7-.9 1.9.2 3.8.9 5.4 2 1.6 1.1 2.9 2.6 3.8 4.4.9 1.8 1.3 3.7 1.2 5.6-.1 2.3-.9 4.5-2.3 6.3-1.3 1.8-3.2 3.3-5.3 4.1-2.1.8-4.3 1-6.5.5l8-15.1c.1-.2.2-.5.2-.8 0-.1 0-.2-.1-.3 0-.1-.1-.2-.2-.3-.1-.1-.2-.1-.3-.2-.1 0-.2-.1-.4 0h-10c-.2 0-.5.1-.7.2 0 .2 0 .3-.1.4 0 .1-.1.2 0 .3 0 .1 0 .2.1.3 0 .2 0 .3.1.4.2.2.4.2.7.2h8.5L9.6 24.7c-.7 1.1-.3 1.7 1.1 2.1 1.9.5 3.8.5 5.7.2 1.9-.4 3.7-1.1 5.3-2.3 1.6-1.1 2.9-2.6 3.8-4.3s1.5-3.6 1.6-5.5c.1-1.9-.1-3.9-.8-5.7-.7-1.8-1.8-3.4-3.1-4.8s-3-2.4-4.9-3C16.5.9 14.6.6 12.7.8z" })10 createElement('path', { fill: '#333', d: "M12.7.8c-2.6.3-5 1.3-7 2.9S2.2 7.5 1.5 10c-.8 2.4-.8 5.1-.2 7.5.7 2.5 2.1 4.7 4 6.4.1.1.2.1.3.2h.3c.1 0 .2 0 .3-.1.1-.1.2-.1.2-.2.1-.1.1-.2.1-.3v-.3c0-.1 0-.2-.1-.3-.1-.1-.1-.2-.2-.2-1.5-1.3-2.6-2.9-3.2-4.8s-.7-3.9-.4-5.8c.3-1.9 1.1-3.7 2.3-5.3s2.8-2.7 4.6-3.5c1.8-.8 3.8-1.1 5.7-.9 1.9.2 3.8.9 5.4 2 1.6 1.1 2.9 2.6 3.8 4.4.9 1.8 1.3 3.7 1.2 5.6-.1 2.3-.9 4.5-2.3 6.3-1.3 1.8-3.2 3.3-5.3 4.1-2.1.8-4.3 1-6.5.5l8-15.1c.1-.2.2-.5.2-.8 0-.1 0-.2-.1-.3 0-.1-.1-.2-.2-.3-.1-.1-.2-.1-.3-.2-.1 0-.2-.1-.4 0h-10c-.2 0-.5.1-.7.2 0 .2 0 .3-.1.4 0 .1-.1.2 0 .3 0 .1 0 .2.1.3 0 .2 0 .3.1.4.2.2.4.2.7.2h8.5L9.6 24.7c-.7 1.1-.3 1.7 1.1 2.1 1.9.5 3.8.5 5.7.2 1.9-.4 3.7-1.1 5.3-2.3 1.6-1.1 2.9-2.6 3.8-4.3s1.5-3.6 1.6-5.5c.1-1.9-.1-3.9-.8-5.7-.7-1.8-1.8-3.4-3.1-4.8s-3-2.4-4.9-3C16.5.9 14.6.6 12.7.8z" }) 11 11 ); 12 12 13 registerBlockType('c7wp/form', {14 title: __( 'Custom Form'), // The title of block in editor.15 description: __( 'Displays a Commerce7 custom form. These can be built in the Website tab of the Commerce7 CRM.'),16 icon: iconEl,13 registerBlockType('c7wp/form', { 14 title: __('Custom Form'), // The title of block in editor. 15 description: __('Displays a Commerce7 custom form. These can be built in the Website tab of the Commerce7 CRM.'), 16 icon: iconEl, 17 17 category: 'commerce7', // The category of block in editor. 18 keywords: [ 'commerce7', 'form', 'custom', 'custom form','contact'],18 keywords: ['commerce7', 'form', 'custom', 'custom form', 'contact'], 19 19 example: {}, 20 attributes: {20 attributes: { 21 21 data: { 22 22 type: 'string', … … 24 24 selector: '.c7-custom-form', 25 25 attribute: 'data-form-code', 26 }, 27 justifyContent: { 28 type: 'string', 29 default: 'center', 26 30 } 27 31 }, 28 edit: function( props) {32 edit: function (props) { 29 33 30 34 function updateData(value) { 31 35 props.setAttributes({ data: value }); 36 } 37 38 function updateJustifyContent(value) { 39 props.setAttributes({ justifyContent: value }); 40 } 41 42 function getAlignmentClass(justifyContent) { 43 const alignmentMap = { 44 'flex-start': 'c7wp-justify-left', 45 'center': 'c7wp-justify-center', 46 'flex-end': 'c7wp-justify-right' 47 }; 48 return alignmentMap[justifyContent] || 'c7wp-justify-center'; 32 49 } 33 50 … … 49 66 value: props.attributes.data, 50 67 onChange: updateData, 68 }), 69 createElement(SelectControl, { 70 label: 'Form Alignment', 71 value: props.attributes.justifyContent || 'center', 72 options: [ 73 { label: 'Left', value: 'flex-start' }, 74 { label: 'Center', value: 'center' }, 75 { label: 'Right', value: 'flex-end' } 76 ], 77 onChange: updateJustifyContent, 51 78 }) 52 79 ), 53 80 ), 54 createElement( 'div', {55 className: props.className56 },57 createElement( 'div', {81 createElement('div', { 82 className: [props.className, getAlignmentClass(props.attributes.justifyContent)].filter(Boolean).join(' ') 83 }, 84 createElement('div', { 58 85 className: 'c7-custom-form', 59 86 'data-form-code': props.attributes.data, 60 },61 slugProvided && createElement( 'form', {87 }, 88 slugProvided && createElement('form', { 62 89 className: 'c7-form' 63 90 }, 64 createElement( 'fieldset', null,65 createElement( 'legend', { className: 'c7-sr-only' }, 'Contact Us'),66 createElement( 'div', { className: 'c7-form__field' },67 createElement( 'label', { className: 'c7-required' }, 'First & Last Name'),68 createElement( 'input', {91 createElement('fieldset', null, 92 createElement('legend', { className: 'c7-sr-only' }, 'Contact Us'), 93 createElement('div', { className: 'c7-form__field' }, 94 createElement('label', { className: 'c7-required' }, 'First & Last Name'), 95 createElement('input', { 69 96 name: 'fullName', 70 97 type: 'text', … … 74 101 }) 75 102 ), 76 createElement( 'div', { className: 'c7-form__field' },77 createElement( 'label', { className: 'c7-required' }, 'Country'),78 createElement( 'select', {103 createElement('div', { className: 'c7-form__field' }, 104 createElement('label', { className: 'c7-required' }, 'Country'), 105 createElement('select', { 79 106 name: 'countryCode', 80 107 disabled: true, 81 108 tabIndex: "-1" 82 109 }, 83 createElement( 'option', { value: 'CA' }, 'Canada'),84 createElement( 'option', { value: 'US' }, 'United States')110 createElement('option', { value: 'CA' }, 'Canada'), 111 createElement('option', { value: 'US' }, 'United States') 85 112 ) 86 113 ), 87 createElement( 'div', { className: 'c7-form__field' },88 createElement( 'label', { className: '' }, 'Phone'),89 createElement( 'input', {114 createElement('div', { className: 'c7-form__field' }, 115 createElement('label', { className: '' }, 'Phone'), 116 createElement('input', { 90 117 name: 'phone', 91 118 type: 'tel', … … 95 122 }) 96 123 ), 97 createElement( 'div', { className: 'c7-form__field' },98 createElement( 'label', { className: 'c7-required' }, 'Email'),99 createElement( 'input', {124 createElement('div', { className: 'c7-form__field' }, 125 createElement('label', { className: 'c7-required' }, 'Email'), 126 createElement('input', { 100 127 name: 'email', 101 128 type: 'email', … … 105 132 }) 106 133 ), 107 createElement( 'div', { className: 'c7-form__field' },108 createElement( 'label', { className: 'c7-required' }, 'Questions/Comments'),109 createElement( 'textarea', {134 createElement('div', { className: 'c7-form__field' }, 135 createElement('label', { className: 'c7-required' }, 'Questions/Comments'), 136 createElement('textarea', { 110 137 name: 'questions-comments', 111 138 rows: '3', … … 115 142 ) 116 143 ), 117 createElement( 'div', { className: 'c7-form__buttons' },118 createElement( 'button', {119 type: 'submit', 120 className: 'c7-btn c7-btn--primary' ,144 createElement('div', { className: 'c7-form__buttons' }, 145 createElement('button', { 146 type: 'submit', 147 className: 'c7-btn c7-btn--primary', 121 148 disabled: true, 122 149 tabIndex: "-1" 123 }, createElement( 'span', null, 'Submit'))150 }, createElement('span', null, 'Submit')) 124 151 ) 125 152 ), … … 143 170 createElement('line', { x1: '12', y1: '16', x2: '12.01', y2: '16' }) 144 171 ), 145 'Please enter a form slug in the block settings (generally in your right sidebar)'172 'Please enter a form slug in the block settings (generally in your right sidebar)' 146 173 ) 147 174 ) 148 175 ) 149 176 ]; 150 }, 151 save: function( props ) { 177 }, 178 deprecated: [ 179 { 180 attributes: { 181 data: { 182 type: 'string', 183 source: 'attribute', 184 selector: '.c7-custom-form', 185 attribute: 'data-form-code', 186 } 187 }, 188 save: function (props) { 189 return ( 190 createElement('div', { 191 className: props.className 192 }, 193 createElement('div', { 194 className: 'c7-custom-form', 195 'data-form-code': props.attributes.data, 196 }) 197 ) 198 ); 199 } 200 } 201 ], 202 save: function (props) { 203 function getAlignmentClass(justifyContent) { 204 const alignmentMap = { 205 'flex-start': 'c7wp-justify-left', 206 'center': 'c7wp-justify-center', 207 'flex-end': 'c7wp-justify-right' 208 }; 209 return alignmentMap[justifyContent] || 'c7wp-justify-center'; 210 } 211 152 212 return ( 153 createElement( 'div', {154 className: props.className155 },156 createElement( 'div', {213 createElement('div', { 214 className: [props.className, getAlignmentClass(props.attributes.justifyContent)].filter(Boolean).join(' ') 215 }, 216 createElement('div', { 157 217 className: 'c7-custom-form', 158 218 'data-form-code': props.attributes.data, 159 }219 } 160 220 ) 161 221 ) 162 222 ); 163 },164 });223 }, 224 }); 165 225 })(window.wp.blocks, window.wp.blockEditor, window.wp.element, window.wp.i18n, window.wp.components); -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/joinnow/c7wp-joinnow.css
r3009702 r3441297 12 12 pointer-events: none; 13 13 } 14 -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/loginform/c7wp-loginform.css
r3009702 r3441297 9 9 pointer-events: none; 10 10 } 11 -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/personalization/c7wp-personalization.css
r3009702 r3441297 2 2 overflow: hidden; 3 3 z-index: 1; 4 border: 1px solid currentColor; 5 padding: 1rem; 4 6 } 5 7 .wp-block-c7wp-personalization > div { … … 14 16 max-height: 100%; 15 17 position: absolute; 16 top: 0;17 right: 0;18 top: 1rem; 19 right: 1rem; 18 20 background-image: url('../../../../assets/c7bg.svg'); 19 21 background-size: contain; 20 22 background-repeat: no-repeat; 21 23 background-position: center right; 22 opacity: 0.0 5;24 opacity: 0.08; 23 25 pointer-events: none; 24 26 z-index: -1; -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/personalization/c7wp-personalization.js
r3343231 r3441297 2 2 3 3 const { registerBlockType } = blocks; 4 const { InspectorControls } = blockEditor;4 const { InspectorControls, useBlockProps } = blockEditor; // ADD useBlockProps here 5 5 const { TextControl, PanelBody } = components; 6 6 const { createElement } = element; … … 11 11 ); 12 12 13 registerBlockType( 'c7wp/personalization', {14 title: __( 'Personalization Block' ), // The title of block in editor.15 description: __( 'Displays a Commerce7 personalization block. These are created in the Developer section inside Commerce7 and can be edited in the Website tab.' ),16 icon: iconEl,17 category: 'commerce7', // The category of block in editor.13 registerBlockType( 'c7wp/personalization', { 14 title: __( 'Personalization Block', 'wp-commerce7' ), 15 description: __( 'Displays a Commerce7 personalization block. These are created in the Developer section inside Commerce7 and can be edited in the Website tab.', 'wp-commerce7' ), 16 icon: iconEl, 17 category: 'commerce7', 18 18 keywords: [ 'commerce7', 'personalization', 'personal' ], 19 19 example: {}, 20 attributes: {20 attributes: { 21 21 data: { 22 22 type: 'string', … … 26 26 } 27 27 }, 28 edit: function( props ) { 28 supports: { 29 html: false, 30 customClassName: false, 31 }, 32 edit: function( props ) { 33 const blockProps = useBlockProps(); // Move inside edit function 29 34 30 35 function updateData(value) { … … 44 49 createElement('small', 45 50 null, 46 'The preview shown in your editor is for example purposes only , it does not reflect the personalization block code you provide nor is it interactive.'51 'The preview shown in your editor is for example purposes only.' 47 52 ) 48 53 ), … … 55 60 ), 56 61 ), 57 slugProvided && createElement( 'div', { 58 className: 'components-placeholder ' + props.className 59 }, 62 slugProvided && createElement( 'div', blockProps, // Use blockProps 60 63 createElement( 'div', { 61 64 className: 'c7-personalization', 62 65 'data-block-code': props.attributes.data, 63 66 }, 64 // todo: insert sample html here 65 createElement( 'div', { style: { 66 textAlign: 'center', 67 } }, 67 createElement( 'div', null, // Add style wrapper 68 68 createElement( 'h2', null, "Commerce7 Personalization" ), 69 createElement( 'p', null, props.attributes.data )69 createElement( 'p', null, "Personalization block code: " + props.attributes.data ) 70 70 ), 71 71 ) 72 72 ), 73 !slugProvided && createElement('div', { className: 'c7-message c7-message--alert-error', role: 'presentation' }, 73 !slugProvided && createElement('div', { 74 ...blockProps, // Spread blockProps 75 className: blockProps.className + ' c7-message c7-message--alert-error', 76 role: 'presentation' 77 }, 74 78 createElement('svg', { 75 79 'aria-hidden': 'true', … … 93 97 ) 94 98 ]; 95 }, 96 save: function( props ) { 99 }, 100 save: function( props ) { 101 const blockProps = useBlockProps.save(); // Move inside save function 97 102 return ( 98 createElement( 'div', { 99 className: props.className 100 }, 103 createElement( 'div', blockProps, // Use blockProps 101 104 createElement( 'div', { 102 105 className: 'c7-personalization', … … 106 109 ) 107 110 ); 108 }, 109 } ); 111 }, 112 // Deprecated version to handle old blocks without proper className 113 deprecated: [ 114 { 115 attributes: { 116 data: { 117 type: 'string', 118 source: 'attribute', 119 selector: '.c7-personalization', 120 attribute: 'data-block-code', 121 } 122 }, 123 save: function( props ) { 124 return ( 125 createElement( 'div', { 126 className: props.className 127 }, 128 createElement( 'div', { 129 className: 'c7-personalization', 130 'data-block-code': props.attributes.data, 131 } 132 ) 133 ) 134 ); 135 } 136 } 137 ] 138 } ); 110 139 })(window.wp.blocks, window.wp.blockEditor, window.wp.element, window.wp.i18n, window.wp.components); -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/reservation/c7wp-reservation.css
r3009702 r3441297 12 12 pointer-events: none; 13 13 } 14 15 16 .c7wp-justify-center { 17 .c7-reservation__search { 18 .c7-form__group { 19 justify-content: center; 20 } 21 } 22 } 23 24 .c7wp-justify-right { 25 .c7-reservation__search { 26 margin-right: 0; 27 .c7-form__group { 28 justify-content: flex-end; 29 } 30 } 31 } 32 33 .c7wp-justify-left { 34 .c7-reservation__search { 35 margin-left: 0; 36 .c7-form__group { 37 justify-content: flex-start; 38 } 39 } 40 } -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/reservation/c7wp-reservation.js
r3167363 r3441297 3 3 const { registerBlockType } = blocks; 4 4 const { InspectorControls } = blockEditor; 5 const { TextControl, PanelBody } = components;5 const { TextControl, PanelBody, SelectControl } = components; 6 6 const { createElement } = element; 7 7 const { __ } = i18n; … … 24 24 selector: '.c7-reservation-availability', 25 25 attribute: 'data-reservation-type-slug', 26 }, 27 justifyContent: { 28 type: 'string', 29 default: 'center', 26 30 } 27 31 }, … … 30 34 function updateData(value) { 31 35 props.setAttributes({ data: value }); 36 } 37 38 function updateJustifyContent(value) { 39 props.setAttributes({ justifyContent: value }); 40 } 41 42 function getAlignmentClass(justifyContent) { 43 const alignmentMap = { 44 'flex-start': 'c7wp-justify-left', 45 'center': 'c7wp-justify-center', 46 'flex-end': 'c7wp-justify-right' 47 }; 48 return alignmentMap[justifyContent] || 'c7wp-justify-center'; 32 49 } 33 50 … … 49 66 value: props.attributes.data, 50 67 onChange: updateData, 68 }), 69 createElement(SelectControl, { 70 label: 'Form Alignment', 71 value: props.attributes.justifyContent || 'center', 72 options: [ 73 { label: 'Left', value: 'flex-start' }, 74 { label: 'Center', value: 'center' }, 75 { label: 'Right', value: 'flex-end' } 76 ], 77 onChange: updateJustifyContent, 51 78 }) 52 79 ), 53 80 ), 54 createElement('div', { className: props.className }, 81 createElement('div', { 82 className: [props.className, getAlignmentClass(props.attributes.justifyContent)].filter(Boolean).join(' ') 83 }, 55 84 createElement('div', { 56 85 className: 'c7-reservation-availability', … … 133 162 ]; 134 163 }, 164 deprecated: [ 165 { 166 attributes: { 167 data: { 168 type: 'string', 169 source: 'attribute', 170 selector: '.c7-reservation-availability', 171 attribute: 'data-reservation-type-slug', 172 } 173 }, 174 save: function (props) { 175 return ( 176 createElement('div', { 177 className: props.className 178 }, 179 createElement('div', { 180 className: 'c7-reservation-availability', 181 'data-reservation-type-slug': props.attributes.data, 182 } 183 ) 184 ) 185 ); 186 } 187 } 188 ], 135 189 save: function (props) { 190 function getAlignmentClass(justifyContent) { 191 const alignmentMap = { 192 'flex-start': 'c7wp-justify-left', 193 'center': 'c7wp-justify-center', 194 'flex-end': 'c7wp-justify-right' 195 }; 196 return alignmentMap[justifyContent] || 'c7wp-justify-center'; 197 } 198 136 199 return ( 137 200 createElement('div', { 138 className: props.className201 className: [props.className, getAlignmentClass(props.attributes.justifyContent)].filter(Boolean).join(' ') 139 202 }, 140 203 createElement('div', { -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/subscribe/c7wp-subscribe.css
r3009702 r3441297 9 9 pointer-events: none; 10 10 } 11 12 .c7wp-justify-center { 13 .c7-subscribe { 14 .c7-form { 15 margin-left: auto; 16 margin-right: auto; 17 } 18 } 19 } 20 21 .c7wp-justify-right { 22 .c7-subscribe { 23 .c7-form { 24 margin-right: 0; 25 margin-left: auto; 26 } 27 } 28 } 29 30 .c7wp-justify-left { 31 .c7-subscribe { 32 margin-left: 0; 33 .c7-form { 34 margin-right: auto; 35 margin-left: 0; 36 } 37 } 38 } -
wp-commerce7/trunk/includes/gutenberg/blocks-v2/subscribe/c7wp-subscribe.js
r3009702 r3441297 3 3 const { registerBlockType } = blocks; 4 4 const { InspectorControls } = blockEditor; 5 const { PanelBody, RadioControl } = components;5 const { PanelBody, RadioControl, SelectControl } = components; 6 6 const { createElement } = element; 7 7 const { __ } = i18n; 8 8 9 9 const iconEl = createElement('svg', { preserveAspectRatio: 'xMinYMin meet', viewBox: '0 0 28 28' }, 10 createElement('path', { fill: '#333', d: "M12.7.8c-2.6.3-5 1.3-7 2.9S2.2 7.5 1.5 10c-.8 2.4-.8 5.1-.2 7.5.7 2.5 2.1 4.7 4 6.4.1.1.2.1.3.2h.3c.1 0 .2 0 .3-.1.1-.1.2-.1.2-.2.1-.1.1-.2.1-.3v-.3c0-.1 0-.2-.1-.3-.1-.1-.1-.2-.2-.2-1.5-1.3-2.6-2.9-3.2-4.8s-.7-3.9-.4-5.8c.3-1.9 1.1-3.7 2.3-5.3s2.8-2.7 4.6-3.5c1.8-.8 3.8-1.1 5.7-.9 1.9.2 3.8.9 5.4 2 1.6 1.1 2.9 2.6 3.8 4.4.9 1.8 1.3 3.7 1.2 5.6-.1 2.3-.9 4.5-2.3 6.3-1.3 1.8-3.2 3.3-5.3 4.1-2.1.8-4.3 1-6.5.5l8-15.1c.1-.2.2-.5.2-.8 0-.1 0-.2-.1-.3 0-.1-.1-.2-.2-.3-.1-.1-.2-.1-.3-.2-.1 0-.2-.1-.4 0h-10c-.2 0-.5.1-.7.2 0 .2 0 .3-.1.4 0 .1-.1.2 0 .3 0 .1 0 .2.1.3 0 .2 0 .3.1.4.2.2.4.2.7.2h8.5L9.6 24.7c-.7 1.1-.3 1.7 1.1 2.1 1.9.5 3.8.5 5.7.2 1.9-.4 3.7-1.1 5.3-2.3 1.6-1.1 2.9-2.6 3.8-4.3s1.5-3.6 1.6-5.5c.1-1.9-.1-3.9-.8-5.7-.7-1.8-1.8-3.4-3.1-4.8s-3-2.4-4.9-3C16.5.9 14.6.6 12.7.8z" })10 createElement('path', { fill: '#333', d: "M12.7.8c-2.6.3-5 1.3-7 2.9S2.2 7.5 1.5 10c-.8 2.4-.8 5.1-.2 7.5.7 2.5 2.1 4.7 4 6.4.1.1.2.1.3.2h.3c.1 0 .2 0 .3-.1.1-.1.2-.1.2-.2.1-.1.1-.2.1-.3v-.3c0-.1 0-.2-.1-.3-.1-.1-.1-.2-.2-.2-1.5-1.3-2.6-2.9-3.2-4.8s-.7-3.9-.4-5.8c.3-1.9 1.1-3.7 2.3-5.3s2.8-2.7 4.6-3.5c1.8-.8 3.8-1.1 5.7-.9 1.9.2 3.8.9 5.4 2 1.6 1.1 2.9 2.6 3.8 4.4.9 1.8 1.3 3.7 1.2 5.6-.1 2.3-.9 4.5-2.3 6.3-1.3 1.8-3.2 3.3-5.3 4.1-2.1.8-4.3 1-6.5.5l8-15.1c.1-.2.2-.5.2-.8 0-.1 0-.2-.1-.3 0-.1-.1-.2-.2-.3-.1-.1-.2-.1-.3-.2-.1 0-.2-.1-.4 0h-10c-.2 0-.5.1-.7.2 0 .2 0 .3-.1.4 0 .1-.1.2 0 .3 0 .1 0 .2.1.3 0 .2 0 .3.1.4.2.2.4.2.7.2h8.5L9.6 24.7c-.7 1.1-.3 1.7 1.1 2.1 1.9.5 3.8.5 5.7.2 1.9-.4 3.7-1.1 5.3-2.3 1.6-1.1 2.9-2.6 3.8-4.3s1.5-3.6 1.6-5.5c.1-1.9-.1-3.9-.8-5.7-.7-1.8-1.8-3.4-3.1-4.8s-3-2.4-4.9-3C16.5.9 14.6.6 12.7.8z" }) 11 11 ); 12 12 13 registerBlockType('c7wp/subscribe', {14 title: __( 'Subscribe Form'), // The title of block in editor.15 description: __( 'Displays a Commerce7 email subscription form with optional name field.'),16 icon: iconEl,13 registerBlockType('c7wp/subscribe', { 14 title: __('Subscribe Form'), // The title of block in editor. 15 description: __('Displays a Commerce7 email subscription form with optional name field.'), 16 icon: iconEl, 17 17 category: 'commerce7', // The category of block in editor. 18 keywords: [ 'commerce7', 'subscribe', 'personal', 'newsletter'],18 keywords: ['commerce7', 'subscribe', 'personal', 'newsletter'], 19 19 example: {}, 20 attributes: {20 attributes: { 21 21 nameFields: { 22 22 type: 'string', … … 25 25 attribute: 'data-has-name-field', 26 26 default: 'false' 27 }, 28 justifyContent: { 29 type: 'string', 30 default: 'center', 27 31 } 28 32 }, 29 edit: function( props) {33 edit: function (props) { 30 34 31 const updateData = function ( value) {32 return props.setAttributes( {35 const updateData = function (value) { 36 return props.setAttributes({ 33 37 nameFields: value, 34 } ); 38 }); 39 } 40 41 const updateJustifyContent = function (value) { 42 return props.setAttributes({ 43 justifyContent: value, 44 }); 45 } 46 47 function getAlignmentClass(justifyContent) { 48 const alignmentMap = { 49 'flex-start': 'c7wp-justify-left', 50 'center': 'c7wp-justify-center', 51 'flex-end': 'c7wp-justify-right' 52 }; 53 return alignmentMap[justifyContent] || 'c7wp-justify-center'; 35 54 } 36 55 … … 52 71 }], 53 72 onChange: updateData, 73 }), 74 createElement(SelectControl, { 75 label: 'Form Alignment', 76 value: props.attributes.justifyContent || 'center', 77 options: [ 78 { label: 'Left', value: 'flex-start' }, 79 { label: 'Center', value: 'center' }, 80 { label: 'Right', value: 'flex-end' } 81 ], 82 onChange: updateJustifyContent, 54 83 }) 55 84 ), 56 85 ), 57 createElement( 'div', { 58 className: props.className 86 createElement('div', { 87 className: [props.className, getAlignmentClass(props.attributes.justifyContent)].filter(Boolean).join(' ') 88 }, 89 createElement('div', { 90 className: 'c7-subscribe', 59 91 }, 60 createElement( 'div', {61 className: 'c7-subscribe',92 createElement('form', { 93 className: 'c7-form' 62 94 }, 63 createElement( 'form', {64 className: 'c7-form'95 createElement('div', { 96 className: 'c7-form__group' 65 97 }, 66 createElement( 'div', {67 className: 'c7-form__group'98 showNameField && createElement('div', { 99 className: 'c7-form__field' 68 100 }, 69 showNameField && createElement( 'div', { 70 className: 'c7-form__field' 71 }, 72 createElement( 'label', { className: 'c7-required' }, 'First & Last Name' ), 73 createElement( 'input', { 101 createElement('label', { className: 'c7-required' }, 'First & Last Name'), 102 createElement('input', { 74 103 name: 'fullName', 75 104 type: 'text', 76 105 tabindex: '-1', 77 106 disabled: true, 78 value: '' 107 value: '' 79 108 }) 80 109 ), 81 createElement( 'div', {110 createElement('div', { 82 111 className: 'c7-form__field' 83 },84 createElement( 'label', { className: 'c7-required' }, 'Email'),85 createElement( 'input', {112 }, 113 createElement('label', { className: 'c7-required' }, 'Email'), 114 createElement('input', { 86 115 name: 'email', 87 116 type: 'email', 88 117 tabindex: '-1', 89 118 disabled: true, 90 value: '' 119 value: '' 91 120 }) 92 121 ), 93 createElement( 'button', {122 createElement('button', { 94 123 type: 'submit', 95 124 tabindex: '-1', 96 125 disabled: true, 97 126 className: 'c7-btn c7-btn--primary' 98 },99 createElement( 'span', null, 'Subscribe')127 }, 128 createElement('span', null, 'Subscribe') 100 129 ) 101 130 ) … … 104 133 ) 105 134 ]; 106 }, 107 save: function( props ) { 135 }, 136 deprecated: [ 137 { 138 attributes: { 139 nameFields: { 140 type: 'string', 141 source: 'attribute', 142 selector: '.c7-subscribe', 143 attribute: 'data-has-name-field', 144 default: 'false' 145 } 146 }, 147 save: function (props) { 148 return ( 149 createElement('div', { 150 className: props.className 151 }, 152 createElement('div', { 153 className: 'c7-subscribe', 154 'data-has-name-field': props.attributes.nameFields, 155 }) 156 ) 157 ); 158 } 159 } 160 ], 161 save: function (props) { 162 function getAlignmentClass(justifyContent) { 163 const alignmentMap = { 164 'flex-start': 'c7wp-justify-left', 165 'center': 'c7wp-justify-center', 166 'flex-end': 'c7wp-justify-right' 167 }; 168 return alignmentMap[justifyContent] || 'c7wp-justify-center'; 169 } 170 108 171 return ( 109 createElement( 'div', {110 className: props.className111 },112 createElement( 'div', {172 createElement('div', { 173 className: [props.className, getAlignmentClass(props.attributes.justifyContent)].filter(Boolean).join(' ') 174 }, 175 createElement('div', { 113 176 className: 'c7-subscribe', 114 177 'data-has-name-field': props.attributes.nameFields, 115 }178 } 116 179 ) 117 180 ) 118 181 ); 119 },120 });182 }, 183 }); 121 184 })(window.wp.blocks, window.wp.blockEditor, window.wp.element, window.wp.i18n, window.wp.components); -
wp-commerce7/trunk/includes/gutenberg/load.php
r3343231 r3441297 6 6 * Author: Michael Bourne 7 7 * ----- 8 * Last Modified: Thursday, August 7th 2025, 9:42:01pm8 * Last Modified: Friday, December 12th 2025, 1:10:02 pm 9 9 * Modified By: Michael Bourne 10 10 * ----- … … 20 20 // Check if Gutenberg is active. 21 21 if ( ! function_exists( 'register_block_type' ) ) { 22 return;22 return; 23 23 } 24 24 25 // Load validation helper 26 require_once C7WP_ROOT . '/includes/class-c7wp-validation.php'; 27 25 28 if ( in_array( $this->widgetsver, array( 'v2', 'v2-compat' ) ) ) { 26 $elements = array(27 'default',28 'personalization',29 'buyslug',30 'subscribe',31 'collection',32 'reservation',33 'form',34 'joinnow',35 'loginform',36 'clubselector',37 'collectionlist',38 );39 $dir= 'blocks-v2';29 $elements = array( 30 'default', 31 'personalization', 32 'buyslug', 33 'subscribe', 34 'collection', 35 'reservation', 36 'form', 37 'joinnow', 38 'loginform', 39 'clubselector', 40 'collectionlist', 41 ); 42 $dir = 'blocks-v2'; 40 43 } else { 41 $elements = array(42 'default',43 'personalization',44 'buy',45 'buyslug',46 'subscribe',47 'collection',48 'reservation',49 'form',50 'joinnow',51 'quickshop',52 'loginform',53 'createaccount',54 );55 $dir= 'blocks';44 $elements = array( 45 'default', 46 'personalization', 47 'buy', 48 'buyslug', 49 'subscribe', 50 'collection', 51 'reservation', 52 'form', 53 'joinnow', 54 'quickshop', 55 'loginform', 56 'createaccount', 57 ); 58 $dir = 'blocks'; 56 59 } 57 60 58 61 foreach ( $elements as $element ) { 62 $block_slug = 'c7wp-' . $element; 59 63 60 $block_slug = 'c7wp-' . $element; 61 // Add block script. 62 wp_register_script( 63 $block_slug, 64 plugins_url( $dir . '/' . $element . '/' . $block_slug . '.js', __FILE__ ), 65 array( 'wp-blocks', 'wp-element' ), 66 C7WP_VERSION, 67 1 68 ); 64 // Check if block.json exists (new format) 65 $block_json_path = C7WP_ROOT . '/includes/gutenberg/' . $dir . '/' . $element . '/block.json'; 66 if ( file_exists( $block_json_path ) ) { 67 // Register block using block.json metadata 68 register_block_type_from_metadata( $block_json_path ); 69 } else { 70 // Fallback to old registration method 71 // Add block script. 72 wp_register_script( 73 $block_slug, 74 plugins_url( $dir . '/' . $element . '/' . $block_slug . '.js', __FILE__ ), 75 array( 'wp-blocks', 'wp-element' ), 76 C7WP_VERSION, 77 1 78 ); 69 79 70 // Add block style.71 wp_register_style(72 $block_slug,73 plugins_url( $dir . '/' . $element . '/' . $block_slug . '.css', __FILE__ ),74 array(),75 C7WP_VERSION76 );80 // Add block style. 81 wp_register_style( 82 $block_slug, 83 plugins_url( $dir . '/' . $element . '/' . $block_slug . '.css', __FILE__ ), 84 array(), 85 C7WP_VERSION 86 ); 77 87 78 // Register block script and style. 79 register_block_type( 'c7wp/' . $element, array( 80 'editor_style' => $block_slug, // Loads both on editor. 81 'editor_script' => $block_slug, // Loads only on editor. 82 ) ); 88 // Register block script and style. 89 register_block_type( 90 'c7wp/' . $element, 91 array( 92 'editor_style' => $block_slug, // Loads both on editor. 93 'editor_script' => $block_slug, // Loads only on editor. 94 ) 95 ); 96 } 83 97 84 // Check for and load frontend assets85 $frontend_js_path= $dir . '/' . $element . '/frontend.js';86 $frontend_css_path = $dir . '/' . $element . '/frontend.css';98 // Check for and load frontend assets 99 $frontend_js_path = $dir . '/' . $element . '/frontend.js'; 100 $frontend_css_path = $dir . '/' . $element . '/frontend.css'; 87 101 88 // Register and enqueue frontend script if it exists89 if ( file_exists( C7WP_ROOT . '/includes/gutenberg/' . $frontend_js_path ) && empty( $_GET['ct_builder'] ) ) {90 $frontend_script_handle = 'c7wp-' . $element . '-frontend';91 wp_register_script(92 $frontend_script_handle,93 plugins_url( $frontend_js_path, __FILE__ ),94 array(),95 C7WP_VERSION,96 true97 );102 // Register and enqueue frontend script if it exists 103 if ( file_exists( C7WP_ROOT . '/includes/gutenberg/' . $frontend_js_path ) && empty( $_GET['ct_builder'] ) ) { 104 $frontend_script_handle = 'c7wp-' . $element . '-frontend'; 105 wp_register_script( 106 $frontend_script_handle, 107 plugins_url( $frontend_js_path, __FILE__ ), 108 array(), 109 C7WP_VERSION, 110 true 111 ); 98 112 99 // Localize settings for clubselector 100 if ( 'clubselector' === $element ) { 101 $options = get_option( 'c7wp_settings' ); 102 wp_localize_script( $frontend_script_handle, 'c7wp_settings', array( 103 'c7wp_frontend_routes' => isset( $options['c7wp_frontend_routes'] ) ? $options['c7wp_frontend_routes'] : array( 'club' => 'club' ), 104 ) ); 105 } 113 // Localize settings for clubselector 114 if ( 'clubselector' === $element ) { 115 $options = get_option( 'c7wp_settings' ); 116 wp_localize_script( 117 $frontend_script_handle, 118 'c7wp_settings', 119 array( 120 'c7wp_frontend_routes' => isset( $options['c7wp_frontend_routes'] ) ? $options['c7wp_frontend_routes'] : array( 'club' => 'club' ), 121 ) 122 ); 123 } 106 124 107 wp_enqueue_script( $frontend_script_handle );108 }125 wp_enqueue_script( $frontend_script_handle ); 126 } 109 127 110 // Register and enqueue frontend styles if they exist111 if ( file_exists( C7WP_ROOT . '/includes/gutenberg/' . $frontend_css_path ) ) {112 wp_register_style(113 'c7wp-' . $element . '-frontend',114 plugins_url( $frontend_css_path, __FILE__ ),115 array(),116 C7WP_VERSION117 );118 wp_enqueue_style( 'c7wp-' . $element . '-frontend' );119 }128 // Register and enqueue frontend styles if they exist 129 if ( file_exists( C7WP_ROOT . '/includes/gutenberg/' . $frontend_css_path ) ) { 130 wp_register_style( 131 'c7wp-' . $element . '-frontend', 132 plugins_url( $frontend_css_path, __FILE__ ), 133 array(), 134 C7WP_VERSION 135 ); 136 wp_enqueue_style( 'c7wp-' . $element . '-frontend' ); 137 } 120 138 } -
wp-commerce7/trunk/includes/rankmath/load.php
r2832594 r3441297 6 6 * Author: Michael Bourne 7 7 * ----- 8 * Last Modified: Monday, December 12th 2022, 10:19:35 am8 * Last Modified: Friday, October 17th 2025, 6:55:09 pm 9 9 * Modified By: Michael Bourne 10 10 * ----- … … 18 18 */ 19 19 20 add_action( ' wp_head', function( $canonical_url ) {20 add_action( 'rank_math/frontend/canonical', function( $canonical ) { 21 21 22 22 $options = get_option( 'c7wp_settings' ); … … 33 33 // If the current page is a product or collection page, remove action to disable canonical URL. 34 34 if ( is_page( [ $product_route, $collection_route ] ) ) { 35 re move_all_actions( 'rank_math/head' );35 return false; 36 36 } 37 37 38 38 }, 1 ); 39
Note: See TracChangeset
for help on using the changeset viewer.