WordPress.org

Make WordPress Core

Changeset 44717


Ignore:
Timestamp:
01/30/2019 11:00:30 AM (3 months ago)
Author:
flixos90
Message:

Bootstrap/Load: Revert fatal error recovery mechanism from 5.1 to polish for 5.2.

Due to the high number of follow-up tickets and associated security concerns, it was decided to reschedule the fatal error recovery feature for WordPress 5.2, in order to address these issues properly. The feature will continue to be developed, with iterations being merged into trunk early in the 5.2 release cycle.

Fixes #46141. See #44458, #45932, #45940, #46038, #46047, #46068.

Location:
trunk
Files:
3 deleted
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/css/list-tables.css

    r44646 r44717  
    13021302}
    13031303
    1304 .plugins tr.paused th.check-column {
    1305     border-left: 4px solid #d54e21;
    1306 }
    1307 
    1308 .plugins tr.paused th,
    1309 .plugins tr.paused td {
    1310     background-color: #fef7f1;
    1311 }
    1312 
    1313 .plugins tr.paused .plugin-title,
    1314 .plugins .paused .dashicons-warning {
    1315     color: #dc3232;
    1316 }
    1317 
    1318 .plugins .paused .error-display p,
    1319 .plugins .paused .error-display code {
    1320     font-size: 90%;
    1321     font-style: italic;
    1322     color: rgb( 0, 0, 0, 0.7 );
    1323 }
    1324 
    1325 .plugins .resume-link {
    1326     color: #dc3232;
    1327 }
    1328 
    13291304.plugin-card .update-now:before {
    13301305    color: #f56e28;
  • trunk/src/wp-admin/includes/admin-filters.php

    r44647 r44717  
    118118
    119119add_action( 'admin_notices', 'update_nag', 3 );
    120 add_action( 'admin_notices', 'paused_plugins_notice', 5 );
    121 add_action( 'admin_notices', 'paused_themes_notice', 5 );
    122120add_action( 'admin_notices', 'maintenance_nag', 10 );
    123121
  • trunk/src/wp-admin/includes/class-wp-plugins-list-table.php

    r44541 r44717  
    4141
    4242        $status = 'all';
    43         if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], array( 'active', 'inactive', 'recently_activated', 'upgrade', 'mustuse', 'dropins', 'search', 'paused' ) ) ) {
     43        if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], array( 'active', 'inactive', 'recently_activated', 'upgrade', 'mustuse', 'dropins', 'search' ) ) ) {
    4444            $status = $_REQUEST['plugin_status'];
    4545        }
     
    100100            'mustuse'            => array(),
    101101            'dropins'            => array(),
    102             'paused'             => array(),
    103102        );
    104103
     
    211210                    // On the non-network screen, show network-active plugins if allowed
    212211                    $plugins['active'][ $plugin_file ] = $plugin_data;
    213                     if ( is_plugin_paused( $plugin_file ) ) {
    214                         $plugins['paused'][ $plugin_file ] = $plugin_data;
    215                     }
    216212                } else {
    217213                    // On the non-network screen, filter out network-active plugins
     
    223219                // On the network-admin screen, populate the active list with plugins that are network activated
    224220                $plugins['active'][ $plugin_file ] = $plugin_data;
    225                 if ( is_plugin_paused( $plugin_file ) ) {
    226                     $plugins['paused'][ $plugin_file ] = $plugin_data;
    227                 }
    228221            } else {
    229222                if ( isset( $recently_activated[ $plugin_file ] ) ) {
     
    453446                    $text = _n( 'Drop-ins <span class="count">(%s)</span>', 'Drop-ins <span class="count">(%s)</span>', $count );
    454447                    break;
    455                 case 'paused':
    456                     /* translators: %s: plugin count */
    457                     $text = _n( 'Paused <span class="count">(%s)</span>', 'Paused <span class="count">(%s)</span>', $count );
    458                     break;
    459448                case 'upgrade':
    460449                    /* translators: %s: plugin count */
     
    645634                        $actions['deactivate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Network Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Network Deactivate' ) . '</a>';
    646635                    }
    647                     if ( current_user_can( 'manage_network_plugins' ) && count_paused_plugin_sites_for_network( $plugin_file ) ) {
    648                         /* translators: %s: plugin name */
    649                         $actions['resume'] = '<a class="resume-link" href="' . wp_nonce_url( 'plugins.php?action=resume&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'resume-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Network Resume %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Network Resume' ) . '</a>';
    650                     }
    651636                } else {
    652637                    if ( current_user_can( 'manage_network_plugins' ) ) {
    653638                        /* translators: %s: plugin name */
    654639                        $actions['activate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file ) . '" class="edit" aria-label="' . esc_attr( sprintf( _x( 'Network Activate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Network Activate' ) . '</a>';
    655                     }
    656                     if ( current_user_can( 'manage_network_plugins' ) && count_paused_plugin_sites_for_network( $plugin_file ) ) {
    657                         /* translators: %s: plugin name */
    658                         $actions['resume'] = '<a class="resume-link" href="' . wp_nonce_url( 'plugins.php?action=resume&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'resume-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Network Resume %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Network Resume' ) . '</a>';
    659640                    }
    660641                    if ( current_user_can( 'delete_plugins' ) && ! is_plugin_active( $plugin_file ) ) {
     
    668649                        'network_active' => __( 'Network Active' ),
    669650                    );
    670                     if ( ! $restrict_network_only && current_user_can( 'resume_plugin', $plugin_file ) && is_plugin_paused( $plugin_file ) ) {
    671                         /* translators: %s: plugin name */
    672                         $actions['resume'] = '<a class="resume-link" href="' . wp_nonce_url( 'plugins.php?action=resume&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'resume-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Resume %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Resume' ) . '</a>';
    673                     }
    674651                } elseif ( $restrict_network_only ) {
    675652                    $actions = array(
     
    681658                        $actions['deactivate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Deactivate' ) . '</a>';
    682659                    }
    683                     if ( current_user_can( 'resume_plugin', $plugin_file ) && is_plugin_paused( $plugin_file ) ) {
    684                         /* translators: %s: plugin name */
    685                         $actions['resume'] = '<a class="resume-link" href="' . wp_nonce_url( 'plugins.php?action=resume&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'resume-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Resume %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Resume' ) . '</a>';
    686                     }
    687660                } else {
    688661                    if ( current_user_can( 'activate_plugin', $plugin_file ) ) {
     
    790763        if ( ! empty( $totals['upgrade'] ) && ! empty( $plugin_data['update'] ) ) {
    791764            $class .= ' update';
    792         }
    793 
    794         $paused                        = is_plugin_paused( $plugin_file );
    795         $paused_on_network_sites_count = $screen->in_admin( 'network' ) ? count_paused_plugin_sites_for_network( $plugin_file ) : 0;
    796         if ( $paused || $paused_on_network_sites_count ) {
    797             $class .= ' paused';
    798765        }
    799766
     
    879846                     * @param string   $status      Status of the plugin. Defaults are 'All', 'Active',
    880847                     *                              'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
    881                      *                              'Drop-ins', 'Search', 'Paused'.
     848                     *                              'Drop-ins', 'Search'.
    882849                     */
    883850                    $plugin_meta = apply_filters( 'plugin_row_meta', $plugin_meta, $plugin_file, $plugin_data, $status );
     
    885852
    886853                    echo '</div>';
    887 
    888                     if ( $paused || $paused_on_network_sites_count ) {
    889                         $notice_text = __( 'This plugin failed to load properly and was paused within the admin backend.' );
    890                         if ( $screen->in_admin( 'network' ) && $paused_on_network_sites_count ) {
    891                             $notice_text = sprintf(
    892                                 /* translators: %s: number of sites */
    893                                 _n( 'This plugin failed to load properly and was paused within the admin backend for %s site.', 'This plugin failed to load properly and was paused within the admin backend for %s sites.', $paused_on_network_sites_count ),
    894                                 number_format_i18n( $paused_on_network_sites_count )
    895                             );
    896                         }
    897 
    898                         printf( '<p><span class="dashicons dashicons-warning"></span> <strong>%s</strong></p>', $notice_text );
    899 
    900                         $error = wp_get_plugin_error( $plugin_file );
    901 
    902                         if ( false !== $error ) {
    903                             $constants = get_defined_constants( true );
    904                             $constants = isset( $constants['Core'] ) ? $constants['Core'] : $constants['internal'];
    905 
    906                             foreach ( $constants as $constant => $value ) {
    907                                 if ( 0 === strpos( $constant, 'E_' ) ) {
    908                                     $core_errors[ $value ] = $constant;
    909                                 }
    910                             }
    911 
    912                             $error['type'] = $core_errors[ $error['type'] ];
    913 
    914                             printf(
    915                                 '<div class="error-display"><p>%s</p></div>',
    916                                 sprintf(
    917                                     /* translators: 1: error type, 2: error line number, 3: error file name, 4: error message */
    918                                     __( 'The plugin caused an error of type %1$s in line %2$s of the file %3$s. Error message: %4$s' ),
    919                                     "<code>{$error['type']}</code>",
    920                                     "<code>{$error['line']}</code>",
    921                                     "<code>{$error['file']}</code>",
    922                                     "<code>{$error['message']}</code>"
    923                                 )
    924                             );
    925                         }
    926                     }
    927854
    928855                    echo '</td>';
     
    959886         * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
    960887         *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
    961          *                            'Drop-ins', 'Search', 'Paused'.
     888         *                            'Drop-ins', 'Search'.
    962889         */
    963890        do_action( 'after_plugin_row', $plugin_file, $plugin_data, $status );
     
    975902         * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
    976903         *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
    977          *                            'Drop-ins', 'Search', 'Paused'.
     904         *                            'Drop-ins', 'Search'.
    978905         */
    979906        do_action( "after_plugin_row_{$plugin_file}", $plugin_file, $plugin_data, $status );
  • trunk/src/wp-admin/includes/plugin.php

    r44675 r44717  
    469469function _get_dropins() {
    470470    $dropins = array(
    471         'advanced-cache.php'      => array( __( 'Advanced caching plugin.' ), 'WP_CACHE' ), // WP_CACHE
    472         'db.php'                  => array( __( 'Custom database class.' ), true ), // auto on load
    473         'db-error.php'            => array( __( 'Custom database error message.' ), true ), // auto on error
    474         'install.php'             => array( __( 'Custom installation script.' ), true ), // auto on installation
    475         'maintenance.php'         => array( __( 'Custom maintenance message.' ), true ), // auto on maintenance
    476         'object-cache.php'        => array( __( 'External object cache.' ), true ), // auto on load
    477         'php-error.php'           => array( __( 'Custom PHP error message.' ), true ), // auto on error
    478         'fatal-error-handler.php' => array( __( 'Custom PHP fatal error handler.' ), true ), // auto on error
     471        'advanced-cache.php' => array( __( 'Advanced caching plugin.' ), 'WP_CACHE' ), // WP_CACHE
     472        'db.php'             => array( __( 'Custom database class.' ), true ), // auto on load
     473        'db-error.php'       => array( __( 'Custom database error message.' ), true ), // auto on error
     474        'install.php'        => array( __( 'Custom installation script.' ), true ), // auto on installation
     475        'maintenance.php'    => array( __( 'Custom maintenance message.' ), true ), // auto on maintenance
     476        'object-cache.php'   => array( __( 'External object cache.' ), true ), // auto on load
    479477    );
    480478
     
    527525function is_plugin_inactive( $plugin ) {
    528526    return ! is_plugin_active( $plugin );
    529 }
    530 
    531 /**
    532  * Determines whether a plugin is technically active but was paused while
    533  * loading.
    534  *
    535  * For more information on this and similar theme functions, check out
    536  * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
    537  * Conditional Tags} article in the Theme Developer Handbook.
    538  *
    539  * @since 5.1.0
    540  *
    541  * @param string $plugin Path to the plugin file relative to the plugins directory.
    542  * @return bool True, if in the list of paused plugins. False, not in the list.
    543  */
    544 function is_plugin_paused( $plugin ) {
    545     if ( ! isset( $GLOBALS['_paused_plugins'] ) ) {
    546         return false;
    547     }
    548 
    549     if ( ! is_plugin_active( $plugin ) && ! is_plugin_active_for_network( $plugin ) ) {
    550         return false;
    551     }
    552 
    553     list( $plugin ) = explode( '/', $plugin );
    554 
    555     return array_key_exists( $plugin, $GLOBALS['_paused_plugins'] );
    556 }
    557 
    558 /**
    559  * Gets the error that was recorded for a paused plugin.
    560  *
    561  * @since 5.1.0
    562  *
    563  * @param string $plugin Path to the plugin file relative to the plugins
    564  *                       directory.
    565  * @return array|false Array of error information as it was returned by
    566  *                     `error_get_last()`, or false if none was recorded.
    567  */
    568 function wp_get_plugin_error( $plugin ) {
    569     if ( ! isset( $GLOBALS['_paused_plugins'] ) ) {
    570         return false;
    571     }
    572 
    573     list( $plugin ) = explode( '/', $plugin );
    574 
    575     if ( ! array_key_exists( $plugin, $GLOBALS['_paused_plugins'] ) ) {
    576         return false;
    577     }
    578 
    579     return $GLOBALS['_paused_plugins'][ $plugin ];
    580 }
    581 
    582 /**
    583  * Gets the number of sites on which a specific plugin is paused.
    584  *
    585  * @since 5.1.0
    586  *
    587  * @param string $plugin Path to the plugin file relative to the plugins directory.
    588  * @return int Site count.
    589  */
    590 function count_paused_plugin_sites_for_network( $plugin ) {
    591     if ( ! is_multisite() ) {
    592         return is_plugin_paused( $plugin ) ? 1 : 0;
    593     }
    594 
    595     list( $plugin ) = explode( '/', $plugin );
    596 
    597     $query_args = array(
    598         'count'      => true,
    599         'number'     => 0,
    600         'network_id' => get_current_network_id(),
    601         'meta_query' => array(
    602             wp_paused_plugins()->get_site_meta_query_clause( $plugin ),
    603         ),
    604     );
    605 
    606     return get_sites( $query_args );
    607527}
    608528
     
    802722        if ( ! is_plugin_active( $plugin ) ) {
    803723            continue;
    804         }
    805 
    806         // Clean up the database before deactivating the plugin.
    807         if ( is_plugin_paused( $plugin ) ) {
    808             resume_plugin( $plugin );
    809724        }
    810725
     
    1003918        }
    1004919
    1005         // Clean up the database before removing the plugin.
    1006         if ( is_plugin_paused( $plugin_file ) ) {
    1007             resume_plugin( $plugin_file );
    1008         }
    1009 
    1010920        /**
    1011921         * Fires immediately before a plugin deletion attempt.
     
    1080990
    1081991        return new WP_Error( 'could_not_remove_plugin', sprintf( $message, implode( ', ', $errors ) ) );
    1082     }
    1083 
    1084     return true;
    1085 }
    1086 
    1087 /**
    1088  * Tries to resume a single plugin.
    1089  *
    1090  * If a redirect was provided, we first ensure the plugin does not throw fatal
    1091  * errors anymore.
    1092  *
    1093  * The way it works is by setting the redirection to the error before trying to
    1094  * include the plugin file. If the plugin fails, then the redirection will not
    1095  * be overwritten with the success message and the plugin will not be resumed.
    1096  *
    1097  * @since 5.1.0
    1098  *
    1099  * @param string $plugin       Single plugin to resume.
    1100  * @param string $redirect     Optional. URL to redirect to. Default empty string.
    1101  * @param bool   $network_wide Optional. Whether to resume the plugin for the entire
    1102  *                             network. Default false.
    1103  * @return bool|WP_Error True on success, false if `$plugin` was not paused,
    1104  *                       `WP_Error` on failure.
    1105  */
    1106 function resume_plugin( $plugin, $redirect = '', $network_wide = false ) {
    1107     /*
    1108      * We'll override this later if the plugin could be included without
    1109      * creating a fatal error.
    1110      */
    1111     if ( ! empty( $redirect ) ) {
    1112         wp_redirect(
    1113             add_query_arg(
    1114                 '_error_nonce',
    1115                 wp_create_nonce( 'plugin-resume-error_' . $plugin ),
    1116                 $redirect
    1117             )
    1118         );
    1119 
    1120         // Load the plugin to test whether it throws a fatal error.
    1121         ob_start();
    1122         plugin_sandbox_scrape( $plugin );
    1123         ob_clean();
    1124     }
    1125 
    1126     $result = wp_forget_extension_error( 'plugins', $plugin, $network_wide );
    1127 
    1128     if ( ! $result ) {
    1129         return new WP_Error(
    1130             'could_not_resume_plugin',
    1131             __( 'Could not resume the plugin.' )
    1132         );
    1133992    }
    1134993
     
    22432102    WP_Privacy_Policy_Content::add( $plugin_name, $policy_text );
    22442103}
    2245 
    2246 /**
    2247  * Renders an admin notice in case some plugins have been paused due to errors.
    2248  *
    2249  * @since 5.1.0
    2250  */
    2251 function paused_plugins_notice() {
    2252     if ( 'plugins.php' === $GLOBALS['pagenow'] ) {
    2253         return;
    2254     }
    2255 
    2256     if ( ! current_user_can( 'deactivate_plugins' ) ) {
    2257         return;
    2258     }
    2259 
    2260     if ( ! isset( $GLOBALS['_paused_plugins'] ) || empty( $GLOBALS['_paused_plugins'] ) ) {
    2261         return;
    2262     }
    2263 
    2264     printf(
    2265         '<div class="notice notice-error"><p><strong>%s</strong><br>%s</p><p>%s</p></div>',
    2266         __( 'One or more plugins failed to load properly.' ),
    2267         __( 'You can find more details and make changes on the Plugins screen.' ),
    2268         sprintf(
    2269             '<a href="%s">%s</a>',
    2270             admin_url( 'plugins.php?plugin_status=paused' ),
    2271             'Go to the Plugins screen'
    2272         )
    2273     );
    2274 }
  • trunk/src/wp-admin/includes/theme.php

    r44675 r44717  
    769769    <?php
    770770}
    771 
    772 /**
    773  * Determines whether a theme is technically active but was paused while
    774  * loading.
    775  *
    776  * For more information on this and similar theme functions, check out
    777  * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
    778  * Conditional Tags} article in the Theme Developer Handbook.
    779  *
    780  * @since 5.1.0
    781  *
    782  * @param string $theme Path to the theme directory relative to the themes directory.
    783  * @return bool True, if in the list of paused themes. False, not in the list.
    784  */
    785 function is_theme_paused( $theme ) {
    786     if ( ! isset( $GLOBALS['_paused_themes'] ) ) {
    787         return false;
    788     }
    789 
    790     if ( $theme !== get_stylesheet() && $theme !== get_template() ) {
    791         return false;
    792     }
    793 
    794     return array_key_exists( $theme, $GLOBALS['_paused_themes'] );
    795 }
    796 
    797 /**
    798  * Gets the error that was recorded for a paused theme.
    799  *
    800  * @since 5.1.0
    801  *
    802  * @param string $theme Path to the theme directory relative to the themes
    803  *                      directory.
    804  * @return array|false Array of error information as it was returned by
    805  *                     `error_get_last()`, or false if none was recorded.
    806  */
    807 function wp_get_theme_error( $theme ) {
    808     if ( ! isset( $GLOBALS['_paused_themes'] ) ) {
    809         return false;
    810     }
    811 
    812     if ( ! array_key_exists( $theme, $GLOBALS['_paused_themes'] ) ) {
    813         return false;
    814     }
    815 
    816     return $GLOBALS['_paused_themes'][ $theme ];
    817 }
    818 
    819 /**
    820  * Gets the number of sites on which a specific theme is paused.
    821  *
    822  * @since 5.1.0
    823  *
    824  * @param string $theme Path to the theme directory relative to the themes directory.
    825  * @return int Site count.
    826  */
    827 function count_paused_theme_sites_for_network( $theme ) {
    828     if ( ! is_multisite() ) {
    829         return is_theme_paused( $theme ) ? 1 : 0;
    830     }
    831 
    832     $query_args = array(
    833         'count'      => true,
    834         'number'     => 0,
    835         'network_id' => get_current_network_id(),
    836         'meta_query' => array(
    837             wp_paused_themes()->get_site_meta_query_clause( $theme ),
    838         ),
    839     );
    840 
    841     return get_sites( $query_args );
    842 }
    843 
    844 /**
    845  * Tries to resume a single theme.
    846  *
    847  * @since 5.1.0
    848  *
    849  * @param string $theme Single theme to resume.
    850  * @return bool|WP_Error True on success, false if `$theme` was not paused,
    851  *                       `WP_Error` on failure.
    852  */
    853 function resume_theme( $theme ) {
    854     $result = wp_forget_extension_error( 'themes', $theme );
    855 
    856     if ( ! $result ) {
    857         return new WP_Error(
    858             'could_not_resume_theme',
    859             __( 'Could not resume the theme.' )
    860         );
    861     }
    862 
    863     return true;
    864 }
    865 
    866 /**
    867  * Renders an admin notice in case some themes have been paused due to errors.
    868  *
    869  * @since 5.1.0
    870  */
    871 function paused_themes_notice() {
    872     if ( 'themes.php' === $GLOBALS['pagenow'] ) {
    873         return;
    874     }
    875 
    876     if ( ! current_user_can( 'switch_themes' ) ) {
    877         return;
    878     }
    879 
    880     if ( ! isset( $GLOBALS['_paused_themes'] ) || empty( $GLOBALS['_paused_themes'] ) ) {
    881         return;
    882     }
    883 
    884     printf(
    885         '<div class="notice notice-error"><p><strong>%s</strong><br>%s</p><p>%s</p></div>',
    886         __( 'One or more themes failed to load properly.' ),
    887         __( 'You can find more details and make changes on the Themes screen.' ),
    888         sprintf(
    889             '<a href="%s">%s</a>',
    890             admin_url( 'themes.php' ),
    891             'Go to the Themes screen'
    892         )
    893     );
    894 }
  • trunk/src/wp-admin/plugins.php

    r44524 r44717  
    390390            break;
    391391
    392         case 'resume':
    393             if ( ! current_user_can( 'resume_plugin', $plugin ) ) {
    394                 wp_die( __( 'Sorry, you are not allowed to resume this plugin.' ) );
    395             }
    396 
    397             if ( is_multisite() && ! is_network_admin() && is_network_only_plugin( $plugin ) ) {
    398                 wp_redirect( self_admin_url( "plugins.php?plugin_status=$status&paged=$page&s=$s" ) );
    399                 exit;
    400             }
    401 
    402             check_admin_referer( 'resume-plugin_' . $plugin );
    403 
    404             $result = resume_plugin( $plugin, self_admin_url( 'plugins.php?error=resuming' ), is_network_admin() );
    405 
    406             if ( is_wp_error( $result ) ) {
    407                 wp_die( $result );
    408             }
    409 
    410             wp_redirect( self_admin_url( "plugins.php?resume=true&plugin_status=$status&paged=$page&s=$s" ) );
    411             exit;
    412 
    413392        default:
    414393            if ( isset( $_POST['checked'] ) ) {
     
    510489        );
    511490        $errmsg .= ' ' . __( 'If you notice &#8220;headers already sent&#8221; messages, problems with syndication feeds or other issues, try deactivating or removing this plugin.' );
    512     } elseif ( 'resuming' === $_GET['error'] ) {
    513         $errmsg = __( 'Plugin could not be resumed because it triggered a <strong>fatal error</strong>.' );
    514491    } else {
    515492        $errmsg = __( 'Plugin could not be activated because it triggered a <strong>fatal error</strong>.' );
     
    565542<?php elseif ( 'update-selected' == $action ) : ?>
    566543    <div id="message" class="updated notice is-dismissible"><p><?php _e( 'All selected plugins are up to date.' ); ?></p></div>
    567 <?php elseif ( isset( $_GET['resume'] ) ) : ?>
    568     <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Plugin <strong>resumed</strong>.' ); ?></p></div>
    569544<?php endif; ?>
    570545
  • trunk/src/wp-admin/themes.php

    r44524 r44717  
    3333        switch_theme( $theme->get_stylesheet() );
    3434        wp_redirect( admin_url( 'themes.php?activated=true' ) );
    35         exit;
    36     } elseif ( 'resume' === $_GET['action'] ) {
    37         check_admin_referer( 'resume-theme_' . $_GET['stylesheet'] );
    38         $theme = wp_get_theme( $_GET['stylesheet'] );
    39 
    40         if ( ! current_user_can( 'resume_themes' ) ) {
    41             wp_die(
    42                 '<h1>' . __( 'You need a higher level of permission.' ) . '</h1>' .
    43                 '<p>' . __( 'Sorry, you are not allowed to resume this theme.' ) . '</p>',
    44                 403
    45             );
    46         }
    47 
    48         $result = resume_theme( $theme->get_stylesheet() );
    49 
    50         if ( is_wp_error( $result ) ) {
    51             wp_die( $result );
    52         }
    53 
    54         wp_redirect( admin_url( 'themes.php?resumed=true' ) );
    5535        exit;
    5636    } elseif ( 'delete' == $_GET['action'] ) {
     
    216196    <div id="message4" class="error"><p><?php _e( 'You cannot delete a theme while it has an active child theme.' ); ?></p></div>
    217197    <?php
    218 } elseif ( isset( $_GET['resumed'] ) ) {
    219     ?>
    220     <div id="message5" class="updated notice is-dismissible"><p><?php _e( 'Theme resumed.' ); ?></p></div>
    221     <?php
    222198}
    223199
     
    373349
    374350    <?php
    375     $can_resume  = current_user_can( 'resume_themes' );
    376351    $can_delete  = current_user_can( 'delete_themes' );
    377352    $can_install = current_user_can( 'install_themes' );
     
    381356        <th><?php _ex( 'Name', 'theme name' ); ?></th>
    382357        <th><?php _e( 'Description' ); ?></th>
    383         <?php if ( $can_resume ) { ?>
    384             <td></td>
    385         <?php } ?>
    386358        <?php if ( $can_delete ) { ?>
    387359            <td></td>
     
    396368            <td><?php echo $broken_theme->errors()->get_error_message(); ?></td>
    397369            <?php
    398             if ( $can_resume ) {
    399                 if ( 'theme_paused' === $broken_theme->errors()->get_error_code() ) {
    400                     $stylesheet = $broken_theme->get_stylesheet();
    401                     $resume_url = add_query_arg(
    402                         array(
    403                             'action'     => 'resume',
    404                             'stylesheet' => urlencode( $stylesheet ),
    405                         ),
    406                         admin_url( 'themes.php' )
    407                     );
    408                     $resume_url = wp_nonce_url( $resume_url, 'resume-theme_' . $stylesheet );
    409                     ?>
    410                     <td><a href="<?php echo esc_url( $resume_url ); ?>" class="button resume-theme"><?php _e( 'Resume' ); ?></a></td>
    411                     <?php
    412                 } else {
    413                     ?>
    414                     <td></td>
    415                     <?php
    416                 }
    417             }
    418 
    419370            if ( $can_delete ) {
    420371                $stylesheet = $broken_theme->get_stylesheet();
  • trunk/src/wp-includes/capabilities.php

    r44524 r44717  
    465465            }
    466466            break;
    467         case 'resume_plugin':
    468             // Even in a multisite, regular administrators should be able to resume a plugin.
    469             $caps[] = 'activate_plugins';
    470             break;
    471         case 'resume_themes':
    472             // Even in a multisite, regular administrators should be able to resume a theme.
    473             $caps[] = 'switch_themes';
    474             break;
    475467        case 'delete_user':
    476468        case 'delete_users':
  • trunk/src/wp-includes/class-wp-theme.php

    r44562 r44717  
    370370            // Set the parent. Pass the current instance so we can do the crazy checks above and assess errors.
    371371            $this->parent = new WP_Theme( $this->template, isset( $theme_root_template ) ? $theme_root_template : $this->theme_root, $this );
    372         }
    373 
    374         if ( wp_paused_themes()->get( $this->stylesheet ) && ( ! is_wp_error( $this->errors ) || ! isset( $this->errors->errors['theme_paused'] ) ) ) {
    375             $this->errors = new WP_Error( 'theme_paused', __( 'This theme failed to load properly and was paused within the admin backend.' ) );
    376372        }
    377373
  • trunk/src/wp-includes/load.php

    r44566 r44717  
    698698    }
    699699
    700     /*
    701      * Remove plugins from the list of active plugins when we're on an endpoint
    702      * that should be protected against WSODs and the plugin is paused.
    703      */
    704     if ( is_protected_endpoint() ) {
    705         $plugins = wp_skip_paused_plugins( $plugins );
    706     }
    707 
    708     return $plugins;
    709 }
    710 
    711 /**
    712  * Filters a given list of plugins, removing any paused plugins from it.
    713  *
    714  * @since 5.1.0
    715  *
    716  * @param array $plugins List of absolute plugin main file paths.
    717  * @return array Filtered value of $plugins, without any paused plugins.
    718  */
    719 function wp_skip_paused_plugins( array $plugins ) {
    720     $paused_plugins = wp_paused_plugins()->get_all();
    721 
    722     if ( empty( $paused_plugins ) ) {
    723         return $plugins;
    724     }
    725 
    726     foreach ( $plugins as $index => $plugin ) {
    727         list( $plugin ) = explode( '/', plugin_basename( $plugin ) );
    728 
    729         if ( array_key_exists( $plugin, $paused_plugins ) ) {
    730             unset( $plugins[ $index ] );
    731 
    732             // Store list of paused plugins for displaying an admin notice.
    733             $GLOBALS['_paused_plugins'][ $plugin ] = $paused_plugins[ $plugin ];
    734         }
    735     }
    736 
    737700    return $plugins;
    738701}
     
    762725
    763726    $themes[] = TEMPLATEPATH;
    764 
    765     /*
    766      * Remove themes from the list of active themes when we're on an endpoint
    767      * that should be protected against WSODs and the theme is paused.
    768      */
    769     if ( is_protected_endpoint() ) {
    770         $themes = wp_skip_paused_themes( $themes );
    771 
    772         // If no active and valid themes exist, skip loading themes.
    773         if ( empty( $themes ) ) {
    774             add_filter( 'wp_using_themes', '__return_false' );
    775         }
    776     }
    777 
    778     return $themes;
    779 }
    780 
    781 /**
    782  * Filters a given list of themes, removing any paused themes from it.
    783  *
    784  * @since 5.1.0
    785  *
    786  * @param array $themes List of absolute theme directory paths.
    787  * @return array Filtered value of $themes, without any paused themes.
    788  */
    789 function wp_skip_paused_themes( array $themes ) {
    790     $paused_themes = wp_paused_themes()->get_all();
    791 
    792     if ( empty( $paused_themes ) ) {
    793         return $themes;
    794     }
    795 
    796     foreach ( $themes as $index => $theme ) {
    797         $theme = basename( $theme );
    798 
    799         if ( array_key_exists( $theme, $paused_themes ) ) {
    800             unset( $themes[ $index ] );
    801 
    802             // Store list of paused themes for displaying an admin notice.
    803             $GLOBALS['_paused_themes'][ $theme ] = $paused_themes[ $theme ];
    804         }
    805     }
    806727
    807728    return $themes;
     
    12911212
    12921213/**
    1293  * Determines whether we are currently on an endpoint that should be protected against WSODs.
    1294  *
    1295  * @since 5.1.0
    1296  *
    1297  * @return bool True if the current endpoint should be protected.
    1298  */
    1299 function is_protected_endpoint() {
    1300     // Protect login pages.
    1301     if ( isset( $GLOBALS['pagenow'] ) && 'wp-login.php' === $GLOBALS['pagenow'] ) {
    1302         return true;
    1303     }
    1304 
    1305     // Protect the admin backend.
    1306     if ( is_admin() && ! wp_doing_ajax() ) {
    1307         return true;
    1308     }
    1309 
    1310     // Protect AJAX actions that could help resolve a fatal error should be available.
    1311     if ( is_protected_ajax_action() ) {
    1312         return true;
    1313     }
    1314 
    1315     /**
    1316      * Filters whether the current request is against a protected endpoint.
    1317      *
    1318      * This filter is only fired when an endpoint is requested which is not already protected by
    1319      * WordPress core. As such, it exclusively allows providing further protected endpoints in
    1320      * addition to the admin backend, login pages and protected AJAX actions.
    1321      *
    1322      * @since 5.1.0
    1323      *
    1324      * @param bool $is_protected_endpoint Whether the currently requested endpoint is protected. Default false.
    1325      */
    1326     return (bool) apply_filters( 'is_protected_endpoint', false );
    1327 }
    1328 
    1329 /**
    1330  * Determines whether we are currently handling an AJAX action that should be protected against WSODs.
    1331  *
    1332  * @since 5.1.0
    1333  *
    1334  * @return bool True if the current AJAX action should be protected.
    1335  */
    1336 function is_protected_ajax_action() {
    1337     if ( ! wp_doing_ajax() ) {
    1338         return false;
    1339     }
    1340 
    1341     if ( ! isset( $_REQUEST['action'] ) ) {
    1342         return false;
    1343     }
    1344 
    1345     $actions_to_protect = array(
    1346         'edit-theme-plugin-file', // Saving changes in the core code editor.
    1347         'heartbeat',              // Keep the heart beating.
    1348         'install-plugin',         // Installing a new plugin.
    1349         'install-theme',          // Installing a new theme.
    1350         'search-plugins',         // Searching in the list of plugins.
    1351         'search-install-plugins', // Searching for a plugin in the plugin install screen.
    1352         'update-plugin',          // Update an existing plugin.
    1353         'update-theme',           // Update an existing theme.
    1354     );
    1355 
    1356     /**
    1357      * Filters the array of protected AJAX actions.
    1358      *
    1359      * This filter is only fired when doing AJAX and the AJAX request has an 'action' property.
    1360      *
    1361      * @since 5.1.0
    1362      *
    1363      * @param array $actions_to_protect Array of strings with AJAX actions to protect.
    1364      */
    1365     $actions_to_protect = (array) apply_filters( 'wp_protected_ajax_actions', $actions_to_protect );
    1366 
    1367     if ( ! in_array( $_REQUEST['action'], $actions_to_protect, true ) ) {
    1368         return false;
    1369     }
    1370 
    1371     return true;
    1372 }
    1373 
    1374 /**
    13751214 * Determines whether the current request is a WordPress cron request.
    13761215 *
  • trunk/src/wp-includes/ms-load.php

    r44524 r44717  
    5252            $plugins[] = WP_PLUGIN_DIR . '/' . $plugin;
    5353        }
    54     }
    55 
    56     /*
    57      * Remove plugins from the list of active plugins when we're on an endpoint
    58      * that should be protected against WSODs and the plugin is paused.
    59      */
    60     if ( is_protected_endpoint() ) {
    61         $plugins = wp_skip_paused_plugins( $plugins );
    6254    }
    6355
  • trunk/src/wp-settings.php

    r44692 r44717  
    1818// Include files required for initialization.
    1919require( ABSPATH . WPINC . '/load.php' );
    20 require( ABSPATH . WPINC . '/class-wp-paused-extensions-storage.php' );
    21 require( ABSPATH . WPINC . '/class-wp-fatal-error-handler.php' );
    22 require( ABSPATH . WPINC . '/error-protection.php' );
    2320require( ABSPATH . WPINC . '/default-constants.php' );
    2421require_once( ABSPATH . WPINC . '/plugin.php' );
    25 
    26 // Make sure we register the shutdown handler for fatal errors as soon as possible.
    27 wp_register_fatal_error_handler();
    2822
    2923/*
     
    531525 */
    532526do_action( 'wp_loaded' );
    533 
    534 /*
    535  * Store the fact that we could successfully execute the entire WordPress
    536  * lifecycle. This is used to skip the premature shutdown handler, as it cannot
    537  * be unregistered.
    538  */
    539 if ( ! defined( 'WP_EXECUTION_SUCCEEDED' ) ) {
    540     define( 'WP_EXECUTION_SUCCEEDED', true );
    541 }
  • trunk/tests/phpunit/tests/user/capabilities.php

    r44525 r44717  
    258258            'erase_others_personal_data'  => array( 'administrator' ),
    259259            'manage_privacy_options'      => array( 'administrator' ),
    260             'resume_themes'               => array( 'administrator' ),
    261260
    262261            'edit_categories'             => array( 'administrator', 'editor' ),
     
    298297            'delete_site'                 => array( 'administrator' ),
    299298            'add_users'                   => array( 'administrator' ),
    300             'resume_themes'               => array( 'administrator' ),
    301299
    302300            'edit_categories'             => array( 'administrator', 'editor' ),
     
    457455            $expected['activate_plugin'],
    458456            $expected['deactivate_plugin'],
    459             $expected['resume_plugin'],
    460457            $expected['remove_user'],
    461458            $expected['promote_user'],
Note: See TracChangeset for help on using the changeset viewer.