Нема описа

class-site-logo.php 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. <?php
  2. /**
  3. * Our Site Logo class for managing a theme-agnostic logo through the Customizer.
  4. *
  5. * @package automattic/jetpack
  6. */
  7. class Site_Logo {
  8. /**
  9. * Stores our single instance.
  10. */
  11. private static $instance;
  12. /**
  13. * Stores the attachment ID of the site logo.
  14. */
  15. public $logo;
  16. /**
  17. * Return our instance, creating a new one if necessary.
  18. *
  19. * @uses Site_Logo::$instance
  20. * @return object Site_Logo
  21. */
  22. public static function instance() {
  23. if ( ! isset( self::$instance ) ) {
  24. self::$instance = new Site_Logo();
  25. self::$instance->register_hooks();
  26. }
  27. return self::$instance;
  28. }
  29. /**
  30. * Get our current logo settings stored in options.
  31. *
  32. * @uses get_option()
  33. */
  34. private function __construct() {
  35. $this->logo = (int) get_option( 'site_logo', null );
  36. }
  37. /**
  38. * Register our actions and filters.
  39. *
  40. * @uses Site_Logo::head_text_styles()
  41. * @uses Site_Logo::customize_register()
  42. * @uses Site_Logo::preview_enqueue()
  43. * @uses Site_Logo::body_classes()
  44. * @uses Site_Logo::media_manager_image_sizes()
  45. * @uses add_action
  46. * @uses add_filter
  47. */
  48. public function register_hooks() {
  49. // This would only happen if a theme supports BOTH site-logo and custom-logo for some reason
  50. if ( current_theme_supports( 'custom-logo' ) ) {
  51. return;
  52. }
  53. add_action( 'wp_head', array( $this, 'head_text_styles' ) );
  54. add_action( 'customize_register', array( $this, 'customize_register' ) );
  55. add_action( 'customize_preview_init', array( $this, 'preview_enqueue' ) );
  56. add_action( 'delete_attachment', array( $this, 'reset_on_attachment_delete' ) );
  57. add_filter( 'body_class', array( $this, 'body_classes' ) );
  58. add_filter( 'image_size_names_choose', array( $this, 'media_manager_image_sizes' ) );
  59. add_filter( 'display_media_states', array( $this, 'add_media_state' ) );
  60. }
  61. /**
  62. * Add our logo uploader to the Customizer.
  63. *
  64. * @param object $wp_customize Customizer object.
  65. * @uses current_theme_supports()
  66. * @uses current_theme_supports()
  67. * @uses WP_Customize_Manager::add_setting()
  68. * @uses WP_Customize_Manager::add_control()
  69. * @uses Site_Logo::sanitize_checkbox()
  70. */
  71. public function customize_register( $wp_customize ) {
  72. // Add a setting to hide header text if the theme isn't supporting the feature itself
  73. if ( ! current_theme_supports( 'custom-header' ) ) {
  74. $wp_customize->add_setting(
  75. 'site_logo_header_text',
  76. array(
  77. 'default' => 1,
  78. 'sanitize_callback' => array( $this, 'sanitize_checkbox' ),
  79. 'transport' => 'postMessage',
  80. )
  81. );
  82. $wp_customize->add_control(
  83. new WP_Customize_Control(
  84. $wp_customize,
  85. 'site_logo_header_text',
  86. array(
  87. 'label' => __( 'Display Header Text', 'jetpack' ),
  88. 'section' => 'title_tagline',
  89. 'settings' => 'site_logo_header_text',
  90. 'type' => 'checkbox',
  91. )
  92. )
  93. );
  94. }
  95. // Add the setting for our logo value.
  96. $wp_customize->add_setting(
  97. 'site_logo',
  98. array(
  99. 'capability' => 'manage_options',
  100. 'default' => 0,
  101. 'sanitize_callback' => array( $this, 'sanitize_logo_setting' ),
  102. 'transport' => 'postMessage',
  103. 'type' => 'option',
  104. )
  105. );
  106. // By default, not setting width and height will suggest a square crop.
  107. $width = null;
  108. $height = null;
  109. $logo_size = jetpack_get_site_logo_dimensions();
  110. // Only suggested a different crop if the theme declares both dimensions.
  111. if ( false !== $logo_size && $logo_size['width'] && $logo_size['height'] ) {
  112. $width = $logo_size['width'];
  113. $height = $logo_size['height'];
  114. }
  115. // Add our image uploader.
  116. $wp_customize->add_control(
  117. new WP_Customize_Cropped_Image_Control(
  118. $wp_customize,
  119. 'site_logo',
  120. array(
  121. 'label' => __( 'Logo', 'jetpack' ),
  122. 'section' => 'title_tagline',
  123. 'settings' => 'site_logo',
  124. 'width' => $width,
  125. 'height' => $height,
  126. 'flex_width' => true,
  127. 'flex_height' => true,
  128. 'button_labels' => array(
  129. 'select' => __( 'Add logo', 'jetpack' ),
  130. 'change' => __( 'Change logo', 'jetpack' ),
  131. 'remove' => __( 'Remove logo', 'jetpack' ),
  132. 'placeholder' => __( 'No logo set', 'jetpack' ),
  133. 'frame_title' => __( 'Set as logo', 'jetpack' ),
  134. 'frame_button' => __( 'Choose logo', 'jetpack' ),
  135. ),
  136. )
  137. )
  138. );
  139. $wp_customize->selective_refresh->add_partial(
  140. 'site_logo',
  141. array(
  142. 'settings' => 'site_logo',
  143. 'selector' => '.site-logo-link',
  144. 'render_callback' => array( $this, 'customizer_preview' ),
  145. 'container_inclusive' => true,
  146. )
  147. );
  148. }
  149. /**
  150. * Enqueue scripts for the Customizer live preview.
  151. *
  152. * @uses wp_enqueue_script()
  153. * @uses plugins_url()
  154. * @uses current_theme_supports()
  155. * @uses Site_Logo::header_text_classes()
  156. * @uses wp_localize_script()
  157. */
  158. public function preview_enqueue() {
  159. // Don't bother passing in header text classes if the theme supports custom headers.
  160. if ( ! current_theme_supports( 'custom-header' ) ) {
  161. $classes = jetpack_sanitize_header_text_classes( $this->header_text_classes() );
  162. wp_enqueue_script( 'site-logo-header-text', plugins_url( '../js/site-logo-header-text.js', __FILE__ ), array( 'media-views' ), '', true );
  163. wp_localize_script( 'site-logo-header-text', 'site_logo_header_classes', array( 'classes' => $classes ) );
  164. }
  165. }
  166. /**
  167. * Get header text classes. If not defined in add_theme_support(), defaults from Underscores will be used.
  168. *
  169. * @uses get_theme_support
  170. * @return string String of classes to hide
  171. */
  172. public function header_text_classes() {
  173. $args = get_theme_support( 'site-logo' );
  174. if ( isset( $args[0]['header-text'] ) ) {
  175. // Use any classes defined in add_theme_support().
  176. $classes = $args[0]['header-text'];
  177. } else {
  178. // Otherwise, use these defaults, which will work with any Underscores-based theme.
  179. $classes = array(
  180. 'site-title',
  181. 'site-description',
  182. );
  183. }
  184. // If we've got an array, reduce them to a string for output
  185. if ( is_array( $classes ) ) {
  186. $classes = (string) '.' . implode( ', .', $classes );
  187. } else {
  188. $classes = (string) '.' . $classes;
  189. }
  190. return $classes;
  191. }
  192. /**
  193. * Hide header text on front-end if necessary.
  194. *
  195. * @uses current_theme_supports()
  196. * @uses get_theme_mod()
  197. * @uses Site_Logo::header_text_classes()
  198. * @uses esc_html()
  199. */
  200. public function head_text_styles() {
  201. // Bail if our theme supports custom headers.
  202. if ( current_theme_supports( 'custom-header' ) ) {
  203. return;
  204. }
  205. // Is Display Header Text unchecked? If so, we need to hide our header text.
  206. if ( ! get_theme_mod( 'site_logo_header_text', 1 ) ) {
  207. $classes = $this->header_text_classes();
  208. ?>
  209. <!-- Site Logo: hide header text -->
  210. <style type="text/css">
  211. <?php echo jetpack_sanitize_header_text_classes( $classes ); ?> {
  212. position: absolute;
  213. clip: rect(1px, 1px, 1px, 1px);
  214. }
  215. </style>
  216. <?php
  217. }
  218. }
  219. /**
  220. * Determine image size to use for the logo.
  221. *
  222. * @uses get_theme_support()
  223. * @return string Size specified in add_theme_support declaration, or 'thumbnail' default
  224. */
  225. public function theme_size() {
  226. $args = get_theme_support( 'site-logo' );
  227. $valid_sizes = get_intermediate_image_sizes();
  228. // Add 'full' to the list of accepted values.
  229. $valid_sizes[] = 'full';
  230. // If the size declared in add_theme_support is valid, use it; otherwise, just go with 'thumbnail'.
  231. $size = ( isset( $args[0]['size'] ) && in_array( $args[0]['size'], $valid_sizes ) ) ? $args[0]['size'] : 'thumbnail';
  232. return $size;
  233. }
  234. /**
  235. * Make custom image sizes available to the media manager.
  236. *
  237. * @param array $sizes
  238. * @uses get_intermediate_image_sizes()
  239. * @return array All default and registered custom image sizes.
  240. */
  241. public function media_manager_image_sizes( $sizes ) {
  242. // Get an array of all registered image sizes.
  243. $intermediate = get_intermediate_image_sizes();
  244. // Have we got anything fun to work with?
  245. if ( is_array( $intermediate ) && ! empty( $intermediate ) ) {
  246. foreach ( $intermediate as $key => $size ) {
  247. // If the size isn't already in the $sizes array, add it.
  248. if ( ! array_key_exists( $size, $sizes ) ) {
  249. $sizes[ $size ] = $size;
  250. }
  251. }
  252. }
  253. return $sizes;
  254. }
  255. /**
  256. * Add site logos to media states in the Media Manager.
  257. *
  258. * @return array The current attachment's media states.
  259. */
  260. public function add_media_state( $media_states ) {
  261. // Only bother testing if we have a site logo set.
  262. if ( $this->has_site_logo() ) {
  263. global $post;
  264. // If our attachment ID and the site logo ID match, this image is the site logo.
  265. if ( $post && $post->ID === $this->logo ) {
  266. $media_states[] = __( 'Site Logo', 'jetpack' );
  267. }
  268. }
  269. return $media_states;
  270. }
  271. /**
  272. * Reset the site logo if the current logo is deleted in the media manager.
  273. *
  274. * @param int $site_id
  275. * @uses Site_Logo::remove_site_logo()
  276. */
  277. public function reset_on_attachment_delete( $post_id ) {
  278. if ( $this->logo === $post_id ) {
  279. $this->remove_site_logo();
  280. }
  281. }
  282. /**
  283. * Determine if a site logo is assigned or not.
  284. *
  285. * @uses Site_Logo::$logo
  286. * @return boolean True if there is an active logo, false otherwise
  287. */
  288. public function has_site_logo() {
  289. return (bool) $this->logo;
  290. }
  291. /**
  292. * Reset the site logo option to zero (empty).
  293. *
  294. * @uses update_option()
  295. */
  296. public function remove_site_logo() {
  297. update_option( 'site_logo', null );
  298. }
  299. /**
  300. * Adds custom classes to the array of body classes.
  301. *
  302. * @uses Site_Logo::has_site_logo()
  303. * @return array Array of <body> classes
  304. */
  305. public function body_classes( $classes ) {
  306. // Add a class if a Site Logo is active
  307. if ( $this->has_site_logo() ) {
  308. $classes[] = 'has-site-logo';
  309. }
  310. return $classes;
  311. }
  312. /**
  313. * Sanitize our header text Customizer setting.
  314. *
  315. * @param $input
  316. * @return mixed 1 if checked, empty string if not checked.
  317. */
  318. public function sanitize_checkbox( $input ) {
  319. return ( 1 == $input ) ? 1 : '';
  320. }
  321. /**
  322. * Validate and sanitize a new site logo setting.
  323. *
  324. * @param $input
  325. * @return mixed 1 if checked, empty string if not checked.
  326. */
  327. public function sanitize_logo_setting( $input ) {
  328. $input = absint( $input );
  329. // If the new setting doesn't point to a valid attachment, just reset the whole thing.
  330. if ( false === wp_get_attachment_image_src( $input ) ) {
  331. $input = 0;
  332. }
  333. return $input;
  334. }
  335. /**
  336. * This function returns the updated HTML in the Customizer preview when the logo is added, updated, or removed.
  337. *
  338. * @return string
  339. */
  340. public function customizer_preview() {
  341. ob_start();
  342. jetpack_the_site_logo();
  343. return ob_get_clean();
  344. }
  345. }
  346. /**
  347. * Allow themes and plugins to access Site_Logo methods and properties.
  348. *
  349. * @uses Site_Logo::instance()
  350. * @return object Site_Logo
  351. */
  352. function site_logo() {
  353. return Site_Logo::instance();
  354. }
  355. /**
  356. * One site logo, please.
  357. */
  358. site_logo();