PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.4
WooCommerce v10.9.4
10.9.4 10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / includes / customizer / class-wc-shop-customizer.php
woocommerce / includes / customizer Last commit date
class-wc-customizer-control-cropping.php 8 years ago class-wc-shop-customizer.php 4 months ago
class-wc-shop-customizer.php
952 lines
1 <?php
2 /**
3 * Adds options to the customizer for WooCommerce.
4 *
5 * @version 3.3.0
6 * @package WooCommerce
7 */
8
9 defined( 'ABSPATH' ) || exit;
10
11 /**
12 * WC_Shop_Customizer class.
13 */
14 class WC_Shop_Customizer {
15
16 /**
17 * Constructor.
18 */
19 public function __construct() {
20 add_action( 'customize_register', array( $this, 'add_sections' ) );
21 add_action( 'customize_controls_print_styles', array( $this, 'add_styles' ) );
22 add_action( 'customize_controls_print_scripts', array( $this, 'add_scripts' ), 30 );
23 add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
24 add_action( 'wp_enqueue_scripts', array( $this, 'add_frontend_scripts' ) );
25 }
26
27 /**
28 * Add settings to the customizer.
29 *
30 * @param WP_Customize_Manager $wp_customize Theme Customizer object.
31 */
32 public function add_sections( $wp_customize ) {
33 $wp_customize->add_panel(
34 'woocommerce',
35 array(
36 'priority' => 200,
37 'capability' => 'manage_woocommerce',
38 'theme_supports' => '',
39 'title' => __( 'WooCommerce', 'woocommerce' ),
40 )
41 );
42
43 $this->add_store_notice_section( $wp_customize );
44 $this->add_product_catalog_section( $wp_customize );
45 $this->add_product_images_section( $wp_customize );
46 $this->add_checkout_section( $wp_customize );
47 }
48
49 /**
50 * Frontend CSS styles.
51 */
52 public function add_frontend_scripts() {
53 if ( ! is_customize_preview() || ! is_store_notice_showing() ) {
54 return;
55 }
56
57 $css = '.woocommerce-store-notice, p.demo_store { display: block !important; }';
58 wp_add_inline_style( 'customize-preview', $css );
59 }
60
61 /**
62 * CSS styles to disable the Checkout section, when the default checkout page contains the
63 * Checkout block, and to enhance form visuals.
64 */
65 public function add_styles() {
66 if ( $this->has_block_checkout() ) {
67 ?>
68 <style type="text/css">
69 li#accordion-section-woocommerce_checkout {
70 pointer-events: none;
71 }
72
73 li#accordion-section-woocommerce_checkout .accordion-section-title {
74 background: #f1f1f1;
75 }
76
77 ul#sub-accordion-panel-woocommerce .notice {
78 border-color: #007cba;
79 border-bottom: 0;
80 border-right: 0;
81 border-top: 0;
82 margin-top: 0;
83 padding-bottom: 10px;
84 padding-top: 10px;
85 }
86 </style>
87 <?php
88 }
89
90 ?>
91 <style type="text/css">
92 .woocommerce-cropping-control {
93 margin: 0 40px 1em 0;
94 padding: 0;
95 display:inline-block;
96 vertical-align: top;
97 }
98
99 .woocommerce-cropping-control input[type=radio] {
100 margin-top: 1px;
101 }
102
103 .woocommerce-cropping-control span.woocommerce-cropping-control-aspect-ratio {
104 margin-top: .5em;
105 display:block;
106 }
107
108 .woocommerce-cropping-control span.woocommerce-cropping-control-aspect-ratio input {
109 width: auto;
110 display: inline-block;
111 }
112 </style>
113 <?php
114 }
115
116 /**
117 * Scripts to improve our form.
118 */
119 public function add_scripts() {
120 $min_rows = wc_get_theme_support( 'product_grid::min_rows', 1 );
121 $max_rows = wc_get_theme_support( 'product_grid::max_rows', '' );
122 $min_columns = wc_get_theme_support( 'product_grid::min_columns', 1 );
123 $max_columns = wc_get_theme_support( 'product_grid::max_columns', '' );
124
125 /* translators: %d: Setting value */
126 $min_notice = __( 'The minimum allowed setting is %d', 'woocommerce' );
127 /* translators: %d: Setting value */
128 $max_notice = __( 'The maximum allowed setting is %d', 'woocommerce' );
129 ?>
130 <script type="text/javascript">
131 jQuery( function( $ ) {
132 $( document.body ).on( 'change', '.woocommerce-cropping-control input[type="radio"]', function() {
133 var $wrapper = $( this ).closest( '.woocommerce-cropping-control' ),
134 value = $wrapper.find( 'input:checked' ).val();
135
136 if ( 'custom' === value ) {
137 $wrapper.find( '.woocommerce-cropping-control-aspect-ratio' ).slideDown( 200 );
138 } else {
139 $wrapper.find( '.woocommerce-cropping-control-aspect-ratio' ).hide();
140 }
141
142 return false;
143 } );
144
145 wp.customize.bind( 'ready', function() { // Ready?
146 $( '.woocommerce-cropping-control' ).find( 'input:checked' ).trigger( 'change' );
147 } );
148
149 wp.customize( 'woocommerce_demo_store', function( setting ) {
150 setting.bind( function( value ) {
151 var notice = wp.customize( 'woocommerce_demo_store_notice' );
152
153 if ( value && ! notice.callbacks.has( notice.preview ) ) {
154 notice.bind( notice.preview );
155 } else if ( ! value ) {
156 notice.unbind( notice.preview );
157 }
158 } );
159 } );
160
161 wp.customize( 'woocommerce_demo_store_notice', function( setting ) {
162 setting.bind( function( value ) {
163 var checkbox = wp.customize( 'woocommerce_demo_store' );
164
165 if ( checkbox.get() ) {
166 $( '.woocommerce-store-notice' ).text( value );
167 }
168 } );
169 } );
170
171 wp.customize.section( 'woocommerce_store_notice', function( section ) {
172 section.expanded.bind( function( isExpanded ) {
173 if ( isExpanded ) {
174 var notice = wp.customize( 'woocommerce_demo_store_notice' ),
175 checkbox = wp.customize( 'woocommerce_demo_store' );
176
177 if ( checkbox.get() && ! notice.callbacks.has( notice.preview ) ) {
178 notice.bind( notice.preview );
179 } else if ( ! checkbox.get() ) {
180 notice.unbind( notice.preview );
181 }
182 }
183 } );
184 } );
185
186 wp.customize.section( 'woocommerce_product_catalog', function( section ) {
187 section.expanded.bind( function( isExpanded ) {
188 if ( isExpanded ) {
189 wp.customize.previewer.previewUrl.set( '<?php echo esc_js( wc_get_page_permalink( 'shop' ) ); ?>' );
190 }
191 } );
192 } );
193
194 wp.customize.section( 'woocommerce_product_images', function( section ) {
195 section.expanded.bind( function( isExpanded ) {
196 if ( isExpanded ) {
197 wp.customize.previewer.previewUrl.set( '<?php echo esc_js( wc_get_page_permalink( 'shop' ) ); ?>' );
198 }
199 } );
200 } );
201
202 wp.customize.section( 'woocommerce_checkout', function( section ) {
203 section.expanded.bind( function( isExpanded ) {
204 if ( isExpanded ) {
205 wp.customize.previewer.previewUrl.set( '<?php echo esc_js( wc_get_page_permalink( 'checkout' ) ); ?>' );
206 }
207 } );
208 } );
209
210 wp.customize( 'woocommerce_catalog_columns', function( setting ) {
211 setting.bind( function( value ) {
212 var min = parseInt( '<?php echo esc_js( $min_columns ); ?>', 10 );
213 var max = parseInt( '<?php echo esc_js( $max_columns ); ?>', 10 );
214
215 value = parseInt( value, 10 );
216
217 if ( max && value > max ) {
218 setting.notifications.add( 'max_columns_error', new wp.customize.Notification(
219 'max_columns_error',
220 {
221 type : 'error',
222 message: '<?php echo esc_js( sprintf( $max_notice, $max_columns ) ); ?>'
223 }
224 ) );
225 } else {
226 setting.notifications.remove( 'max_columns_error' );
227 }
228
229 if ( min && value < min ) {
230 setting.notifications.add( 'min_columns_error', new wp.customize.Notification(
231 'min_columns_error',
232 {
233 type : 'error',
234 message: '<?php echo esc_js( sprintf( $min_notice, $min_columns ) ); ?>'
235 }
236 ) );
237 } else {
238 setting.notifications.remove( 'min_columns_error' );
239 }
240 } );
241 } );
242
243 wp.customize( 'woocommerce_catalog_rows', function( setting ) {
244 setting.bind( function( value ) {
245 var min = parseInt( '<?php echo esc_js( $min_rows ); ?>', 10 );
246 var max = parseInt( '<?php echo esc_js( $max_rows ); ?>', 10 );
247
248 value = parseInt( value, 10 );
249
250 if ( max && value > max ) {
251 setting.notifications.add( 'max_rows_error', new wp.customize.Notification(
252 'max_rows_error',
253 {
254 type : 'error',
255 message: '<?php echo esc_js( sprintf( $max_notice, $max_rows ) ); ?>'
256 }
257 ) );
258 } else {
259 setting.notifications.remove( 'max_rows_error' );
260 }
261
262 if ( min && value < min ) {
263 setting.notifications.add( 'min_rows_error', new wp.customize.Notification(
264 'min_rows_error',
265 {
266 type : 'error',
267 message: '<?php echo esc_js( sprintf( $min_notice, $min_rows ) ); ?>'
268 }
269 ) );
270 } else {
271 setting.notifications.remove( 'min_rows_error' );
272 }
273 } );
274 } );
275 } );
276 </script>
277 <?php
278
279 if ( $this->has_block_checkout() ) {
280 $message = sprintf(
281 /* translators: %s: Link to the editor page with the Checkout block. */
282 __( 'Checkout can be customized <a href="%s">in the Editor</a> with your active theme.', 'woocommerce' ),
283 admin_url( 'post.php?post=' . get_option( 'woocommerce_checkout_page_id' ) . '&action=edit' )
284 );
285 ?>
286 <script type="text/javascript">
287 jQuery( document ).ready( function( $ ) {
288 const message = <?php echo wp_json_encode( $message, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ); ?>;
289 $( "#sub-accordion-panel-woocommerce" ).append( "<li class='notice notice-info'>" + message + "</li>" );
290 } );
291 </script>
292 <?php
293 }
294 }
295
296 /**
297 * Enqueue scripts for the customizer.
298 */
299 public function enqueue_scripts() {
300 $handle = 'custom-notice';
301 wp_register_script( $handle, false, array( 'customize-controls' ), WC_VERSION, false );
302 wp_enqueue_script( $handle );
303 }
304
305 /**
306 * Sanitize the shop page & category display setting.
307 *
308 * @param string $value '', 'subcategories', or 'both'.
309 * @return string
310 */
311 public function sanitize_archive_display( $value ) {
312 $options = array( '', 'subcategories', 'both' );
313
314 return in_array( $value, $options, true ) ? $value : '';
315 }
316
317 /**
318 * Sanitize the catalog orderby setting.
319 *
320 * @param string $value An array key from the below array.
321 * @return string
322 */
323 public function sanitize_default_catalog_orderby( $value ) {
324 /* phpcs:disable WooCommerce.Commenting.CommentHooks.MissingHookComment */
325 $options = apply_filters(
326 'woocommerce_default_catalog_orderby_options',
327 array(
328 'menu_order' => __( 'Default sorting (custom ordering + name)', 'woocommerce' ),
329 'popularity' => __( 'Popularity (sales)', 'woocommerce' ),
330 'rating' => __( 'Average rating', 'woocommerce' ),
331 'date' => __( 'Sort by most recent', 'woocommerce' ),
332 'price' => __( 'Sort by price (asc)', 'woocommerce' ),
333 'price-desc' => __( 'Sort by price (desc)', 'woocommerce' ),
334 )
335 );
336
337 return array_key_exists( $value, $options ) ? $value : 'menu_order';
338 }
339
340 /**
341 * Store notice section.
342 *
343 * @param WP_Customize_Manager $wp_customize Theme Customizer object.
344 */
345 private function add_store_notice_section( $wp_customize ) {
346 $wp_customize->add_section(
347 'woocommerce_store_notice',
348 array(
349 'title' => __( 'Store Notice', 'woocommerce' ),
350 'priority' => 10,
351 'panel' => 'woocommerce',
352 )
353 );
354
355 $wp_customize->add_setting(
356 'woocommerce_demo_store',
357 array(
358 'default' => 'no',
359 'type' => 'option',
360 'capability' => 'manage_woocommerce',
361 'sanitize_callback' => 'wc_bool_to_string',
362 'sanitize_js_callback' => 'wc_string_to_bool',
363 )
364 );
365
366 $wp_customize->add_setting(
367 'woocommerce_demo_store_notice',
368 array(
369 'default' => __( 'This is a demo store for testing purposes &mdash; no orders shall be fulfilled.', 'woocommerce' ),
370 'type' => 'option',
371 'capability' => 'manage_woocommerce',
372 'sanitize_callback' => 'wp_kses_post',
373 'transport' => 'postMessage',
374 )
375 );
376
377 $wp_customize->add_control(
378 'woocommerce_demo_store_notice',
379 array(
380 'label' => __( 'Store notice', 'woocommerce' ),
381 'description' => __( 'If enabled, this text will be shown site-wide. You can use it to show events or promotions to visitors!', 'woocommerce' ),
382 'section' => 'woocommerce_store_notice',
383 'settings' => 'woocommerce_demo_store_notice',
384 'type' => 'textarea',
385 )
386 );
387
388 $wp_customize->add_control(
389 'woocommerce_demo_store',
390 array(
391 'label' => __( 'Enable store notice', 'woocommerce' ),
392 'section' => 'woocommerce_store_notice',
393 'settings' => 'woocommerce_demo_store',
394 'type' => 'checkbox',
395 )
396 );
397
398 if ( isset( $wp_customize->selective_refresh ) ) {
399 $wp_customize->selective_refresh->add_partial(
400 'woocommerce_demo_store_notice',
401 array(
402 'selector' => '.woocommerce-store-notice',
403 'container_inclusive' => true,
404 'render_callback' => 'woocommerce_demo_store',
405 )
406 );
407 }
408 }
409
410 /**
411 * Product catalog section.
412 *
413 * @param WP_Customize_Manager $wp_customize Theme Customizer object.
414 */
415 public function add_product_catalog_section( $wp_customize ) {
416 $wp_customize->add_section(
417 'woocommerce_product_catalog',
418 array(
419 'title' => __( 'Product Catalog', 'woocommerce' ),
420 'priority' => 10,
421 'panel' => 'woocommerce',
422 )
423 );
424
425 $wp_customize->add_setting(
426 'woocommerce_shop_page_display',
427 array(
428 'default' => '',
429 'type' => 'option',
430 'capability' => 'manage_woocommerce',
431 'sanitize_callback' => array( $this, 'sanitize_archive_display' ),
432 )
433 );
434
435 $wp_customize->add_control(
436 'woocommerce_shop_page_display',
437 array(
438 'label' => __( 'Shop page display', 'woocommerce' ),
439 'description' => __( 'Choose what to display on the main shop page.', 'woocommerce' ),
440 'section' => 'woocommerce_product_catalog',
441 'settings' => 'woocommerce_shop_page_display',
442 'type' => 'select',
443 'choices' => array(
444 '' => __( 'Show products', 'woocommerce' ),
445 'subcategories' => __( 'Show categories', 'woocommerce' ),
446 'both' => __( 'Show categories &amp; products', 'woocommerce' ),
447 ),
448 )
449 );
450
451 $wp_customize->add_setting(
452 'woocommerce_category_archive_display',
453 array(
454 'default' => '',
455 'type' => 'option',
456 'capability' => 'manage_woocommerce',
457 'sanitize_callback' => array( $this, 'sanitize_archive_display' ),
458 )
459 );
460
461 $wp_customize->add_control(
462 'woocommerce_category_archive_display',
463 array(
464 'label' => __( 'Category display', 'woocommerce' ),
465 'description' => __( 'Choose what to display on product category pages.', 'woocommerce' ),
466 'section' => 'woocommerce_product_catalog',
467 'settings' => 'woocommerce_category_archive_display',
468 'type' => 'select',
469 'choices' => array(
470 '' => __( 'Show products', 'woocommerce' ),
471 'subcategories' => __( 'Show subcategories', 'woocommerce' ),
472 'both' => __( 'Show subcategories &amp; products', 'woocommerce' ),
473 ),
474 )
475 );
476
477 $wp_customize->add_setting(
478 'woocommerce_default_catalog_orderby',
479 array(
480 'default' => 'menu_order',
481 'type' => 'option',
482 'capability' => 'manage_woocommerce',
483 'sanitize_callback' => array( $this, 'sanitize_default_catalog_orderby' ),
484 )
485 );
486
487 /* phpcs:disable WooCommerce.Commenting.CommentHooks.MissingHookComment */
488 $wp_customize->add_control(
489 'woocommerce_default_catalog_orderby',
490 array(
491 'label' => __( 'Default product sorting', 'woocommerce' ),
492 'description' => __( 'How should products be sorted in the catalog by default?', 'woocommerce' ),
493 'section' => 'woocommerce_product_catalog',
494 'settings' => 'woocommerce_default_catalog_orderby',
495 'type' => 'select',
496 'choices' => apply_filters(
497 'woocommerce_default_catalog_orderby_options',
498 array(
499 'menu_order' => __( 'Default sorting (custom ordering + name)', 'woocommerce' ),
500 'popularity' => __( 'Popularity (sales)', 'woocommerce' ),
501 'rating' => __( 'Average rating', 'woocommerce' ),
502 'date' => __( 'Sort by most recent', 'woocommerce' ),
503 'price' => __( 'Sort by price (asc)', 'woocommerce' ),
504 'price-desc' => __( 'Sort by price (desc)', 'woocommerce' ),
505 )
506 ),
507 )
508 );
509
510 // The following settings should be hidden if the theme is declaring the values.
511 if ( has_filter( 'loop_shop_columns' ) ) {
512 return;
513 }
514
515 $wp_customize->add_setting(
516 'woocommerce_catalog_columns',
517 array(
518 'default' => 4,
519 'type' => 'option',
520 'capability' => 'manage_woocommerce',
521 'sanitize_callback' => 'absint',
522 'sanitize_js_callback' => 'absint',
523 )
524 );
525
526 $wp_customize->add_control(
527 'woocommerce_catalog_columns',
528 array(
529 'label' => __( 'Products per row', 'woocommerce' ),
530 'description' => __( 'How many products should be shown per row?', 'woocommerce' ),
531 'section' => 'woocommerce_product_catalog',
532 'settings' => 'woocommerce_catalog_columns',
533 'type' => 'number',
534 'input_attrs' => array(
535 'min' => wc_get_theme_support( 'product_grid::min_columns', 1 ),
536 'max' => wc_get_theme_support( 'product_grid::max_columns', '' ),
537 'step' => 1,
538 ),
539 )
540 );
541
542 // Only add this setting if something else isn't managing the number of products per page.
543 if ( ! has_filter( 'loop_shop_per_page' ) ) {
544 $wp_customize->add_setting(
545 'woocommerce_catalog_rows',
546 array(
547 'default' => 4,
548 'type' => 'option',
549 'capability' => 'manage_woocommerce',
550 'sanitize_callback' => 'absint',
551 'sanitize_js_callback' => 'absint',
552 )
553 );
554 }
555
556 $wp_customize->add_control(
557 'woocommerce_catalog_rows',
558 array(
559 'label' => __( 'Rows per page', 'woocommerce' ),
560 'description' => __( 'How many rows of products should be shown per page?', 'woocommerce' ),
561 'section' => 'woocommerce_product_catalog',
562 'settings' => 'woocommerce_catalog_rows',
563 'type' => 'number',
564 'input_attrs' => array(
565 'min' => wc_get_theme_support( 'product_grid::min_rows', 1 ),
566 'max' => wc_get_theme_support( 'product_grid::max_rows', '' ),
567 'step' => 1,
568 ),
569 )
570 );
571 }
572
573 /**
574 * Product images section.
575 *
576 * @param WP_Customize_Manager $wp_customize Theme Customizer object.
577 */
578 private function add_product_images_section( $wp_customize ) {
579 if ( class_exists( 'Jetpack' ) && Jetpack::is_module_active( 'photon' ) ) {
580 $regen_description = ''; // Nothing to report; Jetpack will handle magically.
581 /* phpcs:disable WooCommerce.Commenting.CommentHooks.MissingHookComment */
582 } elseif ( apply_filters( 'woocommerce_background_image_regeneration', true ) && ! is_multisite() ) {
583 $regen_description = __( 'After publishing your changes, new image sizes will be generated automatically.', 'woocommerce' );
584 /* phpcs:disable WooCommerce.Commenting.CommentHooks.MissingHookComment */
585 } elseif ( apply_filters( 'woocommerce_background_image_regeneration', true ) && is_multisite() ) {
586 /* translators: 1: tools URL 2: regen thumbs url */
587 $regen_description = sprintf( __( 'After publishing your changes, new image sizes may not be shown until you regenerate thumbnails. You can do this from the <a href="%1$s" target="_blank">tools section in WooCommerce</a> or by using a plugin such as <a href="%2$s" target="_blank">Regenerate Thumbnails</a>.', 'woocommerce' ), admin_url( 'admin.php?page=wc-status&tab=tools' ), 'https://en-gb.wordpress.org/plugins/regenerate-thumbnails/' );
588 } else {
589 /* translators: %s: regen thumbs url */
590 $regen_description = sprintf( __( 'After publishing your changes, new image sizes may not be shown until you <a href="%s" target="_blank">Regenerate Thumbnails</a>.', 'woocommerce' ), 'https://en-gb.wordpress.org/plugins/regenerate-thumbnails/' );
591 }
592
593 $wp_customize->add_section(
594 'woocommerce_product_images',
595 array(
596 'title' => __( 'Product Images', 'woocommerce' ),
597 'description' => $regen_description,
598 'priority' => 20,
599 'panel' => 'woocommerce',
600 )
601 );
602
603 if ( ! wc_get_theme_support( 'single_image_width' ) ) {
604 $wp_customize->add_setting(
605 'woocommerce_single_image_width',
606 array(
607 'default' => 600,
608 'type' => 'option',
609 'capability' => 'manage_woocommerce',
610 'sanitize_callback' => 'absint',
611 'sanitize_js_callback' => 'absint',
612 )
613 );
614
615 $wp_customize->add_control(
616 'woocommerce_single_image_width',
617 array(
618 'label' => __( 'Main image width', 'woocommerce' ),
619 'description' => __( 'Image size used for the main image on single product pages. These images will remain uncropped.', 'woocommerce' ),
620 'section' => 'woocommerce_product_images',
621 'settings' => 'woocommerce_single_image_width',
622 'type' => 'number',
623 'input_attrs' => array(
624 'min' => 0,
625 'step' => 1,
626 ),
627 )
628 );
629 }
630
631 if ( ! wc_get_theme_support( 'thumbnail_image_width' ) ) {
632 $wp_customize->add_setting(
633 'woocommerce_thumbnail_image_width',
634 array(
635 'default' => 300,
636 'type' => 'option',
637 'capability' => 'manage_woocommerce',
638 'sanitize_callback' => 'absint',
639 'sanitize_js_callback' => 'absint',
640 )
641 );
642
643 $wp_customize->add_control(
644 'woocommerce_thumbnail_image_width',
645 array(
646 'label' => __( 'Thumbnail width', 'woocommerce' ),
647 'description' => __( 'Image size used for products in the catalog.', 'woocommerce' ),
648 'section' => 'woocommerce_product_images',
649 'settings' => 'woocommerce_thumbnail_image_width',
650 'type' => 'number',
651 'input_attrs' => array(
652 'min' => 0,
653 'step' => 1,
654 ),
655 )
656 );
657 }
658
659 include_once WC_ABSPATH . 'includes/customizer/class-wc-customizer-control-cropping.php';
660
661 $wp_customize->add_setting(
662 'woocommerce_thumbnail_cropping',
663 array(
664 'default' => '1:1',
665 'type' => 'option',
666 'capability' => 'manage_woocommerce',
667 'sanitize_callback' => 'wc_clean',
668 )
669 );
670
671 $wp_customize->add_setting(
672 'woocommerce_thumbnail_cropping_custom_width',
673 array(
674 'default' => '4',
675 'type' => 'option',
676 'capability' => 'manage_woocommerce',
677 'sanitize_callback' => 'absint',
678 'sanitize_js_callback' => 'absint',
679 )
680 );
681
682 $wp_customize->add_setting(
683 'woocommerce_thumbnail_cropping_custom_height',
684 array(
685 'default' => '3',
686 'type' => 'option',
687 'capability' => 'manage_woocommerce',
688 'sanitize_callback' => 'absint',
689 'sanitize_js_callback' => 'absint',
690 )
691 );
692
693 $wp_customize->add_control(
694 new WC_Customizer_Control_Cropping(
695 $wp_customize,
696 'woocommerce_thumbnail_cropping',
697 array(
698 'section' => 'woocommerce_product_images',
699 'settings' => array(
700 'cropping' => 'woocommerce_thumbnail_cropping',
701 'custom_width' => 'woocommerce_thumbnail_cropping_custom_width',
702 'custom_height' => 'woocommerce_thumbnail_cropping_custom_height',
703 ),
704 'label' => __( 'Thumbnail cropping', 'woocommerce' ),
705 'choices' => array(
706 '1:1' => array(
707 'label' => __( '1:1', 'woocommerce' ),
708 'description' => __( 'Images will be cropped into a square', 'woocommerce' ),
709 ),
710 'custom' => array(
711 'label' => __( 'Custom', 'woocommerce' ),
712 'description' => __( 'Images will be cropped to a custom aspect ratio', 'woocommerce' ),
713 ),
714 'uncropped' => array(
715 'label' => __( 'Uncropped', 'woocommerce' ),
716 'description' => __( 'Images will display using the aspect ratio in which they were uploaded', 'woocommerce' ),
717 ),
718 ),
719 )
720 )
721 );
722 }
723
724 /**
725 * Checkout section.
726 *
727 * @param WP_Customize_Manager $wp_customize Theme Customizer object.
728 */
729 public function add_checkout_section( $wp_customize ) {
730 $wp_customize->add_section(
731 'woocommerce_checkout',
732 array(
733 'title' => __( 'Checkout', 'woocommerce' ),
734 'priority' => 20,
735 'panel' => 'woocommerce',
736 'description' => __( 'These options let you change the appearance of the WooCommerce checkout.', 'woocommerce' ),
737 )
738 );
739
740 // Checkout field controls.
741 $fields = array(
742 'company' => __( 'Company name', 'woocommerce' ),
743 'address_2' => __( 'Address line 2', 'woocommerce' ),
744 'phone' => __( 'Phone', 'woocommerce' ),
745 );
746 foreach ( $fields as $field => $label ) {
747 $wp_customize->add_setting(
748 'woocommerce_checkout_' . $field . '_field',
749 array(
750 'default' => 'phone' === $field ? 'required' : 'optional',
751 'type' => 'option',
752 'capability' => 'manage_woocommerce',
753 'sanitize_callback' => array( $this, 'sanitize_checkout_field_display' ),
754 )
755 );
756 $wp_customize->add_control(
757 'woocommerce_checkout_' . $field . '_field',
758 array(
759 /* Translators: %s field name. */
760 'label' => sprintf( __( '%s field', 'woocommerce' ), $label ),
761 'section' => 'woocommerce_checkout',
762 'settings' => 'woocommerce_checkout_' . $field . '_field',
763 'type' => 'select',
764 'choices' => array(
765 'hidden' => __( 'Hidden', 'woocommerce' ),
766 'optional' => __( 'Optional', 'woocommerce' ),
767 'required' => __( 'Required', 'woocommerce' ),
768 ),
769 )
770 );
771 }
772
773 // Register settings.
774 $wp_customize->add_setting(
775 'woocommerce_checkout_highlight_required_fields',
776 array(
777 'default' => 'yes',
778 'type' => 'option',
779 'capability' => 'manage_woocommerce',
780 'sanitize_callback' => 'wc_bool_to_string',
781 'sanitize_js_callback' => 'wc_string_to_bool',
782 )
783 );
784
785 $wp_customize->add_setting(
786 'woocommerce_checkout_terms_and_conditions_checkbox_text',
787 array(
788 /* translators: %s terms and conditions page name and link */
789 'default' => sprintf( __( 'I have read and agree to the website %s', 'woocommerce' ), '[terms]' ),
790 'type' => 'option',
791 'capability' => 'manage_woocommerce',
792 'sanitize_callback' => 'wp_kses_post',
793 'transport' => 'postMessage',
794 )
795 );
796
797 $wp_customize->add_setting(
798 'woocommerce_checkout_privacy_policy_text',
799 array(
800 /* translators: %s privacy policy page name and link */
801 'default' => sprintf( __( 'Your personal data will be used to process your order, support your experience throughout this website, and for other purposes described in our %s.', 'woocommerce' ), '[privacy_policy]' ),
802 'type' => 'option',
803 'capability' => 'manage_woocommerce',
804 'sanitize_callback' => 'wp_kses_post',
805 'transport' => 'postMessage',
806 )
807 );
808
809 // Register controls.
810 $wp_customize->add_control(
811 'woocommerce_checkout_highlight_required_fields',
812 array(
813 'label' => __( 'Highlight required fields with an asterisk', 'woocommerce' ),
814 'section' => 'woocommerce_checkout',
815 'settings' => 'woocommerce_checkout_highlight_required_fields',
816 'type' => 'checkbox',
817 )
818 );
819
820 if ( current_user_can( 'manage_privacy_options' ) ) {
821 $choose_pages = array(
822 'wp_page_for_privacy_policy' => __( 'Privacy policy', 'woocommerce' ),
823 'woocommerce_terms_page_id' => __( 'Terms and conditions', 'woocommerce' ),
824 );
825 } else {
826 $choose_pages = array(
827 'woocommerce_terms_page_id' => __( 'Terms and conditions', 'woocommerce' ),
828 );
829 }
830 $pages = get_pages(
831 array(
832 'post_type' => 'page',
833 'post_status' => 'publish,private,draft',
834 'child_of' => 0,
835 'parent' => -1,
836 'exclude' => array(
837 wc_get_page_id( 'cart' ),
838 wc_get_page_id( 'checkout' ),
839 wc_get_page_id( 'myaccount' ),
840 ),
841 'sort_order' => 'asc',
842 'sort_column' => 'post_title',
843 )
844 );
845 $page_choices = array( '' => __( 'No page set', 'woocommerce' ) ) + array_combine( array_map( 'strval', wp_list_pluck( $pages, 'ID' ) ), wp_list_pluck( $pages, 'post_title' ) );
846
847 foreach ( $choose_pages as $id => $name ) {
848 $wp_customize->add_setting(
849 $id,
850 array(
851 'default' => '',
852 'type' => 'option',
853 'capability' => 'manage_woocommerce',
854 )
855 );
856 $wp_customize->add_control(
857 $id,
858 array(
859 /* Translators: %s: page name. */
860 'label' => sprintf( __( '%s page', 'woocommerce' ), $name ),
861 'section' => 'woocommerce_checkout',
862 'settings' => $id,
863 'type' => 'select',
864 'choices' => $page_choices,
865 )
866 );
867 }
868
869 $wp_customize->add_control(
870 'woocommerce_checkout_privacy_policy_text',
871 array(
872 'label' => __( 'Privacy policy', 'woocommerce' ),
873 'description' => __( 'Optionally add some text about your store privacy policy to show during checkout.', 'woocommerce' ),
874 'section' => 'woocommerce_checkout',
875 'settings' => 'woocommerce_checkout_privacy_policy_text',
876 'active_callback' => array( $this, 'has_privacy_policy_page_id' ),
877 'type' => 'textarea',
878 )
879 );
880
881 $wp_customize->add_control(
882 'woocommerce_checkout_terms_and_conditions_checkbox_text',
883 array(
884 'label' => __( 'Terms and conditions', 'woocommerce' ),
885 'description' => __( 'Optionally add some text for the terms checkbox that customers must accept.', 'woocommerce' ),
886 'section' => 'woocommerce_checkout',
887 'settings' => 'woocommerce_checkout_terms_and_conditions_checkbox_text',
888 'active_callback' => array( $this, 'has_terms_and_conditions_page_id' ),
889 'type' => 'text',
890 )
891 );
892
893 if ( isset( $wp_customize->selective_refresh ) ) {
894 $wp_customize->selective_refresh->add_partial(
895 'woocommerce_checkout_privacy_policy_text',
896 array(
897 'selector' => '.woocommerce-privacy-policy-text',
898 'container_inclusive' => true,
899 'render_callback' => 'wc_checkout_privacy_policy_text',
900 )
901 );
902 $wp_customize->selective_refresh->add_partial(
903 'woocommerce_checkout_terms_and_conditions_checkbox_text',
904 array(
905 'selector' => '.woocommerce-terms-and-conditions-checkbox-text',
906 'container_inclusive' => false,
907 'render_callback' => 'wc_terms_and_conditions_checkbox_text',
908 )
909 );
910 }
911 }
912
913 /**
914 * Sanitize field display.
915 *
916 * @param string $value '', 'subcategories', or 'both'.
917 * @return string
918 */
919 public function sanitize_checkout_field_display( $value ) {
920 $options = array( 'hidden', 'optional', 'required' );
921 return in_array( $value, $options, true ) ? $value : '';
922 }
923
924 /**
925 * Whether or not a page has been chose for the privacy policy.
926 *
927 * @return bool
928 */
929 public function has_privacy_policy_page_id() {
930 return wc_privacy_policy_page_id() > 0;
931 }
932
933 /**
934 * Whether or not a page has been chose for the terms and conditions.
935 *
936 * @return bool
937 */
938 public function has_terms_and_conditions_page_id() {
939 return wc_terms_and_conditions_page_id() > 0;
940 }
941
942 /**
943 * Weather or not the checkout page contains the Checkout block.
944 *
945 * @return bool
946 */
947 private function has_block_checkout() {
948 $post = get_post( get_option( 'woocommerce_checkout_page_id' ) );
949 return $post && strpos( $post->post_content, '<!-- wp:woocommerce/checkout' ) !== false;
950 }
951 }
952