[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

title

Body

[close]

/wp-admin/includes/ -> class-custom-image-header.php (source)

   1  <?php
   2  /**
   3   * The custom header image script.
   4   *
   5   * @package WordPress
   6   * @subpackage Administration
   7   */
   8  
   9  /**
  10   * The custom header image class.
  11   *
  12   * @since 2.1.0
  13   */
  14  class Custom_Image_Header {
  15  
  16      /**
  17       * Callback for administration header.
  18       *
  19       * @var callable
  20       * @since 2.1.0
  21       */
  22      public $admin_header_callback;
  23  
  24      /**
  25       * Callback for header div.
  26       *
  27       * @var callable
  28       * @since 3.0.0
  29       */
  30      public $admin_image_div_callback;
  31  
  32      /**
  33       * Holds default headers.
  34       *
  35       * @var array
  36       * @since 3.0.0
  37       */
  38      public $default_headers = array();
  39  
  40      /**
  41       * Used to trigger a success message when settings updated and set to true.
  42       *
  43       * @since 3.0.0
  44       * @var bool
  45       */
  46      private $updated;
  47  
  48      /**
  49       * Constructor - Register administration header callback.
  50       *
  51       * @since 2.1.0
  52       * @param callable $admin_header_callback
  53       * @param callable $admin_image_div_callback Optional custom image div output callback.
  54       */
  55  	public function __construct( $admin_header_callback, $admin_image_div_callback = '' ) {
  56          $this->admin_header_callback    = $admin_header_callback;
  57          $this->admin_image_div_callback = $admin_image_div_callback;
  58  
  59          add_action( 'admin_menu', array( $this, 'init' ) );
  60  
  61          add_action( 'customize_save_after', array( $this, 'customize_set_last_used' ) );
  62          add_action( 'wp_ajax_custom-header-crop', array( $this, 'ajax_header_crop' ) );
  63          add_action( 'wp_ajax_custom-header-add', array( $this, 'ajax_header_add' ) );
  64          add_action( 'wp_ajax_custom-header-remove', array( $this, 'ajax_header_remove' ) );
  65      }
  66  
  67      /**
  68       * Set up the hooks for the Custom Header admin page.
  69       *
  70       * @since 2.1.0
  71       */
  72  	public function init() {
  73          $page = add_theme_page( __( 'Header' ), __( 'Header' ), 'edit_theme_options', 'custom-header', array( $this, 'admin_page' ) );
  74          if ( ! $page ) {
  75              return;
  76          }
  77  
  78          add_action( "admin_print_scripts-{$page}", array( $this, 'js_includes' ) );
  79          add_action( "admin_print_styles-{$page}", array( $this, 'css_includes' ) );
  80          add_action( "admin_head-{$page}", array( $this, 'help' ) );
  81          add_action( "admin_head-{$page}", array( $this, 'take_action' ), 50 );
  82          add_action( "admin_head-{$page}", array( $this, 'js' ), 50 );
  83          if ( $this->admin_header_callback ) {
  84              add_action( "admin_head-{$page}", $this->admin_header_callback, 51 );
  85          }
  86      }
  87  
  88      /**
  89       * Adds contextual help.
  90       *
  91       * @since 3.0.0
  92       */
  93  	public function help() {
  94          get_current_screen()->add_help_tab(
  95              array(
  96                  'id'      => 'overview',
  97                  'title'   => __( 'Overview' ),
  98                  'content' =>
  99                      '<p>' . __( 'This screen is used to customize the header section of your theme.' ) . '</p>' .
 100                      '<p>' . __( 'You can choose from the theme&#8217;s default header images, or use one of your own. You can also customize how your Site Title and Tagline are displayed.' ) . '<p>',
 101              )
 102          );
 103  
 104          get_current_screen()->add_help_tab(
 105              array(
 106                  'id'      => 'set-header-image',
 107                  'title'   => __( 'Header Image' ),
 108                  'content' =>
 109                      '<p>' . __( 'You can set a custom image header for your site. Simply upload the image and crop it, and the new header will go live immediately. Alternatively, you can use an image that has already been uploaded to your Media Library by clicking the &#8220;Choose Image&#8221; button.' ) . '</p>' .
 110                      '<p>' . __( 'Some themes come with additional header images bundled. If you see multiple images displayed, select the one you&#8217;d like and click the &#8220;Save Changes&#8221; button.' ) . '</p>' .
 111                      '<p>' . __( 'If your theme has more than one default header image, or you have uploaded more than one custom header image, you have the option of having WordPress display a randomly different image on each page of your site. Click the &#8220;Random&#8221; radio button next to the Uploaded Images or Default Images section to enable this feature.' ) . '</p>' .
 112                      '<p>' . __( 'If you don&#8217;t want a header image to be displayed on your site at all, click the &#8220;Remove Header Image&#8221; button at the bottom of the Header Image section of this page. If you want to re-enable the header image later, you just have to select one of the other image options and click &#8220;Save Changes&#8221;.' ) . '</p>',
 113              )
 114          );
 115  
 116          get_current_screen()->add_help_tab(
 117              array(
 118                  'id'      => 'set-header-text',
 119                  'title'   => __( 'Header Text' ),
 120                  'content' =>
 121                      '<p>' . sprintf(
 122                          /* translators: %s: URL to General Settings screen. */
 123                          __( 'For most themes, the header text is your Site Title and Tagline, as defined in the <a href="%s">General Settings</a> section.' ),
 124                          admin_url( 'options-general.php' )
 125                      ) .
 126                      '</p>' .
 127                      '<p>' . __( 'In the Header Text section of this page, you can choose whether to display this text or hide it. You can also choose a color for the text by clicking the Select Color button and either typing in a legitimate HTML hex value, e.g. &#8220;#ff0000&#8221; for red, or by choosing a color using the color picker.' ) . '</p>' .
 128                      '<p>' . __( 'Don&#8217;t forget to click &#8220;Save Changes&#8221; when you&#8217;re done!' ) . '</p>',
 129              )
 130          );
 131  
 132          get_current_screen()->set_help_sidebar(
 133              '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
 134              '<p>' . __( '<a href="https://codex.wordpress.org/Appearance_Header_Screen">Documentation on Custom Header</a>' ) . '</p>' .
 135              '<p>' . __( '<a href="https://wordpress.org/support/">Support</a>' ) . '</p>'
 136          );
 137      }
 138  
 139      /**
 140       * Get the current step.
 141       *
 142       * @since 2.6.0
 143       *
 144       * @return int Current step
 145       */
 146  	public function step() {
 147          if ( ! isset( $_GET['step'] ) ) {
 148              return 1;
 149          }
 150  
 151          $step = (int) $_GET['step'];
 152          if ( $step < 1 || 3 < $step ||
 153              ( 2 == $step && ! wp_verify_nonce( $_REQUEST['_wpnonce-custom-header-upload'], 'custom-header-upload' ) ) ||
 154              ( 3 == $step && ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'custom-header-crop-image' ) )
 155          ) {
 156              return 1;
 157          }
 158  
 159          return $step;
 160      }
 161  
 162      /**
 163       * Set up the enqueue for the JavaScript files.
 164       *
 165       * @since 2.1.0
 166       */
 167  	public function js_includes() {
 168          $step = $this->step();
 169  
 170          if ( ( 1 == $step || 3 == $step ) ) {
 171              wp_enqueue_media();
 172              wp_enqueue_script( 'custom-header' );
 173              if ( current_theme_supports( 'custom-header', 'header-text' ) ) {
 174                  wp_enqueue_script( 'wp-color-picker' );
 175              }
 176          } elseif ( 2 == $step ) {
 177              wp_enqueue_script( 'imgareaselect' );
 178          }
 179      }
 180  
 181      /**
 182       * Set up the enqueue for the CSS files
 183       *
 184       * @since 2.7.0
 185       */
 186  	public function css_includes() {
 187          $step = $this->step();
 188  
 189          if ( ( 1 == $step || 3 == $step ) && current_theme_supports( 'custom-header', 'header-text' ) ) {
 190              wp_enqueue_style( 'wp-color-picker' );
 191          } elseif ( 2 == $step ) {
 192              wp_enqueue_style( 'imgareaselect' );
 193          }
 194      }
 195  
 196      /**
 197       * Execute custom header modification.
 198       *
 199       * @since 2.6.0
 200       */
 201  	public function take_action() {
 202          if ( ! current_user_can( 'edit_theme_options' ) ) {
 203              return;
 204          }
 205  
 206          if ( empty( $_POST ) ) {
 207              return;
 208          }
 209  
 210          $this->updated = true;
 211  
 212          if ( isset( $_POST['resetheader'] ) ) {
 213              check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
 214              $this->reset_header_image();
 215              return;
 216          }
 217  
 218          if ( isset( $_POST['removeheader'] ) ) {
 219              check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
 220              $this->remove_header_image();
 221              return;
 222          }
 223  
 224          if ( isset( $_POST['text-color'] ) && ! isset( $_POST['display-header-text'] ) ) {
 225              check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
 226              set_theme_mod( 'header_textcolor', 'blank' );
 227          } elseif ( isset( $_POST['text-color'] ) ) {
 228              check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
 229              $_POST['text-color'] = str_replace( '#', '', $_POST['text-color'] );
 230              $color               = preg_replace( '/[^0-9a-fA-F]/', '', $_POST['text-color'] );
 231              if ( strlen( $color ) == 6 || strlen( $color ) == 3 ) {
 232                  set_theme_mod( 'header_textcolor', $color );
 233              } elseif ( ! $color ) {
 234                  set_theme_mod( 'header_textcolor', 'blank' );
 235              }
 236          }
 237  
 238          if ( isset( $_POST['default-header'] ) ) {
 239              check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
 240              $this->set_header_image( $_POST['default-header'] );
 241              return;
 242          }
 243      }
 244  
 245      /**
 246       * Process the default headers
 247       *
 248       * @since 3.0.0
 249       *
 250       * @global array $_wp_default_headers
 251       */
 252  	public function process_default_headers() {
 253          global $_wp_default_headers;
 254  
 255          if ( ! isset( $_wp_default_headers ) ) {
 256              return;
 257          }
 258  
 259          if ( ! empty( $this->default_headers ) ) {
 260              return;
 261          }
 262  
 263          $this->default_headers    = $_wp_default_headers;
 264          $template_directory_uri   = get_template_directory_uri();
 265          $stylesheet_directory_uri = get_stylesheet_directory_uri();
 266          foreach ( array_keys( $this->default_headers ) as $header ) {
 267              $this->default_headers[ $header ]['url']           = sprintf( $this->default_headers[ $header ]['url'], $template_directory_uri, $stylesheet_directory_uri );
 268              $this->default_headers[ $header ]['thumbnail_url'] = sprintf( $this->default_headers[ $header ]['thumbnail_url'], $template_directory_uri, $stylesheet_directory_uri );
 269          }
 270      }
 271  
 272      /**
 273       * Display UI for selecting one of several default headers.
 274       *
 275       * Show the random image option if this theme has multiple header images.
 276       * Random image option is on by default if no header has been set.
 277       *
 278       * @since 3.0.0
 279       *
 280       * @param string $type The header type. One of 'default' (for the Uploaded Images control)
 281       *                     or 'uploaded' (for the Uploaded Images control).
 282       */
 283  	public function show_header_selector( $type = 'default' ) {
 284          if ( 'default' == $type ) {
 285              $headers = $this->default_headers;
 286          } else {
 287              $headers = get_uploaded_header_images();
 288              $type    = 'uploaded';
 289          }
 290  
 291          if ( 1 < count( $headers ) ) {
 292              echo '<div class="random-header">';
 293              echo '<label><input name="default-header" type="radio" value="random-' . $type . '-image"' . checked( is_random_header_image( $type ), true, false ) . ' />';
 294              _e( '<strong>Random:</strong> Show a different image on each page.' );
 295              echo '</label>';
 296              echo '</div>';
 297          }
 298  
 299          echo '<div class="available-headers">';
 300          foreach ( $headers as $header_key => $header ) {
 301              $header_thumbnail = $header['thumbnail_url'];
 302              $header_url       = $header['url'];
 303              $header_alt_text  = empty( $header['alt_text'] ) ? '' : $header['alt_text'];
 304              echo '<div class="default-header">';
 305              echo '<label><input name="default-header" type="radio" value="' . esc_attr( $header_key ) . '" ' . checked( $header_url, get_theme_mod( 'header_image' ), false ) . ' />';
 306              $width = '';
 307              if ( ! empty( $header['attachment_id'] ) ) {
 308                  $width = ' width="230"';
 309              }
 310              echo '<img src="' . set_url_scheme( $header_thumbnail ) . '" alt="' . esc_attr( $header_alt_text ) . '"' . $width . ' /></label>';
 311              echo '</div>';
 312          }
 313          echo '<div class="clear"></div></div>';
 314      }
 315  
 316      /**
 317       * Execute JavaScript depending on step.
 318       *
 319       * @since 2.1.0
 320       */
 321      public function js() {
 322          $step = $this->step();
 323          if ( ( 1 == $step || 3 == $step ) && current_theme_supports( 'custom-header', 'header-text' ) ) {
 324              $this->js_1();
 325          } elseif ( 2 == $step ) {
 326              $this->js_2();
 327          }
 328      }
 329  
 330      /**
 331       * Display JavaScript based on Step 1 and 3.
 332       *
 333       * @since 2.6.0
 334       */
 335  	public function js_1() {
 336          $default_color = '';
 337          if ( current_theme_supports( 'custom-header', 'default-text-color' ) ) {
 338              $default_color = get_theme_support( 'custom-header', 'default-text-color' );
 339              if ( $default_color && false === strpos( $default_color, '#' ) ) {
 340                  $default_color = '#' . $default_color;
 341              }
 342          }
 343          ?>
 344  <script type="text/javascript">
 345  (function($){
 346      var default_color = '<?php echo $default_color; ?>',
 347          header_text_fields;
 348  
 349  	function pickColor(color) {
 350          $('#name').css('color', color);
 351          $('#desc').css('color', color);
 352          $('#text-color').val(color);
 353      }
 354  
 355  	function toggle_text() {
 356          var checked = $('#display-header-text').prop('checked'),
 357              text_color;
 358          header_text_fields.toggle( checked );
 359          if ( ! checked )
 360              return;
 361          text_color = $('#text-color');
 362          if ( '' == text_color.val().replace('#', '') ) {
 363              text_color.val( default_color );
 364              pickColor( default_color );
 365          } else {
 366              pickColor( text_color.val() );
 367          }
 368      }
 369  
 370      $(document).ready(function() {
 371          var text_color = $('#text-color');
 372          header_text_fields = $('.displaying-header-text');
 373          text_color.wpColorPicker({
 374              change: function( event, ui ) {
 375                  pickColor( text_color.wpColorPicker('color') );
 376              },
 377              clear: function() {
 378                  pickColor( '' );
 379              }
 380          });
 381          $('#display-header-text').click( toggle_text );
 382          <?php if ( ! display_header_text() ) : ?>
 383          toggle_text();
 384          <?php endif; ?>
 385      });
 386  })(jQuery);
 387  </script>
 388          <?php
 389      }
 390  
 391      /**
 392       * Display JavaScript based on Step 2.
 393       *
 394       * @since 2.6.0
 395       */
 396  	public function js_2() {
 397  
 398          ?>
 399  <script type="text/javascript">
 400  	function onEndCrop( coords ) {
 401          jQuery( '#x1' ).val(coords.x);
 402          jQuery( '#y1' ).val(coords.y);
 403          jQuery( '#width' ).val(coords.w);
 404          jQuery( '#height' ).val(coords.h);
 405      }
 406  
 407      jQuery(document).ready(function() {
 408          var xinit = <?php echo absint( get_theme_support( 'custom-header', 'width' ) ); ?>;
 409          var yinit = <?php echo absint( get_theme_support( 'custom-header', 'height' ) ); ?>;
 410          var ratio = xinit / yinit;
 411          var ximg = jQuery('img#upload').width();
 412          var yimg = jQuery('img#upload').height();
 413  
 414          if ( yimg < yinit || ximg < xinit ) {
 415              if ( ximg / yimg > ratio ) {
 416                  yinit = yimg;
 417                  xinit = yinit * ratio;
 418              } else {
 419                  xinit = ximg;
 420                  yinit = xinit / ratio;
 421              }
 422          }
 423  
 424          jQuery('img#upload').imgAreaSelect({
 425              handles: true,
 426              keys: true,
 427              show: true,
 428              x1: 0,
 429              y1: 0,
 430              x2: xinit,
 431              y2: yinit,
 432              <?php
 433              if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
 434                  ?>
 435              aspectRatio: xinit + ':' + yinit,
 436                  <?php
 437              }
 438              if ( ! current_theme_supports( 'custom-header', 'flex-height' ) ) {
 439                  ?>
 440              maxHeight: <?php echo get_theme_support( 'custom-header', 'height' ); ?>,
 441                  <?php
 442              }
 443              if ( ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
 444                  ?>
 445              maxWidth: <?php echo get_theme_support( 'custom-header', 'width' ); ?>,
 446                  <?php
 447              }
 448              ?>
 449              onInit: function () {
 450                  jQuery('#width').val(xinit);
 451                  jQuery('#height').val(yinit);
 452              },
 453              onSelectChange: function(img, c) {
 454                  jQuery('#x1').val(c.x1);
 455                  jQuery('#y1').val(c.y1);
 456                  jQuery('#width').val(c.width);
 457                  jQuery('#height').val(c.height);
 458              }
 459          });
 460      });
 461  </script>
 462          <?php
 463      }
 464  
 465      /**
 466       * Display first step of custom header image page.
 467       *
 468       * @since 2.1.0
 469       */
 470  	public function step_1() {
 471          $this->process_default_headers();
 472          ?>
 473  
 474  <div class="wrap">
 475  <h1><?php _e( 'Custom Header' ); ?></h1>
 476  
 477          <?php if ( current_user_can( 'customize' ) ) { ?>
 478  <div class="notice notice-info hide-if-no-customize">
 479      <p>
 480              <?php
 481              printf(
 482                  /* translators: %s: URL to header image configuration in Customizer. */
 483                  __( 'You can now manage and live-preview Custom Header in the <a href="%s">Customizer</a>.' ),
 484                  admin_url( 'customize.php?autofocus[control]=header_image' )
 485              );
 486              ?>
 487      </p>
 488  </div>
 489          <?php } ?>
 490  
 491          <?php if ( ! empty( $this->updated ) ) { ?>
 492  <div id="message" class="updated">
 493      <p>
 494              <?php
 495              /* translators: %s: Home URL. */
 496              printf( __( 'Header updated. <a href="%s">Visit your site</a> to see how it looks.' ), home_url( '/' ) );
 497              ?>
 498      </p>
 499  </div>
 500          <?php } ?>
 501  
 502  <h2><?php _e( 'Header Image' ); ?></h2>
 503  
 504  <table class="form-table" role="presentation">
 505  <tbody>
 506  
 507          <?php if ( get_custom_header() || display_header_text() ) : ?>
 508  <tr>
 509  <th scope="row"><?php _e( 'Preview' ); ?></th>
 510  <td>
 511              <?php
 512              if ( $this->admin_image_div_callback ) {
 513                  call_user_func( $this->admin_image_div_callback );
 514              } else {
 515                  $custom_header = get_custom_header();
 516                  $header_image  = get_header_image();
 517  
 518                  if ( $header_image ) {
 519                      $header_image_style = 'background-image:url(' . esc_url( $header_image ) . ');';
 520                  } else {
 521                      $header_image_style = '';
 522                  }
 523  
 524                  if ( $custom_header->width ) {
 525                      $header_image_style .= 'max-width:' . $custom_header->width . 'px;';
 526                  }
 527                  if ( $custom_header->height ) {
 528                      $header_image_style .= 'height:' . $custom_header->height . 'px;';
 529                  }
 530                  ?>
 531      <div id="headimg" style="<?php echo $header_image_style; ?>">
 532                  <?php
 533                  if ( display_header_text() ) {
 534                      $style = ' style="color:#' . get_header_textcolor() . ';"';
 535                  } else {
 536                      $style = ' style="display:none;"';
 537                  }
 538                  ?>
 539          <h1><a id="name" class="displaying-header-text" <?php echo $style; ?> onclick="return false;" href="<?php bloginfo( 'url' ); ?>" tabindex="-1"><?php bloginfo( 'name' ); ?></a></h1>
 540          <div id="desc" class="displaying-header-text" <?php echo $style; ?>><?php bloginfo( 'description' ); ?></div>
 541      </div>
 542              <?php } ?>
 543  </td>
 544  </tr>
 545          <?php endif; ?>
 546  
 547          <?php if ( current_user_can( 'upload_files' ) && current_theme_supports( 'custom-header', 'uploads' ) ) : ?>
 548  <tr>
 549  <th scope="row"><?php _e( 'Select Image' ); ?></th>
 550  <td>
 551      <p><?php _e( 'You can select an image to be shown at the top of your site by uploading from your computer or choosing from your media library. After selecting an image you will be able to crop it.' ); ?><br />
 552              <?php
 553              if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
 554                  /* translators: 1: Image width in pixels, 2: Image height in pixels. */
 555                  printf( __( 'Images of exactly <strong>%1$d &times; %2$d pixels</strong> will be used as-is.' ) . '<br />', get_theme_support( 'custom-header', 'width' ), get_theme_support( 'custom-header', 'height' ) );
 556              } elseif ( current_theme_supports( 'custom-header', 'flex-height' ) ) {
 557                  if ( ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
 558                      printf(
 559                          /* translators: %s: Size in pixels. */
 560                          __( 'Images should be at least %s wide.' ) . ' ',
 561                          sprintf(
 562                              /* translators: %d: Custom header width. */
 563                              '<strong>' . __( '%d pixels' ) . '</strong>',
 564                              get_theme_support( 'custom-header', 'width' )
 565                          )
 566                      );
 567                  }
 568              } elseif ( current_theme_supports( 'custom-header', 'flex-width' ) ) {
 569                  if ( ! current_theme_supports( 'custom-header', 'flex-height' ) ) {
 570                      printf(
 571                          /* translators: %s: Size in pixels. */
 572                          __( 'Images should be at least %s tall.' ) . ' ',
 573                          sprintf(
 574                              /* translators: %d: Custom header height. */
 575                              '<strong>' . __( '%d pixels' ) . '</strong>',
 576                              get_theme_support( 'custom-header', 'height' )
 577                          )
 578                      );
 579                  }
 580              }
 581              if ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) {
 582                  if ( current_theme_supports( 'custom-header', 'width' ) ) {
 583                      printf(
 584                          /* translators: %s: Size in pixels. */
 585                          __( 'Suggested width is %s.' ) . ' ',
 586                          sprintf(
 587                              /* translators: %d: Custom header width. */
 588                              '<strong>' . __( '%d pixels' ) . '</strong>',
 589                              get_theme_support( 'custom-header', 'width' )
 590                          )
 591                      );
 592                  }
 593                  if ( current_theme_supports( 'custom-header', 'height' ) ) {
 594                      printf(
 595                          /* translators: %s: Size in pixels. */
 596                          __( 'Suggested height is %s.' ) . ' ',
 597                          sprintf(
 598                              /* translators: %d: Custom header height. */
 599                              '<strong>' . __( '%d pixels' ) . '</strong>',
 600                              get_theme_support( 'custom-header', 'height' )
 601                          )
 602                      );
 603                  }
 604              }
 605              ?>
 606      </p>
 607      <form enctype="multipart/form-data" id="upload-form" class="wp-upload-form" method="post" action="<?php echo esc_url( add_query_arg( 'step', 2 ) ); ?>">
 608      <p>
 609          <label for="upload"><?php _e( 'Choose an image from your computer:' ); ?></label><br />
 610          <input type="file" id="upload" name="import" />
 611          <input type="hidden" name="action" value="save" />
 612              <?php wp_nonce_field( 'custom-header-upload', '_wpnonce-custom-header-upload' ); ?>
 613              <?php submit_button( __( 'Upload' ), '', 'submit', false ); ?>
 614      </p>
 615              <?php
 616                  $modal_update_href = esc_url(
 617                      add_query_arg(
 618                          array(
 619                              'page' => 'custom-header',
 620                              'step' => 2,
 621                              '_wpnonce-custom-header-upload' => wp_create_nonce( 'custom-header-upload' ),
 622                          ),
 623                          admin_url( 'themes.php' )
 624                      )
 625                  );
 626              ?>
 627      <p>
 628          <label for="choose-from-library-link"><?php _e( 'Or choose an image from your media library:' ); ?></label><br />
 629          <button id="choose-from-library-link" class="button"
 630              data-update-link="<?php echo esc_attr( $modal_update_href ); ?>"
 631              data-choose="<?php esc_attr_e( 'Choose a Custom Header' ); ?>"
 632              data-update="<?php esc_attr_e( 'Set as header' ); ?>"><?php _e( 'Choose Image' ); ?></button>
 633      </p>
 634      </form>
 635  </td>
 636  </tr>
 637          <?php endif; ?>
 638  </tbody>
 639  </table>
 640  
 641  <form method="post" action="<?php echo esc_url( add_query_arg( 'step', 1 ) ); ?>">
 642          <?php submit_button( null, 'screen-reader-text', 'save-header-options', false ); ?>
 643  <table class="form-table" role="presentation">
 644  <tbody>
 645          <?php if ( get_uploaded_header_images() ) : ?>
 646  <tr>
 647  <th scope="row"><?php _e( 'Uploaded Images' ); ?></th>
 648  <td>
 649      <p><?php _e( 'You can choose one of your previously uploaded headers, or show a random one.' ); ?></p>
 650              <?php
 651              $this->show_header_selector( 'uploaded' );
 652              ?>
 653  </td>
 654  </tr>
 655              <?php
 656      endif;
 657          if ( ! empty( $this->default_headers ) ) :
 658              ?>
 659  <tr>
 660  <th scope="row"><?php _e( 'Default Images' ); ?></th>
 661  <td>
 662              <?php if ( current_theme_supports( 'custom-header', 'uploads' ) ) : ?>
 663      <p><?php _e( 'If you don&lsquo;t want to upload your own image, you can use one of these cool headers, or show a random one.' ); ?></p>
 664      <?php else : ?>
 665      <p><?php _e( 'You can use one of these cool headers or show a random one on each page.' ); ?></p>
 666      <?php endif; ?>
 667              <?php
 668              $this->show_header_selector( 'default' );
 669              ?>
 670  </td>
 671  </tr>
 672              <?php
 673      endif;
 674          if ( get_header_image() ) :
 675              ?>
 676  <tr>
 677  <th scope="row"><?php _e( 'Remove Image' ); ?></th>
 678  <td>
 679      <p><?php _e( 'This will remove the header image. You will not be able to restore any customizations.' ); ?></p>
 680              <?php submit_button( __( 'Remove Header Image' ), '', 'removeheader', false ); ?>
 681  </td>
 682  </tr>
 683              <?php
 684      endif;
 685  
 686          $default_image = sprintf( get_theme_support( 'custom-header', 'default-image' ), get_template_directory_uri(), get_stylesheet_directory_uri() );
 687          if ( $default_image && get_header_image() != $default_image ) :
 688              ?>
 689  <tr>
 690  <th scope="row"><?php _e( 'Reset Image' ); ?></th>
 691  <td>
 692      <p><?php _e( 'This will restore the original header image. You will not be able to restore any customizations.' ); ?></p>
 693              <?php submit_button( __( 'Restore Original Header Image' ), '', 'resetheader', false ); ?>
 694  </td>
 695  </tr>
 696      <?php endif; ?>
 697  </tbody>
 698  </table>
 699  
 700          <?php if ( current_theme_supports( 'custom-header', 'header-text' ) ) : ?>
 701  
 702  <h2><?php _e( 'Header Text' ); ?></h2>
 703  
 704  <table class="form-table" role="presentation">
 705  <tbody>
 706  <tr>
 707  <th scope="row"><?php _e( 'Header Text' ); ?></th>
 708  <td>
 709      <p>
 710      <label><input type="checkbox" name="display-header-text" id="display-header-text"<?php checked( display_header_text() ); ?> /> <?php _e( 'Show header text with your image.' ); ?></label>
 711      </p>
 712  </td>
 713  </tr>
 714  
 715  <tr class="displaying-header-text">
 716  <th scope="row"><?php _e( 'Text Color' ); ?></th>
 717  <td>
 718      <p>
 719              <?php
 720              $default_color = '';
 721              if ( current_theme_supports( 'custom-header', 'default-text-color' ) ) {
 722                  $default_color = get_theme_support( 'custom-header', 'default-text-color' );
 723                  if ( $default_color && false === strpos( $default_color, '#' ) ) {
 724                      $default_color = '#' . $default_color;
 725                  }
 726              }
 727  
 728              $default_color_attr = $default_color ? ' data-default-color="' . esc_attr( $default_color ) . '"' : '';
 729  
 730              $header_textcolor = display_header_text() ? get_header_textcolor() : get_theme_support( 'custom-header', 'default-text-color' );
 731              if ( $header_textcolor && false === strpos( $header_textcolor, '#' ) ) {
 732                  $header_textcolor = '#' . $header_textcolor;
 733              }
 734  
 735              echo '<input type="text" name="text-color" id="text-color" value="' . esc_attr( $header_textcolor ) . '"' . $default_color_attr . ' />';
 736              if ( $default_color ) {
 737                  /* translators: %s: Default text color. */
 738                  echo ' <span class="description hide-if-js">' . sprintf( _x( 'Default: %s', 'color' ), esc_html( $default_color ) ) . '</span>';
 739              }
 740              ?>
 741      </p>
 742  </td>
 743  </tr>
 744  </tbody>
 745  </table>
 746              <?php
 747  endif;
 748  
 749          /**
 750           * Fires just before the submit button in the custom header options form.
 751           *
 752           * @since 3.1.0
 753           */
 754          do_action( 'custom_header_options' );
 755  
 756          wp_nonce_field( 'custom-header-options', '_wpnonce-custom-header-options' );
 757          ?>
 758  
 759          <?php submit_button( null, 'primary', 'save-header-options' ); ?>
 760  </form>
 761  </div>
 762  
 763          <?php
 764      }
 765  
 766      /**
 767       * Display second step of custom header image page.
 768       *
 769       * @since 2.1.0
 770       */
 771  	public function step_2() {
 772          check_admin_referer( 'custom-header-upload', '_wpnonce-custom-header-upload' );
 773          if ( ! current_theme_supports( 'custom-header', 'uploads' ) ) {
 774              wp_die(
 775                  '<h1>' . __( 'Something went wrong.' ) . '</h1>' .
 776                  '<p>' . __( 'The current theme does not support uploading a custom header image.' ) . '</p>',
 777                  403
 778              );
 779          }
 780  
 781          if ( empty( $_POST ) && isset( $_GET['file'] ) ) {
 782              $attachment_id = absint( $_GET['file'] );
 783              $file          = get_attached_file( $attachment_id, true );
 784              $url           = wp_get_attachment_image_src( $attachment_id, 'full' );
 785              $url           = $url[0];
 786          } elseif ( isset( $_POST ) ) {
 787              $data          = $this->step_2_manage_upload();
 788              $attachment_id = $data['attachment_id'];
 789              $file          = $data['file'];
 790              $url           = $data['url'];
 791          }
 792  
 793          if ( file_exists( $file ) ) {
 794              list( $width, $height, $type, $attr ) = @getimagesize( $file );
 795          } else {
 796              $data   = wp_get_attachment_metadata( $attachment_id );
 797              $height = isset( $data['height'] ) ? $data['height'] : 0;
 798              $width  = isset( $data['width'] ) ? $data['width'] : 0;
 799              unset( $data );
 800          }
 801  
 802          $max_width = 0;
 803          // For flex, limit size of image displayed to 1500px unless theme says otherwise
 804          if ( current_theme_supports( 'custom-header', 'flex-width' ) ) {
 805              $max_width = 1500;
 806          }
 807  
 808          if ( current_theme_supports( 'custom-header', 'max-width' ) ) {
 809              $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) );
 810          }
 811          $max_width = max( $max_width, get_theme_support( 'custom-header', 'width' ) );
 812  
 813          // If flexible height isn't supported and the image is the exact right size
 814          if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' )
 815              && $width == get_theme_support( 'custom-header', 'width' ) && $height == get_theme_support( 'custom-header', 'height' ) ) {
 816              // Add the meta-data
 817              if ( file_exists( $file ) ) {
 818                  wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
 819              }
 820  
 821              $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
 822  
 823              /**
 824               * Fires after the header image is set or an error is returned.
 825               *
 826               * @since 2.1.0
 827               *
 828               * @param string $file          Path to the file.
 829               * @param int    $attachment_id Attachment ID.
 830               */
 831              do_action( 'wp_create_file_in_uploads', $file, $attachment_id ); // For replication
 832  
 833              return $this->finished();
 834          } elseif ( $width > $max_width ) {
 835              $oitar = $width / $max_width;
 836              $image = wp_crop_image( $attachment_id, 0, 0, $width, $height, $max_width, $height / $oitar, false, str_replace( wp_basename( $file ), 'midsize-' . wp_basename( $file ), $file ) );
 837              if ( ! $image || is_wp_error( $image ) ) {
 838                  wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) );
 839              }
 840  
 841              /** This filter is documented in wp-admin/includes/class-custom-image-header.php */
 842              $image = apply_filters( 'wp_create_file_in_uploads', $image, $attachment_id ); // For replication
 843  
 844              $url    = str_replace( wp_basename( $url ), wp_basename( $image ), $url );
 845              $width  = $width / $oitar;
 846              $height = $height / $oitar;
 847          } else {
 848              $oitar = 1;
 849          }
 850          ?>
 851  
 852  <div class="wrap">
 853  <h1><?php _e( 'Crop Header Image' ); ?></h1>
 854  
 855  <form method="post" action="<?php echo esc_url( add_query_arg( 'step', 3 ) ); ?>">
 856      <p class="hide-if-no-js"><?php _e( 'Choose the part of the image you want to use as your header.' ); ?></p>
 857      <p class="hide-if-js"><strong><?php _e( 'You need JavaScript to choose a part of the image.' ); ?></strong></p>
 858  
 859      <div id="crop_image" style="position: relative">
 860          <img src="<?php echo esc_url( $url ); ?>" id="upload" width="<?php echo $width; ?>" height="<?php echo $height; ?>" alt="" />
 861      </div>
 862  
 863      <input type="hidden" name="x1" id="x1" value="0"/>
 864      <input type="hidden" name="y1" id="y1" value="0"/>
 865      <input type="hidden" name="width" id="width" value="<?php echo esc_attr( $width ); ?>"/>
 866      <input type="hidden" name="height" id="height" value="<?php echo esc_attr( $height ); ?>"/>
 867      <input type="hidden" name="attachment_id" id="attachment_id" value="<?php echo esc_attr( $attachment_id ); ?>" />
 868      <input type="hidden" name="oitar" id="oitar" value="<?php echo esc_attr( $oitar ); ?>" />
 869          <?php if ( empty( $_POST ) && isset( $_GET['file'] ) ) { ?>
 870      <input type="hidden" name="create-new-attachment" value="true" />
 871      <?php } ?>
 872          <?php wp_nonce_field( 'custom-header-crop-image' ); ?>
 873  
 874      <p class="submit">
 875          <?php submit_button( __( 'Crop and Publish' ), 'primary', 'submit', false ); ?>
 876          <?php
 877          if ( isset( $oitar ) && 1 == $oitar && ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) ) {
 878              submit_button( __( 'Skip Cropping, Publish Image as Is' ), '', 'skip-cropping', false );
 879          }
 880          ?>
 881      </p>
 882  </form>
 883  </div>
 884          <?php
 885      }
 886  
 887  
 888      /**
 889       * Upload the file to be cropped in the second step.
 890       *
 891       * @since 3.4.0
 892       */
 893  	public function step_2_manage_upload() {
 894          $overrides = array( 'test_form' => false );
 895  
 896          $uploaded_file = $_FILES['import'];
 897          $wp_filetype   = wp_check_filetype_and_ext( $uploaded_file['tmp_name'], $uploaded_file['name'] );
 898          if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) ) {
 899              wp_die( __( 'The uploaded file is not a valid image. Please try again.' ) );
 900          }
 901  
 902          $file = wp_handle_upload( $uploaded_file, $overrides );
 903  
 904          if ( isset( $file['error'] ) ) {
 905              wp_die( $file['error'], __( 'Image Upload Error' ) );
 906          }
 907  
 908          $url      = $file['url'];
 909          $type     = $file['type'];
 910          $file     = $file['file'];
 911          $filename = wp_basename( $file );
 912  
 913          // Construct the object array
 914          $object = array(
 915              'post_title'     => $filename,
 916              'post_content'   => $url,
 917              'post_mime_type' => $type,
 918              'guid'           => $url,
 919              'context'        => 'custom-header',
 920          );
 921  
 922          // Save the data
 923          $attachment_id = wp_insert_attachment( $object, $file );
 924          return compact( 'attachment_id', 'file', 'filename', 'url', 'type' );
 925      }
 926  
 927      /**
 928       * Display third step of custom header image page.
 929       *
 930       * @since 2.1.0
 931       * @since 4.4.0 Switched to using wp_get_attachment_url() instead of the guid
 932       *              for retrieving the header image URL.
 933       */
 934  	public function step_3() {
 935          check_admin_referer( 'custom-header-crop-image' );
 936  
 937          if ( ! current_theme_supports( 'custom-header', 'uploads' ) ) {
 938              wp_die(
 939                  '<h1>' . __( 'Something went wrong.' ) . '</h1>' .
 940                  '<p>' . __( 'The current theme does not support uploading a custom header image.' ) . '</p>',
 941                  403
 942              );
 943          }
 944  
 945          if ( ! empty( $_POST['skip-cropping'] ) && ! ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) ) {
 946              wp_die(
 947                  '<h1>' . __( 'Something went wrong.' ) . '</h1>' .
 948                  '<p>' . __( 'The current theme does not support a flexible sized header image.' ) . '</p>',
 949                  403
 950              );
 951          }
 952  
 953          if ( $_POST['oitar'] > 1 ) {
 954              $_POST['x1']     = $_POST['x1'] * $_POST['oitar'];
 955              $_POST['y1']     = $_POST['y1'] * $_POST['oitar'];
 956              $_POST['width']  = $_POST['width'] * $_POST['oitar'];
 957              $_POST['height'] = $_POST['height'] * $_POST['oitar'];
 958          }
 959  
 960          $attachment_id = absint( $_POST['attachment_id'] );
 961          $original      = get_attached_file( $attachment_id );
 962  
 963          $dimensions = $this->get_header_dimensions(
 964              array(
 965                  'height' => $_POST['height'],
 966                  'width'  => $_POST['width'],
 967              )
 968          );
 969          $height     = $dimensions['dst_height'];
 970          $width      = $dimensions['dst_width'];
 971  
 972          if ( empty( $_POST['skip-cropping'] ) ) {
 973              $cropped = wp_crop_image( $attachment_id, (int) $_POST['x1'], (int) $_POST['y1'], (int) $_POST['width'], (int) $_POST['height'], $width, $height );
 974          } elseif ( ! empty( $_POST['create-new-attachment'] ) ) {
 975              $cropped = _copy_image_file( $attachment_id );
 976          } else {
 977              $cropped = get_attached_file( $attachment_id );
 978          }
 979  
 980          if ( ! $cropped || is_wp_error( $cropped ) ) {
 981              wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) );
 982          }
 983  
 984          /** This filter is documented in wp-admin/includes/class-custom-image-header.php */
 985          $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication
 986  
 987          $object = $this->create_attachment_object( $cropped, $attachment_id );
 988  
 989          if ( ! empty( $_POST['create-new-attachment'] ) ) {
 990              unset( $object['ID'] );
 991          }
 992  
 993          // Update the attachment
 994          $attachment_id = $this->insert_attachment( $object, $cropped );
 995  
 996          $url = wp_get_attachment_url( $attachment_id );
 997          $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
 998  
 999          // Cleanup.
