Açıklama Yok

class-wc-shop-customizer.php 30KB

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