wp_config = new WP_Config_Transformer; // already in the DLM\Classes namespace, so, no need to repeat } /** * Get status of WP_DEBUG * * @since 1.0.0 */ public function get_status() { // If non-existent, create an empty index to prevent directory browsing and download of the debug log file $uploads_path = wp_upload_dir()['basedir'] . '/debug-log-manager'; if ( ! is_file( $uploads_path . '/index.php' ) ) { file_put_contents( $uploads_path . '/index.php', '' . esc_html__( 'Error Logging', 'debug-log-manager' ) . ': ' . ucfirst( esc_html__( 'enabled', 'debug-log-manager' ) ) . ' ' . esc_html__( 'on', 'debug-log-manager' ) . ' ' . esc_html( $date_time ) . ''; } elseif ( 'disabled' == $status ) { return '
' . esc_html__( 'Error Logging', 'debug-log-manager' ) . ': ' . ucfirst( esc_html__( 'disabled', 'debug-log-manager' ) ) . ' ' . esc_html__( 'on', 'debug-log-manager' ) . ' ' . esc_html( $date_time ) . '
'; } else {} } /** * Get log auto-refresh status * * @since 1.3.0 */ public function get_autorefresh_status() { if ( false !== get_option( 'debug_log_manager_autorefresh' ) ) { $autorefresh_status = get_option( 'debug_log_manager_autorefresh' ); } else { $autorefresh_status = 'disabled'; update_option( 'debug_log_manager_autorefresh', $autorefresh_status, false ); } if ( 'enabled' == $autorefresh_status ) { return '
Auto-Refresh: ' . ucfirst( esc_html__( 'enabled', 'debug-log-manager' ) ) . '
'; } elseif ( 'disabled' == $autorefresh_status ) { return '
Auto-Refresh: ' . ucfirst( esc_html__( 'disabled', 'debug-log-manager' ) ) . '
'; } } /** * Enable / disable WP_DEBUG * * @since 1.0.0 */ public function toggle_debugging() { if ( isset( $_REQUEST ) ) { $log_info = get_option( 'debug_log_manager' ); $dlm_debug_log_file_path = get_option( 'debug_log_manager_file_path' ); if ( function_exists( 'wp_date' ) ) { $date_time = wp_date( 'M j, Y - H:i:s' ); // Localized according to WP timezone settings } else { $date_time = date_i18n( 'M j, Y - H:i:s' ); } $date_time_for_option = date( 'M j, Y H:i:s' ); // in UTC if ( 'disabled' == $log_info['status'] ) { $option_value = array( 'status' => 'enabled', 'on' => $date_time_for_option, ); update_option( 'debug_log_manager', $option_value, false ); // If WP_DEBUG_LOG is defined, copy content of existing debug.log file into the log file created by this plugin if ( $this->wp_config->exists( 'constant', 'WP_DEBUG_LOG' ) ) { $wp_debug_log_const = $this->wp_config->get_value( 'constant', 'WP_DEBUG_LOG' ); if ( in_array( $wp_debug_log_const, array( 'true', 'false' ), true ) ) { $wp_debug_log_const = (bool) $wp_debug_log_const; } if ( is_bool( $wp_debug_log_const ) ) { // WP_DEBUG_LOG is true or false. Log file is in default location of /wp-content/debug.log. if ( is_file( WP_CONTENT_DIR . '/debug.log' ) ) { // Copy existing debug log content to this plugin's debug log. $default_debug_log_content = file_get_contents( WP_CONTENT_DIR . '/debug.log' ); file_put_contents( $dlm_debug_log_file_path, $default_debug_log_content ); unlink( realpath( WP_CONTENT_DIR . '/debug.log' ) ); // delete existing debug log } } elseif ( is_string( $wp_debug_log_const ) ) { // WP_DEBUG_LOG is custom path to log file. Copy existing debug log content to this plugin's debug log. if ( is_file( $wp_debug_log_const ) && ( $wp_debug_log_const != $dlm_debug_log_file_path ) ) { $custom_debug_log_content = file_get_contents( $wp_debug_log_const ); file_put_contents( $dlm_debug_log_file_path, $custom_debug_log_content ); unlink( $wp_debug_log_const ); // delete existing debug log } } $copy = true; // existing debug.log file's entries are copied to this plugin's debug.log file } else { $copy = false; // existing debug.log file's entries are NOT copied to this plugin's debug.log file } // Define Debug constants in wp-config.php $options = array( 'add' => true, // Add the config if missing. 'raw' => true, // Display value in raw format without quotes. 'normalize' => false, // Normalize config output using WP Coding Standards. ); $this->wp_config->update( 'constant', 'WP_DEBUG', 'true', $options ); $options = array( 'add' => true, // Add the config if missing. 'raw' => true, // Display value in raw format without quotes. 'normalize' => false, // Normalize config output using WP Coding Standards. ); $this->wp_config->update( 'constant', 'SCRIPT_DEBUG', 'true', $options ); $options = array( 'add' => true, // Add the config if missing. 'raw' => false, // Display value in raw format without quotes. 'normalize' => false, // Normalize config output using WP Coding Standards. ); $this->wp_config->update( 'constant', 'WP_DEBUG_LOG', get_option( 'debug_log_manager_file_path' ), $options ); $options = array( 'add' => true, // Add the config if missing. 'raw' => true, // Display value in raw format without quotes. 'normalize' => false, // Normalize config output using WP Coding Standards. ); $this->wp_config->update( 'constant', 'WP_DEBUG_DISPLAY', 'false', $options ); $options = array( 'add' => true, // Add the config if missing. 'raw' => true, // Display value in raw format without quotes. 'normalize' => false, // Normalize config output using WP Coding Standards. ); $this->wp_config->update( 'constant', 'DISALLOW_FILE_EDIT', 'false', $options ); // Get the debug.log file size $log_file_path = get_option( 'debug_log_manager_file_path' ); $log_file_shortpath = str_replace( sanitize_text_field( $_SERVER['DOCUMENT_ROOT'] ), "", $log_file_path ); $file_size = size_format( (int) filesize( $log_file_path ) ); // Prepare entries from the debug log for the data table $errors_master_list = json_decode( $this->get_processed_entries(), true ); $n = 1; $entries = array(); foreach ( $errors_master_list as $error ) { if ( function_exists( 'wp_date' ) ) { $localized_timestamp = wp_date( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); // last occurrence } else { $localized_timestamp = date_i18n( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); } $occurrence_count = count( $error['occurrences'] ); $entry = array( $n, $error['type'], $error['details'], $localized_timestamp . '
(' . sprintf( _n( '%s occurrence logged', '%s occurrences logged', $occurrence_count, 'debug-log-manager' ), number_format_i18n( $occurrence_count ) ) . ')', ); $entries[] = $entry; $n++; } // Assemble data to return $data = array( 'status' => 'enabled', 'copy' => $copy, 'message' => '' . esc_html__( 'Error Logging', 'debug-log-manager' ) . ': ' . esc_html__( 'Enabled on', 'debug-log-manager' ) . ' ' . esc_html( $date_time ), 'entries' => $entries, 'size' => $file_size, ); echo json_encode( $data ); } elseif ( 'enabled' == $log_info['status'] ) { $option_value = array( 'status' => 'disabled', 'on' => $date_time_for_option, ); update_option( 'debug_log_manager', $option_value, false ); // Remove Debug constants in wp-config.php $this->wp_config->remove( 'constant', 'WP_DEBUG' ); $this->wp_config->remove( 'constant', 'SCRIPT_DEBUG' ); $this->wp_config->remove( 'constant', 'WP_DEBUG_LOG' ); $this->wp_config->remove( 'constant', 'WP_DEBUG_DISPLAY' ); $this->wp_config->remove( 'constant', 'DISALLOW_FILE_EDIT' ); // Assemble data to return $data = array( 'status' => 'disabled', 'copy' => false, 'message' => '' . esc_html__( 'Error Logging', 'debug-log-manager' ) . ': ' . esc_html__( 'Disabled on', 'debug-log-manager' ) . ' ' . esc_html( $date_time ), 'entries' => '', 'size' => '', ); echo json_encode( $data ); } else {} } } /** * Toggle auto-refresh of entries table * * @since 1.3.0 */ public function toggle_autorefresh() { if ( isset( $_REQUEST ) ) { $autorefresh_status = get_option( 'debug_log_manager_autorefresh' ); if ( $autorefresh_status == 'disabled' ) { update_option( 'debug_log_manager_autorefresh', 'enabled', false ); $data = array( 'status' => 'enabled', 'message' => '' . esc_html__( 'Auto-Refresh', 'debug-log-manager' ) . ': ' . esc_html__( 'Enabled', 'debug-log-manager' ), ); echo json_encode( $data ); } elseif ( $autorefresh_status == 'enabled' ) { update_option( 'debug_log_manager_autorefresh', 'disabled', false ); $data = array( 'status' => 'disabled', 'message' => '' . esc_html__( 'Auto-Refresh', 'debug-log-manager' ) . ': ' . esc_html__( 'Disabled', 'debug-log-manager' ), ); echo json_encode( $data ); } else {} } } /** * Get the processed debug log data * * @return string $errors_master_list The processed error log entries * @since 1.2.0 */ public function get_processed_entries() { $debug_log_file_path = get_option( 'debug_log_manager_file_path' ); // Read the errors log file $log = file_get_contents( $debug_log_file_path ); $log = str_replace( "[\\", "^\\", $log ); // certain error message contains the '[\' string, which will make the following split via explode() to split lines at places in the message it's not supposed to. So, we temporarily replace those with '^\' $log = str_replace( "[\"", "^\"", $log ); // certain error message contains the '["' string, which will make the following split via explode() to split lines at places in the message it's not supposed to. So, we temporarily replace those with '^"' $log = str_replace( "[internal function]", "^internal function^", $log ); // We are splitting the log file not using PHP_EOL to preserve the stack traces for PHP Fatal Errors among other things $lines = explode("[", $log); $prepended_lines = array(); // Pluck out the last 100k entries, the newest entry is last // To pluck out the first 100000 entries, use array_slice( $lines, 0, 100000 ) $lines = array_slice( $lines, -100000 ); foreach ( $lines as $line ) { if ( !empty($line) ) { $line = str_replace( "UTC]", "UTC]@@@", $line ); // add '@@@' as marker/separator after time stamp $line = str_replace( "Stack trace:", "
Stack trace:", $line ); // add line break for stack trace section if ( strpos( $line, 'PHP Fatal' ) !== false ) { $line = str_replace( "#", "
#", $line ); // add line break on PHP Fatal error's stack trace lines } $line = str_replace( "Argument
#", "Argument #", $line ); // remove hr on certain error message $line = str_replace( "parameter
#", "parameter #", $line ); // remove hr on certain error message $line = str_replace( "the
#", "the #", $line ); // remove hr on certain error message $line = str_replace( "^\\", "[\\", $line ); // reverse the temporary replacement of '[\' with '^\' $line = str_replace( "^\"", "[\"", $line ); // reverse the temporary replacement of '["' with '^"' $line = str_replace( "^internal function^", "[internal function]", $line ); $prepended_line = '[' . $line; // Put back the missing '[' after explode operation $prepended_lines[] = $prepended_line; } } // Reverse the order of the entries, so the newest entry is first $latest_lines = array_reverse( $prepended_lines ); // Will hold error details types $errors_master_list = array(); foreach( $latest_lines as $line ) { $line = explode("@@@ ", trim( $line ) ); // split the line using the '@@@' marker/separator defined earlier. '@@@' will be deleted by explode(). $timestamp = str_replace( [ "[", "]" ], "", $line[0] ); // Initialize error-related variables $error = ''; $error_source = ''; $error_file = ''; $error_file_path = ''; $error_file_line = ''; if ( array_key_exists('1', $line) ) { $error = $line[1]; // Check if there is a file path to pluck out of the error line if ( false !== strpos( $error, ABSPATH ) ) { // Separata file path and error line from error message // Handling for PHP Fatal errors with stack trace included if ( false !== strpos( $error, 'Stack trace:' ) ) { $error_parts = explode( 'Stack trace:', $error ); $error_message = str_replace( '
', '', $error_parts[0] ); if ( isset( $error_parts[1] ) ) { $error_stack_trace = ' ' . $error_parts[1]; } $error_message_parts = explode( ' in /', $error_message ); // Reconstruct the error details without error file path and line info $error = $error_message_parts[0] . '
Stack trace:' . $error_stack_trace; // Shorten the file path in the error details $error = str_replace( ABSPATH, '/', $error ); if ( isset( $error_message_parts[1] ) ) { $error_file = '/' . $error_message_parts[1]; $error_file_info = explode ( ':', $error_file ); $error_file_path = $error_file_info[0]; if ( array_key_exists('1', $error_file_info) ) { $error_file_line = $error_file_info[1]; } } } else { $error_message_parts = explode( ' in /', $error ); $error = $error_message_parts[0]; if ( isset( $error_message_parts[1] ) ) { $error_file = '/' . $error_message_parts[1]; $error_file_info = explode ( ' on line ', $error_file ); $error_file_path = $error_file_info[0]; if ( array_key_exists('1', $error_file_info) ) { $error_file_line = $error_file_info[1]; } } } // Shorten the file path where the error occurred $error_file_path = str_replace( ABSPATH, '/', $error_file_path ); // Define whether source of error is WP Core, Theme, Plugin or Other if ( ( false !== strpos( $error_file, '/wp-admin/' ) ) || ( false !== strpos( $error_file, '/wp-includes/' ) ) ) { $error_source = __( 'WordPress core', 'debug-log-manager' ); } elseif ( ( false !== strpos( $error_file, '/wp-content/themes/' ) ) ) { $error_source = __( 'Theme', 'debug-log-manager' ); } elseif ( ( false !== strpos( $error_file, '/wp-content/plugins/' ) ) ) { $error_source = __( 'Plugin', 'debug-log-manager' ); } else { $error_source = ''; } // Get plugin/theme directory name of error file when error source is plugin or theme if ( ( 'Plugin' == $error_source ) || ( 'Theme' == $error_source ) ) { $error_file_path_parts = explode( '/', $error_file_path ); $error_file_directory = $error_file_path_parts[3]; } // Get plugin name $plugins = get_plugins(); if ( 'Plugin' == $error_source ) { foreach ( $plugins as $plugin_path_file => $plugin_info ) { if ( false !== strpos( $plugin_path_file, $error_file_directory ) ) { $error_source_plugin_path_file = $plugin_path_file; $error_source_plugin_name = $plugin_info['Name']; $error_source_plugin_uri = $plugin_info['PluginURI']; // $error_source_plugin_version = $plugin_info['Version']; } } } // Get theme name if ( 'Theme' == $error_source ) { $theme = wp_get_theme( $error_file_directory ); if ( $theme->exists() ) { $error_source_theme_dir = $error_file_directory; $error_source_theme_name = $theme->get( 'Name' ); $error_source_theme_uri = $theme->get( 'ThemeURI' ); // $error_source_theme_version = $theme->get( 'Version' ); } else { $error_source_theme_name = $error_file_directory; } } } } else { $error = __( 'No error message specified...', 'debug-log-manager' ); } if ( ( false !== strpos( $error, 'PHP Fatal' )) || ( false !== strpos( $error, 'FATAL' ) ) || ( false !== strpos( $error, 'E_ERROR' ) ) ) { $error_type = __( 'PHP Fatal', 'debug-log-manager' ); $error_details = str_replace( "PHP Fatal error: ", "", $error ); $error_details = str_replace( "PHP Fatal: ", "", $error_details ); $error_details = str_replace( "FATAL ", "", $error_details ); $error_details = str_replace( "E_ERROR: ", "", $error_details ); } elseif ( ( false !== strpos( $error, 'PHP Warning' ) ) || ( false !== strpos( $error, 'E_WARNING' ) ) ) { $error_type = __( 'PHP Warning', 'debug-log-manager' ); $error_details = str_replace( "PHP Warning: ", "", $error ); $error_details = str_replace( "E_WARNING: ", "", $error_details ); } elseif ( ( false !== strpos( $error, 'PHP Notice' ) ) || ( false !== strpos( $error, 'E_NOTICE' ) ) ) { $error_type = __( 'PHP Notice', 'debug-log-manager' ); $error_details = str_replace( "PHP Notice: ", "", $error ); $error_details = str_replace( "E_NOTICE: ", "", $error_details ); } elseif ( false !== strpos( $error, 'PHP Deprecated' ) ) { $error_type = __( 'PHP Deprecated', 'debug-log-manager' ); $error_details = str_replace( "PHP Deprecated: ", "", $error ); } elseif ( ( false !== strpos( $error, 'PHP Parse' ) ) || ( false !== strpos( $error, 'E_PARSE' ) ) ) { $error_type = __( 'PHP Parse', 'debug-log-manager' ); $error_details = str_replace( "PHP Parse error: ", "", $error ); $error_details = str_replace( "E_PARSE: ", "", $error_details ); } elseif ( false !== strpos( $error, 'EXCEPTION:' ) ) { $error_type = __( 'PHP Exception', 'debug-log-manager' ); $error_details = str_replace( "EXCEPTION: ", "", $error ); } elseif ( false !== strpos( $error, 'WordPress database error' ) ) { $error_type = __( 'Database', 'debug-log-manager' ); $error_details = str_replace( "WordPress database error ", "", $error ); } elseif ( false !== strpos( $error, 'JavaScript Error' ) ) { $error_type = __( 'JavaScript', 'debug-log-manager' ); $error_details = str_replace( "JavaScript Error: ", "", $error ); } else { $error_type = __( 'Other', 'debug-log-manager' ); $error_details = $error; if ( $this->is_json( $error_details ) ) { // For JSON string in error message, originally added via error_log( json_encode( $variable ) ) // This will output said JSON string as well-formated array in the log entries table $error_details = '
' . print_r( json_decode( $error_details, true ), true ) . '
'; } } // Append error source, file path and line number info to error details. If core plugin/theme editor is not disabled, link file path to the editor view. if ( ! empty( $error_source ) ) { if ( 'WordPress core' == $error_source ) { $wp_version = get_bloginfo( 'version' ); $file_viewer_url = 'https://github.com/WordPress/wordpress-develop/blob/' . $wp_version . '/src' . $error_file_path; $error_details = '' . $error_details . '
' . $error_source . '
' . __( 'File', 'debug-log-manager' ) . ': ' . $error_file_path . '
' . __( 'Line', 'debug-log-manager' ) . ': ' . $error_file_line; } elseif ( 'Theme' == $error_source ) { if ( ! defined( 'DISALLOW_FILE_EDIT' ) || ( false === constant( 'DISALLOW_FILE_EDIT' ) ) ) { $file_viewer_url = get_admin_url() . 'theme-editor.php?file=' . urlencode( str_replace( '/wp-content/themes/', '', $error_file_path ) ) . '&theme=' . $error_source_theme_dir; $error_details = '' . $error_details . '
' . $error_source . ': ' . $error_source_theme_name . '
' . __( 'File', 'debug-log-manager' ) . ': ' . $error_file_path . '
' . __( 'Line', 'debug-log-manager' ) . ': ' . $error_file_line; } if ( defined( 'DISALLOW_FILE_EDIT' ) && ( true === constant( 'DISALLOW_FILE_EDIT' ) ) ) { $error_details = '' . $error_details . '
' . $error_source . ': ' . $error_source_theme_name . '
' . __( 'File', 'debug-log-manager' ) . ': ' . $error_file_path . '
' . __( 'Line', 'debug-log-manager' ) . ': ' . $error_file_line; } } elseif ( 'Plugin' == $error_source ) { if ( ! defined( 'DISALLOW_FILE_EDIT' ) || ( false === constant( 'DISALLOW_FILE_EDIT' ) ) ) { $file_viewer_url = get_admin_url() . 'plugin-editor.php?file=' . urlencode( str_replace( '/wp-content/plugins/', '', $error_file_path ) ) . '&plugin=' . urlencode( $error_source_plugin_path_file ); $error_details = '' . $error_details . '
' . $error_source . ': ' . $error_source_plugin_name . '
' . __( 'File', 'debug-log-manager' ) . ': ' . $error_file_path . '
' . __( 'Line', 'debug-log-manager' ) . ': ' . $error_file_line; } if ( defined( 'DISALLOW_FILE_EDIT' ) && ( true === constant( 'DISALLOW_FILE_EDIT' ) ) ) { $error_details = '' . $error_details . '
' . $error_source . ': ' . $error_source_plugin_name . '
' . __( 'File', 'debug-log-manager' ) . ': ' . $error_file_path . '
' . __( 'Line', 'debug-log-manager' ) . ': ' . $error_file_line; } } } // https://www.php.net/manual/en/function.array-search.php#120784 if ( array_search( trim( $error_details ), array_column( $errors_master_list, 'details' ) ) === false ) { $errors_master_list[] = array( 'type' => $error_type, 'details' => trim( $error_details ), 'occurrences' => array( $timestamp ), ); } else { $error_position = array_search( trim( $error_details ), array_column( $errors_master_list, 'details' ) ); // integer array_push( $errors_master_list[$error_position]['occurrences'], $timestamp ); } } return json_encode( $errors_master_list ); } /** * Get the latest entries for auto-refresh feature * * @since 1.0.0 */ public function get_latest_entries() { $errors_master_list = json_decode( $this->get_processed_entries(), true ); $n = 1; $entries = array(); foreach ( $errors_master_list as $error ) { if ( function_exists( 'wp_date' ) ) { $localized_timestamp = wp_date( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); // last occurrence } else { $localized_timestamp = date_i18n( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); } $occurrence_count = count( $error['occurrences'] ); $entry = array( $n, $error['type'], $error['details'], $localized_timestamp . '
(' . sprintf( _n( '%s occurrence logged', '%s occurrences logged', $occurrence_count, 'debug-log-manager' ), number_format_i18n( $occurrence_count ) ) . ')', ); $entries[] = $entry; $n++; } $data = array( 'entries' => $entries, ); echo json_encode( $data ); } /** * Get debug log in data table format * * @since 1.0.0 */ public function get_entries_datatable() { ?>
get_processed_entries(), true ); $n = 1; foreach ( $errors_master_list as $error ) { if ( function_exists( 'wp_date' ) ) { $localized_timestamp = wp_date( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); // last occurrence } else { $localized_timestamp = date_i18n( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); } $occurrence_count = count( $error['occurrences'] ); ?>
#
get_processed_entries(), true ); $n = 1; $entries_to_show = 5; ?>
true, // Add the config if missing. 'raw' => true, // Display value in raw format without quotes. 'normalize' => false, // Normalize config output using WP Coding Standards. ); $this->wp_config->update( 'constant', 'DISALLOW_FILE_EDIT', 'true', $options ); // Prepare entries from the debug log for the data table $errors_master_list = json_decode( $this->get_processed_entries(), true ); $n = 1; $entries = array(); foreach ( $errors_master_list as $error ) { if ( function_exists( 'wp_date' ) ) { $localized_timestamp = wp_date( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); // last occurrence } else { $localized_timestamp = date_i18n( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); } $occurrence_count = count( $error['occurrences'] ); $entry = array( $n, $error['type'], $error['details'], $localized_timestamp . '
(' . sprintf( _n( '%s occurrence logged', '%s occurrences logged', $occurrence_count, 'debug-log-manager' ), number_format_i18n( $occurrence_count ) ) . ')', ); $entries[] = $entry; $n++; } // Assemble data to return $data = array( 'status' => 'disabled', // Plugin/theme editor 'entries' => $entries, // To parse data table with unlinked plugin/theme file paths ); echo json_encode( $data ); } /** * Log javascript errors * * @since 1.4.0 */ public function log_js_errors() { // Since we are using XHR for the js error logging, JSON data comes in via php://input $request = json_decode(urldecode(file_get_contents('php://input')), true); // an array // Verify error content and nonce and then log the JS error // Source: https://plugins.svn.wordpress.org/lh-javascript-error-log/trunk/lh-javascript-error-log.php if ( isset( $request['message'] ) && isset( $request['script'] ) && isset( $request['lineNo'] ) && isset( $request['columnNo'] ) && ! empty( $request['nonce'] ) && wp_verify_nonce( $request['nonce'], DLM_SLUG ) ) { error_log( 'JavaScript Error: ' . $request['message'] . ' in ' . $request['script'] . ' on line ' . $request['lineNo'] . ' column ' . $request['columnNo'] . ' at ' . get_site_url() . $request['pageUrl'] ); } else { wp_die(); } } /** * Check if a string is valid JSON * * @link https://stackoverflow.com/a/6041773 * @since 2.1.0 */ public function is_json( $string ) { json_decode( $string ); return json_last_error() === JSON_ERROR_NONE; } }