WordPress.org

Make WordPress Core


Ignore:
Timestamp:
05/20/2020 06:47:24 PM (11 months ago)
Author:
whyisjake
Message:

Security: Add user interface to auto-update themes and plugins.

Building on core update mechanisms, this adds the ability to enable automatic updates for themes and plugins to the WordPress admin.

Fixes: #50052.
Props: afercia, afragen, audrasjb, azaozz, bookdude13, davidperonne, desrosj, gmays, gmays, javiercasares, karmatosed, knutsp, mapk, mukesh27, netweb, nicolaskulka, nielsdeblaauw, paaljoachim, passoniate, pbiron, pedromendonca, whodunitagency, whyisjake, wpamitkumar, and xkon.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/class-wp-automatic-updater.php

    r47808 r47835  
    159159        if ( 'core' === $type ) {
    160160            $update = Core_Upgrader::should_update_to_version( $item->current );
     161        } elseif ( 'plugin' === $type || 'theme' === $type ) {
     162            $update = ! empty( $item->autoupdate );
     163
     164            if ( ! $update && wp_is_auto_update_enabled_for_type( $type ) ) {
     165                // Check if the site admin has enabled auto-updates by default for the specific item.
     166                $auto_updates = (array) get_site_option( "auto_update_{$type}s", array() );
     167                $update       = in_array( $item->{$type}, $auto_updates, true );
     168            }
    161169        } else {
    162170            $update = ! empty( $item->autoupdate );
     
    502510            if ( ! empty( $this->update_results['core'] ) ) {
    503511                $this->after_core_update( $this->update_results['core'][0] );
     512            } elseif ( ! empty( $this->update_results['plugin'] ) || ! empty( $this->update_results['theme'] ) ) {
     513                $this->after_plugin_theme_update( $this->update_results );
    504514            }
    505515
     
    855865    }
    856866
     867
     868    /**
     869     * If we tried to perform plugin or theme updates, check if we should send an email.
     870     *
     871     * @since 5.5.0
     872     *
     873     * @param object $results The result of updates tasks.
     874     */
     875    protected function after_plugin_theme_update( $update_results ) {
     876        $successful_updates = array();
     877        $failed_updates     = array();
     878
     879        /**
     880         * Filters whether to send an email following an automatic background plugin update.
     881         *
     882         * @since 5.5.0
     883         *
     884         * @param bool $enabled True if plugins notifications are enabled, false otherwise.
     885         */
     886        $notifications_enabled = apply_filters( 'auto_plugin_update_send_email', true );
     887
     888        if ( ! empty( $update_results['plugin'] ) && $notifications_enabled ) {
     889            foreach ( $update_results['plugin'] as $update_result ) {
     890                if ( true === $update_result->result ) {
     891                    $successful_updates['plugin'][] = $update_result;
     892                } else {
     893                    $failed_updates['plugin'][] = $update_result;
     894                }
     895            }
     896        }
     897
     898        /**
     899         * Filters whether to send an email following an automatic background theme update.
     900         *
     901         * @since 5.5.0
     902         *
     903         * @param bool $enabled True if notifications are enabled, false otherwise.
     904         */
     905        $notifications_enabled = apply_filters( 'send_theme_auto_update_email', true );
     906
     907        if ( ! empty( $update_results['theme'] ) && $notifications_enabled ) {
     908            foreach ( $update_results['theme'] as $update_result ) {
     909                if ( true === $update_result->result ) {
     910                    $successful_updates['theme'][] = $update_result;
     911                } else {
     912                    $failed_updates['theme'][] = $update_result;
     913                }
     914            }
     915        }
     916
     917        if ( empty( $successful_updates ) && empty( $failed_updates ) ) {
     918            return;
     919        }
     920
     921        if ( empty( $failed_updates ) ) {
     922            $this->send_plugin_theme_email( 'success', $successful_updates, $failed_updates );
     923        } elseif ( empty( $successful_updates ) ) {
     924            $this->send_plugin_theme_email( 'fail', $successful_updates, $failed_updates );
     925        } else {
     926            $this->send_plugin_theme_email( 'mixed', $successful_updates, $failed_updates );
     927        }
     928    }
     929
     930    /**
     931     * Sends an email upon the completion or failure of a plugin or theme background update.
     932     *
     933     * @since 5.5.0
     934     *
     935     * @param string $type               The type of email to send. Can be one of 'success', 'failure', 'mixed'.
     936     * @param array  $successful_updates A list of updates that succeeded.
     937     * @param array  $failed_updates     A list of updates that failed.
     938     */
     939    protected function send_plugin_theme_email( $type, $successful_updates, $failed_updates ) {
     940        // No updates were attempted.
     941        if ( empty( $successful_updates ) && empty( $failed_updates ) ) {
     942            return;
     943        }
     944        $body = array();
     945
     946        switch ( $type ) {
     947            case 'success':
     948                /* translators: %s: Site title. */
     949                $subject = __( '[%s] Some plugins or themes were automatically updated' );
     950                break;
     951            case 'fail':
     952                /* translators: %s: Site title. */
     953                $subject = __( '[%s] Some plugins or themes have failed to update' );
     954                $body[]  = sprintf(
     955                    /* translators: %s: Home URL. */
     956                    __( 'Howdy! Failures occurred when attempting to update plugins/themes on your site at %s.' ),
     957                    home_url()
     958                );
     959                $body[] = "\n";
     960                $body[] = __( 'Please check out your site now. It’s possible that everything is working. If it says you need to update, you should do so.' );
     961                break;
     962            case 'mixed':
     963                /* translators: %s: Site title. */
     964                $subject = __( '[%s] Some plugins or themes were automatically updated' );
     965                $body[]  = sprintf(
     966                    /* translators: %s: Home URL. */
     967                    __( 'Howdy! Failures occurred when attempting to update plugins/themes on your site at %s.' ),
     968                    home_url()
     969                );
     970                $body[] = "\n";
     971                $body[] = __( 'Please check out your site now. It’s possible that everything is working. If it says you need to update, you should do so.' );
     972                $body[] = "\n";
     973                break;
     974        }
     975
     976        // Get failed plugin updates.
     977        if ( in_array( $type, array( 'fail', 'mixed' ), true ) && ! empty( $failed_updates['plugin'] ) ) {
     978            $body[] = __( 'The following plugins failed to update:' );
     979            // List failed updates.
     980            foreach ( $failed_updates['plugin'] as $item ) {
     981                $body[] = "- {$item->name}";
     982            }
     983            $body[] = "\n";
     984        }
     985        // Get failed theme updates.
     986        if ( in_array( $type, array( 'fail', 'mixed' ), true ) && ! empty( $failed_updates['theme'] ) ) {
     987            $body[] = __( 'The following themes failed to update:' );
     988            // List failed updates.
     989            foreach ( $failed_updates['theme'] as $item ) {
     990                $body[] = "- {$item->name}";
     991            }
     992            $body[] = "\n";
     993        }
     994        // Get successful plugin updates.
     995        if ( in_array( $type, array( 'success', 'mixed' ), true ) && ! empty( $successful_updates['plugin'] ) ) {
     996            $body[] = __( 'The following plugins were successfully updated:' );
     997            // List successful updates.
     998            foreach ( $successful_updates['plugin'] as $item ) {
     999                $body[] = "- {$item->name}";
     1000            }
     1001            $body[] = "\n";
     1002        }
     1003        // Get successful theme updates.
     1004        if ( in_array( $type, array( 'success', 'mixed' ), true ) && ! empty( $successful_updates['theme'] ) ) {
     1005            $body[] = __( 'The following themes were successfully updated:' );
     1006            // List successful updates.
     1007            foreach ( $successful_updates['theme'] as $item ) {
     1008                $body[] = "- {$item->name}";
     1009            }
     1010            $body[] = "\n";
     1011        }
     1012        $body[] = "\n";
     1013
     1014        // Add a note about the support forums.
     1015        $body[] = __( 'If you experience any issues or need support, the volunteers in the WordPress.org support forums may be able to help.' );
     1016        $body[] = __( 'https://wordpress.org/support/forums/' );
     1017        $body[] = "\n" . __( 'The WordPress Team' );
     1018
     1019        $body    = implode( "\n", $body );
     1020        $to      = get_site_option( 'admin_email' );
     1021        $subject = sprintf( $subject, wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ) );
     1022        $headers = '';
     1023
     1024        $email = compact( 'to', 'subject', 'body', 'headers' );
     1025
     1026        /**
     1027         * Filters the email sent following an automatic background plugin update.
     1028         *
     1029         * @param array $email {
     1030         *     Array of email arguments that will be passed to wp_mail().
     1031         *
     1032         *     @type string $to      The email recipient. An array of emails
     1033         *                           can be returned, as handled by wp_mail().
     1034         *     @type string $subject The email's subject.
     1035         *     @type string $body    The email message body.
     1036         *     @type string $headers Any email headers, defaults to no headers.
     1037         * }
     1038         * @param string $type               The type of email being sent. Can be one of
     1039         *                                   'success', 'fail', 'mixed'.
     1040         * @param object $successful_updates The updates that succeeded.
     1041         * @param object $failed_updates     The updates that failed.
     1042         */
     1043        $email = apply_filters( 'auto_plugin_theme_update_email', $email, $type, $successful_updates, $failed_updates );
     1044        wp_mail( $email['to'], wp_specialchars_decode( $email['subject'] ), $email['body'], $email['headers'] );
     1045    }
     1046
    8571047    /**
    8581048     * Prepares and sends an email of a full log of background update results, useful for debugging and geekery.
Note: See TracChangeset for help on using the changeset viewer.