1000          $medium = str_replace( wp_basename( $original ), 'midsize-' . wp_basename( $original ), $original );
1001          if ( file_exists( $medium ) ) {
1002              wp_delete_file( $medium );
1003          }
1004  
1005          if ( empty( $_POST['create-new-attachment'] ) && empty( $_POST['skip-cropping'] ) ) {
1006              wp_delete_file( $original );
1007          }
1008  
1009          return $this->finished();
1010      }
1011  
1012      /**
1013       * Display last step of custom header image page.
1014       *
1015       * @since 2.1.0
1016       */
1017  	public function finished() {
1018          $this->updated = true;
1019          $this->step_1();
1020      }
1021  
1022      /**
1023       * Display the page based on the current step.
1024       *
1025       * @since 2.1.0
1026       */
1027  	public function admin_page() {
1028          if ( ! current_user_can( 'edit_theme_options' ) ) {
1029              wp_die( __( 'Sorry, you are not allowed to customize headers.' ) );
1030          }
1031          $step = $this->step();
1032          if ( 2 == $step ) {
1033              $this->step_2();
1034          } elseif ( 3 == $step ) {
1035              $this->step_3();
1036          } else {
1037              $this->step_1();
1038          }
1039      }
1040  
1041      /**
1042       * Unused since 3.5.0.
1043       *
1044       * @since 3.4.0
1045       *
1046       * @param array $form_fields
1047       * @return array $form_fields
1048       */
1049  	public function attachment_fields_to_edit( $form_fields ) {
1050          return $form_fields;
1051      }
1052  
1053      /**
1054       * Unused since 3.5.0.
1055       *
1056       * @since 3.4.0
1057       *
1058       * @param array $tabs
1059       * @return array $tabs
1060       */
1061  	public function filter_upload_tabs( $tabs ) {
1062          return $tabs;
1063      }
1064  
1065      /**
1066       * Choose a header image, selected from existing uploaded and default headers,
1067       * or provide an array of uploaded header data (either new, or from media library).
1068       *
1069       * @since 3.4.0
1070       *
1071       * @param mixed $choice Which header image to select. Allows for values of 'random-default-image',
1072       *  for randomly cycling among the default images; 'random-uploaded-image', for randomly cycling
1073       *  among the uploaded images; the key of a default image registered for that theme; and
1074       *  the key of an image uploaded for that theme (the attachment ID of the image).
1075       *  Or an array of arguments: attachment_id, url, width, height. All are required.
1076       */
1077  	final public function set_header_image( $choice ) {
1078          if ( is_array( $choice ) || is_object( $choice ) ) {
1079              $choice = (array) $choice;
1080              if ( ! isset( $choice['attachment_id'] ) || ! isset( $choice['url'] ) ) {
1081                  return;
1082              }
1083  
1084              $choice['url'] = esc_url_raw( $choice['url'] );
1085  
1086              $header_image_data = (object) array(
1087                  'attachment_id' => $choice['attachment_id'],
1088                  'url'           => $choice['url'],
1089                  'thumbnail_url' => $choice['url'],
1090                  'height'        => $choice['height'],
1091                  'width'         => $choice['width'],
1092              );
1093  
1094              update_post_meta( $choice['attachment_id'], '_wp_attachment_is_custom_header', get_stylesheet() );
1095              set_theme_mod( 'header_image', $choice['url'] );
1096              set_theme_mod( 'header_image_data', $header_image_data );
1097              return;
1098          }
1099  
1100          if ( in_array( $choice, array( 'remove-header', 'random-default-image', 'random-uploaded-image' ) ) ) {
1101              set_theme_mod( 'header_image', $choice );
1102              remove_theme_mod( 'header_image_data' );
1103              return;
1104          }
1105  
1106          $uploaded = get_uploaded_header_images();
1107          if ( $uploaded && isset( $uploaded[ $choice ] ) ) {
1108              $header_image_data = $uploaded[ $choice ];
1109  
1110          } else {
1111              $this->process_default_headers();
1112              if ( isset( $this->default_headers[ $choice ] ) ) {
1113                  $header_image_data = $this->default_headers[ $choice ];
1114              } else {
1115                  return;
1116              }
1117          }
1118  
1119          set_theme_mod( 'header_image', esc_url_raw( $header_image_data['url'] ) );
1120          set_theme_mod( 'header_image_data', $header_image_data );
1121      }
1122  
1123      /**
1124       * Remove a header image.
1125       *
1126       * @since 3.4.0
1127       */
1128  	final public function remove_header_image() {
1129          $this->set_header_image( 'remove-header' );
1130      }
1131  
1132      /**
1133       * Reset a header image to the default image for the theme.
1134       *
1135       * This method does not do anything if the theme does not have a default header image.
1136       *
1137       * @since 3.4.0
1138       */
1139  	final public function reset_header_image() {
1140          $this->process_default_headers();
1141          $default = get_theme_support( 'custom-header', 'default-image' );
1142  
1143          if ( ! $default ) {
1144              $this->remove_header_image();
1145              return;
1146          }
1147          $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
1148  
1149          $default_data = array();
1150          foreach ( $this->default_headers as $header => $details ) {
1151              if ( $details['url'] == $default ) {
1152                  $default_data = $details;
1153                  break;
1154              }
1155          }
1156  
1157          set_theme_mod( 'header_image', $default );
1158          set_theme_mod( 'header_image_data', (object) $default_data );
1159      }
1160  
1161      /**
1162       * Calculate width and height based on what the currently selected theme supports.
1163       *
1164       * @since 3.9.0
1165       *
1166       * @param array $dimensions
1167       * @return array dst_height and dst_width of header image.
1168       */
1169  	final public function get_header_dimensions( $dimensions ) {
1170          $max_width       = 0;
1171          $width           = absint( $dimensions['width'] );
1172          $height          = absint( $dimensions['height'] );
1173          $theme_height    = get_theme_support( 'custom-header', 'height' );
1174          $theme_width     = get_theme_support( 'custom-header', 'width' );
1175          $has_flex_width  = current_theme_supports( 'custom-header', 'flex-width' );
1176          $has_flex_height = current_theme_supports( 'custom-header', 'flex-height' );
1177          $has_max_width   = current_theme_supports( 'custom-header', 'max-width' );
1178          $dst             = array(
1179              'dst_height' => null,
1180              'dst_width'  => null,
1181          );
1182  
1183          // For flex, limit size of image displayed to 1500px unless theme says otherwise
1184          if ( $has_flex_width ) {
1185              $max_width = 1500;
1186          }
1187  
1188          if ( $has_max_width ) {
1189              $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) );
1190          }
1191          $max_width = max( $max_width, $theme_width );
1192  
1193          if ( $has_flex_height && ( ! $has_flex_width || $width > $max_width ) ) {
1194              $dst['dst_height'] = absint( $height * ( $max_width / $width ) );
1195          } elseif ( $has_flex_height && $has_flex_width ) {
1196              $dst['dst_height'] = $height;
1197          } else {
1198              $dst['dst_height'] = $theme_height;
1199          }
1200  
1201          if ( $has_flex_width && ( ! $has_flex_height || $width > $max_width ) ) {
1202              $dst['dst_width'] = absint( $width * ( $max_width / $width ) );
1203          } elseif ( $has_flex_width && $has_flex_height ) {
1204              $dst['dst_width'] = $width;
1205          } else {
1206              $dst['dst_width'] = $theme_width;
1207          }
1208  
1209          return $dst;
1210      }
1211  
1212      /**
1213       * Create an attachment 'object'.
1214       *
1215       * @since 3.9.0
1216       *
1217       * @param string $cropped              Cropped image URL.
1218       * @param int    $parent_attachment_id Attachment ID of parent image.
1219       * @return array Attachment object.
1220       */
1221  	final public function create_attachment_object( $cropped, $parent_attachment_id ) {
1222          $parent     = get_post( $parent_attachment_id );
1223          $parent_url = wp_get_attachment_url( $parent->ID );
1224          $url        = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url );
1225  
1226          $size       = @getimagesize( $cropped );
1227          $image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
1228  
1229          $object = array(
1230              'ID'             => $parent_attachment_id,
1231              'post_title'     => wp_basename( $cropped ),
1232              'post_mime_type' => $image_type,
1233              'guid'           => $url,
1234              'context'        => 'custom-header',
1235              'post_parent'    => $parent_attachment_id,
1236          );
1237  
1238          return $object;
1239      }
1240  
1241      /**
1242       * Insert an attachment and its metadata.
1243       *
1244       * @since 3.9.0
1245       *
1246       * @param array  $object  Attachment object.
1247       * @param string $cropped Cropped image URL.
1248       * @return int Attachment ID.
1249       */
1250  	final public function insert_attachment( $object, $cropped ) {
1251          $parent_id = isset( $object['post_parent'] ) ? $object['post_parent'] : null;
1252          unset( $object['post_parent'] );
1253  
1254          $attachment_id = wp_insert_attachment( $object, $cropped );
1255          $metadata      = wp_generate_attachment_metadata( $attachment_id, $cropped );
1256  
1257          // If this is a crop, save the original attachment ID as metadata.
1258          if ( $parent_id ) {
1259              $metadata['attachment_parent'] = $parent_id;
1260          }
1261  
1262          /**
1263           * Filters the header image attachment metadata.
1264           *
1265           * @since 3.9.0
1266           *
1267           * @see wp_generate_attachment_metadata()
1268           *
1269           * @param array $metadata Attachment metadata.
1270           */
1271          $metadata = apply_filters( 'wp_header_image_attachment_metadata', $metadata );
1272  
1273          wp_update_attachment_metadata( $attachment_id, $metadata );
1274  
1275          return $attachment_id;
1276      }
1277  
1278      /**
1279       * Gets attachment uploaded by Media Manager, crops it, then saves it as a
1280       * new object. Returns JSON-encoded object details.
1281       *
1282       * @since 3.9.0
1283       */
1284  	public function ajax_header_crop() {
1285          check_ajax_referer( 'image_editor-' . $_POST['id'], 'nonce' );
1286  
1287          if ( ! current_user_can( 'edit_theme_options' ) ) {
1288              wp_send_json_error();
1289          }
1290  
1291          if ( ! current_theme_supports( 'custom-header', 'uploads' ) ) {
1292              wp_send_json_error();
1293          }
1294  
1295          $crop_details = $_POST['cropDetails'];
1296  
1297          $dimensions = $this->get_header_dimensions(
1298              array(
1299                  'height' => $crop_details['height'],
1300                  'width'  => $crop_details['width'],
1301              )
1302          );
1303  
1304          $attachment_id = absint( $_POST['id'] );
1305  
1306          $cropped = wp_crop_image(
1307              $attachment_id,
1308              (int) $crop_details['x1'],
1309              (int) $crop_details['y1'],
1310              (int) $crop_details['width'],
1311              (int) $crop_details['height'],
1312              (int) $dimensions['dst_width'],
1313              (int) $dimensions['dst_height']
1314          );
1315  
1316          if ( ! $cropped || is_wp_error( $cropped ) ) {
1317              wp_send_json_error( array( 'message' => __( 'Image could not be processed. Please go back and try again.' ) ) );
1318          }
1319  
1320          /** This filter is documented in wp-admin/includes/class-custom-image-header.php */
1321          $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication
1322  
1323          $object = $this->create_attachment_object( $cropped, $attachment_id );
1324  
1325          $previous = $this->get_previous_crop( $object );
1326  
1327          if ( $previous ) {
1328              $object['ID'] = $previous;
1329          } else {
1330              unset( $object['ID'] );
1331          }
1332  
1333          $new_attachment_id = $this->insert_attachment( $object, $cropped );
1334  
1335          $object['attachment_id'] = $new_attachment_id;
1336          $object['url']           = wp_get_attachment_url( $new_attachment_id );
1337  
1338          $object['width']  = $dimensions['dst_width'];
1339          $object['height'] = $dimensions['dst_height'];
1340  
1341          wp_send_json_success( $object );
1342      }
1343  
1344      /**
1345       * Given an attachment ID for a header image, updates its "last used"
1346       * timestamp to now.
1347       *
1348       * Triggered when the user tries adds a new header image from the
1349       * Media Manager, even if s/he doesn't save that change.
1350       *
1351       * @since 3.9.0
1352       */
1353  	public function ajax_header_add() {
1354          check_ajax_referer( 'header-add', 'nonce' );
1355  
1356          if ( ! current_user_can( 'edit_theme_options' ) ) {
1357              wp_send_json_error();
1358          }
1359  
1360          $attachment_id = absint( $_POST['attachment_id'] );
1361          if ( $attachment_id < 1 ) {
1362              wp_send_json_error();
1363          }
1364  
1365          $key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
1366          update_post_meta( $attachment_id, $key, time() );
1367          update_post_meta( $attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() );
1368  
1369          wp_send_json_success();
1370      }
1371  
1372      /**
1373       * Given an attachment ID for a header image, unsets it as a user-uploaded
1374       * header image for the current theme.
1375       *
1376       * Triggered when the user clicks the overlay "X" button next to each image
1377       * choice in the Customizer's Header tool.
1378       *
1379       * @since 3.9.0
1380       */
1381  	public function ajax_header_remove() {
1382          check_ajax_referer( 'header-remove', 'nonce' );
1383  
1384          if ( ! current_user_can( 'edit_theme_options' ) ) {
1385              wp_send_json_error();
1386          }
1387  
1388          $attachment_id = absint( $_POST['attachment_id'] );
1389          if ( $attachment_id < 1 ) {
1390              wp_send_json_error();
1391          }
1392  
1393          $key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
1394          delete_post_meta( $attachment_id, $key );
1395          delete_post_meta( $attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() );
1396  
1397          wp_send_json_success();
1398      }
1399  
1400      /**
1401       * Updates the last-used postmeta on a header image attachment after saving a new header image via the Customizer.
1402       *
1403       * @since 3.9.0
1404       *
1405       * @param WP_Customize_Manager $wp_customize Customize manager.
1406       */
1407  	public function customize_set_last_used( $wp_customize ) {
1408  
1409          $header_image_data_setting = $wp_customize->get_setting( 'header_image_data' );
1410          if ( ! $header_image_data_setting ) {
1411              return;
1412          }
1413          $data = $header_image_data_setting->post_value();
1414  
1415          if ( ! isset( $data['attachment_id'] ) ) {
1416              return;
1417          }
1418  
1419          $attachment_id = $data['attachment_id'];
1420          $key           = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
1421          update_post_meta( $attachment_id, $key, time() );
1422      }
1423  
1424      /**
1425       * Gets the details of default header images if defined.
1426       *
1427       * @since 3.9.0
1428       *
1429       * @return array Default header images.
1430       */
1431  	public function get_default_header_images() {
1432          $this->process_default_headers();
1433  
1434          // Get the default image if there is one.
1435          $default = get_theme_support( 'custom-header', 'default-image' );
1436  
1437          if ( ! $default ) { // If not,
1438              return $this->default_headers; // easy peasy.
1439          }
1440  
1441          $default             = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
1442          $already_has_default = false;
1443  
1444          foreach ( $this->default_headers as $k => $h ) {
1445              if ( $h['url'] === $default ) {
1446                  $already_has_default = true;
1447                  break;
1448              }
1449          }
1450  
1451          if ( $already_has_default ) {
1452              return $this->default_headers;
1453          }
1454  
1455          // If the one true image isn't included in the default set, prepend it.
1456          $header_images            = array();
1457          $header_images['default'] = array(
1458              'url'           => $default,
1459              'thumbnail_url' => $default,
1460              'description'   => 'Default',
1461          );
1462  
1463          // The rest of the set comes after.
1464          return array_merge( $header_images, $this->default_headers );
1465      }
1466  
1467      /**
1468       * Gets the previously uploaded header images.
1469       *
1470       * @since 3.9.0
1471       *
1472       * @return array Uploaded header images.
1473       */
1474  	public function get_uploaded_header_images() {
1475          $header_images = get_uploaded_header_images();
1476          $timestamp_key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
1477          $alt_text_key  = '_wp_attachment_image_alt';
1478  
1479          foreach ( $header_images as &$header_image ) {
1480              $header_meta               = get_post_meta( $header_image['attachment_id'] );
1481              $header_image['timestamp'] = isset( $header_meta[ $timestamp_key ] ) ? $header_meta[ $timestamp_key ] : '';
1482              $header_image['alt_text']  = isset( $header_meta[ $alt_text_key ] ) ? $header_meta[ $alt_text_key ] : '';
1483          }
1484  
1485          return $header_images;
1486      }
1487  
1488      /**
1489       * Get the ID of a previous crop from the same base image.
1490       *
1491       * @since 4.9.0
1492       *
1493       * @param  array $object A crop attachment object.
1494       * @return int|false An attachment ID if one exists. False if none.
1495       */
1496  	public function get_previous_crop( $object ) {
1497          $header_images = $this->get_uploaded_header_images();
1498  
1499          // Bail early if there are no header images.
1500          if ( empty( $header_images ) ) {
1501              return false;
1502          }
1503  
1504          $previous = false;
1505  
1506          foreach ( $header_images as $image ) {
1507              if ( $image['attachment_parent'] === $object['post_parent'] ) {
1508                  $previous = $image['attachment_id'];
1509                  break;
1510              }
1511          }
1512  
1513          return $previous;
1514      }
1515  }


Generated: Sat Nov 23 20:47:33 2019 Cross-referenced by PHPXref 0.7