Make WordPress Core

Ticket #44458: 44458.diff

File 44458.diff, 23.4 KB (added by flixos90, 7 years ago)
  • src/wp-admin/css/list-tables.css

     
    13011301        text-decoration: underline;
    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
    13041329.plugin-card .update-now:before {
    13051330        color: #f56e28;
    13061331        content: "\f463";
  • src/wp-admin/includes/admin-filters.php

     
    119119add_action( 'load-themes.php', 'wp_theme_update_rows', 20 ); // After wp_update_themes() is called.
    120120
    121121add_action( 'admin_notices', 'update_nag', 3 );
     122add_action( 'admin_notices', 'paused_plugins_notice', 5 );
    122123add_action( 'admin_notices', 'maintenance_nag', 10 );
    123124
    124125add_filter( 'update_footer', 'core_update_footer' );
  • src/wp-admin/includes/class-wp-plugins-list-table.php

     
    4040                );
    4141
    4242                $status = 'all';
    43                 if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], array( 'active', 'inactive', 'recently_activated', 'upgrade', 'mustuse', 'dropins', 'search' ) ) ) {
     43                if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], array( 'active', 'inactive', 'recently_activated', 'upgrade', 'mustuse', 'dropins', 'search', 'paused' ) ) ) {
    4444                        $status = $_REQUEST['plugin_status'];
    4545                }
    4646
     
    9999                        'upgrade'            => array(),
    100100                        'mustuse'            => array(),
    101101                        'dropins'            => array(),
     102                        'paused'             => array(),
    102103                );
    103104
    104105                $screen = $this->screen;
     
    209210                                if ( $show_network_active ) {
    210211                                        // On the non-network screen, show network-active plugins if allowed
    211212                                        $plugins['active'][ $plugin_file ] = $plugin_data;
     213                                        if ( is_plugin_paused( $plugin_file ) ) {
     214                                                $plugins['paused'][ $plugin_file ] = $plugin_data;
     215                                        }
    212216                                } else {
    213217                                        // On the non-network screen, filter out network-active plugins
    214218                                        unset( $plugins['all'][ $plugin_file ] );
     
    218222                                // On the non-network screen, populate the active list with plugins that are individually activated
    219223                                // On the network-admin screen, populate the active list with plugins that are network activated
    220224                                $plugins['active'][ $plugin_file ] = $plugin_data;
     225                                if ( is_plugin_paused( $plugin_file ) ) {
     226                                        $plugins['paused'][ $plugin_file ] = $plugin_data;
     227                                }
    221228                        } else {
    222229                                if ( isset( $recently_activated[ $plugin_file ] ) ) {
    223230                                        // Populate the recently activated list with plugins that have been recently activated
     
    436443                                case 'dropins':
    437444                                        $text = _n( 'Drop-ins <span class="count">(%s)</span>', 'Drop-ins <span class="count">(%s)</span>', $count );
    438445                                        break;
     446                                case 'paused':
     447                                        $text = _n( 'Paused <span class="count">(%s)</span>', 'Paused <span class="count">(%s)</span>', $count );
     448                                        break;
    439449                                case 'upgrade':
    440450                                        $text = _n( 'Update Available <span class="count">(%s)</span>', 'Update Available <span class="count">(%s)</span>', $count );
    441451                                        break;
     
    647657                                                /* translators: %s: plugin name */
    648658                                                $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>';
    649659                                        }
     660                                        if ( current_user_can( 'resume_plugin' ) && is_plugin_paused( $plugin_file ) ) {
     661                                                /* translators: %s: plugin name */
     662                                                $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 execution of %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Resume execution' ) . '</a>';
     663                                        }
    650664                                } else {
    651665                                        if ( current_user_can( 'activate_plugin', $plugin_file ) ) {
    652666                                                /* translators: %s: plugin name */
     
    753767                        $class .= ' update';
    754768                }
    755769
     770                $paused = is_plugin_paused( $plugin_file );
     771                if ( $paused ) {
     772                        $class .= ' paused';
     773                }
     774
    756775                $plugin_slug = isset( $plugin_data['slug'] ) ? $plugin_data['slug'] : sanitize_title( $plugin_name );
    757776                printf(
    758777                        '<tr class="%s" data-slug="%s" data-plugin="%s">',
     
    831850                                         * @param array    $plugin_data An array of plugin data.
    832851                                         * @param string   $status      Status of the plugin. Defaults are 'All', 'Active',
    833852                                         *                              'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
    834                                          *                              'Drop-ins', 'Search'.
     853                                         *                              'Drop-ins', 'Search', 'Paused'
    835854                                         */
    836855                                        $plugin_meta = apply_filters( 'plugin_row_meta', $plugin_meta, $plugin_file, $plugin_data, $status );
    837856                                        echo implode( ' | ', $plugin_meta );
    838857
    839                                         echo '</div></td>';
     858                                        echo '</div>';
     859
     860                                        if ( $paused ) {
     861                                                echo sprintf(
     862                                                        '<p><span class="dashicons dashicons-warning"></span> <strong>%s</strong></p>',
     863                                                        __( 'This plugin failed to load properly and was paused within the admin backend.' )
     864                                                );
     865
     866                                                $error = wp_get_plugin_error( $plugin_file );
     867
     868                                                if ( false !== $error ) {
     869                                                        $constants     = get_defined_constants( true );
     870                                                        $core_errors   = array_flip(
     871                                                                array_slice( $constants['Core'], 1, 15, true )
     872                                                        );
     873                                                        $error['type'] = $core_errors[ $error['type'] ];
     874
     875                                                        echo sprintf(
     876                                                                '<div class="error-display"><p>%s</p></div>',
     877                                                                sprintf(
     878                                                                        __( 'The plugin caused an error of type %1$s in line %2$s of the file %3$s. Error message: %4$s' ),
     879                                                                        "<code>{$error['type']}</code>",
     880                                                                        "<code>{$error['line']}</code>",
     881                                                                        "<code>{$error['file']}</code>",
     882                                                                        "<code>{$error['message']}</code>"
     883                                                                )
     884                                                        );
     885                                                }
     886                                        }
     887
     888
     889                                        echo '</td>';
    840890                                        break;
    841891                                default:
    842892                                        $classes = "$column_name column-$column_name $class";
     
    869919                 * @param array  $plugin_data An array of plugin data.
    870920                 * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
    871921                 *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
    872                  *                            'Drop-ins', 'Search'.
     922                 *                            'Drop-ins', 'Search', 'Paused'.
    873923                 */
    874924                do_action( 'after_plugin_row', $plugin_file, $plugin_data, $status );
    875925
     
    885935                 * @param array  $plugin_data An array of plugin data.
    886936                 * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
    887937                 *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
    888                  *                            'Drop-ins', 'Search'.
     938                 *                            'Drop-ins', 'Search', 'Paused'
    889939                 */
    890940                do_action( "after_plugin_row_{$plugin_file}", $plugin_file, $plugin_data, $status );
    891941        }
  • src/wp-admin/includes/plugin.php

     
    444444                'install.php'        => array( __( 'Custom installation script.' ), true ), // auto on installation
    445445                'maintenance.php'    => array( __( 'Custom maintenance message.' ), true ), // auto on maintenance
    446446                'object-cache.php'   => array( __( 'External object cache.' ), true ), // auto on load
     447                'php-error.php'      => array( __( 'Custom PHP error message.' ), true ), // auto on error
     448                'shutdown-handler'   => array( __( 'Custom PHP shutdown handler.' ), true ), // auto on error
    447449        );
    448450
    449451        if ( is_multisite() ) {
     
    497499}
    498500
    499501/**
     502 * Determines whether a plugin is technically active but was paused while
     503 * loading.
     504 *
     505 * For more information on this and similar theme functions, check out
     506 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
     507 * Conditional Tags} article in the Theme Developer Handbook.
     508 *
     509 * @since 5.0.0
     510 *
     511 * @param string $plugin Path to the plugin file relative to the plugins directory.
     512 * @return bool True, if in the active plugins list. False, not in the list.
     513 */
     514function is_plugin_paused( $plugin ) {
     515        if ( ! isset( $GLOBALS['_paused_plugins'] ) ) {
     516                return false;
     517        }
     518
     519        if ( ! is_plugin_active( $plugin ) || is_plugin_active_for_network( $plugin ) ) {
     520                return false;
     521        }
     522
     523        list( $plugin ) = explode( '/', $plugin );
     524
     525        return array_key_exists( $plugin, $GLOBALS['_paused_plugins'] );
     526}
     527
     528/**
     529 * Gets the error that was recorded for a paused plugin.
     530 *
     531 * @since 5.0.0
     532 *
     533 * @param string $plugin Path to the plugin file relative to the plugins
     534 *                       directory.
     535 * @return array|false Array of error information as it was returned by
     536 *                     `error_get_last()`, or false if none was recorded.
     537 */
     538function wp_get_plugin_error( $plugin ) {
     539        if ( ! isset( $GLOBALS['_paused_plugins'] ) ) {
     540                return false;
     541        }
     542
     543        list( $plugin ) = explode( '/', $plugin );
     544
     545        if ( ! array_key_exists( $plugin, $GLOBALS['_paused_plugins'] ) ) {
     546                return false;
     547        }
     548
     549        return $GLOBALS['_paused_plugins'][ $plugin ];
     550}
     551
     552/**
    500553 * Determines whether the plugin is active for the entire network.
    501554 *
    502555 * Only plugins installed in the plugins/ folder can be active.
     
    693746                        continue;
    694747                }
    695748
     749                // Clean up the database before deactivating the plugin.
     750                if ( is_plugin_paused( $plugin ) ) {
     751                        resume_plugin( $plugin );
     752                }
     753
    696754                $network_deactivating = false !== $network_wide && is_plugin_active_for_network( $plugin );
    697755
    698756                if ( ! $silent ) {
     
    887945                        uninstall_plugin( $plugin_file );
    888946                }
    889947
     948                // Clean up the database before removing the plugin.
     949                if ( is_plugin_paused( $plugin_file ) ) {
     950                        resume_plugin( $plugin_file );
     951                }
     952
    890953                /**
    891954                 * Fires immediately before a plugin deletion attempt.
    892955                 *
     
    9601023}
    9611024
    9621025/**
     1026 * Resumes a single plugin.
     1027 *
     1028 * Resuming the plugin basically means removing its entry from the
     1029 * `pause_on_admin` database option.
     1030 *
     1031 * @since 5.0.0
     1032 *
     1033 * @param string $plugin Single plugin to resume.
     1034 *
     1035 * @return bool|WP_Error True on success, false if `$plugin` was not paused, `WP_Error` on failure.
     1036 */
     1037function resume_plugin( $plugin ) {
     1038        $result = wp_forget_extension_error( 'plugins', $plugin );
     1039
     1040        if ( ! $result ) {
     1041                return new WP_Error( 'could_not_resume_plugin', __( 'Could not resume execution of the plugin.' ) );
     1042        }
     1043
     1044        return true;
     1045}
     1046
     1047/**
    9631048 * Validate active plugins
    9641049 *
    9651050 * Validate all active plugins, deactivates invalid and
     
    20662151
    20672152        WP_Privacy_Policy_Content::add( $plugin_name, $policy_text );
    20682153}
     2154
     2155/**
     2156 * Renders an admin notice in case some plugins have been paused due to errors.
     2157 *
     2158 * @since 5.0.0
     2159 *
     2160 * @return void
     2161 */
     2162function paused_plugins_notice() {
     2163        if ( 'plugins.php' === $GLOBALS['pagenow'] ) {
     2164                return;
     2165        }
     2166
     2167        if ( ! current_user_can( 'deactivate_plugins' ) ) {
     2168                return;
     2169        }
     2170
     2171        if ( ! isset( $GLOBALS['_paused_plugins'] ) || empty( $GLOBALS['_paused_plugins'] ) ) {
     2172                return;
     2173        }
     2174
     2175        echo sprintf(
     2176                '<div class="notice notice-error"><p><strong>%s</strong><br>%s</p><p>%s</p></div>',
     2177                __( 'One or more plugins failed to load properly.' ),
     2178                __( 'You can find more details and make changes on the Plugins screen.' ),
     2179                sprintf(
     2180                        '<a href="%s">%s</a>',
     2181                        admin_url( 'plugins.php?plugin_status=paused' ),
     2182                        'Go to the Plugins screen'
     2183                )
     2184        );
     2185}
  • src/wp-admin/plugins.php

     
    389389                        }
    390390                        break;
    391391
     392                case 'resume':
     393                        if ( ! current_user_can( 'resume_plugin', $plugin ) ) {
     394                                wp_die( __( 'Sorry, you are not allowed to resume execution of 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 );
     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
    392413                default:
    393414                        if ( isset( $_POST['checked'] ) ) {
    394415                                check_admin_referer( 'bulk-plugins' );
     
    532553        <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Selected plugins <strong>deactivated</strong>.' ); ?></p></div>
    533554<?php elseif ( 'update-selected' == $action ) : ?>
    534555        <div id="message" class="updated notice is-dismissible"><p><?php _e( 'All selected plugins are up to date.' ); ?></p></div>
     556<?php elseif ( isset( $_GET['resume'] ) ) : ?>
     557        <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Execution of plugin <strong>resumed</strong>.' ); ?></p></div>
    535558<?php endif; ?>
    536559
    537560<div class="wrap">
  • src/wp-content/plugins/hello.php

     
    2525While the band's playin'
    2626One of our old favorite songs from way back when
    2727So, take her wrap, fellas
    28 Dolly, never go away again 
     28Dolly, never go away again
    2929Hello, Dolly
    3030Well, hello, Dolly
    3131It's so nice to have you back where you belong
     
    6868        #dolly {
    6969                float: $x;
    7070                padding-$x: 15px;
    71                 padding-top: 5px;               
     71                padding-top: 5px;
    7272                margin: 0;
    7373                font-size: 11px;
    7474        }
  • src/wp-includes/capabilities.php

     
    455455                case 'deactivate_plugins':
    456456                case 'activate_plugin':
    457457                case 'deactivate_plugin':
     458                case 'resume_plugin':
    458459                        $caps[] = 'activate_plugins';
    459460                        if ( is_multisite() ) {
    460461                                // update_, install_, and delete_ are handled above with is_super_admin().
  • src/wp-includes/load.php

     
    687687                        $plugins[] = WP_PLUGIN_DIR . '/' . $plugin;
    688688                }
    689689        }
     690
     691        /*
     692         * Remove plugins from the list of active plugins when we're on an admin or
     693         * login screen and the plugin appears in the `pause_on_admin` list.
     694         */
     695        if ( 'wp-login.php' === $GLOBALS['pagenow']
     696             || ( is_admin() && ! wp_doing_ajax() ) ) {
     697                $pause_on_admin  = (array) get_option( 'pause_on_admin', array() );
     698
     699                if ( ! array_key_exists( 'plugins', $pause_on_admin ) ) {
     700                        return $plugins;
     701                }
     702
     703                foreach ( $plugins as $index => $plugin ) {
     704                        $parts = explode(
     705                                '/',
     706                                str_replace( WP_CONTENT_DIR . '/', '', $plugin )
     707                        );
     708
     709                        $type   = array_shift( $parts );
     710                        $plugin = array_shift( $parts );
     711
     712                        if ( array_key_exists( $plugin, $pause_on_admin[ $type ] ) ) {
     713                                unset( $plugins[ $index ] );
     714                                // Store list of paused plugins for displaying an admin notice.
     715                                $GLOBALS['_paused_plugins'][ $plugin ] = $pause_on_admin[ $type ][ $plugin ];
     716                        }
     717                }
     718        }
     719
    690720        return $plugins;
    691721}
    692722
     
    12501280        }
    12511281        echo "\n###### wp_scraping_result_end:$scrape_key ######\n";
    12521282}
     1283
     1284/**
     1285 * Prunes the array of recorded extension errors.
     1286 *
     1287 * @since 5.0.0
     1288 *
     1289 * @param array $errors Array of errors to prune.
     1290 * @return array Pruned array of errors.
     1291 */
     1292function wp_prune_extension_errors( $errors ) {
     1293        foreach( array( 'plugins', 'mu-plugins', 'themes' ) as $type ) {
     1294                if ( ! array_key_exists( $type, $errors ) ) {
     1295                        continue;
     1296                }
     1297
     1298                switch( $type ) {
     1299                        case 'plugins':
     1300                                $active_plugins = array_merge(
     1301                                        (array) get_option( 'active_plugins', array() ),
     1302                                        (array) get_option( 'active_sitewide_plugins', array() )
     1303                                );
     1304
     1305                                foreach( $errors[ $type ] as $plugin => $error ) {
     1306                                        $found = false;
     1307
     1308                                        foreach ( $active_plugins as $active_plugin ) {
     1309                                                list( $active_plugin ) = explode( '/', $active_plugin );
     1310
     1311                                                if ( $active_plugin === $plugin ) {
     1312                                                        $found = true;
     1313                                                        break;
     1314                                                }
     1315                                        }
     1316
     1317                                        if ( ! $found ) {
     1318                                                unset( $errors[ $type ][ $plugin ] );
     1319                                        }
     1320                                }
     1321
     1322                                break;
     1323                        case 'mu-plugins':
     1324                                // TODO: Implement MU-plugin-specific behavior.
     1325                                break;
     1326                        case 'themes':
     1327                                // TODO: Implement theme-specific behavior.
     1328                                break;
     1329                }
     1330
     1331                if ( 0 === count( $errors[ $type ] ) ) {
     1332                        unset( $errors[ $type ] );
     1333                }
     1334        }
     1335
     1336        return $errors;
     1337}
     1338
     1339/**
     1340 * Records the extension error as a database option.
     1341 *
     1342 * @since 5.0.0
     1343 *
     1344 * @global array $wp_theme_directories
     1345 *
     1346 * @param array $error Error that was triggered.
     1347 * @return bool Whether the error was correctly recorded.
     1348 */
     1349function wp_record_extension_error( $error ) {
     1350        global $wp_theme_directories;
     1351
     1352        $path = '';
     1353
     1354        switch ( true ) {
     1355                case 0 === strpos( $error['file'], WP_PLUGIN_DIR ):
     1356                        $type = 'plugins';
     1357                        $path = str_replace( WP_PLUGIN_DIR . '/', '', $error['file'] );
     1358                        break;
     1359                case 0 === strpos( $error['file'], WPMU_PLUGIN_DIR ):
     1360                        $type = 'mu-plugins';
     1361                        $path = str_replace( WPMU_PLUGIN_DIR . '/', '', $error['file'] );
     1362                        break;
     1363                default:
     1364                        foreach ( $wp_theme_directories as $theme_directory ) {
     1365                                if ( 0 === strpos( $error['file'], $theme_directory ) ) {
     1366                                        $type = 'themes';
     1367                                        $path = str_replace( $theme_directory . '/', '', $error['file'] );
     1368                                        break;
     1369                                }
     1370                        }
     1371
     1372        }
     1373
     1374        if ( empty( $type ) || empty( $path ) ) {
     1375                return false;
     1376        }
     1377
     1378        $parts     = explode( '/', $path );
     1379        $extension = array_shift( $parts );
     1380
     1381        $errors = (array) get_option( 'pause_on_admin', array() );
     1382
     1383        $modified_errors = $errors;
     1384
     1385        if ( ! array_key_exists( $type, $modified_errors ) ) {
     1386                $modified_errors[ $type ] = array();
     1387        }
     1388
     1389        $modified_errors[ $type ][ $extension ] = $error;
     1390
     1391        $modified_errors = wp_prune_extension_errors( $modified_errors );
     1392
     1393        if ( $modified_errors === $errors ) {
     1394                return true;
     1395        }
     1396
     1397        return update_option( 'pause_on_admin', $modified_errors );
     1398}
     1399
     1400/**
     1401 * Forgets a previously recorded extension error again.
     1402 *
     1403 * @since 5.0.0
     1404 *
     1405 * @param string $type Type of the extension.
     1406 * @param string $extension Relative path of the extension.
     1407 * @return bool Whether the extension error was successfully forgotten.
     1408 */
     1409function wp_forget_extension_error( $type, $extension ) {
     1410        $errors = (array) get_option( 'pause_on_admin', array() );
     1411
     1412        if ( ! array_key_exists( $type, $errors ) ) {
     1413                return false;
     1414        }
     1415
     1416        $modified_errors = $errors;
     1417
     1418        switch ( $type ) {
     1419                case 'plugins':
     1420                        list( $extension ) = explode( '/', $extension );
     1421        }
     1422
     1423        if ( array_key_exists( $extension, $modified_errors[ $type ] ) ) {
     1424                unset( $modified_errors[ $type ][ $extension ] );
     1425        }
     1426
     1427        $modified_errors = wp_prune_extension_errors( $modified_errors );
     1428
     1429        if ( $modified_errors === $errors ) {
     1430                return true;
     1431        }
     1432
     1433        return update_option( 'pause_on_admin', $modified_errors );
     1434}
     1435
     1436/**
     1437 * Wraps the shutdown handler function so it can be made pluggable at a later
     1438 * stage.
     1439 *
     1440 * @since 5.0.0
     1441 *
     1442 * @return void
     1443 */
     1444function wp_shutdown_handler_wrapper() {
     1445        if ( defined( 'WP_EXECUTION_SUCCEEDED' ) && WP_EXECUTION_SUCCEEDED ) {
     1446                return;
     1447        }
     1448
     1449        // Load the pluggable shutdown handler in case we found one.
     1450        if ( function_exists( 'wp_handle_shutdown' ) ) {
     1451                $stop_propagation = (bool) wp_handle_shutdown();
     1452
     1453                if ( $stop_propagation ) {
     1454                        return;
     1455                }
     1456        }
     1457
     1458        $error = error_get_last();
     1459
     1460        // No error, just skip the error handling code.
     1461        if ( null === $error ) {
     1462                return;
     1463        }
     1464
     1465        /*
     1466         * If the option API has not been loaded yet, we cannot persist our
     1467         * discovery, so there's no point in moving forward.
     1468         */
     1469        if ( ! function_exists( 'get_option' ) ) {
     1470                return;
     1471        }
     1472
     1473        // For now, we only trigger our safe mode on parse errors.
     1474        if ( ! isset( $error['type'] ) || E_PARSE !== $error['type'] ) {
     1475                return;
     1476        }
     1477
     1478        try {
     1479                wp_record_extension_error( $error );
     1480
     1481                // Load custom PHP error template, if present.
     1482                if ( is_readable( WP_CONTENT_DIR . '/php-error.php' ) ) {
     1483                        include WP_CONTENT_DIR . '/php-error.php';
     1484                        die();
     1485                }
     1486
     1487                $message = sprintf(
     1488                        '<p>%s</p>',
     1489                        __( 'The site is experiencing technical difficulties.' )
     1490                );
     1491
     1492                if ( function_exists( 'get_admin_url' ) ) {
     1493                        $url = get_admin_url();
     1494                        $message .= sprintf(
     1495                                '<hr><p><em>%s <a href="%s">%s</a></em></p>',
     1496                                __( 'Are you the site owner?' ),
     1497                                $url,
     1498                                __( 'Log into the admin backend to fix this.' )
     1499                        );
     1500                }
     1501
     1502                if ( function_exists( 'apply_filters' ) ) {
     1503                        /**
     1504                         * Filters the message that the default PHP error page displays.
     1505                         *
     1506                         * @since 5.0.0
     1507                         *
     1508                         * @param string $message HTML error message to display.
     1509                         */
     1510                        $message = apply_filters( 'wp_technical_issues_display', $message );
     1511                }
     1512
     1513                wp_die( $message );
     1514        } catch ( Exception $exception ) {
     1515                // Catch exceptions and remain silent.
     1516        }
     1517}
     1518
     1519/**
     1520 * Registers the WordPress premature shutdown handler.
     1521 *
     1522 * @since 5.0.0
     1523 *
     1524 * @return void
     1525 */
     1526function wp_register_premature_shutdown_handler() {
     1527        register_shutdown_function( 'wp_shutdown_handler_wrapper' );
     1528}
  • src/wp-settings.php

     
    2020require( ABSPATH . WPINC . '/default-constants.php' );
    2121require_once( ABSPATH . WPINC . '/plugin.php' );
    2222
     23// Make sure we register the premature shutdown handler as soon as possible.
     24wp_register_premature_shutdown_handler();
     25
    2326/*
    2427 * These can't be directly globalized in version.php. When updating,
    2528 * we're including version.php from another installation and don't want
     
    4043// Set initial default constants including WP_MEMORY_LIMIT, WP_MAX_MEMORY_LIMIT, WP_DEBUG, SCRIPT_DEBUG, WP_CONTENT_DIR and WP_CACHE.
    4144wp_initial_constants();
    4245
     46/*
     47 * Allow an optional shutdown handler to be included through a pluggable file.
     48 * This file should register a function `wp_handle_shutdown( $context )` that
     49 * returns a boolean value. If the return value evaluates to false, the default
     50 * shutdown handler will not be executed.
     51 */
     52if ( is_readable( WP_CONTENT_DIR . '/shutdown-handler.php' ) ) {
     53        include WP_CONTENT_DIR . '/shutdown-handler.php';
     54}
     55
    4356// Check for the required PHP version and for the MySQL extension or a database drop-in.
    4457wp_check_php_mysql_versions();
    4558
     
    482495 * @since 3.0.0
    483496 */
    484497do_action( 'wp_loaded' );
     498
     499/*
     500 * Store the fact that we could successfully execute the entire WordPress
     501 * lifecycle. This is used to skip the premature shutdown handler, as it cannot
     502 * be unregistered.
     503 */
     504if ( ! defined( 'WP_EXECUTION_SUCCEEDED' ) ) {
     505        define( 'WP_EXECUTION_SUCCEEDED', true );
     506}