class-wp-customize-custom-css-setting.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. <?php
  2. /**
  3. * Customize API: WP_Customize_Custom_CSS_Setting class
  4. *
  5. * This handles validation, sanitization and saving of the value.
  6. *
  7. * @package WordPress
  8. * @subpackage Customize
  9. * @since 4.7.0
  10. */
  11. /**
  12. * Custom Setting to handle WP Custom CSS.
  13. *
  14. * @since 4.7.0
  15. *
  16. * @see WP_Customize_Setting
  17. */
  18. final class WP_Customize_Custom_CSS_Setting extends WP_Customize_Setting {
  19. /**
  20. * The setting type.
  21. *
  22. * @since 4.7.0
  23. * @var string
  24. */
  25. public $type = 'custom_css';
  26. /**
  27. * Setting Transport
  28. *
  29. * @since 4.7.0
  30. * @var string
  31. */
  32. public $transport = 'postMessage';
  33. /**
  34. * Capability required to edit this setting.
  35. *
  36. * @since 4.7.0
  37. * @var string
  38. */
  39. public $capability = 'edit_css';
  40. /**
  41. * Stylesheet
  42. *
  43. * @since 4.7.0
  44. * @var string
  45. */
  46. public $stylesheet = '';
  47. /**
  48. * WP_Customize_Custom_CSS_Setting constructor.
  49. *
  50. * @since 4.7.0
  51. *
  52. * @throws Exception If the setting ID does not match the pattern `custom_css[$stylesheet]`.
  53. *
  54. * @param WP_Customize_Manager $manager Customizer bootstrap instance.
  55. * @param string $id A specific ID of the setting.
  56. * Can be a theme mod or option name.
  57. * @param array $args Setting arguments.
  58. */
  59. public function __construct( $manager, $id, $args = array() ) {
  60. parent::__construct( $manager, $id, $args );
  61. if ( 'custom_css' !== $this->id_data['base'] ) {
  62. throw new Exception( 'Expected custom_css id_base.' );
  63. }
  64. if ( 1 !== count( $this->id_data['keys'] ) || empty( $this->id_data['keys'][0] ) ) {
  65. throw new Exception( 'Expected single stylesheet key.' );
  66. }
  67. $this->stylesheet = $this->id_data['keys'][0];
  68. }
  69. /**
  70. * Add filter to preview post value.
  71. *
  72. * @since 4.7.9
  73. *
  74. * @return bool False when preview short-circuits due no change needing to be previewed.
  75. */
  76. public function preview() {
  77. if ( $this->is_previewed ) {
  78. return false;
  79. }
  80. $this->is_previewed = true;
  81. add_filter( 'wp_get_custom_css', array( $this, 'filter_previewed_wp_get_custom_css' ), 9, 2 );
  82. return true;
  83. }
  84. /**
  85. * Filters `wp_get_custom_css` for applying the customized value.
  86. *
  87. * This is used in the preview when `wp_get_custom_css()` is called for rendering the styles.
  88. *
  89. * @since 4.7.0
  90. *
  91. * @see wp_get_custom_css()
  92. *
  93. * @param string $css Original CSS.
  94. * @param string $stylesheet Current stylesheet.
  95. * @return string CSS.
  96. */
  97. public function filter_previewed_wp_get_custom_css( $css, $stylesheet ) {
  98. if ( $stylesheet === $this->stylesheet ) {
  99. $customized_value = $this->post_value( null );
  100. if ( ! is_null( $customized_value ) ) {
  101. $css = $customized_value;
  102. }
  103. }
  104. return $css;
  105. }
  106. /**
  107. * Fetch the value of the setting. Will return the previewed value when `preview()` is called.
  108. *
  109. * @since 4.7.0
  110. *
  111. * @see WP_Customize_Setting::value()
  112. *
  113. * @return string
  114. */
  115. public function value() {
  116. if ( $this->is_previewed ) {
  117. $post_value = $this->post_value( null );
  118. if ( null !== $post_value ) {
  119. return $post_value;
  120. }
  121. }
  122. $id_base = $this->id_data['base'];
  123. $value = '';
  124. $post = wp_get_custom_css_post( $this->stylesheet );
  125. if ( $post ) {
  126. $value = $post->post_content;
  127. }
  128. if ( empty( $value ) ) {
  129. $value = $this->default;
  130. }
  131. /** This filter is documented in wp-includes/class-wp-customize-setting.php */
  132. $value = apply_filters( "customize_value_{$id_base}", $value, $this );
  133. return $value;
  134. }
  135. /**
  136. * Validate a received value for being valid CSS.
  137. *
  138. * Checks for imbalanced braces, brackets, and comments.
  139. * Notifications are rendered when the customizer state is saved.
  140. *
  141. * @since 4.7.0
  142. * @since 4.9.0 Checking for balanced characters has been moved client-side via linting in code editor.
  143. * @since 5.9.0 Renamed `$css` to `$value` for PHP 8 named parameter support.
  144. *
  145. * @param string $value CSS to validate.
  146. * @return true|WP_Error True if the input was validated, otherwise WP_Error.
  147. */
  148. public function validate( $value ) {
  149. // Restores the more descriptive, specific name for use within this method.
  150. $css = $value;
  151. $validity = new WP_Error();
  152. if ( preg_match( '#</?\w+#', $css ) ) {
  153. $validity->add( 'illegal_markup', __( 'Markup is not allowed in CSS.' ) );
  154. }
  155. if ( ! $validity->has_errors() ) {
  156. $validity = parent::validate( $css );
  157. }
  158. return $validity;
  159. }
  160. /**
  161. * Store the CSS setting value in the custom_css custom post type for the stylesheet.
  162. *
  163. * @since 4.7.0
  164. * @since 5.9.0 Renamed `$css` to `$value` for PHP 8 named parameter support.
  165. *
  166. * @param string $value CSS to update.
  167. * @return int|false The post ID or false if the value could not be saved.
  168. */
  169. public function update( $value ) {
  170. // Restores the more descriptive, specific name for use within this method.
  171. $css = $value;
  172. if ( empty( $css ) ) {
  173. $css = '';
  174. }
  175. $r = wp_update_custom_css_post(
  176. $css,
  177. array(
  178. 'stylesheet' => $this->stylesheet,
  179. )
  180. );
  181. if ( $r instanceof WP_Error ) {
  182. return false;
  183. }
  184. $post_id = $r->ID;
  185. // Cache post ID in theme mod for performance to avoid additional DB query.
  186. if ( $this->manager->get_stylesheet() === $this->stylesheet ) {
  187. set_theme_mod( 'custom_css_post_id', $post_id );
  188. }
  189. return $post_id;
  190. }
  191. }