Make WordPress Core

Ticket #16434: 16434.2.diff

File 16434.2.diff, 21.1 KB (added by jorbin, 13 years ago)

remove ico library, clean things up a bit, add in nonces

  • wp-includes/functions.php

     
    17731773                'png' => 'image/png',
    17741774                'bmp' => 'image/bmp',
    17751775                'tif|tiff' => 'image/tiff',
    1776                 'ico' => 'image/x-icon',
     1776                'ico' => 'image/vnd.microsoft.icon',
    17771777                'asf|asx|wax|wmv|wmx' => 'video/asf',
    17781778                'avi' => 'video/avi',
    17791779                'divx' => 'video/divx',
  • wp-includes/general-template.php

     
    15871587}
    15881588
    15891589/**
     1590 * Convenience function that echoes the HTML for the site's favicon icon.
     1591 * By default, automatically included in the header via the 'wp_head' action, which can be removed by themes if a custom favicon is desired.
     1592 *
     1593 * @uses generate_site_favicon_html() to do the actual heavy lifting
     1594 */
     1595function site_favicon(){
     1596        echo generate_site_favicon_html();
     1597}
     1598add_action( 'wp_head', 'site_favicon' );
     1599add_action( 'admin_head', 'site_favicon' );
     1600
     1601/**
     1602 * Return the HTML for the site's favicon icon, if such has been defined.
     1603 *
     1604 * @uses get_site_favicon_uri();
     1605 *
     1606 * Includes the conditional tag wrapper for an IE (.ico) version.
     1607 */
     1608function generate_site_favicon_html() {
     1609        $favicon_uri = get_site_favicon_uri();
     1610
     1611        $content = "";
     1612        if (! is_wp_error( $favicon_uri ) ){
     1613
     1614                $content .= <<<FAVICON_HTML
     1615<!--Favicon (via 'wp_head' action) -->
     1616<link href="{$favicon_uri}" rel="icon" type="image/png" />
     1617FAVICON_HTML;
     1618    }
     1619        return $content;
     1620}
     1621
     1622/**
     1623 * Get the attachment post object associated with the current site favicon, based on the 'sitefavicon' option
     1624 *
     1625 * @param string $format Default 'png'. Format of the file we're looking for
     1626 * @return object If found, returns the post object; if not, a WP_Error object
     1627 */
     1628function get_site_favicon_attachment( $format = 'png' ){
     1629        $favicon_basename = get_option ( 'sitefavicon' );
     1630       
     1631        if ( ! empty( $favicon_basename ) ) {
     1632                $favicon_fullname = $favicon_basename . '-' . $format;
     1633               
     1634                $posts = get_posts( array( 'name' => $favicon_fullname, 'post_type' => 'attachment' ) );
     1635                if ( $posts[0] ){
     1636                        return $posts[0];
     1637                } else {
     1638                        return new WP_Error( 'attachment_missing', __( "No attachment for '$favicon_fullname' was found." ) );
     1639                }
     1640        } else {
     1641                return new WP_Error( 'not_defined', __( "No favicon file provided." ) );
     1642        }
     1643}
     1644
     1645/**
     1646 * Returns the URI for the site's favicon based on the option set in  Admin > Settings > General.
     1647 *
     1648 * @param string $format png|ico default 'png'. Use 'ico' for serving up an IE-compatible ICO file
     1649 * @return string fully qualified URI
     1650 */
     1651function get_site_favicon_uri( $format = 'png' ){
     1652        /** @TODO provide error checking for validity of $format and $size */
     1653        $favicon_attachment = get_site_favicon_attachment( $format );
     1654       
     1655        /** @TODO provide the ability to define a 'default' favicon that would be distributed with fresh WP installations */
     1656        if ( ! is_wp_error( $favicon_attachment ) ) {
     1657                return wp_get_attachment_url( $favicon_attachment->ID );
     1658        }
     1659       
     1660        // We get here because of an error condition
     1661        /** @TODO default to the theme's favicon **/
     1662        // ATM do nothing (so URI is blank, rather than a WP_Error)
     1663}
     1664
     1665/**
     1666 * Gets the path to the favicon file, or returns a WP_Error
     1667 * @param string $format Default 'png'
     1668 * @return mixed File string or WP_Error object
     1669 */
     1670function get_site_favicon_file( $format = 'png' ){
     1671        $favicon_attachment = get_site_favicon_attachment( $format );
     1672       
     1673        /** @TODO provide the ability to define a 'default' favicon that would be distributed with fresh WP installations */
     1674        if ( ! is_wp_error( $favicon_attachment ) ) {
     1675                return get_attached_file( $favicon_attachment->ID );
     1676        } else {
     1677                return $favicon_attachment; // returns the WP_Error object
     1678        }
     1679}
     1680
     1681/**
     1682 * Returns true or false depending on whether a custom favicon has been defined in Admin
     1683 * @return boolean
     1684 */
     1685function has_custom_favicon(){
     1686        $favicon_basename = get_option ( 'sitefavicon' );
     1687        /** @TODO more robust checking: don't just check that the option has been set: check that the file exists */
     1688        return ( ! empty( $favicon_basename ) );
     1689}
     1690
     1691/**
     1692 * Returns an HTML <img> tag populated with the site favicon, in the format specified (usually PNG)
     1693 * @param string $format Default 'png'. Valid values are 'png', 'bmp' (note 'ico' is NOT valid)
     1694 * @return mixed Returns HTML <img> tag or WP_Error if invalid format given. Returns nothing if the file is missing.
     1695 */
     1696function get_favicon_img( $format = 'png' ){
     1697        if (in_array( strtolower( $format ), array( 'png', 'bmp' ) ) ){
     1698                // Does the file actually exist?
     1699                $file = get_site_favicon_file( $format );
     1700                if (! is_wp_error( $file ) && file_exists( $file ) ){
     1701                        $src = get_site_favicon_uri( $format );
     1702                        if (!is_wp_error( $src ) ){
     1703                                return '<img src="' . $src . '" alt="' . _x( 'Site favicon thumbnail', 'Thumbnail image accessibility text' ) .'" />';
     1704                        }
     1705                }
     1706        } else {
     1707                return new WP_Error( 'invalid_file_format', __( 'Invalid file format. Valid formats are "png", "bmp".' ) );
     1708        }
     1709}
     1710
     1711/**
    15901712 * Display the links to the general feeds.
    15911713 *
    15921714 * @since 2.8.0
  • wp-includes/script-loader.php

     
    8888
    8989        $scripts->add( 'wp-fullscreen', "/wp-admin/js/wp-fullscreen$suffix.js", array('jquery'), false, 1 );
    9090
     91        $scripts->add( 'wp-favicon', "/wp-admin/js/wp-favicon$suffix.js", array('jquery'), false, 1 );
     92
    9193        $scripts->add( 'prototype', '/wp-includes/js/prototype.js', array(), '1.6.1');
    9294
    9395        $scripts->add( 'wp-ajax-response', "/wp-includes/js/wp-ajax-response$suffix.js", array('jquery'), false, 1 );
  • wp-admin/js/wp-favicon.dev.js

     
     1(function($){
     2    $('#faviconfile').change(function(){
     3        // check the file extention
     4        if (! $.inArray( $(this).val().split('.').pop().toLowerCase() , /* valid file extentions */ ['gif','png','jpg','jpeg'] ) )
     5            $('#favicon-invalid-filetype').show();
     6        else
     7        {
     8            $('#faviconupload').submit();
     9        }
     10    });
     11
     12})(jQuery);
  • wp-admin/js/wp-favicon.js

     
     1(function($){
     2    $('#faviconfile').change(function(){
     3        // check the file extention
     4        if (! $.inArray( $(this).val().split('.').pop().toLowerCase() , /* valid file extentions */ ['gif','png','jpg','jpeg'] ) )
     5            $('#favicon-invalid-filetype').show();
     6        else
     7        {
     8            $('#faviconupload').submit();
     9        }
     10    });
     11
     12})(jQuery);
  • wp-admin/options-general.php

     
    8181        '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
    8282);
    8383
     84wp_enqueue_script('wp-favicon');
     85
    8486include('./admin-header.php');
    8587?>
    8688
     
    8890<?php screen_icon(); ?>
    8991<h2><?php echo esc_html( $title ); ?></h2>
    9092
     93<form action="<?php echo admin_url('favicon-upload.php')?>" method="post" enctype="multipart/form-data" id="faviconupload">
     94    <?php settings_fields('favicon_upload') ?>
     95        <table class="form-table">
     96                <tr valign="top">
     97                        <th scope="row"><label for="sitefavicon"><?php _e('Favicon') ?></label></th>
     98                        <td>
     99                                <?php
     100                                        // display the icon and the remove link if appropriate
     101                                        if ( has_custom_favicon() ){
     102                                                if ( $thumbnail = get_favicon_img() ) echo $thumbnail;
     103                                                echo "\t" . '<input type="submit" name="REMOVE_FAVICON" value="Remove Favicon" id="remove-favicon-button" />';
     104                                                echo ' <span class="description no-js">' . __( 'The image at right is used as your site\'s favicon. To change it, first remove this one.' ) . '</span>';
     105                                        } else {
     106                                ?>
     107                                        <input class="button" name="avatarfile" type="file" id="faviconfile" size="20" />
     108                                        <p class="submit no-js hide-if-js"><input type="submit" name="Submit" value="Upload Image &raquo;" id="faviconsubmit" /></p>
     109                                        <span class="description no-js"><?php _e('Click to upload your own custom icon ("favicon") for your blog. You\'ll be able to crop and scale it once it\'s uploaded.') ?></span>
     110                                <?php } ?>
     111                        </td>
     112                </tr>
     113        </table>
     114</form>
     115
    91116<form method="post" action="options.php">
    92117<?php settings_fields('general'); ?>
    93118
  • wp-admin/favicon-upload.php

     
     1<?php
     2/**
     3 * Handles the uploading, cropping and scaling of favicons.
     4 *
     5 * @uses ico2_3.php JPEXS class for reading / writing .ICO files
     6 *
     7 * @package WordPress
     8 * @subpackage Administration
     9 * @since 3.4.1
     10 */
     11
     12// Bootstrap admin and all its goodies
     13require_once( 'admin.php' );
     14
     15define( 'FAVICON_SIZE', 32 ); // Width (and height) of the favicon (in pixels)
     16
     17/*      Upload is a 2-step process:     
     18 *      1. Process the uploaded file and show the crop UI
     19 *      2. Manipulate the pixel data, save to PNG and ICO and write to options.
     20 */
     21if (! current_user_can('manage_options') )
     22    wp_die(__('Cheatin&#8217; uh?'));
     23check_admin_referer('favicon_upload-options');
     24
     25if ( isset( $_POST['CROP_AND_SAVE'] ) ) {
     26        if ( isset( $_POST['attachment_id'] ) && is_numeric( $_POST['attachment_id'] ) ){
     27                $image_basename = process_crop_thumbnail( $_POST['attachment_id'] );
     28
     29                if ( is_wp_error( $image_basename ) ) {
     30                        include_once('./admin-header.php');
     31                        echo '<div class="wrap">';
     32                                echo '<h2>' . __( 'Image upload error' ) . '</h2>';
     33                                echo '<p>' . $image_basename->get_error_message() . '</p>';
     34                                echo '<p><a href="' . admin_url( 'options-general.php' ) . '">&laquo;' . __( 'Back to Settings &gt; General' ) . '</a></p>';
     35                        echo '</div><!-- .wrap -->';
     36                        include_once('./admin-footer.php');
     37                } else {
     38            $attachment_id = $_POST['attachment_id'] ;
     39            save_thumbnail_attachment( $image_basename . '.png', $attachment_id );
     40
     41                        // And save the basename out to options.
     42                        update_option( 'sitefavicon', basename( $image_basename ) );
     43                       
     44                        /** @TODO need to find a way to notify the user that the process has completed successfully - admin_notices? */
     45                        wp_redirect( admin_url( 'options-general.php' ) );
     46                }
     47        } else {
     48                return new WP_Error( 'attachment_id_missing', 'Form submission error.' );
     49        }
     50} elseif ( isset( $_REQUEST['REMOVE_FAVICON'] ) ) {
     51        remove_favicon();
     52} else {
     53        /** @TODO make sure that we trap for someone just pressing "Upload image" but with no image attached */
     54        // Enqueue the JS for the cropper...
     55        add_action( 'admin_enqueue_scripts', 'enqueue_cropper' );
     56        // ...and our own script for populating the crop form
     57        add_action( 'admin_footer', 'cropping_js', 10,  1);
     58       
     59        // Process the upload and create the attachment file in the media center
     60        $image_results = process_thumbnail_upload();
     61       
     62        include_once('./admin-header.php');
     63       
     64        // hack because image replication isn't fast enough. See https://wpcom.automattic.com/ticket/1294
     65        sleep( 2 );
     66
     67        echo '<div class="wrap">';
     68       
     69        if ( is_wp_error( $image_results ) )  {
     70                echo '<h2>' . __( 'Image upload error' ) . '</h2>';
     71                echo '<p>' . $image_results->get_error_message() . '</p>';
     72                echo '<p><a href="' . admin_url( 'options-general.php' ) . '">&laquo;' . __( 'Back to Settings &gt; General' ) . '</a></p>';
     73        } else {
     74                // Image upload successful.
     75                // Now we can hook in our javascript and provide the width/height of our image as the default crop size
     76                $crop_size = min( $image_results['width'], $image_results['height'] );
     77                echo '<script type="text/javascript">var jcrop_starting_size = ' . $crop_size . '; // Initialize jcrop crop area starting size</script>';
     78       
     79                echo '<h2>' . __( 'Crop uploaded image' ) . '</h2>';
     80                echo '<p>' . __( 'Choose the part of the image you want to use for your favicon.' ) . '</p>';
     81               
     82                echo '<form id="favicon-crop-form" method="post" action="' . $_SERVER['REQUEST_URI'] . '">'; // Point the form action back to this script
     83        settings_fields('favicon_upload');
     84               
     85                        echo <<<CROP_FORM
     86                        <input type="hidden" name="x1" id="x1" />
     87                        <input type="hidden" name="y1" id="y1" />
     88                        <input type="hidden" name="x2" id="x2" />
     89                        <input type="hidden" name="y2" id="y2" />
     90                        <input type="hidden" name="width" id="width" />
     91                        <input type="hidden" name="height" id="height" />
     92                        <input type="hidden" name="attachment_id" id="attachment_id" value="{$image_results['attachment_id']}" />
     93                        <input type="hidden" name="scaling_factor" id="scaling_factor" value="{$image_results['scaling_factor']}" />
     94CROP_FORM;
     95               
     96                        echo '<img src="' . $image_results['src'] . '" id="upload" width="' . $image_results['width'] . '" height="' . $image_results['height'] . '" />';
     97               
     98                        echo '<p class="submit"><input type="submit" name="CROP_AND_SAVE" value="' . __( 'Crop image' ) . ' &raquo;" /></p>';
     99                echo '</form>';
     100        }
     101       
     102        echo '</div><!-- .wrap -->';
     103       
     104        include_once('./admin-footer.php');
     105}
     106
     107
     108/**
     109 * Process the image file upload and return a WP_Error or details about the attachment image file.
     110 *
     111 * @return mixed WP_Error | $image_results array
     112 */
     113function process_thumbnail_upload(){
     114        $file = wp_handle_upload( $_FILES['avatarfile'], array( 'action' => 'update') );
     115        if ( isset($file['error']) ) die( $file['error'] );
     116       
     117        $url = $file['url'];
     118        $file = $file['file'];
     119        $filename = basename($file);
     120       
     121        // Construct the object array
     122        $object = array(
     123                'post_title' => $filename,
     124                'post_content' => $url,
     125                'post_mime_type' => 'import',
     126                'guid' => $url
     127        );
     128
     129        // Save the data.  Also makes replication work
     130        $id = wp_insert_attachment($object, $file);
     131
     132        // Retrieve the image dimensions
     133        list( $orig_width, $orig_height, $type, $attr ) = getimagesize( $file );
     134       
     135        // Do we need to scale down the image so we can display it nicely in the interactive Crop tool?
     136        if ( $orig_width > 600 || $orig_height > 600 ) {
     137                $image = wp_create_thumbnail( $file, 600 );
     138                list( $width, $height, $type, $attr ) = getimagesize( $image );
     139               
     140                 // Update the attachment record to reflect the newly-scaled thumbnail image
     141                $thumb = basename( $image );
     142                $metadata = array( 'thumb' => $thumb );
     143                wp_update_attachment_metadata( $id, $metadata );
     144
     145                $url = str_replace( basename( $url ), $thumb, $url );
     146
     147                $scaling = $orig_width / $width;
     148        } else {
     149                // No scaling required; just copy original values.
     150                $width = $orig_width;
     151                $height = $orig_height;
     152                $scaling = 1;
     153        }
     154
     155        // Check image file format
     156        $image_type = exif_imagetype( get_attached_file( $id ) );
     157        if (! in_array( $image_type, array( IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_BMP ) ) )
     158                $error = new WP_Error( 'bad_file_format', __( 'Please only use PNG (.png), JPEG (.jpg) or BMP (.bmp) image files for favicons. ' ) );
     159       
     160        // return WP_Error or the $image_results array
     161        if ( isset($error) && $error ){
     162                return $error;
     163        } else {
     164                return array(
     165                        'attachment_id' => $id,
     166                        'src' => $url,
     167                        'width' => $width,
     168                        'height' => $height,
     169                        'scaling_factor' => $scaling
     170                );
     171        }
     172}
     173
     174/**
     175 * Create PNG and BMP image resources based on the form submission of the cropped thumbnail.
     176 *
     177 * @param int $attachment_id The ID of the original attachment's post record.
     178 * @return mixed WP_Error | Favicon file base name (ie: fully qualified file name without any TLA file extension)
     179 */
     180function process_crop_thumbnail( $attachment_id ){
     181        $src_file = get_attached_file( $attachment_id );
     182
     183        // Highly unlikely, but let's check
     184        if (! file_exists( $src_file ) )
     185                return new WP_Error( 'file_missing', __( 'Attachment image file missing (possible save error: check space on web server).' ) );
     186
     187        // Make sure we're still within accepted image types
     188        $image_type = exif_imagetype( $src_file );
     189        if (! $image_type || ! in_array( $image_type, array( IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_BMP ) ) )
     190                return new WP_Error( 'bad_file_format', __( 'Please only use PNG (.png), JPEG (.jpg) or BMP (.bmp) image files for favicons. ' ) );
     191
     192        // Parse image file bytes
     193        $src_image = wp_load_image( $src_file );
     194        if ( !is_resource($src_image) )
     195                return new WP_Error( 'is_not_resource', __( 'Error loading image. You got me: I\'m stumped.' ) );
     196
     197        // We crop from the original, not the medium sized, display-only thumbnail
     198        $src_x = $_POST['x1'] * $_POST['scaling_factor'];
     199        $src_y = $_POST['y1'] * $_POST['scaling_factor'];
     200        $src_width = $_POST['width'] * $_POST['scaling_factor'];
     201        $src_height = $_POST['height'] * $_POST['scaling_factor'];
     202
     203        $dst_width = $dst_height = FAVICON_SIZE;
     204        // Avoid upscaling
     205        if ( $src_width < $dst_width || $src_height < $dst_height ) {
     206                $dst_width = $src_width;
     207                $dst_height = $src_height;
     208        }
     209
     210        $dst_image = wp_imagecreatetruecolor( $dst_width, $dst_height );
     211        if ( function_exists( 'imageantialias' ) ) imageantialias( $dst_image, true );
     212        imagealphablending( $dst_image, false );
     213        imagesavealpha( $dst_image, true );
     214        imagecopyresampled( $dst_image, $src_image, 0, 0, $src_x, $src_y, $dst_width, $dst_height, $src_width, $src_height );
     215        imagedestroy( $src_image );
     216
     217
     218        // Save the image in PNG and ICO formats
     219        $file_info = pathinfo( $src_file );
     220        $src_basename = basename( $src_file, '.' . $file_info['extension'] );
     221        $dst_filename = str_replace( $src_basename, $src_basename . '_' . FAVICON_SIZE . 'x' . FAVICON_SIZE, $src_file );
     222        // Strip the TLA from the filename
     223        $dst_filename = preg_replace( '/\\.[^\\.]+$/', '', $dst_filename );
     224
     225        $png_filename = $dst_filename . '.png';
     226        if (! imagepng( $dst_image, $png_filename, 0 ) )
     227                return new WP_Error( 'png_write_error', 'Error writing PNG favicon file.' );
     228       
     229        $ico_filename = $dst_filename . '.ico';
     230
     231        imagedestroy( $dst_image );
     232
     233        return $dst_filename;
     234}
     235
     236/**
     237 * Creates an attachment post record for a newly created thumbnail
     238 *
     239 * @param string $file_name Fully qualified file name for the image asset file.
     240 * @param int $parent_attachment_id The ID of the original thumbnail's attachment post record
     241 *
     242 * @return int The ID of the newly-created thumbnail attachment post record
     243 */
     244function save_thumbnail_attachment( $file_name, $parent_attachment_id ){
     245        $file_info = pathinfo( $file_name ); // So we can get the TLA later on
     246       
     247        $file_name = apply_filters( 'wp_create_file_in_uploads', $file_name, $parent_attachment_id ); // For replication
     248
     249        $parent = get_post( $parent_attachment_id );
     250        $parent_url = $parent->guid;
     251       
     252        // Update the attachment
     253        $mimes = get_allowed_mime_types();
     254        $attachment_id = wp_insert_attachment( array(
     255                'post_title' => basename( $file_name ),
     256                'post_mime_type' => $mimes[ $file_info['extension'] ],
     257                'context' => 'favicon'
     258        ), $file_name );
     259        wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file_name ) );
     260       
     261        return $attachment_id;
     262}
     263
     264/**
     265 * Currently, doesn't actually "remove" the favicon images. It only deletes the option
     266 * that tells us there's a favicon, so the code isn't generated (or the default is used)
     267 */
     268function remove_favicon(){
     269        update_option( 'sitefavicon', false );
     270                       
     271        /** @TODO need to find a way to notify the user that the process has completed successfully - admin_notices? */
     272        wp_redirect( admin_url( 'options-general.php' ) );
     273}
     274
     275
     276/**
     277 * Called in admin_enqueue_scripts to add the cropper.js script and styles
     278 */
     279function enqueue_cropper(){
     280        wp_enqueue_script( 'jcrop', 'jquery' );
     281        wp_enqueue_style('jcrop'); // We can enqueue styles within the admin_enqueue_script action hook {@link http://wpdevel.wordpress.com/2011/12/12/use-wp_enqueue_scripts-not-wp_print_styles-to-enqueue-scripts-and-styles-for-the-frontend/}
     282}
     283
     284function cropping_js(){
     285        // Purely for coding convenience and legibility
     286        $favicon_size = FAVICON_SIZE;
     287       
     288        echo <<<CROP_JS
     289        <!-- Favicon cropping -->
     290        <script type="text/javascript">
     291                // Update the crop form
     292                function onEndCrop( coords ) {
     293                        jQuery( '#x1' ).val(coords.x);
     294                        jQuery( '#y1' ).val(coords.y);
     295                        jQuery( '#x2' ).val(coords.x2);
     296                        jQuery( '#y2' ).val(coords.y2);
     297                        jQuery( '#width' ).val(coords.w);
     298                        jQuery( '#height' ).val(coords.h);
     299                }
     300
     301                // with a supplied ratio
     302                jQuery(function($) {
     303                        if (! jcrop_starting_size) jcrop_starting_size = {$favicon_size}; // jcrop_starting_size should be set in the body once the image has been processed
     304
     305                        // Set up default values on the crop form
     306                        jQuery( '#x1' ).val(0);
     307                        jQuery( '#y1' ).val(0);
     308                        jQuery( '#x2' ).val(jcrop_starting_size);
     309                        jQuery( '#y2' ).val(jcrop_starting_size);
     310                        jQuery( '#width' ).val(jcrop_starting_size);
     311                        jQuery( '#height' ).val(jcrop_starting_size);
     312
     313                        // Initialize Jcrop
     314                        $('#upload').Jcrop({
     315                                aspectRatio: 1,
     316                                setSelect: [0, 0, jcrop_starting_size, jcrop_starting_size],
     317                                onSelect: onEndCrop
     318                        });
     319                });
     320        </script>
     321CROP_JS;
     322
     323}