empty( $event_times['plugin_installed'] )
? $event_times['plugin_installed']
: '';
if ( $installed_at && is_array( $configs ) ) {
foreach ( $configs as $index => $config ) {
if ( ! empty( $config['default'] ) && empty( $config['date'] ) ) {
$configs[ $index ]['date'] = $installed_at;
}
}
}
$script = ( new Script() )
->set_handle( 'smush-ui-settings' )
->set_source( WP_SMUSH_URL . 'app/assets/js/smush-ui-settings.min.js' )
->set_dependencies( array( 'smush-ui-vendor', 'wp-i18n', 'media-editor', 'clipboard' ) )
->set_version( WP_SMUSH_VERSION )
->set_in_footer( true )
->set_localization_data(
array(
'activeSettingsTab' => $current_tab,
'links' => array(),
'requestsData' => array(
'ImageRestoreData' => array(
'restore_ids' => ( new Backups() )->get_attachments_with_backups(),
'smush_bulk_restore' => wp_create_nonce( 'smush_bulk_restore' ),
),
),
'bulkSmushMetaData' => array(
'imageSizes' => array(
'allSelected' => $all_selected,
'sizes' => $sizes,
'selected' => is_array( $image_sizes ) ? $image_sizes : array(),
),
),
'configsData' => array(
'nonce' => wp_create_nonce( 'smush_handle_config' ),
'restNonce' => wp_create_nonce( 'wp_rest' ),
'restUrl' => rest_url( 'wp-smush/v1/preset_configs' ),
// Initial configs list (avoids a separate REST fetch on page load).
'configs' => $configs,
'configTipsDismissed' => ! empty( get_option( 'wp-smush-dismissed-notices', array() )['config_tips_toast'] ),
),
)
);
$style = ( new Style() )
->set_handle( 'smush-ui-settings-style' )
->set_source( WP_SMUSH_URL . 'app/assets/css/smush-ui-settings.min.css' )
->set_dependencies( array() )
->set_version( WP_SMUSH_VERSION );
return ( new Admin_Page() )
->set_slug( self::PAGE_SETTINGS )
->set_title( __( 'Settings', 'wp-smushit' ) )
->set_scripts( array( $script ) )
->set_styles( array( $style ) );
}
public function smush_body_classes( $classes ) {
// Exit if function doesn't exists.
if ( ! function_exists( 'get_current_screen' ) ) {
return $classes;
}
$current_screen_id = get_current_screen()->id;
// If not on plugin page.
if ( ! in_array( $current_screen_id, Admin::$plugin_pages, true ) && false === strpos( $current_screen_id, 'page_smush' ) ) {
return $classes;
}
// Remove old wpmud class from body of smush page to avoid style conflict.
$classes = str_replace( 'wpmud ', '', $classes );
$classes .= ' wpmudev-core-ui';
if ( $this->show_onboarding_wizard() ) {
$classes .= ' smush-onboarding-wizard smush-onboarding-wizard--fullscreen';
}
if ( Settings::get_instance()->get( 'accessible_colors' ) ) {
$classes .= ' wpmudev-core-ui__mono';
}
$classes .= Membership::get_instance()->get_guest_value( ' smush-plan-free', ' smush-plan-pro' );
return $classes;
}
/**
* Get user avatar URL.
*
* @return string|bool Avatar URL or false on failure.
* @since 3.24.0
*/
protected function get_user_avatar() {
$current_user = wp_get_current_user();
if ( ! $this->has_real_gravatar( $current_user->user_email ) ) {
return false;
}
$avatar_url = get_avatar_url( $current_user->ID );
return $avatar_url;
}
/**
* Checks if the current user has a real Gravatar image set.
* * @return bool True if they have a custom photo, false if they are using a default.
*/
protected function has_real_gravatar( $user_email = null ) {
$email = trim( strtolower( $user_email ) );
$hash = md5( $email );
$cache_key = 'smush_user_gravatar_' . $hash;
$has_gravatar = get_transient( $cache_key );
if ( $has_gravatar ) {
return (bool) $has_gravatar;
}
// Build a URL that asks Gravatar to return a 404 error if no image exists.
$check_url = "https://www.gravatar.com/avatar/$hash?d=404";
// Use WordPress remote_head to check just the headers (and save some bandwidth).
$response = wp_remote_head( $check_url );
// If the response code is 200, the image exists. If it is 404, it doesn't.
$has_gravatar = wp_remote_retrieve_response_code( $response ) === 200;
set_transient( $cache_key, $has_gravatar, DAY_IN_SECONDS );
return $has_gravatar;
}
/**
* Get user initials from first and last name.
*
* @return string User initials.
* @since 3.24.0
*/
protected function get_user_initials() {
$current_user = wp_get_current_user();
$first = $current_user->user_firstname;
$last = $current_user->user_lastname;
if ( ! empty( $first ) || ! empty( $last ) ) {
$first_initial = ! empty( $first ) ? substr( $first, 0, 1 ) : '';
$last_initial = ! empty( $last ) ? substr( $last, 0, 1 ) : '';
return strtoupper( $first_initial . $last_initial );
}
// Fallback: Use the first letter of the Display Name if no first or last name is set.
return strtoupper( substr( $current_user->display_name, 0, 1 ) );
}
/**
* Get current user email address.
*
* @return string User email or empty string if not available.
* @since 3.24.0
*/
protected function get_user_email() {
$current_user = wp_get_current_user();
if ( ! $current_user->exists() ) {
return '';
}
return $current_user->user_email ?? '';
}
/**
* Get current user display name.
*
* @return string User display name or empty string if not available.
* @since 4.0
*/
protected function get_user_display_name() {
$current_user = wp_get_current_user();
if ( ! $current_user->exists() ) {
return '';
}
return $current_user->display_name ?? '';
}
private function show_onboarding_wizard() {
if ( is_multisite() && ! is_network_admin() ) {
return false;
}
$skip_quick_setup = ! empty( get_option( 'skip-smush-setup' ) );
$smush_action = isset( $_GET['smush_action'] ) ? sanitize_text_field( $_GET['smush_action'] ) : '';
$should_skip_wizard = Hub_Connector::is_syncing() || ( 'skip-wizard' === $smush_action );
if ( $should_skip_wizard ) {
if ( ! $skip_quick_setup ) {
// If syncing, and not skipped, we consider the setup is done.
update_option( 'skip-smush-setup', true );
}
return false;
}
$is_our_page = false;
foreach ( $this->get_admin_pages() as $admin_page ) {
if ( $admin_page->get_slug() === $this->get_current_page() ) {
$is_our_page = true;
break;
}
}
if ( ! $is_our_page ) {
return false;
}
// Keep users on the login flow when Hub returns an auth error.
if ( Hub_Connector::has_error_in_login() ) {
return true;
}
$settings = Settings::get_instance();
if (
$skip_quick_setup
|| ! $settings->has_bulk_smush_page()
) {
return false;
}
return true;
}
private function enqueue_onboarding_wizard_script( $page ) {
wp_enqueue_script(
'smush-ui-onboarding-wizard',
WP_SMUSH_URL . 'app/assets/js/smush-ui-onboarding-wizard.min.js',
array( 'smush-ui-vendor', 'wp-i18n' ),
WP_SMUSH_VERSION,
true
);
wp_set_script_translations( 'smush-ui-onboarding-wizard', 'wp-smushit', WP_SMUSH_DIR . 'languages' );
$this->localize_script(
'smush-ui-onboarding-wizard',
array(
'smushSetupNonce' => wp_create_nonce( 'smush_quick_setup' ),
'showOnboardingWizard' => true,
),
$page
);
wp_enqueue_style(
'smush-ui-onboarding-wizard-style',
WP_SMUSH_URL . 'app/assets/css/smush-ui-onboarding-wizard.min.css',
array(),
WP_SMUSH_VERSION
);
}
/**
* @return string
*/
private function get_plugin_update_url() {
return add_query_arg(
array(
'action' => 'upgrade-plugin',
'plugin' => WP_SMUSH_BASENAME,
'_wpnonce' => wp_create_nonce( 'upgrade-plugin_' . WP_SMUSH_BASENAME ),
),
self_admin_url( 'update.php' )
);
}
private function get_current_page() {
return isset( $_GET['page'] ) ? sanitize_text_field( $_GET['page'] ) : '';
}
/**
* Handle a React UI error event and forward it to product analytics.
*
* Accepts:
* message (string) – error.message
* code (string) – error.name (e.g. "TypeError")
* stack (string) – error.stack, truncated to 2000 chars by the client
* component_stack (string) – React component hierarchy from ErrorInfo
* page (string) – window.location.pathname at the time of the error
*
* @return void
*/
public function ajax_ui_error() {
check_ajax_referer( 'wp-smush-ajax' );
if ( ! Helper::is_user_allowed() ) {
wp_send_json_error( array( 'message' => __( 'Insufficient permissions', 'wp-smushit' ) ), 403 );
}
$message = isset( $_POST['message'] ) ? sanitize_text_field( wp_unslash( $_POST['message'] ) ) : '';
$code = isset( $_POST['code'] ) ? sanitize_text_field( wp_unslash( $_POST['code'] ) ) : 'UnknownError';
$stack = isset( $_POST['stack'] ) ? sanitize_textarea_field( wp_unslash( $_POST['stack'] ) ) : '';
$component_stack = isset( $_POST['component_stack'] ) ? sanitize_textarea_field( wp_unslash( $_POST['component_stack'] ) ) : '';
$page = isset( $_POST['page'] ) ? sanitize_text_field( wp_unslash( $_POST['page'] ) ) : '';
$extra_properties = array_filter( array(
'Stack Trace' => $stack,
'Component Stack' => $component_stack,
'Page' => $page,
) );
Product_Analytics::get_instance()->maybe_track_error( 'react_ui', $code, $message, $extra_properties );
wp_send_json_success();
}
/**
* Render the deactivation survey modal.
*
* @return void
*/
public function render_deactivate_survey_modal() {
$current_screen = get_current_screen();
if ( ! $current_screen || 'plugins' !== $current_screen->id ) {
return;
}
wp_enqueue_script( 'smush-shared-ui' );
wp_enqueue_style( 'smush-shared-ui' );
$this->view( 'deactivation-survey' );
}
/**
* Load an admin view.
*
* @param string $name View name = file name.
* @param array $args Arguments.
* @param string $dir Directory for the views. Default: views.
*/
private function view( $name, $args = array(), $dir = 'views' ) {
$file = WP_SMUSH_DIR . "app/{$dir}/{$name}.php";
$content = '';
if ( is_file( $file ) ) {
ob_start();
if ( isset( $args['id'] ) ) {
$args['orig_id'] = $args['id'];
$args['id'] = str_replace( '/', '-', $args['id'] );
}
extract( $args );//phpcs:ignore
include $file;
$content = ob_get_clean();
}
// Everything escaped in all template files.
echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* Check if the upgrade modal should be shown.
*
* @return bool
*/
private function should_show_upgrade_modal() {
return get_site_option( 'wp-smush-show_upgrade_modal' );
}
/**
* Hide the new features modal
*/
public function hide_new_features_modal() {
check_ajax_referer( 'wp-smush-ajax' );
// Check for permission.
if ( ! Helper::is_user_allowed( 'manage_options' ) ) {
wp_die( esc_html__( 'Unauthorized', 'wp-smushit' ), 403 );
}
delete_site_option( 'wp-smush-show_upgrade_modal' );
wp_send_json_success();
}
/**
* Provide translations for JavaScript files.
*
* @param mixed $translations
* @param mixed $file
* @param mixed $handle
* @param mixed $domain
*/
public function provide_script_translations( $translations, $file, $handle, $domain ) {
if ( 'wp-smushit' !== $domain ) {
return $translations;
}
static $served = false;
static $cached_json = null;
if ( $served ) {
return wp_json_encode(
array(
'locale_data' => array(
'wp-smushit' => array(
'' => array(
'domain' => 'wp-smushit',
),
),
),
)
);
}
if ( null !== $cached_json ) {
return $cached_json;
}
$locale = is_admin() ? get_user_locale() : get_locale();
$mo_file = WP_LANG_DIR . "/plugins/{$domain}-{$locale}.mo";
if ( ! file_exists( $mo_file ) ) {
return $translations;
}
$mo = new \MO();
if ( ! $mo->import_from_file( $mo_file ) ) {
return $translations;
}
$locale_data = array(
'' => array(
'domain' => $domain,
'lang' => $locale,
),
);
if ( ! empty( $mo->headers['Plural-Forms'] ) ) {
$locale_data['']['plural-forms'] = $mo->headers['Plural-Forms'];
}
foreach ( $mo->entries as $msgid => $entry ) {
$locale_data[ $msgid ] = $entry->translations;
}
$cached_json = wp_json_encode(
array(
'locale_data' => array(
$domain => $locale_data,
),
)
);
$served = true;
return $cached_json;
}
/**
* White-label the plugin name as displayed on the Plugins screen (`plugins.php`).
*
* This only affects display (the plugin file/slug stays the same).
*
* @param array $plugins All plugins.
*
* @return array
*/
public function maybe_whitelabel_plugin_name_in_plugins_list( $plugins ) {
if ( ! is_array( $plugins ) || ! defined( 'WP_SMUSH_BASENAME' ) || empty( $plugins[ WP_SMUSH_BASENAME ] ) ) {
return $plugins;
}
if ( ! $this->whitelabel->is_whitelabel_enabled() ) {
return $plugins;
}
$whitelabel_keys = array(
'Name',
'Title',
);
// Whitelabel the plugin name and title.
foreach ( $whitelabel_keys as $key ) {
if ( isset( $plugins[ WP_SMUSH_BASENAME ][ $key ] ) ) {
$plugins[ WP_SMUSH_BASENAME ][ $key ] = $this->whitelabel->replace_branding_terms( $plugins[ WP_SMUSH_BASENAME ][ $key ] );
}
}
// Whitelabel the plugin description.
$whitelabel_description = $this->whitelabel->replace_branding_terms(
$this->whitelabel->remove_brand_links( $plugins[ WP_SMUSH_BASENAME ]['Description'] )
);
$plugins[ WP_SMUSH_BASENAME ]['Description'] = $whitelabel_description;
// Whitelabel the plugin author.
if ( $this->whitelabel->hide_doc_link() ) {
$plugins[ WP_SMUSH_BASENAME ]['Author'] = '';
$plugins[ WP_SMUSH_BASENAME ]['PluginURI'] = '';
}
return $plugins;
}
/**
* Adds action links on plugin page.
*
* @param array $links Current links.
*
* @return array|string
*/
public function plugin_action_links( $links ) {
// Upgrade link.
if ( Membership::get_instance()->get_guest_value( true, false ) ) {
$upgrade_url = add_query_arg(
array(
'utm_source' => 'smush',
'utm_medium' => 'plugin',
'utm_campaign' => 'wp-smush-pro/wp-smush.php' !== WP_SMUSH_BASENAME ? 'smush_pluginlist_upgrade' : 'smush_pluginlist_renew',
),
esc_url( 'https://wpmudev.com/project/wp-smush-pro/' )
);
$using_free_version = 'wp-smush-pro/wp-smush.php' !== WP_SMUSH_BASENAME;
if ( $using_free_version ) {
$label = __( 'Upgrade to Smush Pro', 'wp-smushit' );
$text = __( 'Get Smush Pro', 'wp-smushit' );
} else {
$label = __( 'Renew Membership', 'wp-smushit' );
$text = __( 'Renew Membership', 'wp-smushit' );
}
if ( isset( $text ) ) {
$links['smush_upgrade'] = '' . esc_html( $text ) . '';
}
}
if ( ! $this->whitelabel->should_hide_doc_link() ) {
// Documentation link.
$docs_link = Helper::get_utm_link(
array( 'utm_campaign' => 'smush_pluginlist_docs' ),
'https://wpmudev.com/docs/wpmu-dev-plugins/smush/'
);
$links['smush_docs'] = '' . esc_html__( 'Docs', 'wp-smushit' ) . '';
}
// Dashboard link.
$dashboard_page = is_multisite() && is_network_admin() ? network_admin_url( 'admin.php?page=smush' ) : menu_page_url( 'smush', false );
$links['smush_dashboard'] = '' . esc_html__( 'Dashboard', 'wp-smushit' ) . '';
$access = get_site_option( 'wp-smush-networkwide' );
if ( ! is_network_admin() && is_plugin_active_for_network( WP_SMUSH_BASENAME ) && ! $access ) {
// Remove settings link for subsites if Subsite Controls is not set on network permissions tab.
unset( $links['smush_dashboard'] );
}
return array_reverse( $links );
}
/**
* Add additional links next to the plugin version.
*
* @param array $links Links array.
* @param string $file Plugin basename.
*
* @return array
*/
public function add_plugin_meta_links( $links, $file ) {
if ( ! defined( 'WP_SMUSH_BASENAME' ) || WP_SMUSH_BASENAME !== $file ) {
return $links;
}
if ( 'wp-smush-pro/wp-smush.php' !== WP_SMUSH_BASENAME ) {
$links[] = '' . esc_html__( 'Rate Smush', 'wp-smushit' ) . '';
$links[] = '' . esc_html__( 'Support', 'wp-smushit' ) . '';
} elseif ( ! $this->whitelabel->should_hide_doc_link() ) {
if ( isset( $links[2] ) && false !== strpos( $links[2], 'project/wp-smush-pro' ) ) {
$links[2] = sprintf(
'%s',
__( 'View details', 'wp-smushit' )
);
}
$links[] = '' . esc_html__( 'Premium Support', 'wp-smushit' ) . '';
}
if ( $this->whitelabel->should_hide_doc_link() ) {
return $links;
}
$roadmap_link = Helper::get_utm_link(
array(
'utm_campaign' => 'smush_pluginlist_roadmap',
),
'https://wpmudev.com/roadmap/'
);
$links[] = '' . esc_html__( 'Roadmap', 'wp-smushit' ) . '';
$links[] = '
★★★★★
';
echo '';
return $links;
}
/**
* Dismiss the plugin conflicts notice.
*/
public function dismiss_notice() {
check_ajax_referer( 'wp-smush-ajax' );
// Check capability.
if ( ! Helper::is_user_allowed( 'manage_options' ) ) {
wp_die( esc_html__( 'Unauthorized', 'wp-smushit' ), 403 );
}
if ( empty( $_REQUEST['key'] ) ) {
wp_send_json_error();
}
$this->set_notice_dismissed( sanitize_key( $_REQUEST['key'] ) );
wp_send_json_success();
}
private function set_notice_dismissed( $notice ) {
$option_id = 'wp-smush-dismissed-notices';
$dismissed_notices = get_option( $option_id, array() );
$dismissed_notices[ $notice ] = true;
update_option( $option_id, $dismissed_notices );
}
/**
* Hide API Message
*/
public function hide_api_message() {
check_ajax_referer( 'wp-smush-ajax' );
// Check capability.
if ( ! Helper::is_user_allowed( 'manage_options' ) ) {
wp_die( esc_html__( 'Unauthorized', 'wp-smushit' ), 403 );
}
$api_message = get_site_option( 'wp-smush-api_message', array() );
if ( ! empty( $api_message ) && is_array( $api_message ) ) {
$api_message[ key( $api_message ) ]['status'] = 'hide';
update_site_option( 'wp-smush-api_message', $api_message );
}
wp_send_json_success();
}
public function print_upgrade_submenu_script() {
}
/**
* @return void
*/
public function add_upgrade_submenu_page() {
add_submenu_page(
self::PAGE_DASHBOARD,
__( 'Upgrade to Smush Pro', 'wp-smushit' ),
sprintf(
'%1$s',
__( 'Upgrade', 'wp-smushit' ),
__( 'Pro', 'wp-smushit' )
),
$this->get_permission_level_for_menus(),
esc_url( 'https://wpmudev.com/project/wp-smush-pro/?utm_source=smush&utm_medium=plugin&utm_campaign=smush_new-submenu_upsell#dev-pricing' )
);
}
}