class-wc-shop-customizer.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. <?php
  2. /**
  3. * Adds options to the customizer for WooCommerce.
  4. *
  5. * @version 3.3.0
  6. * @package WooCommerce
  7. */
  8. defined( 'ABSPATH' ) || exit;
  9. /**
  10. * WC_Shop_Customizer class.
  11. */
  12. class WC_Shop_Customizer {
  13. /**
  14. * Constructor.
  15. */
  16. public function __construct() {
  17. add_action( 'customize_register', array( $this, 'add_sections' ) );
  18. add_action( 'customize_controls_print_styles', array( $this, 'add_styles' ) );
  19. add_action( 'customize_controls_print_scripts', array( $this, 'add_scripts' ), 30 );
  20. add_action( 'wp_enqueue_scripts', array( $this, 'add_frontend_scripts' ) );
  21. }
  22. /**
  23. * Add settings to the customizer.
  24. *
  25. * @param WP_Customize_Manager $wp_customize Theme Customizer object.
  26. */
  27. public function add_sections( $wp_customize ) {
  28. $wp_customize->add_panel( 'woocommerce', array(
  29. 'priority' => 200,
  30. 'capability' => 'manage_woocommerce',
  31. 'theme_supports' => '',
  32. 'title' => __( 'WooCommerce', 'woocommerce' ),
  33. ) );
  34. $this->add_store_notice_section( $wp_customize );
  35. $this->add_product_catalog_section( $wp_customize );
  36. $this->add_product_images_section( $wp_customize );
  37. $this->add_checkout_section( $wp_customize );
  38. }
  39. /**
  40. * Frontend CSS styles.
  41. */
  42. public function add_frontend_scripts() {
  43. if ( ! is_customize_preview() || ! is_store_notice_showing() ) {
  44. return;
  45. }
  46. $css = '.woocommerce-store-notice, p.demo_store { display: block !important; }';
  47. wp_add_inline_style( 'customize-preview', $css );
  48. }
  49. /**
  50. * CSS styles to improve our form.
  51. */
  52. public function add_styles() {
  53. ?>
  54. <style type="text/css">
  55. .woocommerce-cropping-control {
  56. margin: 0 40px 1em 0;
  57. padding: 0;
  58. display:inline-block;
  59. vertical-align: top;
  60. }
  61. .woocommerce-cropping-control input[type=radio] {
  62. margin-top: 1px;
  63. }
  64. .woocommerce-cropping-control span.woocommerce-cropping-control-aspect-ratio {
  65. margin-top: .5em;
  66. display:block;
  67. }
  68. .woocommerce-cropping-control span.woocommerce-cropping-control-aspect-ratio input {
  69. width: auto;
  70. display: inline-block;
  71. }
  72. </style>
  73. <?php
  74. }
  75. /**
  76. * Scripts to improve our form.
  77. */
  78. public function add_scripts() {
  79. $min_rows = wc_get_theme_support( 'product_grid::min_rows', 1 );
  80. $max_rows = wc_get_theme_support( 'product_grid::max_rows', '' );
  81. $min_columns = wc_get_theme_support( 'product_grid::min_columns', 1 );
  82. $max_columns = wc_get_theme_support( 'product_grid::max_columns', '' );
  83. /* translators: %d: Setting value */
  84. $min_notice = __( 'The minimum allowed setting is %d', 'woocommerce' );
  85. /* translators: %d: Setting value */
  86. $max_notice = __( 'The maximum allowed setting is %d', 'woocommerce' );
  87. ?>
  88. <script type="text/javascript">
  89. jQuery( document ).ready( function( $ ) {
  90. $( document.body ).on( 'change', '.woocommerce-cropping-control input[type="radio"]', function() {
  91. var $wrapper = $( this ).closest( '.woocommerce-cropping-control' ),
  92. value = $wrapper.find( 'input:checked' ).val();
  93. if ( 'custom' === value ) {
  94. $wrapper.find( '.woocommerce-cropping-control-aspect-ratio' ).slideDown( 200 );
  95. } else {
  96. $wrapper.find( '.woocommerce-cropping-control-aspect-ratio' ).hide();
  97. }
  98. return false;
  99. } );
  100. wp.customize.bind( 'ready', function() { // Ready?
  101. $( '.woocommerce-cropping-control' ).find( 'input:checked' ).change();
  102. } );
  103. wp.customize( 'woocommerce_demo_store', function( setting ) {
  104. setting.bind( function( value ) {
  105. var notice = wp.customize( 'woocommerce_demo_store_notice' );
  106. if ( value && ! notice.callbacks.has( notice.preview ) ) {
  107. notice.bind( notice.preview );
  108. } else if ( ! value ) {
  109. notice.unbind( notice.preview );
  110. }
  111. } );
  112. } );
  113. wp.customize( 'woocommerce_demo_store_notice', function( setting ) {
  114. setting.bind( function( value ) {
  115. var checkbox = wp.customize( 'woocommerce_demo_store' );
  116. if ( checkbox.get() ) {
  117. $( '.woocommerce-store-notice' ).text( value );
  118. }
  119. } );
  120. } );
  121. wp.customize.section( 'woocommerce_store_notice', function( section ) {
  122. section.expanded.bind( function( isExpanded ) {
  123. if ( isExpanded ) {
  124. var notice = wp.customize( 'woocommerce_demo_store_notice' ),
  125. checkbox = wp.customize( 'woocommerce_demo_store' );
  126. if ( checkbox.get() && ! notice.callbacks.has( notice.preview ) ) {
  127. notice.bind( notice.preview );
  128. } else if ( ! checkbox.get() ) {
  129. notice.unbind( notice.preview );
  130. }
  131. }
  132. } );
  133. } );
  134. wp.customize.section( 'woocommerce_product_catalog', function( section ) {
  135. section.expanded.bind( function( isExpanded ) {
  136. if ( isExpanded ) {
  137. wp.customize.previewer.previewUrl.set( '<?php echo esc_js( wc_get_page_permalink( 'shop' ) ); ?>' );
  138. }
  139. } );
  140. } );
  141. wp.customize.section( 'woocommerce_product_images', function( section ) {
  142. section.expanded.bind( function( isExpanded ) {
  143. if ( isExpanded ) {
  144. wp.customize.previewer.previewUrl.set( '<?php echo esc_js( wc_get_page_permalink( 'shop' ) ); ?>' );
  145. }
  146. } );
  147. } );
  148. wp.customize.section( 'woocommerce_checkout', function( section ) {
  149. section.expanded.bind( function( isExpanded ) {
  150. if ( isExpanded ) {
  151. wp.customize.previewer.previewUrl.set( '<?php echo esc_js( wc_get_page_permalink( 'checkout' ) ); ?>' );
  152. }
  153. } );
  154. } );
  155. wp.customize( 'woocommerce_catalog_columns', function( setting ) {
  156. setting.bind( function( value ) {
  157. var min = parseInt( '<?php echo esc_js( $min_columns ); ?>', 10 );
  158. var max = parseInt( '<?php echo esc_js( $max_columns ); ?>', 10 );
  159. value = parseInt( value, 10 );
  160. if ( max && value > max ) {
  161. setting.notifications.add( 'max_columns_error', new wp.customize.Notification(
  162. 'max_columns_error',
  163. {
  164. type : 'error',
  165. message: '<?php echo esc_js( sprintf( $max_notice, $max_columns ) ); ?>'
  166. }
  167. ) );
  168. } else {
  169. setting.notifications.remove( 'max_columns_error' );
  170. }
  171. if ( min && value < min ) {
  172. setting.notifications.add( 'min_columns_error', new wp.customize.Notification(
  173. 'min_columns_error',
  174. {
  175. type : 'error',
  176. message: '<?php echo esc_js( sprintf( $min_notice, $min_columns ) ); ?>'
  177. }
  178. ) );
  179. } else {
  180. setting.notifications.remove( 'min_columns_error' );
  181. }
  182. } );
  183. } );
  184. wp.customize( 'woocommerce_catalog_rows', function( setting ) {
  185. setting.bind( function( value ) {
  186. var min = parseInt( '<?php echo esc_js( $min_rows ); ?>', 10 );
  187. var max = parseInt( '<?php echo esc_js( $max_rows ); ?>', 10 );
  188. value = parseInt( value, 10 );
  189. if ( max && value > max ) {
  190. setting.notifications.add( 'max_rows_error', new wp.customize.Notification(
  191. 'max_rows_error',
  192. {
  193. type : 'error',
  194. message: '<?php echo esc_js( sprintf( $min_notice, $max_rows ) ); ?>'
  195. }
  196. ) );
  197. } else {
  198. setting.notifications.remove( 'max_rows_error' );
  199. }
  200. if ( min && value < min ) {
  201. setting.notifications.add( 'min_rows_error', new wp.customize.Notification(
  202. 'min_rows_error',
  203. {
  204. type : 'error',
  205. message: '<?php echo esc_js( sprintf( $min_notice, $min_rows ) ); ?>'
  206. }
  207. ) );
  208. } else {
  209. setting.notifications.remove( 'min_rows_error' );
  210. }
  211. } );
  212. } );
  213. } );
  214. </script>
  215. <?php
  216. }
  217. /**
  218. * Sanitize the shop page & category display setting.
  219. *
  220. * @param string $value '', 'subcategories', or 'both'.
  221. * @return string
  222. */
  223. public function sanitize_archive_display( $value ) {
  224. $options = array( '', 'subcategories', 'both' );
  225. return in_array( $value, $options, true ) ? $value : '';
  226. }
  227. /**
  228. * Sanitize the catalog orderby setting.
  229. *
  230. * @param string $value An array key from the below array.
  231. * @return string
  232. */
  233. public function sanitize_default_catalog_orderby( $value ) {
  234. $options = apply_filters( 'woocommerce_default_catalog_orderby_options', array(
  235. 'menu_order' => __( 'Default sorting (custom ordering + name)', 'woocommerce' ),
  236. 'popularity' => __( 'Popularity (sales)', 'woocommerce' ),
  237. 'rating' => __( 'Average rating', 'woocommerce' ),
  238. 'date' => __( 'Sort by most recent', 'woocommerce' ),
  239. 'price' => __( 'Sort by price (asc)', 'woocommerce' ),
  240. 'price-desc' => __( 'Sort by price (desc)', 'woocommerce' ),
  241. ) );
  242. return array_key_exists( $value, $options ) ? $value : 'menu_order';
  243. }
  244. /**
  245. * Store notice section.
  246. *
  247. * @param WP_Customize_Manager $wp_customize Theme Customizer object.
  248. */
  249. private function add_store_notice_section( $wp_customize ) {
  250. $wp_customize->add_section(
  251. 'woocommerce_store_notice',
  252. array(
  253. 'title' => __( 'Store Notice', 'woocommerce' ),
  254. 'priority' => 10,
  255. 'panel' => 'woocommerce',
  256. )
  257. );
  258. $wp_customize->add_setting(
  259. 'woocommerce_demo_store',
  260. array(
  261. 'default' => 'no',
  262. 'type' => 'option',
  263. 'capability' => 'manage_woocommerce',
  264. 'sanitize_callback' => 'wc_bool_to_string',
  265. 'sanitize_js_callback' => 'wc_string_to_bool',
  266. )
  267. );
  268. $wp_customize->add_setting(
  269. 'woocommerce_demo_store_notice',
  270. array(
  271. 'default' => __( 'This is a demo store for testing purposes &mdash; no orders shall be fulfilled.', 'woocommerce' ),
  272. 'type' => 'option',
  273. 'capability' => 'manage_woocommerce',
  274. 'sanitize_callback' => 'wp_kses_post',
  275. 'transport' => 'postMessage',
  276. )
  277. );
  278. $wp_customize->add_control(
  279. 'woocommerce_demo_store_notice',
  280. array(
  281. 'label' => __( 'Store notice', 'woocommerce' ),
  282. 'description' => __( 'If enabled, this text will be shown site-wide. You can use it to show events or promotions to visitors!', 'woocommerce' ),
  283. 'section' => 'woocommerce_store_notice',
  284. 'settings' => 'woocommerce_demo_store_notice',
  285. 'type' => 'textarea',
  286. )
  287. );
  288. $wp_customize->add_control(
  289. 'woocommerce_demo_store',
  290. array(
  291. 'label' => __( 'Enable store notice', 'woocommerce' ),
  292. 'section' => 'woocommerce_store_notice',
  293. 'settings' => 'woocommerce_demo_store',
  294. 'type' => 'checkbox',
  295. )
  296. );
  297. if ( isset( $wp_customize->selective_refresh ) ) {
  298. $wp_customize->selective_refresh->add_partial(
  299. 'woocommerce_demo_store_notice', array(
  300. 'selector' => '.woocommerce-store-notice',
  301. 'container_inclusive' => true,
  302. 'render_callback' => 'woocommerce_demo_store',
  303. )
  304. );
  305. }
  306. }
  307. /**
  308. * Product catalog section.
  309. *
  310. * @param WP_Customize_Manager $wp_customize Theme Customizer object.
  311. */
  312. public function add_product_catalog_section( $wp_customize ) {
  313. $wp_customize->add_section(
  314. 'woocommerce_product_catalog',
  315. array(
  316. 'title' => __( 'Product Catalog', 'woocommerce' ),
  317. 'priority' => 10,
  318. 'panel' => 'woocommerce',
  319. )
  320. );
  321. $wp_customize->add_setting(
  322. 'woocommerce_shop_page_display',
  323. array(
  324. 'default' => '',
  325. 'type' => 'option',
  326. 'capability' => 'manage_woocommerce',
  327. 'sanitize_callback' => array( $this, 'sanitize_archive_display' ),
  328. )
  329. );
  330. $wp_customize->add_control(
  331. 'woocommerce_shop_page_display',
  332. array(
  333. 'label' => __( 'Shop page display', 'woocommerce' ),
  334. 'description' => __( 'Choose what to display on the main shop page.', 'woocommerce' ),
  335. 'section' => 'woocommerce_product_catalog',
  336. 'settings' => 'woocommerce_shop_page_display',
  337. 'type' => 'select',
  338. 'choices' => array(
  339. '' => __( 'Show products', 'woocommerce' ),
  340. 'subcategories' => __( 'Show categories', 'woocommerce' ),
  341. 'both' => __( 'Show categories &amp; products', 'woocommerce' ),
  342. ),
  343. )
  344. );
  345. $wp_customize->add_setting(
  346. 'woocommerce_category_archive_display',
  347. array(
  348. 'default' => '',
  349. 'type' => 'option',
  350. 'capability' => 'manage_woocommerce',
  351. 'sanitize_callback' => array( $this, 'sanitize_archive_display' ),
  352. )
  353. );
  354. $wp_customize->add_control(
  355. 'woocommerce_category_archive_display',
  356. array(
  357. 'label' => __( 'Category display', 'woocommerce' ),
  358. 'description' => __( 'Choose what to display on product category pages.', 'woocommerce' ),
  359. 'section' => 'woocommerce_product_catalog',
  360. 'settings' => 'woocommerce_category_archive_display',
  361. 'type' => 'select',
  362. 'choices' => array(
  363. '' => __( 'Show products', 'woocommerce' ),
  364. 'subcategories' => __( 'Show subcategories', 'woocommerce' ),
  365. 'both' => __( 'Show subcategories &amp; products', 'woocommerce' ),
  366. ),
  367. )
  368. );
  369. $wp_customize->add_setting(
  370. 'woocommerce_default_catalog_orderby',
  371. array(
  372. 'default' => 'menu_order',
  373. 'type' => 'option',
  374. 'capability' => 'manage_woocommerce',
  375. 'sanitize_callback' => array( $this, 'sanitize_default_catalog_orderby' ),
  376. )
  377. );
  378. $wp_customize->add_control(
  379. 'woocommerce_default_catalog_orderby',
  380. array(
  381. 'label' => __( 'Default product sorting', 'woocommerce' ),
  382. 'description' => __( 'How should products be sorted in the catalog by default?', 'woocommerce' ),
  383. 'section' => 'woocommerce_product_catalog',
  384. 'settings' => 'woocommerce_default_catalog_orderby',
  385. 'type' => 'select',
  386. 'choices' => apply_filters( 'woocommerce_default_catalog_orderby_options', array(
  387. 'menu_order' => __( 'Default sorting (custom ordering + name)', 'woocommerce' ),
  388. 'popularity' => __( 'Popularity (sales)', 'woocommerce' ),
  389. 'rating' => __( 'Average rating', 'woocommerce' ),
  390. 'date' => __( 'Sort by most recent', 'woocommerce' ),
  391. 'price' => __( 'Sort by price (asc)', 'woocommerce' ),
  392. 'price-desc' => __( 'Sort by price (desc)', 'woocommerce' ),
  393. ) ),
  394. )
  395. );
  396. // The following settings should be hidden if the theme is declaring the values.
  397. if ( has_filter( 'loop_shop_columns' ) ) {
  398. return;
  399. }
  400. $wp_customize->add_setting(
  401. 'woocommerce_catalog_columns',
  402. array(
  403. 'default' => 4,
  404. 'type' => 'option',
  405. 'capability' => 'manage_woocommerce',
  406. 'sanitize_callback' => 'absint',
  407. 'sanitize_js_callback' => 'absint',
  408. )
  409. );
  410. $wp_customize->add_control(
  411. 'woocommerce_catalog_columns',
  412. array(
  413. 'label' => __( 'Products per row', 'woocommerce' ),
  414. 'description' => __( 'How many products should be shown per row?', 'woocommerce' ),
  415. 'section' => 'woocommerce_product_catalog',
  416. 'settings' => 'woocommerce_catalog_columns',
  417. 'type' => 'number',
  418. 'input_attrs' => array(
  419. 'min' => wc_get_theme_support( 'product_grid::min_columns', 1 ),
  420. 'max' => wc_get_theme_support( 'product_grid::max_columns', '' ),
  421. 'step' => 1,
  422. ),
  423. )
  424. );
  425. // Only add this setting if something else isn't managing the number of products per page.
  426. if ( ! has_filter( 'loop_shop_per_page' ) ) {
  427. $wp_customize->add_setting(
  428. 'woocommerce_catalog_rows',
  429. array(
  430. 'default' => 4,
  431. 'type' => 'option',
  432. 'capability' => 'manage_woocommerce',
  433. 'sanitize_callback' => 'absint',
  434. 'sanitize_js_callback' => 'absint',
  435. )
  436. );
  437. }
  438. $wp_customize->add_control(
  439. 'woocommerce_catalog_rows',
  440. array(
  441. 'label' => __( 'Rows per page', 'woocommerce' ),
  442. 'description' => __( 'How many rows of products should be shown per page?', 'woocommerce' ),
  443. 'section' => 'woocommerce_product_catalog',
  444. 'settings' => 'woocommerce_catalog_rows',
  445. 'type' => 'number',
  446. 'input_attrs' => array(
  447. 'min' => wc_get_theme_support( 'product_grid::min_rows', 1 ),
  448. 'max' => wc_get_theme_support( 'product_grid::max_rows', '' ),
  449. 'step' => 1,
  450. ),
  451. )
  452. );
  453. }
  454. /**
  455. * Product images section.
  456. *
  457. * @param WP_Customize_Manager $wp_customize Theme Customizer object.
  458. */
  459. private function add_product_images_section( $wp_customize ) {
  460. if ( class_exists( 'Jetpack' ) && Jetpack::is_module_active( 'photon' ) ) {
  461. $regen_description = ''; // Nothing to report; Jetpack will handle magically.
  462. } elseif ( apply_filters( 'woocommerce_background_image_regeneration', true ) && ! is_multisite() ) {
  463. $regen_description = __( 'After publishing your changes, new image sizes will be generated automatically.', 'woocommerce' );
  464. } elseif ( apply_filters( 'woocommerce_background_image_regeneration', true ) && is_multisite() ) {
  465. /* translators: 1: tools URL 2: regen thumbs url */
  466. $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/' );
  467. } else {
  468. /* translators: %s: regen thumbs url */
  469. $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/' );
  470. }
  471. $wp_customize->add_section(
  472. 'woocommerce_product_images',
  473. array(
  474. 'title' => __( 'Product Images', 'woocommerce' ),
  475. 'description' => $regen_description,
  476. 'priority' => 20,
  477. 'panel' => 'woocommerce',
  478. )
  479. );
  480. if ( ! wc_get_theme_support( 'single_image_width' ) ) {
  481. $wp_customize->add_setting(
  482. 'woocommerce_single_image_width',
  483. array(
  484. 'default' => 600,
  485. 'type' => 'option',
  486. 'capability' => 'manage_woocommerce',
  487. 'sanitize_callback' => 'absint',
  488. 'sanitize_js_callback' => 'absint',
  489. )
  490. );
  491. $wp_customize->add_control(
  492. 'woocommerce_single_image_width',
  493. array(
  494. 'label' => __( 'Main image width', 'woocommerce' ),
  495. 'description' => __( 'Image size used for the main image on single product pages. These images will remain uncropped.', 'woocommerce' ),
  496. 'section' => 'woocommerce_product_images',
  497. 'settings' => 'woocommerce_single_image_width',
  498. 'type' => 'number',
  499. 'input_attrs' => array(
  500. 'min' => 0,
  501. 'step' => 1,
  502. ),
  503. )
  504. );
  505. }
  506. if ( ! wc_get_theme_support( 'thumbnail_image_width' ) ) {
  507. $wp_customize->add_setting(
  508. 'woocommerce_thumbnail_image_width',
  509. array(
  510. 'default' => 300,
  511. 'type' => 'option',
  512. 'capability' => 'manage_woocommerce',
  513. 'sanitize_callback' => 'absint',
  514. 'sanitize_js_callback' => 'absint',
  515. )
  516. );
  517. $wp_customize->add_control(
  518. 'woocommerce_thumbnail_image_width',
  519. array(
  520. 'label' => __( 'Thumbnail width', 'woocommerce' ),
  521. 'description' => __( 'Image size used for products in the catalog.', 'woocommerce' ),
  522. 'section' => 'woocommerce_product_images',
  523. 'settings' => 'woocommerce_thumbnail_image_width',
  524. 'type' => 'number',
  525. 'input_attrs' => array(
  526. 'min' => 0,
  527. 'step' => 1,
  528. ),
  529. )
  530. );
  531. }
  532. include_once WC_ABSPATH . 'includes/customizer/class-wc-customizer-control-cropping.php';
  533. $wp_customize->add_setting(
  534. 'woocommerce_thumbnail_cropping',
  535. array(
  536. 'default' => '1:1',
  537. 'type' => 'option',
  538. 'capability' => 'manage_woocommerce',
  539. 'sanitize_callback' => 'wc_clean',
  540. )
  541. );
  542. $wp_customize->add_setting(
  543. 'woocommerce_thumbnail_cropping_custom_width',
  544. array(
  545. 'default' => '4',
  546. 'type' => 'option',
  547. 'capability' => 'manage_woocommerce',
  548. 'sanitize_callback' => 'absint',
  549. 'sanitize_js_callback' => 'absint',
  550. )
  551. );
  552. $wp_customize->add_setting(
  553. 'woocommerce_thumbnail_cropping_custom_height',
  554. array(
  555. 'default' => '3',
  556. 'type' => 'option',
  557. 'capability' => 'manage_woocommerce',
  558. 'sanitize_callback' => 'absint',
  559. 'sanitize_js_callback' => 'absint',
  560. )
  561. );
  562. $wp_customize->add_control(
  563. new WC_Customizer_Control_Cropping(
  564. $wp_customize,
  565. 'woocommerce_thumbnail_cropping',
  566. array(
  567. 'section' => 'woocommerce_product_images',
  568. 'settings' => array(
  569. 'cropping' => 'woocommerce_thumbnail_cropping',
  570. 'custom_width' => 'woocommerce_thumbnail_cropping_custom_width',
  571. 'custom_height' => 'woocommerce_thumbnail_cropping_custom_height',
  572. ),
  573. 'label' => __( 'Thumbnail cropping', 'woocommerce' ),
  574. 'choices' => array(
  575. '1:1' => array(
  576. 'label' => __( '1:1', 'woocommerce' ),
  577. 'description' => __( 'Images will be cropped into a square', 'woocommerce' ),
  578. ),
  579. 'custom' => array(
  580. 'label' => __( 'Custom', 'woocommerce' ),
  581. 'description' => __( 'Images will be cropped to a custom aspect ratio', 'woocommerce' ),
  582. ),
  583. 'uncropped' => array(
  584. 'label' => __( 'Uncropped', 'woocommerce' ),
  585. 'description' => __( 'Images will display using the aspect ratio in which they were uploaded', 'woocommerce' ),
  586. ),
  587. ),
  588. )
  589. )
  590. );
  591. }
  592. /**
  593. * Checkout section.
  594. *
  595. * @param WP_Customize_Manager $wp_customize Theme Customizer object.
  596. */
  597. public function add_checkout_section( $wp_customize ) {
  598. $wp_customize->add_section(
  599. 'woocommerce_checkout',
  600. array(
  601. 'title' => __( 'Checkout', 'woocommerce' ),
  602. 'priority' => 20,
  603. 'panel' => 'woocommerce',
  604. 'description' => __( 'These options let you change the appearance of the WooCommerce checkout.', 'woocommerce' ),
  605. )
  606. );
  607. // Checkout field controls.
  608. $fields = array(
  609. 'company' => __( 'Company name', 'woocommerce' ),
  610. 'address_2' => __( 'Address line 2', 'woocommerce' ),
  611. 'phone' => __( 'Phone', 'woocommerce' ),
  612. );
  613. foreach ( $fields as $field => $label ) {
  614. $wp_customize->add_setting(
  615. 'woocommerce_checkout_' . $field . '_field',
  616. array(
  617. 'default' => 'phone' === $field ? 'required' : 'optional',
  618. 'type' => 'option',
  619. 'capability' => 'manage_woocommerce',
  620. 'sanitize_callback' => array( $this, 'sanitize_checkout_field_display' ),
  621. )
  622. );
  623. $wp_customize->add_control(
  624. 'woocommerce_checkout_' . $field . '_field',
  625. array(
  626. /* Translators: %s field name. */
  627. 'label' => sprintf( __( '%s field', 'woocommerce' ), $label ),
  628. 'section' => 'woocommerce_checkout',
  629. 'settings' => 'woocommerce_checkout_' . $field . '_field',
  630. 'type' => 'select',
  631. 'choices' => array(
  632. 'hidden' => __( 'Hidden', 'woocommerce' ),
  633. 'optional' => __( 'Optional', 'woocommerce' ),
  634. 'required' => __( 'Required', 'woocommerce' ),
  635. ),
  636. )
  637. );
  638. }
  639. // Register settings.
  640. $wp_customize->add_setting(
  641. 'woocommerce_checkout_highlight_required_fields',
  642. array(
  643. 'default' => 'yes',
  644. 'type' => 'option',
  645. 'capability' => 'manage_woocommerce',
  646. 'sanitize_callback' => 'wc_bool_to_string',
  647. 'sanitize_js_callback' => 'wc_string_to_bool',
  648. )
  649. );
  650. $wp_customize->add_setting(
  651. 'woocommerce_checkout_terms_and_conditions_checkbox_text',
  652. array(
  653. /* translators: %s terms and conditions page name and link */
  654. 'default' => sprintf( __( 'I have read and agree to the website %s', 'woocommerce' ), '[terms]' ),
  655. 'type' => 'option',
  656. 'capability' => 'manage_woocommerce',
  657. 'sanitize_callback' => 'wp_kses_post',
  658. 'transport' => 'postMessage',
  659. )
  660. );
  661. $wp_customize->add_setting(
  662. 'woocommerce_checkout_privacy_policy_text',
  663. array(
  664. /* translators: %s privacy policy page name and link */
  665. '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]' ),
  666. 'type' => 'option',
  667. 'capability' => 'manage_woocommerce',
  668. 'sanitize_callback' => 'wp_kses_post',
  669. 'transport' => 'postMessage',
  670. )
  671. );
  672. // Register controls.
  673. $wp_customize->add_control(
  674. 'woocommerce_checkout_highlight_required_fields',
  675. array(
  676. 'label' => __( 'Highlight required fields with an asterisk', 'woocommerce' ),
  677. 'section' => 'woocommerce_checkout',
  678. 'settings' => 'woocommerce_checkout_highlight_required_fields',
  679. 'type' => 'checkbox',
  680. )
  681. );
  682. $choose_pages = array(
  683. 'wp_page_for_privacy_policy' => __( 'Privacy policy', 'woocommerce' ),
  684. 'woocommerce_terms_page_id' => __( 'Terms and conditions', 'woocommerce' ),
  685. );
  686. $pages = get_pages( array(
  687. 'post_type' => 'page',
  688. 'post_status' => 'publish,private,draft',
  689. 'child_of' => 0,
  690. 'parent' => -1,
  691. 'exclude' => array(
  692. wc_get_page_id( 'cart' ),
  693. wc_get_page_id( 'checkout' ),
  694. wc_get_page_id( 'myaccount' ),
  695. ),
  696. 'sort_order' => 'asc',
  697. 'sort_column' => 'post_title',
  698. ) );
  699. $page_choices = array( '' => __( 'No page set', 'woocommerce' ) ) + array_combine( array_map( 'strval', wp_list_pluck( $pages, 'ID' ) ), wp_list_pluck( $pages, 'post_title' ) );
  700. foreach ( $choose_pages as $id => $name ) {
  701. $wp_customize->add_setting(
  702. $id,
  703. array(
  704. 'default' => '',
  705. 'type' => 'option',
  706. 'capability' => 'manage_woocommerce',
  707. )
  708. );
  709. $wp_customize->add_control(
  710. $id,
  711. array(
  712. /* Translators: %s: page name. */
  713. 'label' => sprintf( __( '%s page', 'woocommerce' ), $name ),
  714. 'section' => 'woocommerce_checkout',
  715. 'settings' => $id,
  716. 'type' => 'select',
  717. 'choices' => $page_choices,
  718. )
  719. );
  720. }
  721. $wp_customize->add_control(
  722. 'woocommerce_checkout_privacy_policy_text',
  723. array(
  724. 'label' => __( 'Privacy policy', 'woocommerce' ),
  725. 'description' => __( 'Optionally add some text about your store privacy policy to show during checkout.', 'woocommerce' ),
  726. 'section' => 'woocommerce_checkout',
  727. 'settings' => 'woocommerce_checkout_privacy_policy_text',
  728. 'active_callback' => 'wc_privacy_policy_page_id',
  729. 'type' => 'textarea',
  730. )
  731. );
  732. $wp_customize->add_control(
  733. 'woocommerce_checkout_terms_and_conditions_checkbox_text',
  734. array(
  735. 'label' => __( 'Terms and conditions', 'woocommerce' ),
  736. 'description' => __( 'Optionally add some text for the terms checkbox that customers must accept.', 'woocommerce' ),
  737. 'section' => 'woocommerce_checkout',
  738. 'settings' => 'woocommerce_checkout_terms_and_conditions_checkbox_text',
  739. 'active_callback' => 'wc_terms_and_conditions_page_id',
  740. 'type' => 'text',
  741. )
  742. );
  743. if ( isset( $wp_customize->selective_refresh ) ) {
  744. $wp_customize->selective_refresh->add_partial(
  745. 'woocommerce_checkout_privacy_policy_text', array(
  746. 'selector' => '.woocommerce-privacy-policy-text',
  747. 'container_inclusive' => true,
  748. 'render_callback' => 'wc_checkout_privacy_policy_text',
  749. )
  750. );
  751. $wp_customize->selective_refresh->add_partial(
  752. 'woocommerce_checkout_terms_and_conditions_checkbox_text', array(
  753. 'selector' => '.woocommerce-terms-and-conditions-checkbox-text',
  754. 'container_inclusive' => false,
  755. 'render_callback' => 'wc_terms_and_conditions_checkbox_text',
  756. )
  757. );
  758. }
  759. }
  760. /**
  761. * Sanitize field display.
  762. *
  763. * @param string $value '', 'subcategories', or 'both'.
  764. * @return string
  765. */
  766. public function sanitize_checkout_field_display( $value ) {
  767. $options = array( 'hidden', 'optional', 'required' );
  768. return in_array( $value, $options, true ) ? $value : '';
  769. }
  770. }
  771. new WC_Shop_Customizer();