File: /home/ukqcurpj/www/wp-content/plugins/paid-memberships-pro/classes/class-pmpro-site-health.php
<?php
/**
* The functionality that includes PMPro data within Site Health information.
*
* @since 2.6.2
*/
class PMPro_Site_Health {
/**
* The current object instance.
*
* @var self
*/
private static $instance;
/**
* Initialize class object and use it for future init calls.
*
* @since 2.6.2
*
* @return self The class object.
*/
public static function init() {
if ( ! is_object( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Add hooks needed for functionality.
*
* @since 2.6.2
*/
public function hook() {
add_filter( 'debug_information', [ $this, 'debug_information' ] );
}
/**
* Remove hooks needed for functionality.
*
* @since 2.6.2
*/
public function unhook() {
remove_filter( 'debug_information', [ $this, 'debug_information' ] );
}
/**
* Add our data to Site Health information.
*
* @since 2.6.2
*
* @param array $info The Site Health information.
*
* @return array The updated Site Health information.
*/
public function debug_information( $info ) {
$info['pmpro'] = [
'label' => 'Paid Memberships Pro',
'description' => __( 'This debug information for your Paid Memberships Pro installation can assist you in getting support.', 'paid-memberships-pro' ),
'fields' => [
'pmpro-cron-jobs' => [
'label' => __( 'Cron Job Status', 'paid-memberships-pro' ),
'value' => self::get_cron_jobs(),
],
'pmpro-action-scheduler-health' => [
'label' => __( 'Action Scheduler Health', 'paid-memberships-pro' ),
'value' => self::action_scheduler_issues(),
],
'pmpro-gateway' => [
'label' => __( 'Payment Gateway', 'paid-memberships-pro' ),
'value' => self::get_gateway(),
],
'pmpro-gateway-env' => [
'label' => __( 'Payment Gateway Environment', 'paid-memberships-pro' ),
'value' => self::get_gateway_env(),
],
'pmpro-orders' => [
'label' => __( 'Orders', 'paid-memberships-pro' ),
'value' => self::get_orders(),
],
'pmpro-discount-codes' => [
'label' => __( 'Discount Codes', 'paid-memberships-pro' ),
'value' => self::get_discount_codes(),
],
'pmpro-sessions' => [
'label' => __( 'PHP Sessions', 'paid-memberships-pro' ),
'value' => self::test_sessions(),
],
'pmpro-membership-levels' => [
'label' => __( 'Membership Levels', 'paid-memberships-pro' ),
'value' => self::get_levels(),
],
'pmpro-level-groups' => [
'label' => __( 'Level Groups', 'paid-memberships-pro' ),
'value' => self::get_level_groups(),
],
'pmpro-custom-templates' => [
'label' => __( 'Custom Templates', 'paid-memberships-pro' ),
'value' => self::get_custom_templates(),
],
'pmpro-getfile-usage' => [
'label' => __( 'getfile.php Usage', 'paid-memberships-pro' ),
'value' => self::get_getfile_usage(),
],
'pmpro-htaccess-cache-usage' => [
'label' => __( '.htaccess Cache Usage', 'paid-memberships-pro' ),
'value' => self::get_htaccess_cache_usage(),
],
'pmpro-pages' => [
'label' => __( 'Membership Pages', 'paid-memberships-pro' ),
'value' => self::get_pmpro_pages(),
],
'pmpro-library-conflicts' => [
'label' => __( 'Library Conflicts', 'paid-memberships-pro' ),
'value' => self::get_library_conflicts(),
],
'pmpro-add-ons-incorrect-folder-names' => [
'label' => __( 'Incorrect Add On Folder Names', 'paid-memberships-pro' ),
'value' => self::get_add_ons_with_incorrect_folder_name(),
],
'pmpro-current-site-url' => [
'label' => __( 'Current Site URL', 'paid-memberships-pro' ),
'value' => get_site_url(),
],
'pmpro-recorded-site-url' => [
'label' => __( 'Last Known Site URL', 'paid-memberships-pro' ),
'value' => get_option( 'pmpro_last_known_url' ),
],
'pmpro-pause-mode' => [
'label' => __( 'Pause Mode', 'paid-memberships-pro' ),
'value' => self::get_pause_mode_state(),
],
],
];
// Automatically add information about constants set.
$info['pmpro']['fields'] = array_merge( $info['pmpro']['fields'], self::get_constants() );
if ( function_exists( 'pmpro_add_site_health_info_2_10_6' ) ) {
// If the 2.10.6 update cleaned up sensitive order meta data, we want to show that.
$info = pmpro_add_site_health_info_2_10_6( $info );
}
return $info;
}
/**
* Gets the level information.
*
* @since 2.6.2
*
* @return string The level information.
*/
public function get_levels() {
$membership_levels = pmpro_getAllLevels( true, true );
if ( ! $membership_levels ) {
return __( 'No Levels Found', 'paid-memberships-pro' );
}
foreach ( $membership_levels as &$membership_level ) {
$membership_level->meta = get_pmpro_membership_level_meta( $membership_level->id );
$membership_level = apply_filters( 'pmpro_site_health_info_membership_level', $membership_level );
}
return wp_json_encode( $membership_levels, JSON_PRETTY_PRINT );
}
/**
* Get the level group information.
*
* @since 3.0.2
*
* @return string The level group information.
*/
public function get_level_groups() {
$level_groups = pmpro_get_level_groups();
if ( ! $level_groups ) {
return __( 'No Level Groups Found', 'paid-memberships-pro' );
}
// Add the level IDs to the group objects.
foreach ( $level_groups as $group_id => $group ) {
$group->level_ids = pmpro_get_level_ids_for_group( $group_id );
}
return wp_json_encode( $level_groups, JSON_PRETTY_PRINT );
}
/**
* Get the discount code information.
*
* @since 2.6.2
*
* @return string The discount code information.
*/
public function get_discount_codes() {
global $wpdb;
$count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `$wpdb->pmpro_discount_codes`" );
// translators: %d: The total count of discount codes.
return sprintf( _n( '%d discount code', '%d discount codes', $count, 'paid-memberships-pro' ), $count );
}
/**
* Get the order information.
*
* @since 2.6.2
*
* @return string The order information.
*/
public function get_orders() {
global $wpdb;
$count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `$wpdb->pmpro_membership_orders`" );
// translators: %d: The total count of orders.
return sprintf( _n( '%d order', '%d orders', $count, 'paid-memberships-pro' ), $count );
}
/**
* Get the payment gateway information.
*
* @since 2.6.2
*
* @return string The payment gateway information.
*/
public function get_gateway() {
$gateway = get_option( 'pmpro_gateway' );
$gateways = pmpro_gateways();
// Check if gateway is registered.
if ( ! isset( $gateways[ $gateway ] ) ) {
// translators: %s: The gateway name that is not registered.
return sprintf( __( '%s (gateway not registered)', 'paid-memberships-pro' ), $gateway );
}
$gateway_text = $gateways[ $gateway ];
// Custom Stripe gateway information.
if ( 'stripe' === $gateway ) {
$stripe = new PMProGateway_stripe();
$legacy = $stripe->using_legacy_keys();
$api = $stripe->using_api_keys();
$connect = $stripe->has_connect_credentials();
if ( defined( 'PMPRO_STRIPE_API_VERSION' ) ) {
$gateway_text .= ' (' . __( 'API Version', 'paid-memberships-pro' ) . ': ' . PMPRO_STRIPE_API_VERSION . ')';
}
if ( $legacy ) {
$gateway_text .= ' (' . __( 'Legacy Keys', 'paid-memberships-pro' ) . ')';
return $gateway_text . ' [' . $gateway . ':legacy-keys]';
}
if ( $api ) {
$gateway_text .= ' (' . __( 'API Keys', 'paid-memberships-pro' ) . ')';
return $gateway_text . ' [' . $gateway . ':api-keys ]';
}
if ( $connect ) {
$gateway_text .= ' (' . __( 'Stripe Connect', 'paid-memberships-pro' ) . ')';
return $gateway_text . ' [' . $gateway . ':stripe-connect]';
}
}
return $gateway_text . ' [' . $gateway . ']';
}
/**
* Get the payment gateway environment information.
*
* @since 2.6.2
*
* @return string The payment gateway environment information.
*/
public function get_gateway_env() {
$environment = get_option( 'pmpro_gateway_environment' );
$environments = [
'sandbox' => __( 'Sandbox/Testing', 'paid-memberships-pro' ),
'live' => __( 'Live/Production', 'paid-memberships-pro' ),
];
// Check if environment is registered.
if ( ! isset( $environments[ $environment ] ) ) {
// translators: %s: The environment name that is not registered.
return sprintf( __( '%s (environment not registered)', 'paid-memberships-pro' ), $environment );
}
return $environments[ $environment ] . ' [' . $environment . ']';
}
/**
* Tests if PHP sessions are enabled
*
* @since 2.9
*
* @return string The PHP Session data.
*/
public function test_sessions() {
$session_data = array();
$php_session_status = session_status();
if ( $php_session_status !== 0 || $php_session_status !== PHP_SESSIONS_DISABLED ) {
$session_data['session_status'] = __( 'Active', 'paid-memberships-pro' );
} else {
$session_data['session_status'] = __( 'Inactive', 'paid-memberships-pro' );
}
if ( defined( 'PANTHEON_SESSIONS_VERSION' ) ) {
$session_data['wp_native_sessions'] = __( 'Active', 'paid-memberships-pro' );
}
return $session_data;
}
/**
* Get the custom template information.
*
* @since 2.6.2
*
* @return string The custom template information.
*/
public function get_custom_templates() {
// Create a $template => $path array of all default page templates.
$default_templates = array(
'account' => PMPRO_DIR . '/pages/account.php',
'billing' => PMPRO_DIR . '/pages/billing.php',
'cancel' => PMPRO_DIR . '/pages/cancel.php',
'checkout' => PMPRO_DIR . '/pages/checkout.php',
'confirmation' => PMPRO_DIR . '/pages/confirmation.php',
'invoice' => PMPRO_DIR . '/pages/invoice.php',
'levels' => PMPRO_DIR . '/pages/levels.php',
'login' => PMPRO_DIR . '/pages/login.php',
'member_profile_edit' => PMPRO_DIR . '/pages/member_profile_edit.php',
);
// Filter $default_templates so that Add Ons can add their own templates.
$default_templates = apply_filters( 'pmpro_default_page_templates', $default_templates );
// Loop through each template. For each, if a custom page template is being loaded, store:
// - The custom path being loaded.
// - The version of the default template.
// - The version of the custom template.
$custom_templates = array(); // Array of $template => array( 'default_version' => $default_version, 'loaded_version' => $loaded_version, 'loaded_path' => $loaded_path ).
foreach ( $default_templates as $template => $path ) {
// Gather information about the default and loaded templates.
$default_version = pmpro_get_version_for_page_template_at_path( $path );
$custom_path = pmpro_get_template_path_to_load( $template );
$custom_version = pmpro_get_version_for_page_template_at_path( $custom_path );
// If the $path and $loaded_path are different, a custom template is being loaded.
if ( $path !== $custom_path ) {
$custom_templates[ $template ] = 'Default Version: ' . $default_version . ' | Custom Version: ' . $custom_version . ' | Custom Path: ' . $custom_path . ' | Action: ';
$use_custom_page_template = get_option( 'pmpro_use_custom_page_template_' . $template );
switch( $use_custom_page_template ) {
case 'yes':
$custom_templates[ $template ] .= 'Custom';
break;
case 'no':
$custom_templates[ $template ] .= 'Core';
break;
default:
$custom_templates[ $template ] .= 'Fallback';
break;
}
$custom_templates[ $template ] = esc_html( $custom_templates[ $template] );
}
}
return $custom_templates;
}
/**
* Get the cron job information.
*
* @since 2.6.2
*
* @return string The cron job information.
*/
public function get_cron_jobs() {
$crons = _get_cron_array();
$cron_times = [];
// These are our crons.
$expected_crons = array_keys( pmpro_get_crons() );
// Find any of our crons and when their next run is.
if ( $crons ) {
foreach ( $crons as $time => $cron ) {
$keys = array_keys( $cron );
$matches = array_intersect( $expected_crons, $keys );
foreach ( $matches as $cron_hook ) {
$cron_times[ $cron_hook ] = date( 'Y-m-d H:i:s', $time );
}
}
}
$missing_crons = array_diff( $expected_crons, array_keys( $cron_times ) );
$cron_information = [];
foreach ( $missing_crons as $cron_hook ) {
$cron_information[] = $cron_hook . ' (' . __( 'missing', 'paid-memberships-pro' ) . ')';
}
// Build the information of what crons are missing and what crons are going to run.
foreach ( $cron_times as $cron_hook => $next_run ) {
$cron_information[] = $cron_hook . ' (' . $next_run . ')';
}
if ( empty( $cron_information ) ) {
return __( 'No cron jobs scheduled', 'paid-memberships-pro' );
}
return implode( " | \n", $cron_information );
}
/**
* Get the assigned Member pages and their URL's
*
* @since 2.7.3
*
* @return string|string[] The member page information
*/
public function get_pmpro_pages() {
global $pmpro_pages;
$page_information = array();
if( !empty( $pmpro_pages ) ){
foreach( $pmpro_pages as $key => $val ){
$permalink = get_the_permalink( (int)$val );
if( empty( $permalink ) ){
$page_information[$key] = 'Not Set'; //Not translating this
} else {
$page_information[$key] = $permalink;
}
}
} else {
return __( 'No Membership Pages Found', 'paid-memberships-pro' );
}
return $page_information;
}
/**
* Get the .htaccess services/getfile.php usage information.
*
* @since 2.6.4
*
* @return string The .htaccess services/getfile.php usage information.
*/
public function get_getfile_usage() {
if ( ! defined( 'PMPRO_GETFILE_ENABLED' ) ) {
return __( 'PMPRO_GETFILE_ENABLED is not set', 'paid-memberships-pro' );
}
if ( ! PMPRO_GETFILE_ENABLED ) {
return __( 'PMPRO_GETFILE_ENABLED is off', 'paid-memberships-pro' );
}
require_once ABSPATH . 'wp-admin/includes/file.php';
/**
* @var $wp_filesystem WP_Filesystem_Base
*/
global $wp_filesystem;
WP_Filesystem();
if ( ! $wp_filesystem ) {
return __( 'Unable to access .htaccess file', 'paid-memberships-pro' );
}
if ( ! $wp_filesystem->exists( ABSPATH . '/.htaccess' ) ) {
return __( 'Off - No .htaccess file', 'paid-memberships-pro' );
}
$htaccess_contents = $wp_filesystem->get_contents( ABSPATH . '/.htaccess' );
if ( false === strpos( $htaccess_contents, '/services/getfile.php' ) ) {
return __( 'Off', 'paid-memberships-pro' );
}
return __( 'On - .htaccess contains services/getfile.php usage', 'paid-memberships-pro' );
}
/**
* Get the .htaccess cache usage information.
*
* @since 2.6.4
*
* @return string The .htaccess cache usage information.
*/
public function get_htaccess_cache_usage() {
require_once ABSPATH . 'wp-admin/includes/file.php';
/**
* @var $wp_filesystem WP_Filesystem_Base
*/
global $wp_filesystem;
WP_Filesystem();
if ( ! $wp_filesystem || ! is_object($wp_filesystem) || ( is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->has_errors() ) ) {
return __( 'Unable to access .htaccess file', 'paid-memberships-pro' );
}
if ( ! $wp_filesystem->exists( ABSPATH . '/.htaccess' ) ) {
return __( 'Off - No .htaccess file', 'paid-memberships-pro' );
}
$htaccess_contents = $wp_filesystem->get_contents( ABSPATH . '/.htaccess' );
if ( false !== strpos( $htaccess_contents, 'ExpiresByType text/html' ) ) {
return __( 'On - Browser cache enabled for HTML (ExpiresByType text/html), this may interfere with Content Restriction after Login. Remove that line from your .htaccess to resolve this problem.', 'paid-memberships-pro' );
} elseif ( false !== strpos( $htaccess_contents, 'ExpiresDefault' ) ) {
return __( 'On - Browser cache enabled for HTML (ExpiresDefault), this may interfere with Content Restriction after Login. Remove that line from your .htaccess to resolve this problem.', 'paid-memberships-pro' );
}
return __( 'Off', 'paid-memberships-pro' );
}
/**
* Get library conflicts.
*
* @since 2.8
*
* @return string|string[] The member page information
*/
function get_library_conflicts() {
// Get the current list of library conflicts.
$library_conflicts = get_option( 'pmpro_library_conflicts' );
// If there are no library conflicts, return a message.
if ( empty( $library_conflicts ) ) {
return __( 'No library conflicts detected.', 'paid-memberships-pro' );
}
// Format data to be displayed in site health.
$return_arr = array();
// Loop through all libraries that have conflicts.
foreach ( $library_conflicts as $library_name => $conflicting_plugins ) {
$conflict_strings = array();
// Loop through all plugins that have conflicts with this library.
foreach ( $conflicting_plugins as $conflicting_plugin_path => $conflicting_plugin_data ) {
$conflict_strings[] = 'v' . $conflicting_plugin_data['version'] . ' (' . $conflicting_plugin_data['timestamp'] . ')' . ' - ' . $conflicting_plugin_path;
}
$return_arr[ $library_name ] = implode( ' | ', $conflict_strings );
}
return $return_arr;
}
function get_add_ons_with_incorrect_folder_name() {
// Get the current list of Add Ons with the wrong name.
$incorrect_folder_names = PMPro_AddOns::instance()->get_add_ons_with_incorrect_folder_names();
// Build error messages for each Add On with the wrong name.
$errors = array();
foreach ( $incorrect_folder_names as $installed_name => $addon ) {
$errors[] = "{$addon['Name']} ( {$addon['plugin']} => {$installed_name} )";
}
return empty( $errors ) ? __( 'No add ons with incorrect folder names detected.', 'paid-memberships-pro' ) : implode( " | \n", $errors );
}
/**
* Get the constants site health information.
*
* @since 2.6.4
*
* @return array The constants site health information.
*/
public function get_constants() {
$constants = [
'PMPRO_CRON_LIMIT' => __( 'Cron Limit', 'paid-memberships-pro' ),
'PMPRO_DEFAULT_LEVEL' => __( 'Default Membership Level', 'paid-memberships-pro' ),
'PMPRO_USE_SESSIONS' => __( 'Use Sessions', 'paid-memberships-pro' ),
];
$gateway_specific_constants = [
'authorizenet' => [
'PMPRO_AUTHNET_SILENT_POST_DEBUG' => __( 'Authorize.net Silent Post Debug Mode', 'paid-memberships-pro' ),
],
'braintree' => [
'PMPRO_BRAINTREE_WEBHOOK_DEBUG' => __( 'Braintree Webhook Debug Mode', 'paid-memberships-pro' ),
],
'paypal' => [
'PMPRO_IPN_DEBUG' => __( 'PayPal IPN Debug Mode', 'paid-memberships-pro' ),
],
'paypalexpress' => [
'PMPRO_IPN_DEBUG' => __( 'PayPal IPN Debug Mode', 'paid-memberships-pro' ),
],
'paypalstandard' => [
'PMPRO_IPN_DEBUG' => __( 'PayPal IPN Debug Mode', 'paid-memberships-pro' ),
],
'stripe' => [
'PMPRO_STRIPE_WEBHOOK_DEBUG' => __( 'Stripe Webhook Debug Mode', 'paid-memberships-pro' ),
],
'twocheckout' => [
'PMPRO_INS_DEBUG' => __( '2Checkout INS Debug Mode', 'paid-memberships-pro' ),
],
];
$gateway = get_option( 'pmpro_gateway' );
if ( $gateway && isset( $gateway_specific_constants[ $gateway ] ) ) {
$constants = array_merge( $constants, $gateway_specific_constants[ $gateway ] );
}
/**
* Allow filtering the supported Site Health constants by other add ons.
*
* @since 2.6.4
*
* @param array $constants The list of constants to show in Site Health.
* @param string $gateway The current payment gateway.
*/
$constants = apply_filters( 'pmpro_site_health_constants', $constants, $gateway );
// Get and format constant information.
$constants_formatted = [];
foreach ( $constants as $constant => $label ) {
// Only get site health info for constants that are set.
if ( ! defined( $constant ) ) {
continue;
}
$constants_formatted[ 'pmpro-constants-' . $constant ] = [
'label' => $label . ' (' . $constant . ')',
'value' => var_export( constant( $constant ), true ),
];
}
return $constants_formatted;
}
/**
* Get the pause mode state
*
* @since 2.10
*
* @return string What state is pause mode in
*/
public function get_pause_mode_state() {
$pause_mode = pmpro_is_paused();
if( $pause_mode ) {
return __( 'Enabled', 'paid-memberships-pro' );
}
return __( 'Disabled', 'paid-memberships-pro' );
}
/**
* Check for Action Scheduler issues.
*
* @since 3.5.3
*
* @return string Count any issues found with Action Scheduler or its tables.
*/
public function action_scheduler_issues() {
// This is a wrapper for the Action Scheduler method.
$issues = PMPro_Action_Scheduler::check_action_scheduler_table_health();
if ( empty( $issues ) ) {
return __( 'No issues found with the Action Scheduler tables.', 'paid-memberships-pro' );
} else {
// Let's format the issues into a semicolon-separated string.
return implode( '; ', array_map( 'esc_html', $issues ) ) . '.';
}
}
}