Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 831 |
|
0.00% |
0 / 61 |
CRAP | |
0.00% |
0 / 1 |
| add_color_rule | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| add_color_palette | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| colors_manager_gutenberg_load | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| load_corresponding_color_manager | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
20 | |||
| Colors_Manager_Common | |
0.00% |
0 / 822 |
|
0.00% |
0 / 57 |
64770 | |
0.00% |
0 / 1 |
| init | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
56 | |||
| is_gutenberg | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| enqueue_classic_stats | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
| modify_admin_menu_links | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
20 | |||
| core_bg_enqueue_styles | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| core_bg_admin_notice | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| pick_theme | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
72 | |||
| has_annotations | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
30 | |||
| theme_has_set_colors | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
20 | |||
| will_never_support | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| admin_scripts_and_css | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
2 | |||
| register_scripts_and_styles | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
| body_class | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| spinner_scripts | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| get_colors | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
| get_default_colors | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| get_color_slots | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| color_grid | |
0.00% |
0 / 67 |
|
0.00% |
0 / 1 |
30 | |||
| print_current_color_grid | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
20 | |||
| ajax_color_palettes | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| ajax_generate_palette | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| ajax_color_recommendations | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| ajax_pattern_recommendations | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| format_colourlovers_urls | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 | |||
| save_colourlovers_metadata | |
0.00% |
0 / 39 |
|
0.00% |
0 / 1 |
552 | |||
| is_same_color | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| is_default_palette | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
20 | |||
| is_featured_palette | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
72 | |||
| should_enable_colors | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
| get_color_palettes | |
0.00% |
0 / 32 |
|
0.00% |
0 / 1 |
132 | |||
| gravatar_image_url | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
| get_generated_palette | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
30 | |||
| get_theme_color_palettes | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
30 | |||
| get_patterns | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
110 | |||
| normalize_color | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
42 | |||
| get_color_recommendations | |
0.00% |
0 / 49 |
|
0.00% |
0 / 1 |
272 | |||
| get_pattern_recommendations | |
0.00% |
0 / 34 |
|
0.00% |
0 / 1 |
72 | |||
| color_palettes | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
| color_patterns | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
| in_customizer | |
0.00% |
0 / 34 |
|
0.00% |
0 / 1 |
6 | |||
| sanitize_colors_on_save | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| sanitize_colors | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
72 | |||
| override_themecolors | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
72 | |||
| theme_colors_js | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
| print_theme_css | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
| get_theme_css | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
20 | |||
| css_rule | |
0.00% |
0 / 42 |
|
0.00% |
0 / 1 |
272 | |||
| get_extra_css | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
72 | |||
| add_color_rule | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
20 | |||
| add_color_palette | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
6 | |||
| load_annotations | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
6 | |||
| handle_unset_colors | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 | |||
| prime_color_labels | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
6 | |||
| color_suggestions | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
| color_suggestions_from_palette | |
0.00% |
0 / 35 |
|
0.00% |
0 / 1 |
20 | |||
| exception_mailer | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| color_suggestions_from_math | |
0.00% |
0 / 79 |
|
0.00% |
0 / 1 |
380 | |||
| Colors_Manager | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | n/a |
0 / 0 |
|||
| Colors_Manager_Gutenberg | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | n/a |
0 / 0 |
|||
| 1 | <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName |
| 2 | /** |
| 3 | * Plugin Name: Custom Colors |
| 4 | * Plugin URI: http://automattic.com/ |
| 5 | * Description: Part of the WordPress.com Custom Design upgrade, this plugin allows you to easily add a customized color palette and background pattern to your blog. |
| 6 | * Version: 1.1 |
| 7 | * Author: Automattic |
| 8 | * Author URI: http://automattic.com/ |
| 9 | * License: GNU General Public License v2 or later |
| 10 | * License URI: http://www.gnu.org/licenses/gpl-2.0.html |
| 11 | */ |
| 12 | |
| 13 | // phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed |
| 14 | // phpcs:disable Generic.Files.OneObjectStructurePerFile.MultipleFound |
| 15 | |
| 16 | /** |
| 17 | * The common color manager class. |
| 18 | */ |
| 19 | class Colors_Manager_Common { |
| 20 | |
| 21 | /** |
| 22 | * Colors. |
| 23 | * |
| 24 | * @var array |
| 25 | */ |
| 26 | protected static $colors = array(); |
| 27 | |
| 28 | /** |
| 29 | * Default colors. |
| 30 | * |
| 31 | * @var array |
| 32 | */ |
| 33 | protected static $default_colors = array(); |
| 34 | |
| 35 | /** |
| 36 | * Text colors. |
| 37 | * |
| 38 | * @var array |
| 39 | */ |
| 40 | protected static $text_colors = array(); |
| 41 | |
| 42 | /** |
| 43 | * Extra colors. |
| 44 | * |
| 45 | * @var array |
| 46 | */ |
| 47 | protected static $extra_colors = array(); |
| 48 | |
| 49 | /** |
| 50 | * Labels. |
| 51 | * |
| 52 | * @var array |
| 53 | */ |
| 54 | protected static $labels = array(); |
| 55 | |
| 56 | /** |
| 57 | * Color pallettes.. |
| 58 | * |
| 59 | * @var array |
| 60 | */ |
| 61 | protected static $color_palettes = array(); |
| 62 | |
| 63 | /** |
| 64 | * If we're using Gutenberg or not. |
| 65 | * |
| 66 | * @var boolean |
| 67 | */ |
| 68 | protected static $is_gutenberg = false; |
| 69 | |
| 70 | /** |
| 71 | * Themes that will never support Custom Colors. |
| 72 | * |
| 73 | * Criteria for not supporting: |
| 74 | * 1. Two years or older and not in the top 50 is usage. |
| 75 | * 2. Not a good match because of odd use of colors or images. |
| 76 | * 3. Retired, ignored, and mobile. |
| 77 | * |
| 78 | * @var array |
| 79 | */ |
| 80 | protected static $never_support = array( |
| 81 | 'pub/almost-spring', |
| 82 | 'pub/banana-smoothie', |
| 83 | 'pub/blue-green', |
| 84 | 'pub/classic', |
| 85 | 'pub/connections', |
| 86 | 'pub/dark-wood', |
| 87 | 'pub/daydream', |
| 88 | 'pub/duotone', |
| 89 | 'pub/dusk', |
| 90 | 'pub/duster', |
| 91 | 'pub/emire', |
| 92 | 'pub/fadtastic', |
| 93 | 'pub/fauna', |
| 94 | 'pub/fleur', |
| 95 | 'pub/flower-power', |
| 96 | 'pub/fresh-bananas', |
| 97 | 'pub/fusion', |
| 98 | 'pub/green-marinee', |
| 99 | 'pub/grid-focus', |
| 100 | 'pub/hemingway', |
| 101 | 'pub/jentri', |
| 102 | 'pub/journalist-13', |
| 103 | 'pub/k2', |
| 104 | 'pub/kubrick', |
| 105 | 'pub/light', |
| 106 | 'pub/minileven', |
| 107 | 'pub/monotone', |
| 108 | 'pub/neat', |
| 109 | 'pub/neo-sapien-05', |
| 110 | 'pub/notesil', |
| 111 | 'pub/ocadia', |
| 112 | 'pub/pool', |
| 113 | 'pub/prologue', |
| 114 | 'pub/quentin', |
| 115 | 'pub/redoable-lite', |
| 116 | 'pub/rounded', |
| 117 | 'pub/rubric', |
| 118 | 'pub/sandbox', |
| 119 | 'pub/sandbox-10', |
| 120 | 'pub/sandbox-16', |
| 121 | 'pub/sandbox-161', |
| 122 | 'pub/sandbox-162', |
| 123 | 'pub/sapphire', |
| 124 | 'pub/silver-black', |
| 125 | 'pub/solipsus', |
| 126 | 'pub/steira', |
| 127 | 'pub/sunburn', |
| 128 | 'pub/supposedly-clean', |
| 129 | 'pub/sweet-blossoms', |
| 130 | 'pub/tarski', |
| 131 | 'pub/thirteen', |
| 132 | 'pub/toni', |
| 133 | 'pub/toolbox', |
| 134 | 'pub/treba', |
| 135 | 'pub/twenty-eight', |
| 136 | 'pub/under-the-influence', |
| 137 | 'pub/unsleepable', |
| 138 | 'pub/vermilion-christmas', |
| 139 | 'pub/whiteasmilk', |
| 140 | 'pub/wp-mobile', |
| 141 | 'pub/wptouch', |
| 142 | 'pub/_s', |
| 143 | ); |
| 144 | |
| 145 | const COLOURLOVERS_HOST = 'http://colourlovers.com.s3.amazonaws.com/'; |
| 146 | |
| 147 | /** |
| 148 | * Initialize the object. |
| 149 | */ |
| 150 | public static function init() { |
| 151 | if ( ! apply_filters( 'enable_custom_customizer', true ) ) { |
| 152 | return; |
| 153 | } |
| 154 | |
| 155 | if ( ! self::is_gutenberg() ) { |
| 156 | // Classic Background stats |
| 157 | add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_classic_stats' ) ); |
| 158 | // always load ajax actions |
| 159 | add_action( 'wp_ajax_color_palettes', array( __CLASS__, 'ajax_color_palettes' ) ); |
| 160 | add_action( 'wp_ajax_generate_palette', array( __CLASS__, 'ajax_generate_palette' ) ); |
| 161 | add_action( 'wp_ajax_color_recommendations', array( __CLASS__, 'ajax_color_recommendations' ) ); |
| 162 | add_action( 'wp_ajax_pattern_recommendations', array( __CLASS__, 'ajax_pattern_recommendations' ) ); |
| 163 | |
| 164 | // Notice in the core bg admin screen |
| 165 | add_action( 'admin_print_styles-appearance_page_custom-background', array( __CLASS__, 'core_bg_enqueue_styles' ) ); |
| 166 | add_action( 'admin_notices', array( __CLASS__, 'core_bg_admin_notice' ) ); |
| 167 | |
| 168 | // Replace the Backgrounds link with a link to this plugin's section |
| 169 | add_action( 'admin_menu', array( __CLASS__, 'modify_admin_menu_links' ) ); |
| 170 | |
| 171 | // Load the Colors API class for fetching palettes and patterns from WordPress.com. |
| 172 | require_once __DIR__ . '/colors-api.php'; |
| 173 | |
| 174 | $current_theme = get_option( 'stylesheet' ); |
| 175 | |
| 176 | // High priority so that no other code manages to modify our URL before we do. The default URL |
| 177 | // saved for background_image isn't meant to ever be used as is. |
| 178 | add_filter( 'pre_update_option_theme_mods_' . $current_theme, array( __CLASS__, 'format_colourlovers_urls' ), 1, 2 ); |
| 179 | add_action( 'update_option_theme_mods_' . $current_theme, array( __CLASS__, 'save_colourlovers_metadata' ), 10, 2 ); |
| 180 | |
| 181 | add_action( 'init', array( __CLASS__, 'register_scripts_and_styles' ), 20 ); |
| 182 | |
| 183 | // stuff for the customizer - only load if there are annotations. |
| 184 | if ( self::has_annotations() ) { |
| 185 | add_action( 'customize_register', array( __CLASS__, 'in_customizer' ), 10 ); |
| 186 | add_action( 'customize_register', array( __CLASS__, 'theme_colors_js' ) ); |
| 187 | add_action( 'customize_controls_init', array( __CLASS__, 'spinner_scripts' ) ); |
| 188 | } |
| 189 | |
| 190 | // CSS only to be printed if colors are set. |
| 191 | if ( self::theme_has_set_colors() ) { |
| 192 | self::override_themecolors(); |
| 193 | add_filter( 'body_class', array( __CLASS__, 'body_class' ) ); |
| 194 | add_action( 'wp_head', array( __CLASS__, 'print_theme_css' ), 20 ); |
| 195 | } |
| 196 | |
| 197 | add_filter( 'tonesque_image_url', array( __CLASS__, 'gravatar_image_url' ) ); |
| 198 | } |
| 199 | |
| 200 | if ( self::is_gutenberg() ) { |
| 201 | // If colors are set, print them in the Block Editor as well. |
| 202 | if ( self::theme_has_set_colors() ) { |
| 203 | self::override_themecolors(); |
| 204 | add_action( 'enqueue_block_editor_assets', array( __CLASS__, 'print_theme_css' ), 20 ); |
| 205 | } |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | /** |
| 210 | * Checks if we're in Gutenberg (Editor) mode. |
| 211 | * |
| 212 | * @see https://stackoverflow.com/a/14919877 |
| 213 | */ |
| 214 | private static function is_gutenberg() { |
| 215 | return static::$is_gutenberg; |
| 216 | } |
| 217 | |
| 218 | /** |
| 219 | * Adds classic Stats assets to loading queue. |
| 220 | * |
| 221 | * @param string $hook the current hook name. |
| 222 | */ |
| 223 | public static function enqueue_classic_stats( $hook ) { |
| 224 | if ( 'appearance_page_custom-background' === $hook ) { |
| 225 | wp_enqueue_script( |
| 226 | 'custom-bg-classic-stats', |
| 227 | plugins_url( 'js/classic-background-stats.js', __FILE__ ), |
| 228 | array( 'jquery' ), |
| 229 | '20140310', |
| 230 | true |
| 231 | ); |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | /** |
| 236 | * The Background menu in wp-admin autofocuses the Background section in the |
| 237 | * Customizer, but on wpcom that section is removed, so we need to redirect |
| 238 | * that link to this section instead. |
| 239 | */ |
| 240 | public static function modify_admin_menu_links() { |
| 241 | global $submenu; |
| 242 | if ( ! isset( $submenu ) || ! isset( $submenu['themes.php'] ) || ! isset( $submenu['themes.php'][20] ) ) { |
| 243 | return; |
| 244 | } |
| 245 | $colors_section = admin_url( 'customize.php?autofocus%5Bsection%5D=colors_manager_tool' ); |
| 246 | $submenu['themes.php'][20][2] = esc_url( $colors_section ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited |
| 247 | } |
| 248 | |
| 249 | /** |
| 250 | * Enqueues styles for Core notices. |
| 251 | */ |
| 252 | public static function core_bg_enqueue_styles() { |
| 253 | wp_enqueue_style( 'colors-core-bg-notice', plugins_url( 'css/core-bg-notice.css', __FILE__ ) ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion |
| 254 | } |
| 255 | |
| 256 | /** |
| 257 | * Enqueues styles for Core admin notices. |
| 258 | */ |
| 259 | public static function core_bg_admin_notice() { |
| 260 | // just Appearance -> Background |
| 261 | if ( 'appearance_page_custom-background' !== $GLOBALS['page_hook'] ) { |
| 262 | return; |
| 263 | } |
| 264 | |
| 265 | require __DIR__ . '/core-bg-admin-notice.php'; |
| 266 | } |
| 267 | |
| 268 | /** |
| 269 | * A helper function to pick an unspecified theme based on the current context. |
| 270 | * |
| 271 | * @param ?boolean|string $theme A theme that, if false, the function will specify. |
| 272 | * @return string The theme. |
| 273 | */ |
| 274 | protected static function pick_theme( $theme = false ) { |
| 275 | if ( false !== $theme ) { |
| 276 | return $theme; |
| 277 | } |
| 278 | |
| 279 | $theme = get_option( 'stylesheet' ); |
| 280 | |
| 281 | // In an Ajax call from the Customizer, we might be previewing a separate theme. |
| 282 | // Detect that and use it if it's there. |
| 283 | |
| 284 | if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) { |
| 285 | if ( ! isset( $_SERVER['HTTP_REFERER'] ) ) { |
| 286 | return $theme; |
| 287 | } |
| 288 | $parsed_url = wp_parse_url( sanitize_url( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) ); |
| 289 | if ( $parsed_url && ! isset( $parsed_url['query'] ) ) { |
| 290 | return $theme; |
| 291 | } |
| 292 | wp_parse_str( $parsed_url['query'] ?? '', $query_parts ); |
| 293 | if ( isset( $query_parts['theme'] ) ) { |
| 294 | return $query_parts['theme']; |
| 295 | } |
| 296 | } |
| 297 | return $theme; |
| 298 | } |
| 299 | |
| 300 | /** |
| 301 | * Does the theme have annotations? Will load them as well. |
| 302 | * |
| 303 | * @param ?boolean|string $theme A theme or false. |
| 304 | * @return boolean theme has annotations |
| 305 | */ |
| 306 | public static function has_annotations( $theme = false ) { |
| 307 | // if we're not gonna support it, avoid the filesys hit |
| 308 | if ( self::will_never_support( $theme ) ) { |
| 309 | return false; |
| 310 | } |
| 311 | // if $colors is populated, we've run some add_color_rule calls. |
| 312 | // but skip if we directly asked for a theme to avoid false positives |
| 313 | if ( ! $theme && ! empty( self::$colors ) ) { |
| 314 | return true; |
| 315 | } |
| 316 | // if we called a direct string, we probably don't want to actually load them |
| 317 | if ( $theme ) { |
| 318 | $file = get_template_directory() . '/inc/wpcom-colors.php'; |
| 319 | return is_readable( $file ); |
| 320 | } |
| 321 | // try to load annotations, which returns status of finding them. |
| 322 | return self::load_annotations( $theme ); |
| 323 | } |
| 324 | |
| 325 | /** |
| 326 | * Do we have colors to work with? |
| 327 | * |
| 328 | * @return boolean active state |
| 329 | */ |
| 330 | public static function theme_has_set_colors() { |
| 331 | $opts = get_theme_mod( 'colors_manager', array( 'colors' => false ) ); |
| 332 | |
| 333 | if ( ! isset( $opts['colors'] ) ) { |
| 334 | return false; |
| 335 | } |
| 336 | |
| 337 | $opts = $opts['colors']; |
| 338 | // need the softer non-equal on the last in case keys are in different order. |
| 339 | return self::has_annotations() && (bool) $opts && $opts !== self::get_default_colors(); |
| 340 | } |
| 341 | |
| 342 | /** |
| 343 | * Will the theme never support Custom Colors? |
| 344 | * |
| 345 | * @param boolean|string $theme Optional theme slug. Uses current theme by default. |
| 346 | * @return boolean |
| 347 | */ |
| 348 | public static function will_never_support( $theme = false ) { |
| 349 | $theme = self::pick_theme( $theme ); |
| 350 | return in_array( $theme, self::$never_support, true ); |
| 351 | } |
| 352 | |
| 353 | /** |
| 354 | * Admin Javascript and CSS |
| 355 | */ |
| 356 | public static function admin_scripts_and_css() { |
| 357 | wp_enqueue_style( 'colors-tool' ); |
| 358 | wp_enqueue_style( 'noticons' ); |
| 359 | wp_enqueue_script( 'colors-tool' ); |
| 360 | |
| 361 | $settings = array( |
| 362 | 'defaultColors' => self::get_default_colors(), |
| 363 | 'themeSupport' => array( 'customBackground' => current_theme_supports( 'custom-background' ) ), |
| 364 | 'defaultImage' => get_theme_support( 'custom-background', 'default-image' ), |
| 365 | 'topPatterns' => self::get_patterns( array( 'limit' => 30 ) ), |
| 366 | 'genPalette' => __( 'Generating...', 'wpcomsh' ), |
| 367 | 'backgroundTitle' => __( 'Background', 'wpcomsh' ), |
| 368 | 'colorsTitle' => __( 'Colors', 'wpcomsh' ), |
| 369 | 'mediaTitle' => __( 'Select background image', 'wpcomsh' ), |
| 370 | 'mediaSelectButton' => __( 'Select', 'wpcomsh' ), |
| 371 | ); |
| 372 | |
| 373 | wp_localize_script( 'colors-tool', 'ColorsTool', $settings ); |
| 374 | } |
| 375 | |
| 376 | /** |
| 377 | * Registers scripts and styles. |
| 378 | */ |
| 379 | public static function register_scripts_and_styles() { |
| 380 | // register styles |
| 381 | wp_register_style( 'colors-tool', plugins_url( 'css/colors-control.css', __FILE__ ), array(), '20220727' ); |
| 382 | wp_register_style( 'noticons', '//s0.wp.com/i/noticons/noticons.css', array(), '20120621', 'all' ); |
| 383 | |
| 384 | // register scripts |
| 385 | wp_register_script( 'Color.js', plugins_url( 'js/color.js', __FILE__ ), array(), '20121210', true ); |
| 386 | wp_register_script( 'colors-instapreview', plugins_url( 'js/colors-theme-preview.js', __FILE__ ), array( 'customize-preview', 'jquery', 'Color.js' ), '20121210', true ); |
| 387 | wp_register_script( 'colors-tool', plugins_url( 'js/colors-control.js', __FILE__ ), array( 'customize-controls', 'iris' ), '20250102', true ); |
| 388 | wp_register_script( 'spin', plugins_url( 'js/spin.js', __FILE__ ), array(), '1.3', true ); |
| 389 | wp_register_script( 'jquery.spin', plugins_url( 'js/jquery.spin.js', __FILE__ ), array( 'spin' ), '20210111', true ); |
| 390 | } |
| 391 | |
| 392 | /** |
| 393 | * Add a 'custom-colors' body class to blogs with Custom Colors active. |
| 394 | * |
| 395 | * @param array $classes the array of classes to add custom class to. |
| 396 | */ |
| 397 | public static function body_class( $classes ) { |
| 398 | $classes[] = 'custom-colors'; |
| 399 | return $classes; |
| 400 | } |
| 401 | |
| 402 | /** |
| 403 | * Enqueue WP.com spinner scripts. |
| 404 | */ |
| 405 | public static function spinner_scripts() { |
| 406 | wp_enqueue_script( 'spin' ); |
| 407 | wp_enqueue_script( 'jquery.spin' ); |
| 408 | } |
| 409 | |
| 410 | /** |
| 411 | * Constructs the color array |
| 412 | */ |
| 413 | public static function get_colors() { |
| 414 | $opts = get_theme_mod( 'colors_manager', array( 'colors' => false ) ); |
| 415 | $colors = ! empty( $opts['colors'] ) ? $opts['colors'] : self::$default_colors; |
| 416 | unset( $colors['undefined'] ); |
| 417 | return $colors; |
| 418 | } |
| 419 | |
| 420 | /** |
| 421 | * Returns default colors. |
| 422 | */ |
| 423 | public static function get_default_colors() { |
| 424 | return self::$default_colors; |
| 425 | } |
| 426 | |
| 427 | /** |
| 428 | * Returns color slots. |
| 429 | */ |
| 430 | public static function get_color_slots() { |
| 431 | return array( 'bg', 'txt', 'link', 'fg1', 'fg2' ); |
| 432 | } |
| 433 | |
| 434 | /** |
| 435 | * The Color Grid |
| 436 | * |
| 437 | * This method outputs the core UI structure of the colors tool |
| 438 | * Includes color_palettes. |
| 439 | */ |
| 440 | public static function color_grid() { |
| 441 | ?> |
| 442 | <script type="text/template" id="tmpl-background-change"> |
| 443 | <div class="background-rectangle"> |
| 444 | <div class="done"><span class="float-button"><?php esc_html_e( 'Done', 'wpcomsh' ); ?></span></div> |
| 445 | </div> |
| 446 | <a class="button background-options"><?php esc_html_e( 'Options', 'wpcomsh' ); ?></a> |
| 447 | <a class="button select-image"><?php esc_html_e( 'Select Image', 'wpcomsh' ); ?></a> |
| 448 | <div class="sep"></div> |
| 449 | <div class="view background-options"></div> |
| 450 | </script> |
| 451 | |
| 452 | <script type="text/template" id="tmpl-background-options"> |
| 453 | <p class="radios"> |
| 454 | <?php esc_html_e( 'Position', 'wpcomsh' ); ?> |
| 455 | <input type="radio" id="position_x_right" name="position_x" value="right"> |
| 456 | <label title="<?php esc_attr_e( 'Right', 'wpcomsh' ); ?>" for="position_x_right"><span class="dashicons dashicons-editor-alignright"></span></label> |
| 457 | <input type="radio" id="position_x_center" name="position_x" value="center"> |
| 458 | <label title="<?php esc_attr_e( 'Center', 'wpcomsh' ); ?>" for="position_x_center"><span class="dashicons dashicons-editor-aligncenter"></span></label> |
| 459 | <input type="radio" id="position_x_left" name="position_x" value="left"> |
| 460 | <label title="<?php esc_attr_e( 'Left', 'wpcomsh' ); ?>" for="position_x_left"><span class="dashicons dashicons-editor-alignleft"></span></label> |
| 461 | </p> |
| 462 | |
| 463 | <p class="radios"> |
| 464 | <?php esc_html_e( 'Repeat', 'wpcomsh' ); ?> |
| 465 | <input type="radio" id="repeat" name="repeat" value="repeat"> |
| 466 | <label title="<?php esc_attr_e( 'Tile', 'wpcomsh' ); ?>" for="repeat"><span class="noticon noticon-gridview"></span></label> |
| 467 | <input type="radio" id="repeat-y" name="repeat" value="repeat-y"> |
| 468 | <label title="<?php esc_attr_e( 'Vertically', 'wpcomsh' ); ?>" for="repeat-y"><span class="noticon noticon-tile-vertically"></label> |
| 469 | <input type="radio" id="repeat-x" name="repeat" value="repeat-x"> |
| 470 | <label title="<?php esc_attr_e( 'Horizontally', 'wpcomsh' ); ?>" for="repeat-x"><span class="noticon noticon-tile-horizontally"></label> |
| 471 | <input type="radio" id="repeat-no-repeat" name="repeat" value="no-repeat"> |
| 472 | <label title="<?php esc_attr_e( 'None', 'wpcomsh' ); ?>" for="repeat-no-repeat"><span class="noticon noticon-tile-none"></label> |
| 473 | </p> |
| 474 | |
| 475 | <p class="radios"> |
| 476 | <?php esc_html_e( 'Fixed Position', 'wpcomsh' ); ?> |
| 477 | <input id="attachment-fixed" type="checkbox" name="attachment" value="fixed"> |
| 478 | <label for="attachment-fixed"><span class="dashicons dashicons-admin-post"></span></label> |
| 479 | </p> |
| 480 | |
| 481 | <p class="radios"> |
| 482 | <?php esc_html_e( 'Underlying color', 'wpcomsh' ); ?> |
| 483 | <input id="underlying-color" class="underlying-color" name="color"> |
| 484 | <label for="underlying-color" class="underlying-color"><span class="dashicons"></span></label> |
| 485 | </p> |
| 486 | |
| 487 | <div class="iris-container"></div> |
| 488 | |
| 489 | <p class="bottom"> |
| 490 | <a href="#" class="hide-image"><?php esc_html_e( 'Hide background image', 'wpcomsh' ); ?></a> |
| 491 | </p> |
| 492 | |
| 493 | </script> |
| 494 | |
| 495 | <div id="background-change"> |
| 496 | </div> |
| 497 | <div id="color-picker" class="color-picker"> |
| 498 | <ul class="color-grid main" id="color-grid"> |
| 499 | <?php |
| 500 | foreach ( self::get_color_slots() as $cat ) { |
| 501 | $class = isset( self::$colors[ $cat ] ) ? $cat : "{$cat} unavailable"; |
| 502 | if ( 'bg' === $cat ) { |
| 503 | // background is always available for back compat with core |
| 504 | $class = 'bg'; |
| 505 | } |
| 506 | printf( |
| 507 | '<li data-role="%s" class="%s clr" data-title="%s">', |
| 508 | esc_attr( $cat ), |
| 509 | esc_attr( $class ), |
| 510 | esc_attr( self::$labels[ $cat ] ) |
| 511 | ); |
| 512 | if ( 'bg' === $cat ) { |
| 513 | printf( |
| 514 | '<span class="change-background float-button">%s</span>', |
| 515 | esc_html__( 'Change', 'wpcomsh' ) |
| 516 | ); |
| 517 | } |
| 518 | printf( '</li>' ); |
| 519 | } |
| 520 | ?> |
| 521 | </ul> |
| 522 | <span class="action-button-wrap"> |
| 523 | <a class="revert revert-default button" title="<?php esc_attr_e( 'Go back to your theme’s default colors', 'wpcomsh' ); ?>"><?php esc_html_e( 'Default', 'wpcomsh' ); ?></a> |
| 524 | </span> |
| 525 | <span id="color-tooltip"></span> |
| 526 | <div id="the-bg-picker-prompt" style="display: none;"> |
| 527 | <span class="customize-control-title"><?php esc_html_e( 'Customize Your Background', 'wpcomsh' ); ?></span> |
| 528 | <div> |
| 529 | <a href="#" class="bg choose-color">O</a> |
| 530 | <h4>Change <b>Color</b></h4> |
| 531 | </div> |
| 532 | <div> |
| 533 | <a href="#" class="bg choose-pattern">O</a> |
| 534 | <h4>Choose <b>Image</b></h4> |
| 535 | </div> |
| 536 | </div> |
| 537 | <div class="the-picker" id="the-picker"> |
| 538 | <span class="color-label" id="color-reference"></span> |
| 539 | <p><?php esc_html_e( 'These are colors that work well with the other colors in your palette:', 'wpcomsh' ); ?></p> |
| 540 | <ul class="color-suggestions"> |
| 541 | <li></li> |
| 542 | <li></li> |
| 543 | <li></li> |
| 544 | <li></li> |
| 545 | <li></li> |
| 546 | <li></li> |
| 547 | <li></li> |
| 548 | <li></li> |
| 549 | <li></li> |
| 550 | <li></li> |
| 551 | <li></li> |
| 552 | <li></li> |
| 553 | </ul> |
| 554 | <p class="iris-launch"> |
| 555 | <?php |
| 556 | echo wp_kses( |
| 557 | __( 'You can also <a href="#" id="pick-your-nose">pick your own color</a>.', 'wpcomsh' ), |
| 558 | array( |
| 559 | 'a' => array( |
| 560 | 'href' => array(), |
| 561 | 'id' => array(), |
| 562 | ), |
| 563 | ) |
| 564 | ); |
| 565 | ?> |
| 566 | </p> |
| 567 | <div id="iris-container" class="hidden"> |
| 568 | <input type="text" id="iris" /> |
| 569 | </div> |
| 570 | </div> |
| 571 | <?php Colors_Manager::color_palettes(); ?> |
| 572 | <?php Colors_Manager::color_patterns(); ?> |
| 573 | </div> |
| 574 | <?php |
| 575 | } |
| 576 | |
| 577 | /** |
| 578 | * Prints current color grid. |
| 579 | */ |
| 580 | public static function print_current_color_grid() { |
| 581 | if ( ! self::theme_has_set_colors() ) { |
| 582 | return; |
| 583 | } |
| 584 | ?> |
| 585 | <ul class="color-grid main"> |
| 586 | <?php |
| 587 | foreach ( self::get_colors() as $cat => $value ) { |
| 588 | $class = isset( self::$colors[ $cat ] ) ? $cat : "{$cat} unavailable"; |
| 589 | printf( |
| 590 | '<li class="%s" style="background-color: %s" title="%s">%s</li>', |
| 591 | esc_attr( $class ), |
| 592 | esc_attr( $value ), |
| 593 | esc_attr( self::$labels[ $cat ] ), |
| 594 | esc_html( $value ) |
| 595 | ); |
| 596 | } |
| 597 | ?> |
| 598 | </ul> |
| 599 | <?php |
| 600 | } |
| 601 | |
| 602 | /** |
| 603 | * Outputs color pallettes for AJAX requests. |
| 604 | * |
| 605 | * @return never |
| 606 | */ |
| 607 | public static function ajax_color_palettes() { |
| 608 | $palettes = self::get_color_palettes( $_REQUEST ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- this is a GET request that doesn't change anything. |
| 609 | |
| 610 | $response = array( 'palettes' => $palettes ); |
| 611 | |
| 612 | header( 'Content-Type: text/javascript' ); |
| 613 | // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- It takes null, but its phpdoc only says int. |
| 614 | wp_send_json( $response, null, JSON_UNESCAPED_SLASHES ); |
| 615 | } |
| 616 | |
| 617 | /** |
| 618 | * Outputs generated color pallette for AJAX requests. |
| 619 | * |
| 620 | * @return never |
| 621 | */ |
| 622 | public static function ajax_generate_palette() { |
| 623 | $response = self::get_generated_palette( $_REQUEST ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- this is a GET request that doesn't change anything. |
| 624 | header( 'Content-Type: text/javascript' ); |
| 625 | // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- It takes null, but its phpdoc only says int. |
| 626 | wp_send_json( $response, null, JSON_UNESCAPED_SLASHES ); |
| 627 | } |
| 628 | |
| 629 | /** |
| 630 | * Outputs color recommendations for AJAX requests. |
| 631 | * |
| 632 | * @return never |
| 633 | */ |
| 634 | public static function ajax_color_recommendations() { |
| 635 | $colors = self::get_color_recommendations( $_REQUEST ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- this is a GET request that doesn't change anything. |
| 636 | |
| 637 | $response = array( 'colors' => $colors ); |
| 638 | |
| 639 | header( 'Content-Type: text/javascript' ); |
| 640 | // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- It takes null, but its phpdoc only says int. |
| 641 | wp_send_json( $response, null, JSON_UNESCAPED_SLASHES ); |
| 642 | } |
| 643 | |
| 644 | /** |
| 645 | * Outputs pattern recommendations for AJAX requests. |
| 646 | * |
| 647 | * @return never |
| 648 | */ |
| 649 | public static function ajax_pattern_recommendations() { |
| 650 | $patterns = self::get_pattern_recommendations( $_REQUEST ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- this is a GET request that doesn't change anything. |
| 651 | |
| 652 | $response = array( 'patterns' => $patterns ); |
| 653 | |
| 654 | header( 'Content-Type: text/javascript' ); |
| 655 | // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- It takes null, but its phpdoc only says int. |
| 656 | wp_send_json( $response, null, JSON_UNESCAPED_SLASHES ); |
| 657 | } |
| 658 | |
| 659 | /** |
| 660 | * Ensure that COLOURLovers URLs are saved without any imgpress stuff. |
| 661 | * |
| 662 | * @param array $new_theme_mods new theme mods. |
| 663 | * @return array |
| 664 | */ |
| 665 | public static function format_colourlovers_urls( $new_theme_mods ) { |
| 666 | if ( ! empty( $new_theme_mods['background_image'] ) && false !== strpos( $new_theme_mods['background_image'], '/imgpress?url=' . rawurlencode( self::COLOURLOVERS_HOST ) ) ) { |
| 667 | $parts = explode( '/imgpress?url=', $new_theme_mods['background_image'], 2 ); |
| 668 | $new_theme_mods['background_image'] = urldecode( array_pop( $parts ) ); |
| 669 | } |
| 670 | |
| 671 | return $new_theme_mods; |
| 672 | } |
| 673 | |
| 674 | /** |
| 675 | * When a user saves a COLOURLovers palette or pattern, save the CL metadata |
| 676 | * for attribution later on. |
| 677 | * |
| 678 | * Also used to track COLOURlovers asset usage. |
| 679 | * See https://mc.a8c.com/s/colourlovers-pattern/ and |
| 680 | * https://mc.a8c.com/s/colourlovers-palette/ |
| 681 | * |
| 682 | * 1. Which color palettes are chosen, and overall number of times a pattern is switched to. |
| 683 | * 2. Which background patterns are chosen, and the overall number of times a pattern is switched to. |
| 684 | * |
| 685 | * @param array $oldvalue old metadata. |
| 686 | * @param array $newvalue new metadata value. |
| 687 | */ |
| 688 | public static function save_colourlovers_metadata( $oldvalue, $newvalue ) { |
| 689 | $mods = $newvalue; |
| 690 | |
| 691 | if ( isset( $oldvalue['background_image'] ) && isset( $newvalue['background_image'] ) && $oldvalue['background_image'] !== $newvalue['background_image'] ) { |
| 692 | $using_colourlovers_pattern = false; |
| 693 | |
| 694 | if ( 0 === strpos( $mods['background_image'], self::COLOURLOVERS_HOST ) ) { |
| 695 | $matches = array(); |
| 696 | |
| 697 | if ( preg_match( '/\/([0-9]+)\.png$/i', $mods['background_image'], $matches ) ) { |
| 698 | $using_colourlovers_pattern = true; |
| 699 | |
| 700 | $pattern_id = $matches[1]; |
| 701 | |
| 702 | if ( empty( $mods['background_image_metadata'] ) || $pattern_id !== $mods['background_image_metadata']['pattern_id'] ) { |
| 703 | $pattern = Colors_API::call( 'patterns', array(), (int) $pattern_id ); |
| 704 | if ( ! is_wp_error( $pattern ) && is_array( $pattern ) ) { |
| 705 | set_theme_mod( |
| 706 | 'background_image_metadata', |
| 707 | array( |
| 708 | 'pattern_id' => $pattern_id, |
| 709 | 'username' => $pattern['username'], |
| 710 | 'title' => $pattern['title'], |
| 711 | ) |
| 712 | ); |
| 713 | } |
| 714 | } |
| 715 | } |
| 716 | } |
| 717 | |
| 718 | if ( ! $using_colourlovers_pattern && ! empty( $mods['background_image_metadata'] ) ) { |
| 719 | remove_theme_mod( 'background_image_metadata' ); |
| 720 | } |
| 721 | } |
| 722 | |
| 723 | if ( isset( $newvalue['background_image'] ) && 0 === strpos( $newvalue['background_image'], self::COLOURLOVERS_HOST ) && $newvalue['background_image'] !== $newvalue['background_image_thumb'] ) { |
| 724 | /** |
| 725 | * Due to a bug with percent signs in background_image URLs, we need to make sure that |
| 726 | * our background image is also saved as the background_image_thumb value. We need to |
| 727 | * do this any time theme_mods is updated, because there is other code aggressively |
| 728 | * trying to delete background_image_thumb completely. |
| 729 | */ |
| 730 | set_theme_mod( 'background_image_thumb', $newvalue['background_image'] ); |
| 731 | } |
| 732 | |
| 733 | if ( isset( $oldvalue['colors_manager'] ) && isset( $newvalue['colors_manager'] ) && $newvalue['colors_manager']['colors'] !== $oldvalue['colors_manager']['colors'] ) { |
| 734 | if ( empty( $newvalue['colors_manager']['colors'] ) && $newvalue['color_palette_metadata'] ) { |
| 735 | remove_theme_mod( 'color_palette_metadata' ); |
| 736 | } else { |
| 737 | require_once __DIR__ . '/class-palette.php'; |
| 738 | |
| 739 | $palette = Palette::get( array( 'colors' => $newvalue['colors_manager']['colors'] ) ); |
| 740 | |
| 741 | if ( $palette ) { |
| 742 | if ( empty( $newvalue['color_palette_metadata'] ) || $palette->id !== $newvalue['color_palette_metadata']['palette_id'] ) { |
| 743 | set_theme_mod( |
| 744 | 'color_palette_metadata', |
| 745 | array( |
| 746 | 'palette_id' => $palette->id, |
| 747 | 'username' => $palette->username, |
| 748 | 'title' => $palette->title, |
| 749 | ) |
| 750 | ); |
| 751 | } |
| 752 | } else { |
| 753 | remove_theme_mod( 'color_palette_metadata' ); |
| 754 | } |
| 755 | } |
| 756 | } |
| 757 | } |
| 758 | |
| 759 | /** |
| 760 | * Are colors the same? |
| 761 | * |
| 762 | * @param string $a color A. |
| 763 | * @param string $b color B. |
| 764 | * @return boolean |
| 765 | */ |
| 766 | public static function is_same_color( $a, $b ) { |
| 767 | $a = trim( strtolower( $a ), ' #' ); |
| 768 | $b = trim( strtolower( $b ), ' #' ); |
| 769 | return $a === $b; |
| 770 | } |
| 771 | |
| 772 | /** |
| 773 | * Are we on the default pallette? |
| 774 | * |
| 775 | * @param array $colors tested colors. |
| 776 | * @return boolean |
| 777 | */ |
| 778 | public static function is_default_palette( $colors ) { |
| 779 | // a saved palette may have more colors than the default palette. So, |
| 780 | // iterate over the default palette |
| 781 | foreach ( self::$default_colors as $id => $default_color ) { |
| 782 | if ( ! isset( $colors[ $id ] ) ) { |
| 783 | return false; |
| 784 | } |
| 785 | if ( ! self::is_same_color( $default_color, $colors[ $id ] ) ) { |
| 786 | return false; |
| 787 | } |
| 788 | } |
| 789 | return true; |
| 790 | } |
| 791 | |
| 792 | /** |
| 793 | * Are we on the featured pallette? |
| 794 | * |
| 795 | * @param array $colors tested colors. |
| 796 | * @return boolean |
| 797 | */ |
| 798 | public static function is_featured_palette( $colors ) { |
| 799 | |
| 800 | $featured_palettes = self::$color_palettes; |
| 801 | |
| 802 | foreach ( $colors as $c ) { |
| 803 | $c = strtolower( $c ); |
| 804 | } |
| 805 | |
| 806 | // look for our palette in featured palettes |
| 807 | foreach ( $featured_palettes as $p ) { |
| 808 | $p = $p['palette']; |
| 809 | $found = true; |
| 810 | // for each color of the featured palette |
| 811 | foreach ( $p as $i => $c ) { |
| 812 | // we don't care about the background color; non-CD users are |
| 813 | // free to change it |
| 814 | if ( 0 === $i ) { |
| 815 | continue; |
| 816 | } |
| 817 | |
| 818 | $c = strtolower( $c ); |
| 819 | // if that color isn't in our palette |
| 820 | if ( ! empty( $c ) && ! in_array( $c, $colors, true ) ) { |
| 821 | // try another featured palette |
| 822 | $found = false; |
| 823 | break; |
| 824 | } |
| 825 | } |
| 826 | if ( $found ) { |
| 827 | return true; |
| 828 | } |
| 829 | } |
| 830 | return false; |
| 831 | } |
| 832 | |
| 833 | /** |
| 834 | * Should we enable custom colors? |
| 835 | */ |
| 836 | public static function should_enable_colors() { |
| 837 | $opts = get_theme_mod( 'colors_manager', array( 'colors' => false ) ); |
| 838 | if ( ! $opts['colors'] ) { |
| 839 | return false; |
| 840 | } |
| 841 | |
| 842 | $colors = $opts['colors']; |
| 843 | |
| 844 | // If we managed to save the default palette, bail. It does not actually render |
| 845 | // the same thing as the theme's default style |
| 846 | if ( self::is_default_palette( $colors ) ) { |
| 847 | return false; |
| 848 | } |
| 849 | |
| 850 | return apply_filters( 'custom_colors_enable', true ); |
| 851 | } |
| 852 | |
| 853 | /** |
| 854 | * Query and return palette data. |
| 855 | * |
| 856 | * @param array{color?:string,limit?:int,offset?:int} $args initial color settings. |
| 857 | * @return array An array of color palettes. |
| 858 | */ |
| 859 | public static function get_color_palettes( $args = array() ) { |
| 860 | $defaults = array( |
| 861 | 'color' => false, |
| 862 | 'limit' => 6, |
| 863 | 'offset' => 0, |
| 864 | ); |
| 865 | |
| 866 | $args = wp_parse_args( $args, $defaults ); |
| 867 | |
| 868 | if ( $args['color'] ) { |
| 869 | $args['color'] = self::normalize_color( $args['color'] ); |
| 870 | |
| 871 | $palettes = wp_cache_get( 'color-palettes-from-' . $args['color'], 'colors' ); |
| 872 | |
| 873 | if ( false === $palettes ) { |
| 874 | $palettes = Colors_API::call( 'palettes', array( 'color' => $args['color'] ) ); |
| 875 | if ( ! is_wp_error( $palettes ) ) { |
| 876 | wp_cache_set( 'color-palettes-from-' . $args['color'], $palettes, 'colors', MONTH_IN_SECONDS ); |
| 877 | } |
| 878 | } |
| 879 | } else { |
| 880 | $palettes = wp_cache_get( 'color-palettes-top', 'colors' ); |
| 881 | |
| 882 | if ( false === $palettes ) { |
| 883 | $palettes = Colors_API::call( 'palettes' ); |
| 884 | if ( ! is_wp_error( $palettes ) ) { |
| 885 | wp_cache_set( 'color-palettes-top', $palettes, 'colors', MONTH_IN_SECONDS ); |
| 886 | } |
| 887 | } |
| 888 | } |
| 889 | |
| 890 | $palettes = array_slice( $palettes, $args['offset'], $args['limit'] ); |
| 891 | |
| 892 | if ( ! empty( $palettes ) ) { |
| 893 | foreach ( $palettes as $palette_index => $palette ) { |
| 894 | $colors = array(); |
| 895 | |
| 896 | foreach ( self::get_color_slots() as $color_index => $color_key ) { |
| 897 | if ( count( $palette['colors'] ) === $color_index ) { |
| 898 | break; |
| 899 | } |
| 900 | |
| 901 | $colors[ $color_key ] = $palette['colors'][ $color_index ]['hex']; |
| 902 | } |
| 903 | |
| 904 | $palettes[ $palette_index ]['colors'] = $colors; |
| 905 | } |
| 906 | } |
| 907 | |
| 908 | // Shuffle palettes to make them less repetitive |
| 909 | shuffle( $palettes ); |
| 910 | |
| 911 | // Prepend theme-defined palettes to the first set of palettes |
| 912 | if ( 0 === (int) $args['offset'] ) { |
| 913 | $palettes = array_merge( self::get_theme_color_palettes(), $palettes ); |
| 914 | $palettes = array_slice( $palettes, 0, (int) $args['limit'] ); |
| 915 | } |
| 916 | |
| 917 | return $palettes; |
| 918 | } |
| 919 | |
| 920 | /** |
| 921 | * Return an image URL based on Gravatar URL. |
| 922 | * |
| 923 | * @param string $image_url URL to be transformed. |
| 924 | * @return string |
| 925 | */ |
| 926 | public static function gravatar_image_url( $image_url ) { |
| 927 | $prefix_http = preg_quote( 'http://www.gravatar.com/avatar/', '/' ); |
| 928 | $prefix_https = preg_quote( 'https://secure.gravatar.com/avatar/', '/' ); |
| 929 | $gravatar_prefix = sprintf( '/^(%s|%s)/', $prefix_http, $prefix_https ); |
| 930 | $is_gravatar_url = preg_match( $gravatar_prefix, $image_url ); |
| 931 | |
| 932 | if ( $is_gravatar_url ) { |
| 933 | $image_url = preg_replace( '#/([0-9a-f]+)/#', '/$1.jpg', $image_url ); |
| 934 | } |
| 935 | |
| 936 | return $image_url; |
| 937 | } |
| 938 | |
| 939 | /** |
| 940 | * Returns a color palette matching a given image thanks to the Tonesque |
| 941 | * lib. |
| 942 | * |
| 943 | * @param array{image?:string} $args an image URL in the form of an array. |
| 944 | * @return array A single color palette |
| 945 | */ |
| 946 | public static function get_generated_palette( $args = array() ) { |
| 947 | // Some themes, like Ryu, include an older version of Tonesque, which is loaded instead of the version in `/wp-content/lib/`. |
| 948 | // For now, only load the shared library if Tonesque isn't already present. See #5557. |
| 949 | if ( ! class_exists( 'Tonesque' ) ) { |
| 950 | require_lib( 'tonesque' ); |
| 951 | } |
| 952 | |
| 953 | // If the loaded version doesn't have the method needed to support palette generation, abort for now until the themes are updated. See #5557. |
| 954 | if ( ! method_exists( 'Tonesque', 'grab_points' ) ) { |
| 955 | return array(); |
| 956 | } |
| 957 | |
| 958 | $defaults = array( |
| 959 | 'image' => false, |
| 960 | ); |
| 961 | |
| 962 | $args = wp_parse_args( $args, $defaults ); |
| 963 | $image = $args['image'] ?? ''; |
| 964 | |
| 965 | if ( ! $image ) { |
| 966 | return array(); |
| 967 | } |
| 968 | |
| 969 | $tonesque = new Tonesque( $image ); |
| 970 | $points = $tonesque->grab_points( 'hex' ); |
| 971 | |
| 972 | $roles = self::get_color_slots(); |
| 973 | shuffle( $roles ); |
| 974 | |
| 975 | if ( ! is_array( $points ) ) { |
| 976 | return array(); |
| 977 | } |
| 978 | |
| 979 | $colors = array_combine( $roles, $points ); |
| 980 | |
| 981 | $palette = array( |
| 982 | 'id' => 'generated-palette', |
| 983 | 'colors' => $colors, |
| 984 | ); |
| 985 | |
| 986 | return $palette; |
| 987 | } |
| 988 | |
| 989 | /** |
| 990 | * Returns theme color pallettes. |
| 991 | */ |
| 992 | public static function get_theme_color_palettes() { |
| 993 | if ( empty( self::$color_palettes ) ) { |
| 994 | return array(); |
| 995 | } |
| 996 | |
| 997 | $map = self::get_color_slots(); |
| 998 | $formatted_palettes = array(); |
| 999 | foreach ( self::$color_palettes as $id => $palette ) { |
| 1000 | $formatted_palette = array( |
| 1001 | 'id' => $id, |
| 1002 | 'colors' => array(), |
| 1003 | ); |
| 1004 | foreach ( $map as $index => $key ) { |
| 1005 | if ( ! isset( $palette['palette'][ $index ] ) ) { |
| 1006 | continue; |
| 1007 | } |
| 1008 | $formatted_palette['colors'][ $key ] = str_replace( '#', '', $palette['palette'][ $index ] ); |
| 1009 | } |
| 1010 | |
| 1011 | $formatted_palettes[] = $formatted_palette; |
| 1012 | } |
| 1013 | |
| 1014 | return $formatted_palettes; |
| 1015 | } |
| 1016 | |
| 1017 | /** |
| 1018 | * Query and return pattern data. |
| 1019 | * |
| 1020 | * @param array{color?:string,limit?:int,offset?:int} $args initial settings. |
| 1021 | * @return array An array of patterns. |
| 1022 | */ |
| 1023 | public static function get_patterns( $args = array() ) { |
| 1024 | $defaults = array( |
| 1025 | 'color' => false, |
| 1026 | 'limit' => 4, |
| 1027 | 'offset' => 0, |
| 1028 | ); |
| 1029 | |
| 1030 | $args = wp_parse_args( $args, $defaults ); |
| 1031 | |
| 1032 | if ( $args['color'] ) { |
| 1033 | $args['color'] = self::normalize_color( $args['color'] ); |
| 1034 | |
| 1035 | $patterns = wp_cache_get( 'patterns-from-' . $args['color'], 'colors' ); |
| 1036 | |
| 1037 | if ( false === $patterns ) { |
| 1038 | $patterns = Colors_API::call( 'patterns', array( 'color' => $args['color'] ) ); |
| 1039 | if ( ! is_wp_error( $patterns ) ) { |
| 1040 | wp_cache_set( 'patterns-from-' . $args['color'], $patterns, 'colors', MONTH_IN_SECONDS ); |
| 1041 | } |
| 1042 | } |
| 1043 | } else { |
| 1044 | $patterns = wp_cache_get( 'patterns-top', 'colors' ); |
| 1045 | |
| 1046 | if ( false === $patterns ) { |
| 1047 | $patterns = Colors_API::call( 'patterns' ); |
| 1048 | if ( ! is_wp_error( $patterns ) ) { |
| 1049 | wp_cache_set( 'patterns-top', $patterns, 'colors', MONTH_IN_SECONDS ); |
| 1050 | } |
| 1051 | } |
| 1052 | } |
| 1053 | |
| 1054 | $patterns = array_slice( $patterns, $args['offset'], $args['limit'] ); |
| 1055 | |
| 1056 | if ( ! empty( $patterns ) ) { |
| 1057 | foreach ( $patterns as $pattern_index => $pattern ) { |
| 1058 | $colors = array(); |
| 1059 | |
| 1060 | foreach ( self::get_color_slots() as $color_index => $color_key ) { |
| 1061 | if ( count( $pattern['colors'] ) === $color_index ) { |
| 1062 | break; |
| 1063 | } |
| 1064 | |
| 1065 | $colors[ $color_key ] = $pattern['colors'][ $color_index ]['hex']; |
| 1066 | } |
| 1067 | |
| 1068 | $patterns[ $pattern_index ]['colors'] = $colors; |
| 1069 | $patterns[ $pattern_index ]['preview_image_url'] = apply_filters( 'jetpack_photon_url', $pattern['preview_image_url'], array(), 'network_path' ); |
| 1070 | } |
| 1071 | } |
| 1072 | |
| 1073 | return $patterns; |
| 1074 | } |
| 1075 | |
| 1076 | /** |
| 1077 | * Converts rgb() or hex color codes to the AABBCC format: |
| 1078 | * |
| 1079 | * @param string $color An rgb or hex color code. |
| 1080 | * @return string |
| 1081 | */ |
| 1082 | public static function normalize_color( $color ) { |
| 1083 | if ( false !== strpos( $color, 'rgb' ) ) { |
| 1084 | $color_data = preg_replace( '/[^0-9\.,]/', '', $color ); |
| 1085 | $color_components = explode( ',', $color_data ); |
| 1086 | |
| 1087 | $hex_color = ''; |
| 1088 | |
| 1089 | for ( $i = 0; $i < 3; $i++ ) { |
| 1090 | $hex_equivalent = dechex( intval( $color_components[ $i ] ) ); |
| 1091 | if ( strlen( $hex_equivalent ) < 2 ) { |
| 1092 | $hex_color .= '0'; |
| 1093 | } |
| 1094 | $hex_color .= $hex_equivalent; |
| 1095 | } |
| 1096 | |
| 1097 | return strtoupper( $hex_color ); |
| 1098 | } else { |
| 1099 | $hex = strtoupper( substr( preg_replace( '/[^0-9A-Z]/i', '', $color ), 0, 6 ) ); |
| 1100 | |
| 1101 | if ( strlen( $hex ) === 3 ) { |
| 1102 | $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2]; |
| 1103 | } else { |
| 1104 | for ( $i = strlen( $hex ); $i < 6; $i++ ) { |
| 1105 | $hex = '0' . $hex; |
| 1106 | } |
| 1107 | } |
| 1108 | |
| 1109 | return $hex; |
| 1110 | } |
| 1111 | } |
| 1112 | |
| 1113 | /** |
| 1114 | * Finds colors that could be suitable complement to a given set of colors. |
| 1115 | * |
| 1116 | * @param array{color?:string,role?:string,colors?:array,limit?:int} $args initial settings. |
| 1117 | * @return array An array of color codes. |
| 1118 | */ |
| 1119 | public static function get_color_recommendations( $args ) { |
| 1120 | $defaults = array( |
| 1121 | 'color' => false, |
| 1122 | 'role' => false, |
| 1123 | 'colors' => false, |
| 1124 | 'limit' => 8, |
| 1125 | ); |
| 1126 | |
| 1127 | $args = wp_parse_args( $args, $defaults ); |
| 1128 | |
| 1129 | if ( $args['color'] ) { |
| 1130 | $args['color'] = self::normalize_color( $args['color'] ); |
| 1131 | } |
| 1132 | |
| 1133 | $colors = array(); |
| 1134 | |
| 1135 | foreach ( $args['colors'] as $role => $color ) { |
| 1136 | $color = self::normalize_color( $color ); |
| 1137 | $args['colors'][ $role ] = $color; |
| 1138 | |
| 1139 | $palettes = Colors_API::call( |
| 1140 | 'palettes', |
| 1141 | array( |
| 1142 | 'color' => $color, |
| 1143 | 'limit' => 8, |
| 1144 | ) |
| 1145 | ); |
| 1146 | |
| 1147 | if ( is_array( $palettes ) ) { |
| 1148 | foreach ( $palettes as $palette ) { |
| 1149 | $multiplier = 0; |
| 1150 | |
| 1151 | foreach ( $palette['colors'] as $_color ) { |
| 1152 | if ( ! $_color ) { |
| 1153 | continue; |
| 1154 | } |
| 1155 | |
| 1156 | // If this palette contains more than one of the guide colors, |
| 1157 | // give it more weight. |
| 1158 | if ( in_array( $_color, $args['colors'], true ) ) { |
| 1159 | ++$multiplier; |
| 1160 | } |
| 1161 | } |
| 1162 | |
| 1163 | foreach ( $palette['colors'] as $palette_role => $_color ) { |
| 1164 | if ( ! $_color ) { |
| 1165 | continue; |
| 1166 | } |
| 1167 | |
| 1168 | $colors[ $_color ] += ( 1 * $multiplier ); |
| 1169 | |
| 1170 | if ( $palette_role === $args['role'] ) { |
| 1171 | $colors[ $_color ] += ( 1 * $multiplier ); |
| 1172 | } |
| 1173 | } |
| 1174 | } |
| 1175 | } |
| 1176 | } |
| 1177 | |
| 1178 | foreach ( $args['colors'] as $color ) { |
| 1179 | unset( $colors[ $color ] ); |
| 1180 | } |
| 1181 | |
| 1182 | if ( $args['color'] ) { |
| 1183 | unset( $colors[ $args['color'] ] ); |
| 1184 | } |
| 1185 | |
| 1186 | arsort( $colors ); |
| 1187 | $colors = array_keys( $colors ); |
| 1188 | |
| 1189 | if ( count( $colors ) < 8 ) { |
| 1190 | $more_suggestions = self::color_suggestions( $args['colors'], $args['role'] ); |
| 1191 | $colors = array_merge( $colors, $more_suggestions ); |
| 1192 | |
| 1193 | foreach ( $args['colors'] as $color ) { |
| 1194 | unset( $colors[ $color ] ); |
| 1195 | } |
| 1196 | |
| 1197 | if ( $args['color'] ) { |
| 1198 | unset( $colors[ $args['color'] ] ); |
| 1199 | } |
| 1200 | } |
| 1201 | |
| 1202 | $colors = array_slice( $colors, 0, $args['limit'] ); |
| 1203 | |
| 1204 | return $colors; |
| 1205 | } |
| 1206 | |
| 1207 | /** |
| 1208 | * Finds patterns that could be suitable complement to a given set of colors. |
| 1209 | * |
| 1210 | * @param array{colors?:array,limit?:int} $args initial settings. |
| 1211 | * @return array An array of patterns. |
| 1212 | */ |
| 1213 | public static function get_pattern_recommendations( $args ) { |
| 1214 | $defaults = array( |
| 1215 | 'colors' => false, |
| 1216 | 'limit' => 4, |
| 1217 | ); |
| 1218 | |
| 1219 | $args = wp_parse_args( $args, $defaults ); |
| 1220 | |
| 1221 | $patterns_by_id = array(); |
| 1222 | $pattern_ids = array(); |
| 1223 | |
| 1224 | foreach ( $args['colors'] as $role => $color ) { |
| 1225 | $color = self::normalize_color( $color ); |
| 1226 | $args['colors'][ $role ] = $color; |
| 1227 | |
| 1228 | $color_patterns = Colors_API::call( |
| 1229 | 'patterns', |
| 1230 | array( |
| 1231 | 'color' => $color, |
| 1232 | 'limit' => 5, |
| 1233 | ) |
| 1234 | ); |
| 1235 | |
| 1236 | if ( is_array( $color_patterns ) ) { |
| 1237 | foreach ( $color_patterns as $pattern ) { |
| 1238 | $patterns_by_id[ $pattern['id'] ] = $pattern; |
| 1239 | |
| 1240 | if ( ! isset( $pattern_ids[ $pattern['id'] ] ) ) { |
| 1241 | $pattern_ids[ $pattern['id'] ] = 0; |
| 1242 | } |
| 1243 | $pattern_ids[ $pattern['id'] ] += 1; |
| 1244 | |
| 1245 | foreach ( $pattern['colors'] as $value ) { |
| 1246 | if ( in_array( $value, $args['colors'], true ) ) { |
| 1247 | $pattern_ids[ $pattern['id'] ] += 1; |
| 1248 | } |
| 1249 | } |
| 1250 | } |
| 1251 | } |
| 1252 | } |
| 1253 | |
| 1254 | arsort( $pattern_ids ); |
| 1255 | $pattern_ids = array_keys( $pattern_ids ); |
| 1256 | $pattern_ids = array_slice( $pattern_ids, 0, $args['limit'] ); |
| 1257 | |
| 1258 | $patterns = array(); |
| 1259 | |
| 1260 | foreach ( $pattern_ids as $pattern_id ) { |
| 1261 | unset( $patterns_by_id[ $pattern_id ]['colors'] ); |
| 1262 | $patterns[] = $patterns_by_id[ $pattern_id ]; |
| 1263 | } |
| 1264 | |
| 1265 | return $patterns; |
| 1266 | } |
| 1267 | |
| 1268 | /** |
| 1269 | * Renders the color palettes |
| 1270 | */ |
| 1271 | public static function color_palettes() { |
| 1272 | ?> |
| 1273 | <div id="colourlovers-palettes-container"> |
| 1274 | <h3><?php esc_html_e( 'Choose a Palette', 'wpcomsh' ); ?></h3> |
| 1275 | <div id="colourlovers-palettes"></div> |
| 1276 | <div class="palette-buttons"> |
| 1277 | <a class="button next" id="more-palettes"><?php esc_html_e( 'More', 'wpcomsh' ); ?></a> |
| 1278 | <a class="button previous" id="less-palettes" style="display: none;"><?php esc_html_e( 'Back', 'wpcomsh' ); ?></a> |
| 1279 | <a class="button generate" id="generate-palette"><?php esc_html_e( 'Match header image', 'wpcomsh' ); ?></a> |
| 1280 | </div> |
| 1281 | </div> |
| 1282 | <?php |
| 1283 | } |
| 1284 | |
| 1285 | /** |
| 1286 | * Renders the pattern grid |
| 1287 | */ |
| 1288 | public static function color_patterns() { |
| 1289 | ?> |
| 1290 | <div class="the-pattern-picker" id="the-pattern-picker" style="display: none;"> |
| 1291 | <span class="customize-control-title"> |
| 1292 | <?php esc_html_e( 'Pick a Background Pattern', 'wpcomsh' ); ?> |
| 1293 | </span> |
| 1294 | <ul id="colourlovers-patterns"></ul> |
| 1295 | <div class="pagination"> |
| 1296 | <a id="more-patterns" class="button"><?php esc_html_e( 'More', 'wpcomsh' ); ?></a> |
| 1297 | <a id="less-patterns" class="button previous" style="display: none;"><?php esc_html_e( 'Back', 'wpcomsh' ); ?></a> |
| 1298 | </div> |
| 1299 | <p class="noresults" style="display: none;"><?php esc_html_e( "There aren't any patterns that match your chosen color scheme. It's just too unique!", 'wpcomsh' ); ?></p> |
| 1300 | </div> |
| 1301 | <?php |
| 1302 | } |
| 1303 | |
| 1304 | /** |
| 1305 | * Make this work inside the Customizer. |
| 1306 | * |
| 1307 | * @param WP_Customize_Manager $wp_customize the customizer manager instance. |
| 1308 | */ |
| 1309 | public static function in_customizer( $wp_customize ) { |
| 1310 | // Include controller class |
| 1311 | require_once __DIR__ . '/class-colors-controller.php'; |
| 1312 | |
| 1313 | $wp_customize->add_section( |
| 1314 | 'colors_manager_tool', |
| 1315 | array( |
| 1316 | 'title' => __( 'Colors & Backgrounds', 'wpcomsh' ), |
| 1317 | 'priority' => 35, |
| 1318 | ) |
| 1319 | ); |
| 1320 | |
| 1321 | $setting_opts = array( |
| 1322 | 'default' => self::get_colors(), |
| 1323 | 'capability' => 'edit_theme_options', |
| 1324 | 'transport' => 'postMessage', |
| 1325 | 'type' => 'theme_mod', |
| 1326 | ); |
| 1327 | |
| 1328 | if ( is_admin() ) { |
| 1329 | $setting_opts = array_merge( |
| 1330 | $setting_opts, |
| 1331 | array( |
| 1332 | 'sanitize_callback' => array( __CLASS__, 'sanitize_colors_on_save' ), |
| 1333 | 'sanitize_js_callback' => array( __CLASS__, 'sanitize_colors' ), |
| 1334 | ) |
| 1335 | ); |
| 1336 | } |
| 1337 | |
| 1338 | $wp_customize->add_setting( 'colors_manager[colors]', $setting_opts ); |
| 1339 | |
| 1340 | $wp_customize->add_control( |
| 1341 | new Colors_Manager_Control( |
| 1342 | $wp_customize, |
| 1343 | 'colors-tool', |
| 1344 | array( |
| 1345 | 'label' => __( 'Colors', 'wpcomsh' ), |
| 1346 | 'section' => 'colors_manager_tool', |
| 1347 | 'settings' => 'colors_manager[colors]', |
| 1348 | ) |
| 1349 | ) |
| 1350 | ); |
| 1351 | } |
| 1352 | |
| 1353 | /** |
| 1354 | * Sanitizes colors on save. |
| 1355 | * |
| 1356 | * @param array $set_colors saved colors. |
| 1357 | * @return array |
| 1358 | */ |
| 1359 | public static function sanitize_colors_on_save( $set_colors ) { |
| 1360 | return self::sanitize_colors( $set_colors ); |
| 1361 | } |
| 1362 | |
| 1363 | /** |
| 1364 | * Sanitizes colors. |
| 1365 | * |
| 1366 | * @param array $set_colors saved colors. |
| 1367 | * @return array |
| 1368 | */ |
| 1369 | public static function sanitize_colors( $set_colors ) { |
| 1370 | if ( ! is_array( $set_colors ) && ! is_object( $set_colors ) ) { |
| 1371 | return array(); |
| 1372 | } |
| 1373 | // let's make sure all of our keys/values are proper |
| 1374 | $colors_wanted = array(); |
| 1375 | $cats = self::get_color_slots(); |
| 1376 | if ( ! class_exists( 'Jetpack_color' ) ) { |
| 1377 | require_lib( 'class.color' ); |
| 1378 | } |
| 1379 | foreach ( $set_colors as $key => $color ) { |
| 1380 | if ( ! in_array( $key, $cats, true ) || ! $color ) { |
| 1381 | continue; |
| 1382 | } |
| 1383 | try { |
| 1384 | $color_object = new Jetpack_Color( $color ); |
| 1385 | $colors_wanted[ $key ] = '#' . $color_object->toHex(); |
| 1386 | } catch ( Exception $e ) { // phpcs:ignore |
| 1387 | // Exception not handled to avoid it propagating further, apparently. |
| 1388 | } |
| 1389 | } |
| 1390 | return $colors_wanted; |
| 1391 | } |
| 1392 | |
| 1393 | /** |
| 1394 | * Overriding theme colors. |
| 1395 | */ |
| 1396 | public static function override_themecolors() { |
| 1397 | global $themecolors; |
| 1398 | |
| 1399 | if ( ! self::should_enable_colors() ) { |
| 1400 | return; |
| 1401 | } |
| 1402 | |
| 1403 | $opts = get_theme_mod( 'colors_manager', array( 'colors' => false ) ); |
| 1404 | if ( ! isset( $opts ) ) { |
| 1405 | return; |
| 1406 | } |
| 1407 | |
| 1408 | $colors = $opts['colors']; |
| 1409 | |
| 1410 | if ( isset( $colors['fg1'] ) ) { |
| 1411 | $colors['border'] = $colors['fg1']; |
| 1412 | } |
| 1413 | if ( isset( $colors['link'] ) ) { |
| 1414 | $colors['url'] = $colors['link']; |
| 1415 | } |
| 1416 | if ( isset( $colors['txt'] ) ) { |
| 1417 | $colors['text'] = $colors['txt']; |
| 1418 | } |
| 1419 | |
| 1420 | unset( $colors['fg1'] ); |
| 1421 | unset( $colors['fg2'] ); |
| 1422 | unset( $colors['txt'] ); |
| 1423 | |
| 1424 | foreach ( $colors as $role => $color ) { |
| 1425 | if ( $color ) { |
| 1426 | $themecolors[ $role ] = substr( $color, 1 ); |
| 1427 | } |
| 1428 | } |
| 1429 | } |
| 1430 | |
| 1431 | /** |
| 1432 | * Injects our postMessage listener scripts into the theme |
| 1433 | * |
| 1434 | * @param WP_Customize_Manager $wp_customize the customizer manager instance. |
| 1435 | */ |
| 1436 | public static function theme_colors_js( $wp_customize ) { |
| 1437 | if ( $wp_customize->is_preview() && ! is_admin() ) { |
| 1438 | wp_enqueue_script( 'colors-instapreview' ); |
| 1439 | $js_data = array( |
| 1440 | 'colors' => self::$colors, |
| 1441 | 'defaultColors' => self::get_default_colors(), |
| 1442 | 'extraCss' => self::get_extra_css( true ), |
| 1443 | 'extraColors' => self::$extra_colors, |
| 1444 | ); |
| 1445 | wp_localize_script( 'colors-instapreview', 'ColorsTool', $js_data ); |
| 1446 | } |
| 1447 | } |
| 1448 | |
| 1449 | /** |
| 1450 | * Prints theme CSS. |
| 1451 | */ |
| 1452 | public static function print_theme_css() { |
| 1453 | if ( ! self::should_enable_colors() ) { |
| 1454 | return; |
| 1455 | } |
| 1456 | $css = self::get_theme_css(); |
| 1457 | printf( |
| 1458 | '<style type="text/css" id="custom-colors-css">%s</style>%s', |
| 1459 | wp_strip_all_tags( $css ), // phpcs:ignore -- CSS can't be properly escaped with esc_html |
| 1460 | "\n" |
| 1461 | ); |
| 1462 | } |
| 1463 | |
| 1464 | /** |
| 1465 | * Return theme CSS. |
| 1466 | */ |
| 1467 | public static function get_theme_css() { |
| 1468 | $opts = get_theme_mod( |
| 1469 | 'colors_manager', |
| 1470 | array( |
| 1471 | 'colors' => false, |
| 1472 | ) |
| 1473 | ); |
| 1474 | $colors = $opts['colors']; |
| 1475 | |
| 1476 | // extra colors/CSS: always on |
| 1477 | $css = self::get_extra_css(); |
| 1478 | |
| 1479 | // user colors |
| 1480 | foreach ( self::$colors as $cat => $rules ) { |
| 1481 | if ( ! isset( $colors[ $cat ] ) ) { |
| 1482 | continue; |
| 1483 | } |
| 1484 | |
| 1485 | $color = $colors[ $cat ]; |
| 1486 | foreach ( $rules as $rule ) { |
| 1487 | $css .= self::css_rule( $rule, $color ); |
| 1488 | } |
| 1489 | } |
| 1490 | |
| 1491 | // Minify & cache for future use. |
| 1492 | $minifier = new tubalmartin\CssMin\Minifier(); |
| 1493 | $css = $minifier->run( $css ); |
| 1494 | |
| 1495 | return $css; |
| 1496 | } |
| 1497 | |
| 1498 | /** |
| 1499 | * Get CSS rule. |
| 1500 | * |
| 1501 | * @todo possibly combine all of this into a keyed array to prevent selector duplication bloat |
| 1502 | * @param array $rule the CSS rule. |
| 1503 | * @param string $color the color string. |
| 1504 | * @return string |
| 1505 | */ |
| 1506 | public static function css_rule( $rule, $color ) { |
| 1507 | $css = ''; |
| 1508 | |
| 1509 | if ( ! isset( $rule[0] ) || ! isset( $rule[1] ) ) { |
| 1510 | return $css; |
| 1511 | } |
| 1512 | |
| 1513 | if ( isset( $rule[2] ) ) { |
| 1514 | // we'll need it in either case |
| 1515 | if ( ! class_exists( 'Jetpack_color' ) ) { |
| 1516 | require_lib( 'class.color' ); |
| 1517 | } |
| 1518 | |
| 1519 | try { |
| 1520 | $working_color = new Jetpack_Color( $color ); |
| 1521 | } catch ( RangeException $e ) { |
| 1522 | $message = 'rule: ' . print_r( $rule, 1 ) . "\n"; // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r |
| 1523 | $message .= 'call: $working_color = new Jetpack_Color( ' . $color . ' );' . "\n"; |
| 1524 | self::exception_mailer( $message ); |
| 1525 | return ''; |
| 1526 | } |
| 1527 | |
| 1528 | $number = (float) $rule[2]; |
| 1529 | // ensure contrast or darken/lighten |
| 1530 | if ( is_string( $rule[2] ) ) { |
| 1531 | $first_char = substr( $rule[2], 0, 1 ); |
| 1532 | // darken/lighten |
| 1533 | if ( '+' === $first_char || '-' === $first_char ) { |
| 1534 | $modify = 10 * $number; |
| 1535 | $color = $working_color->incrementLightness( intval( $modify ) )->toString(); |
| 1536 | } else { |
| 1537 | // hex bg for contrast |
| 1538 | if ( '#' === $first_char ) { |
| 1539 | try { |
| 1540 | $bg_color = new Jetpack_Color( $rule[2] ); |
| 1541 | } catch ( RangeException $e ) { |
| 1542 | $message = 'function: ' . __FUNCTION__ . "\n"; |
| 1543 | $message .= 'call: $bg_color = new Jetpack_Color( ' . $rule[2] . ' );' . "\n"; |
| 1544 | self::exception_mailer( $message ); |
| 1545 | return ''; |
| 1546 | } |
| 1547 | } elseif ( isset( self::$colors[ $rule[2] ] ) ) { // set color bg for contrast |
| 1548 | |
| 1549 | $set_colors = self::get_colors(); |
| 1550 | try { |
| 1551 | $bg_color = new Jetpack_Color( $set_colors[ $rule[2] ] ?? null ); |
| 1552 | } catch ( RangeException $e ) { |
| 1553 | $message = 'function: ' . __FUNCTION__ . "\n"; |
| 1554 | $message .= 'call: $bg_color = new Jetpack_Color( ' . $set_colors[ $rule[2] ] . ' );' . "\n"; |
| 1555 | self::exception_mailer( $message ); |
| 1556 | return ''; |
| 1557 | } |
| 1558 | } |
| 1559 | |
| 1560 | // we have a bg color to contrast |
| 1561 | if ( isset( $bg_color ) && is_a( $bg_color, 'Jetpack_Color' ) ) { |
| 1562 | // default contrast of 5, can be overridden with 4th arg. |
| 1563 | $contrast = $rule[3] ?? 5; |
| 1564 | $color = $working_color->getReadableContrastingColor( $bg_color, $contrast )->toString(); |
| 1565 | } |
| 1566 | } |
| 1567 | } elseif ( $rule[2] < 1 ) { // alpha |
| 1568 | unset( $rule[2] ); |
| 1569 | // back compat for non-rgba browsers |
| 1570 | $css .= self::css_rule( $rule, $color ); |
| 1571 | $color = $working_color->toCSS( 'rgba', intval( $number ) ); |
| 1572 | } |
| 1573 | } |
| 1574 | |
| 1575 | $css .= "{$rule[0]} { {$rule[1]}: {$color};}\n"; |
| 1576 | return $css; |
| 1577 | } |
| 1578 | |
| 1579 | /** |
| 1580 | * Get extra CSS. |
| 1581 | * |
| 1582 | * @param boolean $only_callback no processing, just callback. |
| 1583 | */ |
| 1584 | public static function get_extra_css( $only_callback = false ) { |
| 1585 | $css = ''; |
| 1586 | $extra_cb = get_theme_support( 'custom_colors_extra_css' ); |
| 1587 | |
| 1588 | if ( is_array( $extra_cb ) && is_callable( $extra_cb[0] ) ) { |
| 1589 | // will work with return values or straight printing |
| 1590 | ob_start(); |
| 1591 | $css = call_user_func( $extra_cb[0] ); |
| 1592 | $css .= ob_get_clean(); |
| 1593 | } |
| 1594 | |
| 1595 | if ( $only_callback ) { |
| 1596 | return $css; |
| 1597 | } |
| 1598 | |
| 1599 | foreach ( self::$extra_colors as $extra ) { |
| 1600 | if ( ! isset( $extra['rules'] ) || ! is_array( $extra['rules'] ) ) { |
| 1601 | continue; |
| 1602 | } |
| 1603 | $color = $extra['color']; |
| 1604 | foreach ( $extra['rules'] as $rule ) { |
| 1605 | $css .= self::css_rule( $rule, (string) $color ); |
| 1606 | } |
| 1607 | } |
| 1608 | return $css; |
| 1609 | } |
| 1610 | |
| 1611 | /** |
| 1612 | * Function for making theme annotations. |
| 1613 | * |
| 1614 | * @param string $category The color category. One of bg, txt, link, fg1, fg2. |
| 1615 | * @param string $default_color The default color for this category. |
| 1616 | * @param array $rules Array of rule arrays. $rule: array( selector, property, opacity );. |
| 1617 | * @param bool|string $label Optional. A UI helper label for identifying what a particular color will change in the theme. |
| 1618 | */ |
| 1619 | public static function add_color_rule( $category, $default_color, $rules, $label = false ) { |
| 1620 | // extra rules |
| 1621 | if ( 'extra' === $category ) { |
| 1622 | self::$extra_colors[] = array( |
| 1623 | 'color' => $default_color, |
| 1624 | 'rules' => $rules, |
| 1625 | ); |
| 1626 | return; |
| 1627 | } |
| 1628 | // prime it |
| 1629 | if ( ! isset( self::$colors[ $category ] ) ) { |
| 1630 | self::$colors[ $category ] = array(); |
| 1631 | } |
| 1632 | self::$colors[ $category ] = array_merge( self::$colors[ $category ], $rules ); |
| 1633 | |
| 1634 | self::$default_colors[ $category ] = $default_color; |
| 1635 | if ( $label ) { |
| 1636 | self::$labels[ $category ] = $label; |
| 1637 | } |
| 1638 | } |
| 1639 | |
| 1640 | /** |
| 1641 | * Allow a theme to declare its own color palettes. |
| 1642 | * |
| 1643 | * @param array $palette An array with 5 colors. |
| 1644 | * @param bool|string $title optional title string. |
| 1645 | */ |
| 1646 | public static function add_color_palette( $palette, $title = false ) { |
| 1647 | if ( ! $title ) { |
| 1648 | $theme = wp_get_theme(); |
| 1649 | $title = sprintf( |
| 1650 | // translators: %1$s is a theme name, %2$s is its custom color scheme number. |
| 1651 | __( '%1$s Alternative Scheme %2$s', 'wpcomsh' ), |
| 1652 | $theme->display( 'Name' ), |
| 1653 | count( self::$color_palettes ) + 1 |
| 1654 | ); |
| 1655 | } |
| 1656 | |
| 1657 | $id = sanitize_title_with_dashes( $title ); |
| 1658 | |
| 1659 | self::$color_palettes[ $id ] = compact( 'title', 'palette' ); |
| 1660 | } |
| 1661 | |
| 1662 | /** |
| 1663 | * Loads theme annotations, and filter them if loaded. |
| 1664 | * |
| 1665 | * @param boolean $theme Which theme to check for annotations on. Defaults to current theme. |
| 1666 | * @return boolean Theme has annotations. |
| 1667 | */ |
| 1668 | protected static function load_annotations( $theme = false ) { |
| 1669 | $theme_name = 'pub/' . self::pick_theme( $theme ); |
| 1670 | $annotations_file = get_stylesheet_directory() . '/inc/wpcom-colors.php'; |
| 1671 | self::prime_color_labels(); |
| 1672 | if ( is_readable( $annotations_file ) ) { |
| 1673 | require_once $annotations_file; |
| 1674 | self::$colors = apply_filters( 'custom_colors_rules', self::$colors, $theme_name ); |
| 1675 | self::handle_unset_colors(); |
| 1676 | return true; |
| 1677 | } |
| 1678 | return false; |
| 1679 | } |
| 1680 | |
| 1681 | /** |
| 1682 | * Unset colors that need to be unset. |
| 1683 | */ |
| 1684 | protected static function handle_unset_colors() { |
| 1685 | foreach ( self::$colors as $key => $value ) { |
| 1686 | if ( empty( $value ) ) { |
| 1687 | // set Label to Unused |
| 1688 | self::$labels[ $key ] = __( 'Unused', 'wpcomsh' ); |
| 1689 | unset( self::$colors[ $key ] ); |
| 1690 | } |
| 1691 | } |
| 1692 | } |
| 1693 | |
| 1694 | /** |
| 1695 | * Sets default, i10n-ized default color labels that can be overridden in annotations. |
| 1696 | */ |
| 1697 | protected static function prime_color_labels() { |
| 1698 | if ( ! empty( self::$labels ) ) { |
| 1699 | return; |
| 1700 | } |
| 1701 | |
| 1702 | self::$labels = array( |
| 1703 | 'bg' => __( 'Background', 'wpcomsh' ), |
| 1704 | 'txt' => __( 'Headings', 'wpcomsh' ), |
| 1705 | 'link' => __( 'Links', 'wpcomsh' ), |
| 1706 | 'fg1' => __( 'Accent #1', 'wpcomsh' ), |
| 1707 | 'fg2' => __( 'Accent #2', 'wpcomsh' ), |
| 1708 | ); |
| 1709 | } |
| 1710 | |
| 1711 | /** |
| 1712 | * Generate color suggestions for a given role from a set of colors. |
| 1713 | * |
| 1714 | * @param array $colors color array. |
| 1715 | * @param string $role (bg|fg1|fg2|txt|link). |
| 1716 | * @return array |
| 1717 | */ |
| 1718 | public static function color_suggestions( $colors, $role ) { |
| 1719 | if ( ! class_exists( 'Jetpack_color' ) ) { |
| 1720 | require_lib( 'class.color' ); |
| 1721 | } |
| 1722 | |
| 1723 | $suggestions = array(); |
| 1724 | |
| 1725 | $suggestions = array_merge( $suggestions, self::color_suggestions_from_palette( $colors, $role ) ); |
| 1726 | $suggestions = array_merge( $suggestions, self::color_suggestions_from_math( $colors, $role ) ); |
| 1727 | |
| 1728 | shuffle( $suggestions ); |
| 1729 | |
| 1730 | return $suggestions; |
| 1731 | } |
| 1732 | |
| 1733 | /** |
| 1734 | * Generate color suggestions by grabbing a popular palette and applying |
| 1735 | * it as a transformation to the colors we're using as a guide. |
| 1736 | * |
| 1737 | * @param array $colors color array. |
| 1738 | * @param string $role (bg|fg1|fg2|txt|link). |
| 1739 | * @return array |
| 1740 | */ |
| 1741 | public static function color_suggestions_from_palette( $colors, $role ) { |
| 1742 | $suggestions = array(); |
| 1743 | |
| 1744 | $top_palette = self::get_color_palettes( |
| 1745 | array( |
| 1746 | 'limit' => 1, |
| 1747 | 'offset' => wp_rand( |
| 1748 | 0, |
| 1749 | 100 |
| 1750 | ), |
| 1751 | ) |
| 1752 | ); |
| 1753 | |
| 1754 | if ( ! $top_palette ) { |
| 1755 | return array(); |
| 1756 | } |
| 1757 | |
| 1758 | $top_palette = $top_palette[0]; |
| 1759 | |
| 1760 | $equivalent_color_hex = $top_palette['colors'][ $role ]; |
| 1761 | |
| 1762 | foreach ( $top_palette['colors'] as $palette_role => $palette_color_hex ) { |
| 1763 | $base_color_hex = $colors[ $palette_role ]; |
| 1764 | try { |
| 1765 | // phpcs:ignore -- $base_color:$new_color :: $palette_color:$equivalent_color |
| 1766 | $base_color = new Jetpack_Color( $base_color_hex ); |
| 1767 | $palette_color = new Jetpack_Color( $palette_color_hex ); |
| 1768 | $equivalent_color = new Jetpack_Color( $equivalent_color_hex ); |
| 1769 | |
| 1770 | $palette_hsl = $palette_color->toHsl(); |
| 1771 | $equivalent_hsl = $equivalent_color->toHsl(); |
| 1772 | |
| 1773 | $base_color->incrementHue( $equivalent_hsl['h'] - $palette_hsl['h'] ); |
| 1774 | $base_color->saturate( $equivalent_hsl['s'] - $palette_hsl['s'] ); |
| 1775 | $base_color->lighten( $equivalent_hsl['l'] - $palette_hsl['l'] ); |
| 1776 | |
| 1777 | $suggestions[] = self::normalize_color( $base_color->toHex() ); |
| 1778 | } catch ( RangeException $e ) { |
| 1779 | $message = "Color exception!\n\n"; |
| 1780 | $message .= "role: $role\n"; |
| 1781 | $message .= "base: $base_color_hex\n"; |
| 1782 | $message .= "palette: $palette_color_hex\n"; |
| 1783 | $message .= "equiv: $equivalent_color_hex\n"; |
| 1784 | $message .= 'colors arg: ' . print_r( $colors, 1 ); // phpcs:ignore |
| 1785 | self::exception_mailer( $message ); |
| 1786 | continue; |
| 1787 | } |
| 1788 | } |
| 1789 | |
| 1790 | return $suggestions; |
| 1791 | } |
| 1792 | |
| 1793 | // phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable |
| 1794 | /** |
| 1795 | * Mail the exception. |
| 1796 | * |
| 1797 | * @param string $message the exception private. |
| 1798 | */ |
| 1799 | public static function exception_mailer( $message = 'Needs a message' ) { |
| 1800 | $message .= "\n\nblog: " . home_url() . "\n"; |
| 1801 | $message .= 'backtrace: ' . wp_debug_backtrace_summary() . "\n"; // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_wp_debug_backtrace_summary |
| 1802 | // phpcs:ignore -- wp_mail( 'wiebe@automattic.com', 'Color Exception on WordPress.com', $message ); |
| 1803 | } |
| 1804 | // phpcs:enable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable |
| 1805 | |
| 1806 | /** |
| 1807 | * Use a set of predefined transformations to generate color suggestions |
| 1808 | * based on roles. |
| 1809 | * |
| 1810 | * @param array $colors color array. |
| 1811 | * @param string $role (bg|fg1|fg2|txt|link). |
| 1812 | * @return array |
| 1813 | */ |
| 1814 | public static function color_suggestions_from_math( $colors, $role ) { |
| 1815 | $suggestions = array(); |
| 1816 | |
| 1817 | // These are the result of a couple of hours of playing around. |
| 1818 | // Nothing here is set in stone. |
| 1819 | $relations = array( |
| 1820 | 'bg:fg1' => array( 'brighter', 'saturate' ), |
| 1821 | 'bg:fg2' => array( 'darker', 'desaturate' ), |
| 1822 | 'bg:txt' => array( '+triad' ), |
| 1823 | 'bg:link' => array( '-triad' ), |
| 1824 | 'fg1:bg' => array( 'desaturate', 'darker' ), |
| 1825 | 'fg1:fg2' => array( '+analog' ), |
| 1826 | 'fg1:txt' => array( '-tetrad' ), |
| 1827 | 'fg1:link' => array( 'darker', 'saturate' ), |
| 1828 | 'fg2:bg' => array( 'saturate', 'brighter' ), |
| 1829 | 'fg2:fg1' => array( '-analog' ), |
| 1830 | 'fg2:txt' => array( '-tetrad' ), |
| 1831 | 'fg2:link' => array( 'darker', 'saturate' ), |
| 1832 | 'txt:bg' => array( '+triad' ), |
| 1833 | 'txt:fg1' => array( '+tetrad' ), |
| 1834 | 'txt:fg2' => array( '+tetrad' ), |
| 1835 | 'txt:link' => array( '-split-complement', 'saturate' ), |
| 1836 | 'link:bg' => array( '-triad' ), |
| 1837 | 'link:fg1' => array( 'desaturate', 'brighter' ), |
| 1838 | 'link:fg2' => array( 'desaturate', 'brighter' ), |
| 1839 | 'link:txt' => array( 'darker', 'saturate' ), |
| 1840 | ); |
| 1841 | |
| 1842 | foreach ( $colors as $known_role => $color_code ) { |
| 1843 | if ( $known_role === $role ) { |
| 1844 | continue; |
| 1845 | } |
| 1846 | |
| 1847 | $transforms = $relations[ $known_role . ':' . $role ]; |
| 1848 | try { |
| 1849 | $new_color = new Jetpack_Color( self::normalize_color( $color_code ) ); |
| 1850 | } catch ( RangeException $e ) { |
| 1851 | $message = 'function: ' . __FUNCTION__ . "\n"; |
| 1852 | $message .= 'call: $new_color = new Jetpack_Color( self::normalize_color( ' . $color_code . ' ) );' . "\n"; |
| 1853 | $message .= 'normalized color: ' . self::normalize_color( $color_code ); |
| 1854 | self::exception_mailer( $message ); |
| 1855 | continue; |
| 1856 | } |
| 1857 | |
| 1858 | foreach ( $transforms as $transform ) { |
| 1859 | switch ( $transform ) { |
| 1860 | case 'complement': |
| 1861 | $new_color->getComplement(); |
| 1862 | break; |
| 1863 | case 'brighter': |
| 1864 | $new_color->lighten( 25 ); |
| 1865 | break; |
| 1866 | case 'darker': |
| 1867 | $new_color->darken( 25 ); |
| 1868 | break; |
| 1869 | case 'grayscale': |
| 1870 | $new_color->toGrayscale(); |
| 1871 | break; |
| 1872 | case '+split-complement': |
| 1873 | $new_color->getSplitComplement( 1 ); |
| 1874 | break; |
| 1875 | case '-split-complement': |
| 1876 | $new_color->getSplitComplement( -1 ); |
| 1877 | break; |
| 1878 | case '+triad': |
| 1879 | $new_color->getTriad( 1 ); |
| 1880 | break; |
| 1881 | case '-triad': |
| 1882 | $new_color->getTriad( -1 ); |
| 1883 | break; |
| 1884 | case 'saturate': |
| 1885 | $new_color->saturate( 25 ); |
| 1886 | break; |
| 1887 | case 'desaturate': |
| 1888 | $new_color->desaturate( 25 ); |
| 1889 | break; |
| 1890 | case '+analog': |
| 1891 | $new_color->getAnalog( 1 ); |
| 1892 | break; |
| 1893 | case '-analog': |
| 1894 | $new_color->getAnalog( -1 ); |
| 1895 | break; |
| 1896 | case '+tetrad': |
| 1897 | $new_color->getTetrad( 1 ); |
| 1898 | break; |
| 1899 | case '-tetrad': |
| 1900 | $new_color->getTetrad( -1 ); |
| 1901 | break; |
| 1902 | } |
| 1903 | } |
| 1904 | |
| 1905 | $suggestions[] = self::normalize_color( $new_color->toHex() ); |
| 1906 | } |
| 1907 | |
| 1908 | return $suggestions; |
| 1909 | } |
| 1910 | } |
| 1911 | |
| 1912 | /** |
| 1913 | * Nothing to override |
| 1914 | */ |
| 1915 | class Colors_Manager extends Colors_Manager_Common {} |
| 1916 | |
| 1917 | /** |
| 1918 | * Adds a color rule. |
| 1919 | * |
| 1920 | * @param string $category The color category. One of bg, txt, link, fg1, fg2. |
| 1921 | * @param string $default_color The default color for this category. |
| 1922 | * @param array $rules Array of rule arrays. $rule: array( selector, property, opacity );. |
| 1923 | * @param bool|string $label Optional. A UI helper label for identifying what a particular color will change in the theme. |
| 1924 | */ |
| 1925 | function add_color_rule( $category, $default_color, $rules, $label = false ) { |
| 1926 | Colors_Manager::add_color_rule( $category, $default_color, $rules, $label ); |
| 1927 | } |
| 1928 | |
| 1929 | /** |
| 1930 | * Adds color palette. |
| 1931 | * |
| 1932 | * @param array $palette An array with 5 colors. |
| 1933 | * @param bool|string $title optional title string. |
| 1934 | */ |
| 1935 | function add_color_palette( $palette, $title = false ) { |
| 1936 | return Colors_Manager::add_color_palette( $palette, $title ); |
| 1937 | } |
| 1938 | |
| 1939 | /** |
| 1940 | * Gutenberg color manager. |
| 1941 | */ |
| 1942 | class Colors_Manager_Gutenberg extends Colors_Manager_Common { |
| 1943 | |
| 1944 | /** |
| 1945 | * Whether we're in Gutenberg. |
| 1946 | * |
| 1947 | * @var boolean |
| 1948 | */ |
| 1949 | protected static $is_gutenberg = true; |
| 1950 | |
| 1951 | /** |
| 1952 | * Annotations file path. |
| 1953 | * |
| 1954 | * @var string |
| 1955 | */ |
| 1956 | protected static $annotations_file = 'wpcom-editor-colors.php'; |
| 1957 | } |
| 1958 | |
| 1959 | /** |
| 1960 | * Load Gutenberg's color manager. |
| 1961 | */ |
| 1962 | function colors_manager_gutenberg_load() { |
| 1963 | if ( get_current_screen()->is_block_editor() ) { |
| 1964 | Colors_Manager_Gutenberg::init(); // Gutenberg |
| 1965 | } |
| 1966 | } |
| 1967 | |
| 1968 | /** |
| 1969 | * Load corresponding color manager. |
| 1970 | */ |
| 1971 | function load_corresponding_color_manager() { |
| 1972 | global $pagenow; |
| 1973 | if ( is_admin() && 'customize.php' !== $pagenow && ! defined( 'DOING_AJAX' ) ) { |
| 1974 | add_action( 'current_screen', 'colors_manager_gutenberg_load' ); |
| 1975 | } else { |
| 1976 | Colors_Manager::init(); |
| 1977 | } |
| 1978 | } |
| 1979 | |
| 1980 | add_action( 'init', 'load_corresponding_color_manager' ); |