ShouldCheck.
*/
public static function menu() {
add_management_page( 'ShouldCheck', 'ShouldCheck', 'manage_options', self::SLUG, array( __CLASS__, 'render' ) );
}
/**
* Load CSS and scripts only where they are needed.
*
* @param string $hook Admin page hook.
*/
public static function assets( $hook ) {
if ( 'tools_page_' . self::SLUG === $hook ) {
wp_enqueue_style( 'shouldcheck-admin', SHOULDCHECK_URL . 'assets/css/admin.css', array(), SHOULDCHECK_VERSION );
wp_enqueue_script( 'shouldcheck-review', SHOULDCHECK_URL . 'assets/js/review.js', array(), SHOULDCHECK_VERSION, true );
}
if ( in_array( $hook, array( 'plugin-install.php', 'plugins.php' ), true ) && current_user_can( 'install_plugins' ) && ShouldCheck_Settings::active( 'beside' ) ) {
wp_enqueue_style( 'shouldcheck-screens', SHOULDCHECK_URL . 'assets/css/screens.css', array( 'dashicons' ), SHOULDCHECK_VERSION );
}
if ( 'plugin-install.php' === $hook && current_user_can( 'install_plugins' ) && ! is_multisite() && ShouldCheck_Settings::active( 'beside' ) ) {
wp_enqueue_script( 'shouldcheck-install-screen', SHOULDCHECK_URL . 'assets/js/install-screen.js', array(), SHOULDCHECK_VERSION, true );
wp_localize_script(
'shouldcheck-install-screen',
'shouldcheckInstall',
array(
'action' => admin_url( 'admin-post.php' ),
'nonce' => wp_create_nonce( 'shouldcheck_check_zip' ),
)
);
}
}
/**
* "ShouldCheck" link on the Plugins screen row for this plugin.
*
* @param array $links Action links.
* @return array
*/
public static function action_links( $links ) {
array_unshift( $links, 'Open ShouldCheck' );
return $links;
}
/**
* Ask for the first-run choices on the Plugins screens until they are made. After a reinstall that found
* kept data, point to the choice about it instead. Activation does not redirect, so this is the way in.
*/
public static function setup_notice() {
global $pagenow;
if ( ! in_array( $pagenow, array( 'plugins.php', 'plugin-install.php' ), true ) || ! current_user_can( 'manage_options' ) ) {
return;
}
if ( get_user_meta( get_current_user_id(), 'shouldcheck_setup_dismissed', true ) ) {
return;
}
$dismiss = wp_nonce_url( admin_url( 'admin-post.php?action=shouldcheck_dismiss_setup' ), 'shouldcheck_dismiss_setup' );
if ( is_array( get_option( 'shouldcheck_kept_data', false ) ) ) {
echo '
';
return;
}
if ( ShouldCheck_Settings::get( 'onboarded' ) ) {
return;
}
echo 'ShouldCheck needs two choices before it appears on these screens. Choose now · Not now
';
}
/**
* Hide the first-run notice for this person. They can still choose on the ShouldCheck screen.
*/
public static function dismiss_setup() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'Forbidden', 'shouldcheck' ), '', array( 'response' => 403 ) );
}
check_admin_referer( 'shouldcheck_dismiss_setup' );
update_user_meta( get_current_user_id(), 'shouldcheck_setup_dismissed', 1 );
wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url( 'plugins.php' ) );
exit;
}
/**
* Record the site's current state now.
*/
public static function check_now() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'Forbidden', 'shouldcheck' ), '', array( 'response' => 403 ) );
}
check_admin_referer( 'shouldcheck_check_now' );
ShouldCheck_Site::reconcile();
wp_safe_redirect( ShouldCheck_Views::url( array( 'shouldcheck_message' => 'checked' ) ) );
exit;
}
/**
* Save the two settings.
*/
public static function save_settings() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'Forbidden', 'shouldcheck' ), '', array( 'response' => 403 ) );
}
check_admin_referer( 'shouldcheck_save_settings' );
$lookup = sanitize_key( wp_unslash( $_POST['package_lookup'] ?? 'no' ) );
$mode = sanitize_key( wp_unslash( $_POST['mode'] ?? 'beside' ) );
ShouldCheck_Settings::update(
array(
'package_lookup' => 'yes' === $lookup ? 'yes' : 'no',
'beside' => 'manual' !== $mode,
'onboarded' => true,
'keep_data' => '1' === sanitize_key( wp_unslash( $_POST['keep_data'] ?? '0' ) ),
)
);
wp_safe_redirect( ShouldCheck_Views::url( array( 'shouldcheck_message' => 'saved' ) ) );
exit;
}
/**
* Show the first-run setup again. Reviews, history and settings stay as they are.
*/
public static function reset_setup() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'Forbidden', 'shouldcheck' ), '', array( 'response' => 403 ) );
}
check_admin_referer( 'shouldcheck_reset_setup' );
ShouldCheck_Settings::update( array( 'onboarded' => false ) );
wp_safe_redirect( ShouldCheck_Views::url() . '#shouldcheck-settings' );
exit;
}
/**
* After a reinstall that found kept data: keep it, or delete it now.
*/
public static function kept_decide() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'Forbidden', 'shouldcheck' ), '', array( 'response' => 403 ) );
}
check_admin_referer( 'shouldcheck_kept_decide' );
$choice = sanitize_key( wp_unslash( $_POST['choice'] ?? '' ) );
if ( 'delete' === $choice ) {
foreach ( array( ShouldCheck_Site::OPT_SNAPSHOTS, ShouldCheck_Site::OPT_EVENTS, ShouldCheck_Site::OPT_LAST_CHECK, ShouldCheck_Reports::OPTION, ShouldCheck_Settings::OPTION ) as $option ) {
delete_option( $option );
}
delete_option( 'shouldcheck_kept_data' );
ShouldCheck_Site::reconcile();
wp_safe_redirect( ShouldCheck_Views::url( array( 'shouldcheck_message' => 'cleared' ) ) . '#shouldcheck-settings' );
exit;
}
delete_option( 'shouldcheck_kept_data' );
wp_safe_redirect( ShouldCheck_Views::url( array( 'shouldcheck_message' => 'kept' ) ) );
exit;
}
/**
* Delete one saved review.
*/
public static function delete_report() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'Forbidden', 'shouldcheck' ), '', array( 'response' => 403 ) );
}
check_admin_referer( 'shouldcheck_report_delete' );
$id = sanitize_text_field( wp_unslash( $_POST['report_id'] ?? '' ) );
if ( ShouldCheck_Reports::is_id( $id ) ) {
ShouldCheck_Reports::delete( $id );
}
wp_safe_redirect(
ShouldCheck_Views::url(
array(
'shouldcheck_tab' => 'reviews',
'shouldcheck_message' => 'deleted',
)
)
);
exit;
}
/**
* Read a query argument as plain text.
*
* @param string $key Argument name.
* @return string
*/
private static function arg( $key ) {
return isset( $_GET[ $key ] ) ? sanitize_text_field( wp_unslash( $_GET[ $key ] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
}
/**
* Render the screen.
*/
public static function render() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'Forbidden', 'shouldcheck' ), '', array( 'response' => 403 ) );
}
echo '';
echo self::flash(); // phpcs:ignore WordPress.Security.EscapeOutput
$upload = self::arg( 'shouldcheck_upload' );
$dir = self::arg( 'shouldcheck_directory' );
$update = self::arg( 'shouldcheck_update' );
$file = self::arg( 'shouldcheck_file' );
$inst = self::arg( 'shouldcheck_installed' );
if ( '' !== $upload ) {
echo ShouldCheck_Installer::render_zip_review( $upload ); // phpcs:ignore WordPress.Security.EscapeOutput
} elseif ( '' !== $dir && ShouldCheck_Requirements::valid_slug( $dir ) ) {
echo ShouldCheck_Installer::render_directory_review( $dir ); // phpcs:ignore WordPress.Security.EscapeOutput
} elseif ( '' !== $inst ) {
echo ShouldCheck_Installer::render_installed_review( $inst ); // phpcs:ignore WordPress.Security.EscapeOutput
} elseif ( '' !== $update && '' !== $file ) {
echo ShouldCheck_Installer::render_update_review( $update, $file ); // phpcs:ignore WordPress.Security.EscapeOutput
} else {
if ( '' !== $dir ) {
echo '
That is not a valid plugin identifier.
';
}
$tab = self::arg( 'shouldcheck_tab' );
$tab = in_array( $tab, array( 'reviews', 'changes' ), true ) ? $tab : 'overview';
if ( '' !== self::arg( 'shouldcheck_view' ) ) {
$tab = 'reviews';
}
echo ShouldCheck_Views::heading( 'ShouldCheck', 'Tools' ); // phpcs:ignore WordPress.Security.EscapeOutput
echo ShouldCheck_Views::tabs( $tab ); // phpcs:ignore WordPress.Security.EscapeOutput
if ( 'reviews' === $tab ) {
echo self::reviews_tab(); // phpcs:ignore WordPress.Security.EscapeOutput
} elseif ( 'changes' === $tab ) {
echo self::changes_tab(); // phpcs:ignore WordPress.Security.EscapeOutput
} else {
echo self::overview_tab(); // phpcs:ignore WordPress.Security.EscapeOutput
}
}
echo '
';
}
/**
* One-time notices after an action.
*
* @return string
*/
private static function flash() {
$out = '';
$msg = self::arg( 'shouldcheck_message' );
if ( 'checked' === $msg ) {
$out .= 'Site checked. Any changes were recorded.
';
} elseif ( 'saved' === $msg ) {
$out .= '';
} elseif ( 'kept' === $msg ) {
$out .= 'Your earlier reviews and history are back.
';
} elseif ( 'cleared' === $msg ) {
$out .= 'Earlier data deleted. Start fresh below.
';
} elseif ( 'deleted' === $msg ) {
$out .= '';
}
return $out;
}
/**
* Overview.
*
* @return string
*/
private static function overview_tab() {
$site = ShouldCheck_Site::snapshot();
$out = '';
$kept = get_option( 'shouldcheck_kept_data', false );
if ( is_array( $kept ) ) {
$out .= ShouldCheck_Views::welcome_back_card( $kept );
}
$out .= 'Check a plugin before you install it
Choose a plugin ZIP. ShouldCheck reads it and tells you, in plain words, what it found and what it could not check.
';
if ( current_user_can( 'install_plugins' ) && ! is_multisite() ) {
$out .= '';
$out .= '- Takes a few seconds
- Nothing is installed until you confirm
- ShouldCheck never runs the plugin
';
} else {
$out .= 'Checking uploads is not available for this user or on a multisite network.
';
}
if ( ! ShouldCheck_Settings::get( 'onboarded' ) ) {
$out .= 'First time here? Finish the quick setup below.
';
}
$out .= '';
$out .= 'Recent reviews
' . ShouldCheck_Views::reports_table( ShouldCheck_Reports::all(), 8 );
if ( count( ShouldCheck_Reports::all() ) > 8 ) {
$out .= 'All reviews
';
}
$out .= '';
$out .= '';
$last = get_option( ShouldCheck_Site::OPT_LAST_CHECK, '' );
$out .= '
This site
' . ShouldCheck_Views::site_card( $site ) . 'Last compared: ' . esc_html( $last ? $last . ' UTC' : 'not yet' ) . '. Compared hourly by WP-Cron, which depends on site traffic.
';
$out .= '
';
$out .= ShouldCheck_Views::checkout_card();
$out .= 'Recent site changes
' . ShouldCheck_Views::timeline_table( ShouldCheck_Site::timeline( 6 ) ) . 'All site changes
';
$out .= ShouldCheck_Views::settings_card( ShouldCheck_Settings::all() );
return $out;
}
/**
* Reviews tab: list and one report.
*
* @return string
*/
private static function reviews_tab() {
$out = '';
$selected = self::arg( 'shouldcheck_view' );
$reports = ShouldCheck_Reports::all();
if ( '' !== $selected ) {
$report = ShouldCheck_Reports::find( $selected );
if ( $report ) {
$out .= ShouldCheck_Views::report_page( $report );
} else {
$out .= 'That review was not found. It may have been deleted.
';
}
}
$out .= 'All reviews ' . (int) count( $reports ) . ' kept, newest first
' . ShouldCheck_Views::reports_table( $reports, 0 ) . '';
return $out;
}
/**
* Site changes tab.
*
* @return string
*/
private static function changes_tab() {
$site = ShouldCheck_Site::snapshot();
$out = 'Site changes
' . ShouldCheck_Views::timeline_table( ShouldCheck_Site::timeline( 60 ) ) . '';
$out .= 'Current state
' . ShouldCheck_Views::site_card( $site ) . '';
return $out;
}
}