wp-customize-colors.php 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. <?php
  2. require_once 'wp-customize-global-styles-setting.php';
  3. require_once 'wp-customize-utils.php';
  4. class GlobalStylesColorCustomizer {
  5. private $section_key = 'customize-global-styles-colors';
  6. private $user_color_palette;
  7. function __construct() {
  8. add_action( 'customize_register', array( $this, 'initialize' ) );
  9. add_action( 'customize_preview_init', array( $this, 'customize_preview_js' ) );
  10. add_action( 'customize_register', array( $this, 'create_customization_style_element' ) );
  11. add_action( 'customize_save_after', array( $this, 'handle_customize_save_after' ) );
  12. }
  13. function customize_preview_js() {
  14. wp_enqueue_script( 'customizer-preview-color', get_template_directory_uri() . '/inc/customizer/wp-customize-colors-preview.js', array( 'customize-preview' ) );
  15. wp_add_inline_script( 'customizer-preview-color', 'var userColorSectionKey="' . $this->section_key . '";', 'before' );
  16. wp_localize_script( 'customizer-preview-color', 'userColorPalette', $this->user_color_palette );
  17. if ( $this->theme_duotone_settings ) {
  18. wp_enqueue_script( 'colord', get_template_directory_uri() . '/inc/customizer/vendors/colord.min.js' );
  19. wp_localize_script( 'customizer-preview-color', 'userColorDuotone', $this->theme_duotone_settings );
  20. }
  21. }
  22. function update_user_color_palette( $wp_customize ) {
  23. foreach ( $this->user_color_palette as $key => $palette_item ) {
  24. $setting = $wp_customize->get_setting( $this->section_key . $palette_item['slug'] );
  25. if ( null !== $setting->post_value() ) {
  26. $this->user_color_palette[ $key ]['color'] = $setting->post_value();
  27. }
  28. }
  29. }
  30. function create_customization_style_element( $wp_customize ) {
  31. wp_enqueue_style( 'global-styles-colors-customizations', ' ', array( 'global-styles' ) ); // This needs to load after global_styles, hence the dependency
  32. $this->update_user_color_palette( $wp_customize );
  33. $css = ':root,body{';
  34. foreach ( $this->user_color_palette as $key => $palette_item ) {
  35. $setting = $wp_customize->get_setting( $this->section_key . $palette_item['slug'] );
  36. $css .= '--wp--preset--color--' . $palette_item['slug'] . ':' . $palette_item['color'] . ';';
  37. }
  38. $css .= '}';
  39. wp_add_inline_style( 'global-styles-colors-customizations', $css );
  40. }
  41. function initialize( $wp_customize ) {
  42. $this->user_color_palette = $this->build_user_color_palette();
  43. $this->theme_duotone_settings = $this->get_theme_duotone_settings();
  44. $this->register_color_controls( $wp_customize, $this->user_color_palette );
  45. }
  46. function get_theme_duotone_settings() {
  47. // Get the merged theme.json.
  48. $theme_json = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_raw_data();
  49. if ( array_key_exists( 'settings', $theme_json ) && array_key_exists( 'color', $theme_json['settings'] ) && array_key_exists( 'duotone', $theme_json['settings']['color'] ) && array_key_exists( 'theme', $theme_json['settings']['color']['duotone'] ) ) {
  50. return $theme_json['settings']['color']['duotone']['theme'];
  51. }
  52. return false;
  53. }
  54. function build_user_color_palette() {
  55. // Get the merged theme.json.
  56. $theme_json = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_raw_data();
  57. $combined_color_palette = $theme_json['settings']['color']['palette']['theme'];
  58. $user_color_palette = null;
  59. if ( isset( $theme_json['settings']['color']['palette']['custom'] ) ) {
  60. $user_color_palette = $theme_json['settings']['color']['palette']['custom'];
  61. }
  62. // NOTE: This should be removed once Gutenberg 12.1 lands stably in all environments
  63. else if ( isset( $theme_json['settings']['color']['palette']['user'] ) ) {
  64. $user_color_palette = $theme_json['settings']['color']['palette']['user'];
  65. }
  66. // End Gutenberg < 12.1 compatibility patch
  67. // Combine theme settings with user settings.
  68. foreach ( $combined_color_palette as $key => $palette_item ) {
  69. //make theme color value the default
  70. $combined_color_palette[ $key ]['default'] = $combined_color_palette[ $key ]['color'];
  71. //use user color value if there is one
  72. $user_color_value = $this->get_user_color_value( $palette_item['slug'], $user_color_palette );
  73. if ( isset( $user_color_value ) ) {
  74. $combined_color_palette[ $key ]['color'] = $user_color_value;
  75. }
  76. }
  77. return $combined_color_palette;
  78. }
  79. function get_user_color_value( $slug, $palette ) {
  80. if ( ! isset( $palette ) ) {
  81. return null;
  82. }
  83. foreach ( $palette as $palette_item ) {
  84. if ( $palette_item['slug'] === $slug ) {
  85. return $palette_item['color'];
  86. }
  87. }
  88. return null;
  89. }
  90. function register_color_controls( $wp_customize, $palette ) {
  91. $theme = wp_get_theme();
  92. //Add a Section to the Customizer for these bits
  93. $wp_customize->add_section(
  94. $this->section_key,
  95. array(
  96. 'capability' => 'edit_theme_options',
  97. 'description' => sprintf( __( 'Color Customization for %1$s', 'blockbase' ), $theme->name ),
  98. 'title' => __( 'Colors', 'blockbase' ),
  99. )
  100. );
  101. foreach ( $palette as $palette_item ) {
  102. $this->register_color_control( $wp_customize, $palette_item );
  103. }
  104. }
  105. function register_color_control( $wp_customize, $palette_item ) {
  106. $setting_key = $this->section_key . $palette_item['slug'];
  107. $global_styles_setting = new WP_Customize_Global_Styles_Setting(
  108. $wp_customize,
  109. $setting_key,
  110. array(
  111. 'default' => $palette_item['default'],
  112. 'user_value' => $palette_item['color'],
  113. )
  114. );
  115. $wp_customize->add_setting(
  116. $global_styles_setting,
  117. array(
  118. 'sanitize_callback' => 'sanitize_hex_color'
  119. )
  120. );
  121. $wp_customize->add_control(
  122. new WP_Customize_Color_Control(
  123. $wp_customize,
  124. $setting_key,
  125. array(
  126. 'section' => $this->section_key,
  127. 'label' => $palette_item['name'],
  128. )
  129. )
  130. );
  131. }
  132. function handle_customize_save_after( $wp_customize ) {
  133. //update the palette based on the controls
  134. $this->update_user_color_palette( $wp_customize );
  135. // Get the user's theme.json from the CPT.
  136. if ( method_exists( 'WP_Theme_JSON_Resolver_Gutenberg', 'get_user_global_styles_post_id' ) ) { // This is the new name.
  137. $user_custom_post_type_id = WP_Theme_JSON_Resolver_Gutenberg::get_user_global_styles_post_id();
  138. } else if ( method_exists( 'WP_Theme_JSON_Resolver_Gutenberg', 'get_user_custom_post_type_id' ) ) { // This is the old name.
  139. $user_custom_post_type_id = WP_Theme_JSON_Resolver_Gutenberg::get_user_custom_post_type_id();
  140. }
  141. $user_theme_json_post = get_post( $user_custom_post_type_id );
  142. $user_theme_json_post_content = json_decode( $user_theme_json_post->post_content );
  143. // Set meta settings.
  144. $user_theme_json_post_content->version = 1;
  145. $user_theme_json_post_content->isGlobalStylesUserThemeJSON = true;
  146. // Only reset the palette if the setting exists, otherwise the whole settings array gets destroyed.
  147. if ( property_exists( $user_theme_json_post_content, 'settings' ) && property_exists( $user_theme_json_post_content->settings, 'color' ) && property_exists( $user_theme_json_post_content->settings->color, 'palette' ) ) {
  148. // Start with reset palette settings.
  149. unset( $user_theme_json_post_content->settings->color->palette );
  150. }
  151. //Set the color palette if it is !== the default
  152. if ( ! $this->check_if_colors_are_default() ) {
  153. $user_theme_json_post_content = set_settings_array(
  154. $user_theme_json_post_content,
  155. array( 'settings', 'color', 'palette', 'custom' ),
  156. $this->user_color_palette
  157. );
  158. $primary_key = array_search('primary', array_column($this->user_color_palette, 'slug'));
  159. $background_key = array_search('background', array_column($this->user_color_palette, 'slug'));
  160. if ( $this->theme_duotone_settings && $primary_key !== null && $background_key !== null ) {
  161. $primary = $this->user_color_palette[$primary_key];
  162. $background = $this->user_color_palette[$background_key];
  163. //we invert the colors when the background is darker than the primary color
  164. if( colorLuminescence($primary['color']) > colorLuminescence($background['color']) ) {
  165. $primary = $this->user_color_palette[$background_key];
  166. $background = $this->user_color_palette[$primary_key];
  167. }
  168. $custom_duotone_filter = array(
  169. array(
  170. "colors" => array( $primary['color'], $background['color'] ),
  171. "slug" => "custom-filter",
  172. "name" => "Custom filter"
  173. )
  174. );
  175. $custom_duotone_filter_variable = "var(--wp--preset--duotone--custom-filter)";
  176. $user_theme_json_post_content = set_settings_array(
  177. $user_theme_json_post_content,
  178. array( 'settings', 'color', 'duotone', 'custom' ),
  179. array_merge( $custom_duotone_filter, $this->theme_duotone_settings )
  180. );
  181. //replace the new filter in all blocks using duotone
  182. $theme_json = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_raw_data();
  183. if ( $theme_json['styles'] && $theme_json['styles']['blocks'] ) {
  184. foreach ( $theme_json['styles']['blocks'] as $key => $block ) {
  185. if( $block['filter'] ) {
  186. $user_theme_json_post_content = set_settings_array(
  187. $user_theme_json_post_content,
  188. array( 'styles', 'blocks', $key, 'filter', 'duotone', 'custom' ),
  189. $custom_duotone_filter_variable
  190. );
  191. }
  192. }
  193. }
  194. }
  195. }
  196. // Update the theme.json with the new settings.
  197. $user_theme_json_post->post_content = json_encode( $user_theme_json_post_content );
  198. wp_update_post( $user_theme_json_post );
  199. delete_transient( 'global_styles' );
  200. delete_transient( 'global_styles_' . get_stylesheet() );
  201. delete_transient( 'gutenberg_global_styles' );
  202. delete_transient( 'gutenberg_global_styles_' . get_stylesheet() );
  203. }
  204. function check_if_colors_are_default() {
  205. foreach ( $this->user_color_palette as $palette_color ) {
  206. if ( strtoupper( $palette_color['color'] ) !== strtoupper( $palette_color['default'] ) ) {
  207. return false;
  208. }
  209. }
  210. return true;
  211. }
  212. }
  213. new GlobalStylesColorCustomizer;