REDROOM
PHP 8.2.31
Path:
Logout
Edit File
Size: 14.91 KB
Close
//home/nshryvcy/radiantskinclinics.org/wp-content/plugins/metform/utils/feedback/plugin-unsubscribe.php
Text
Base64
<?php /** * Plugin Unsubscribe / Deactivation Feedback Handler * * Renders a feedback modal on plugin deactivation, collects user input, * and sends telemetry to the MetForm API. * * @package MetForm\Utils\Feedback * @since 1.0.0 */ namespace MetForm\Utils\Feedback; use MetForm\Plugin; use WP_Error; defined( 'ABSPATH' ) || exit; class Plugin_Unsubscribe { /** * Constructor. * * Registers all admin-side hooks required by this feature. * * @since 1.0.0 */ public function __construct() { if ( ! is_admin() ) { return; } add_action( 'admin_footer', array( $this, 'render_modal' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); add_action( 'wp_ajax_metform_deactivation_feedback', array( $this, 'handle_feedback' ) ); } /** * Enqueue CSS and JS assets for the deactivation feedback modal. * * Passes localised data (nonce, AJAX URL, plugin URL) * to the front-end script via {@see wp_localize_script()}. * * @since 1.0.0 * * @return void */ public function enqueue_scripts( $hook_suffix ) { if ( 'plugins.php' !== $hook_suffix ) { return; } $plugin_url = Plugin::instance()->plugin_url(); $version = Plugin::instance()->version(); wp_enqueue_style( 'metform-deactivation-modal', $plugin_url . 'utils/feedback/assets/css/metform-deactivation-modal.css', array(), $version ); wp_enqueue_script( 'metform-deactivation-modal', $plugin_url . 'utils/feedback/assets/js/metform-deactivation-modal.js', array( 'jquery' ), $version, true ); wp_localize_script( 'metform-deactivation-modal', 'MetFormDeactivation', array( 'nonce' => wp_create_nonce( 'metform-deactivation' ), 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'plugin_url' => $plugin_url, ) ); } /** * Output the deactivation feedback modal markup in the admin footer. * * @since 1.0.0 * * @return void */ public function render_modal() { $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; if ( ! $screen || 'plugins' !== $screen->id ) { return; } $reasons = $this->get_deactivation_reasons(); ?> <div id="mf-deactivation-modal" class="mf-deactivation-modal"> <div class="mf-deactivation-content"> <?php $this->render_modal_header(); ?> <div class="mf-deactivation-body"> <div id="mf-deactivation-error-message" class="mf-deactivation-error-message" style="display: none;"></div> <h2 class="mf-deactivation-title"> <?php esc_html_e( 'Before you go, what made you deactivate MetForm?', 'metform' ); ?> </h2> <form id="mf-deactivation-form" class="mf-deactivation-form"> <input type="hidden" name="metform_nonce" value="<?php echo esc_attr( wp_create_nonce( 'metform-deactivation' ) ); ?>" /> <div class="mf-deactivation-radio-group"> <?php foreach ( $reasons as $reason ) : ?> <?php $this->render_reason_item( $reason ); ?> <?php endforeach; ?> </div> <?php $this->render_modal_footer(); ?> </form> </div><!-- .mf-deactivation-body --> </div><!-- .mf-deactivation-content --> </div><!-- #mf-deactivation-modal --> <?php } /** * Handle the AJAX feedback-submission request. * * Verifies the nonce and user capabilities, collects payload data, * then dispatches the data to the remote API via {@see send_feedback_data()}. * * Sends a JSON error response on failure; a JSON success response otherwise. * * @since 1.0.0 * * @return void Terminates execution via {@see wp_send_json_error()} or * {@see wp_send_json_success()}. */ public function handle_feedback() { $this->verify_request(); $selected_reason = isset( $_POST['reason'] ) ? sanitize_text_field( wp_unslash( $_POST['reason'] ) ) : ''; $data = array( 'plugin_slug' => 'metform', 'plugin_name' => 'MetForm', 'plugin_version' => Plugin::instance()->version(), 'user' => array( 'email' => $this->get_user_email(), ), 'feedback' => array( 'reason_key' => isset( $_POST['reason_key'] ) ? sanitize_text_field( wp_unslash( $_POST['reason_key'] ) ) : 'other', 'reason_label' => isset( $_POST['reason_label'] ) ? sanitize_text_field( wp_unslash( $_POST['reason_label'] ) ) : $selected_reason, 'message' => isset( $_POST['feedback'] )? sanitize_textarea_field( wp_unslash( $_POST['feedback'] ) ) : '', ), 'usage' => array( 'user_type' => $this->get_user_type(), 'active_days' => $this->get_days_active(), ), 'environment' => array( 'multisite_status' => is_multisite(), 'wp_version' => get_bloginfo( 'version' ), 'php_version' => PHP_VERSION, 'elementor_version' => defined( 'ELEMENTOR_VERSION' ) ? ELEMENTOR_VERSION : '', 'site_url' => get_site_url(), ), ); $response = $this->send_feedback_data( $data ); if ( is_wp_error( $response ) ) { wp_send_json_error( array( 'message' => $response->get_error_message() ) ); } $response_code = (int) wp_remote_retrieve_response_code( $response ); if ( $response_code < 200 || $response_code >= 300 ) { wp_send_json_error( array( 'message' => esc_html__( 'Failed to submit feedback.', 'metform' ), 'code' => $response_code, ) ); } wp_send_json_success( array( 'message' => esc_html__( 'Thank you for your feedback!', 'metform' ) ) ); } /** * Output the modal header, including the MetForm logo SVG and title. * * @since 1.0.0 * * @return void */ private function render_modal_header() { ?> <div class="mf-deactivation-header"> <h2> <svg class="mf-deactivation-logo" width="36" height="30" viewBox="0 0 33 30" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"> <path d="M33.0867 11.0338L26.2037 11.5706V3.1014C26.2037 1.37178 24.8151 0 23.0641 0H3.13962C1.38868 0 0 1.37178 0 3.1014V17.177L8.87546 22.5447L33.0867 11.0338Z" fill="url(#mf_paint0)"/> <path d="M8.99687 28.4493L0.0610352 17.1769V26.8986C0.0610352 28.6282 1.44971 30 3.20065 30H23.1252C24.8761 30 26.2648 28.6282 26.2648 26.8986V19.324L33.1478 11.1531L8.99687 28.4493Z" fill="url(#mf_paint1)"/> <!-- Form lines --> <rect x="4" y="4" width="1.6" height="1.6" rx="0.8" fill="white"/> <rect x="7" y="4.3" width="11" height="1" rx="0.5" fill="white"/> <rect x="4" y="7.5" width="1.6" height="1.6" rx="0.8" fill="white"/> <rect x="7" y="7.8" width="9" height="1" rx="0.5" fill="white"/> <rect x="4" y="11" width="1.6" height="1.6" rx="0.8" fill="white"/> <rect x="7" y="11.3" width="10" height="1" rx="0.5" fill="white"/> <!-- Checkmark --> <polyline points="5.5,23 9,26.5 15.5,19" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <defs> <linearGradient id="mf_paint0" x1="6.07564" y1="21.0648" x2="21.5844" y2="-0.929494" gradientUnits="userSpaceOnUse"> <stop stop-color="#F8003C"/> <stop offset="1" stop-color="#FF8438"/> </linearGradient> <linearGradient id="mf_paint1" x1="0.721864" y1="28.075" x2="25.5087" y2="17.7559" gradientUnits="userSpaceOnUse"> <stop offset="0.1645" stop-color="#0099AC"/> <stop offset="0.9996" stop-color="#00D5C9"/> </linearGradient> </defs> </svg> <span><?php esc_html_e( 'Quick Feedback', 'metform' ); ?></span> </h2> <button type="button" class="mf-deactivation-close" aria-label="<?php esc_attr_e( 'Close', 'metform' ); ?>"> <span aria-hidden="true">×</span> </button> </div><!-- .mf-deactivation-header --> <?php } /** * Output a single radio-option item inside the feedback form. * * Each item consists of a radio button, its label, hidden key/label inputs, * and an optional follow-up textarea. * * @since 1.0.0 * * @param array $reason { * Associative array describing a single deactivation reason. * * @type string $value The radio button value / display label. * @type string $key Programmatic key sent with the AJAX request. * @type string $label Human-readable label sent with the AJAX request. * @type string $placeholder Placeholder text for the follow-up textarea. * } * @return void */ private function render_reason_item( array $reason ) { $reason_key = esc_attr( $reason['key'] ); ?> <div class="mf-deactivation-radio-item" data-reason-key="<?php echo esc_attr( $reason['key'] ); ?>"> <label class="mf-deactivation-radio-option"> <input type="radio" name="reason" value="<?php echo esc_attr( $reason['value'] ); ?>" class="mf-form-control-radio" > <span><?php echo esc_html( $reason['value'] ); ?></span> </label> <input type="hidden" class="mf-reason-key" value="<?php echo esc_attr( $reason['key'] ); ?>" /> <input type="hidden" class="mf-reason-label" value="<?php echo esc_attr( $reason['label'] ); ?>" /> <textarea name="feedback_<?php echo $reason_key; ?>" class="mf-deactivation-radio-feedback" placeholder="<?php echo esc_attr( $reason['placeholder'] ); ?>" rows="2" ></textarea> </div> <?php } /** * Output the modal footer containing the action buttons. * * @since 1.0.0 * * @return void */ private function render_modal_footer() { ?> <div class="mf-deactivation-footer"> <button type="button" class="mf-btn mf-btn-secondary mf-deactivation-skip" data-deactivate-link=""> <?php esc_html_e( 'Skip & Deactivate', 'metform' ); ?> </button> <button type="submit" class="mf-btn mf-btn-primary mf-deactivation-submit"> <?php esc_html_e( 'Submit & Deactivate', 'metform' ); ?> </button> </div><!-- .mf-deactivation-footer --> <?php } /** * Verify AJAX request nonce and user capabilities. * * Sends a JSON error response and terminates execution if either check fails. * * @since 1.0.0 * * @return void */ private function verify_request() { $nonce = isset( $_POST['metform_nonce'] ) ? sanitize_key( wp_unslash( $_POST['metform_nonce'] ) ) : ''; if ( ! wp_verify_nonce( $nonce, 'metform-deactivation' ) ) { wp_send_json_error( array( 'message' => esc_html__( 'Security check failed', 'metform' ) ) ); } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => esc_html__( 'Insufficient permissions', 'metform' ) ) ); } } /** * Send collected feedback data to the MetForm remote API. * * @since 1.0.0 * * @param array $data Associative array of feedback payload data. * @return array|\WP_Error The raw HTTP response array, or a WP_Error on failure. */ private function send_feedback_data( array $data ) { // Plugin class does not expose an api_url() helper. Use the WPMet public API endpoint. $url = 'https://api.wpmet.com/public/plugin-unsubscribe/'; return wp_remote_post( $url, array( 'method' => 'POST', 'timeout' => 20, 'headers' => array( 'Content-Type' => 'application/json', ), 'body' => wp_json_encode( $data ), ) ); } /** * Return the number of days the plugin has been active. * * Reads the `metform_install_date` option and computes the * difference between that date and the current server time. * * @since 1.0.0 * * @return int Number of complete days since installation, or 0 if unknown. */ private function get_days_active() { $installed_time = get_option( 'metform_install_date' ); if ( ! $installed_time ) { return 0; } $installed_timestamp = strtotime( $installed_time ); $current_time = current_time( 'timestamp' ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested return (int) floor( ( $current_time - $installed_timestamp ) / DAY_IN_SECONDS ); } /** * Return the current user's license/subscription type. * * Possible return values: * - `'pro_valid'` – Pro plugin is active with a valid licence. * - `'pro'` – Pro plugin is installed but licence is missing or invalid. * - `'free'` – Only the Lite version is installed. * * @since 1.0.0 * * @return string One of `'pro_valid'`, `'pro'`, or `'free'`. */ private function get_user_type() { if ( 'pro' !== Plugin::instance()->package_type() ) { return 'free'; } return 'valid' === Plugin::instance()->license_status() ? 'pro_valid' : 'pro'; } /** * Return the admin email address stored in plugin options, if available. * * @since 1.0.0 * * @return string A sanitized email address, or an empty string when not set. */ private function get_user_email() { $options = get_option( 'metform_options', array() ); if ( empty( $options['settings']['newsletter_email'] ) ) { return ''; } return sanitize_email( $options['settings']['newsletter_email'] ); } /** * Return the list of available deactivation reasons shown in the modal. * * Each entry is an associative array with the following keys: * - `value` (string) The user-visible radio-button label. * - `key` (string) The programmatic key sent to the API. * - `label` (string) The human-readable label sent to the API. * - `placeholder` (string) Placeholder text for the follow-up textarea. * * @since 1.0.0 * * @return array[] List of reason definition arrays. */ private function get_deactivation_reasons() { return array( array( 'value' => __( 'I no longer need the plugin', 'metform' ), 'key' => 'no_longer_needed', 'label' => 'I no longer need the plugin', 'placeholder' => __( 'Tell us more...', 'metform' ), ), array( 'value' => __( 'I found a better plugin', 'metform' ), 'key' => 'found_better_plugin', 'label' => 'I found a better plugin', 'placeholder' => __( 'Which plugin are you using instead?', 'metform' ), ), array( 'value' => __( "I couldn't get the plugin to work", 'metform' ), 'key' => 'plugin_bug', 'label' => "I couldn't get the plugin to work", 'placeholder' => __( 'What specific issue did you face?', 'metform' ), ), array( 'value' => __( "It's missing a specific feature", 'metform' ), 'key' => 'missing_feature', 'label' => "It's missing a specific feature", 'placeholder' => __( 'What feature do you need?', 'metform' ), ), array( 'value' => __( 'The plugin affects site performance', 'metform' ), 'key' => 'performance_issue', 'label' => 'Slowing down my site', 'placeholder' => __( 'Please share details about the performance issues you experienced...', 'metform' ), ), array( 'value' => __( "It's a temporary deactivation", 'metform' ), 'key' => 'temporary_deactivation', 'label' => "It's a temporary deactivation", 'placeholder' => __( 'When will you reactivate it?', 'metform' ), ), array( 'value' => __( 'Other', 'metform' ), 'key' => 'other', 'label' => 'Other', 'placeholder' => __( 'Please tell us why...', 'metform' ), ), ); } }
Save
Close
Exit & Reset
Text mode: syntax highlighting auto-detects file type.
Directory Contents
Dirs: 1 × Files: 1
Delete Selected
Select All
Select None
Sort:
Name
Size
Modified
Enable drag-to-move
Name
Size
Perms
Modified
Actions
assets
DIR
-
drwxr-xr-x
2026-06-11 02:40:12
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
plugin-unsubscribe.php
14.91 KB
lrw-r--r--
2026-06-09 12:11:42
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
Zip Selected
If ZipArchive is unavailable, a
.tar
will be created (no compression).