Medivot screen. * * @package Medivot */ if ( ! defined( 'ABSPATH' ) ) { exit; } /** * Admin settings page, settings sanitisation and the connection check. */ final class Medivot_Admin { /** * Settings page slug. */ const PAGE = 'medivot'; /** * Settings group used by settings_fields(). */ const GROUP = 'medivot'; /** * Hook everything up. */ public static function register() { add_action( 'admin_menu', array( __CLASS__, 'add_page' ) ); add_action( 'admin_init', array( __CLASS__, 'register_settings' ) ); add_action( 'admin_post_medivot_check_connection', array( __CLASS__, 'handle_check_connection' ) ); add_action( 'update_option_' . Medivot_Plugin::OPTION, array( __CLASS__, 'on_settings_updated' ), 10, 2 ); add_action( 'add_option_' . Medivot_Plugin::OPTION, array( __CLASS__, 'on_settings_added' ), 10, 2 ); add_filter( 'plugin_action_links_' . plugin_basename( MEDIVOT_PLUGIN_FILE ), array( __CLASS__, 'action_links' ) ); } /** * Add Settings > Medivot. */ public static function add_page() { add_options_page( __( 'Medivot', 'medivot' ), __( 'Medivot', 'medivot' ), 'manage_options', self::PAGE, array( __CLASS__, 'render_page' ) ); } /** * "Settings" link on the Plugins screen. * * @param array $links Existing links. * @return array */ public static function action_links( $links ) { $url = admin_url( 'options-general.php?page=' . self::PAGE ); array_unshift( $links, '' . esc_html__( 'Settings', 'medivot' ) . '' ); return $links; } /** * Register the option, sections and fields. */ public static function register_settings() { register_setting( self::GROUP, Medivot_Plugin::OPTION, array( 'type' => 'array', 'sanitize_callback' => array( __CLASS__, 'sanitize' ), 'default' => Medivot_Plugin::defaults(), 'show_in_rest' => false, ) ); add_settings_section( 'medivot_chat', __( 'Live chat widget', 'medivot' ), array( __CLASS__, 'section_chat' ), self::PAGE ); add_settings_field( 'medivot_widget_key', __( 'Widget key', 'medivot' ), array( __CLASS__, 'field_widget_key' ), self::PAGE, 'medivot_chat', array( 'label_for' => 'medivot_widget_key' ) ); add_settings_field( 'medivot_chat_enabled', __( 'Show on this site', 'medivot' ), array( __CLASS__, 'field_chat_enabled' ), self::PAGE, 'medivot_chat', array( 'label_for' => 'medivot_chat_enabled' ) ); add_settings_section( 'medivot_booking', __( 'Booking', 'medivot' ), array( __CLASS__, 'section_booking' ), self::PAGE ); add_settings_field( 'medivot_booking_slug', __( 'Booking page handle', 'medivot' ), array( __CLASS__, 'field_booking_slug' ), self::PAGE, 'medivot_booking', array( 'label_for' => 'medivot_booking_slug' ) ); add_settings_section( 'medivot_api', __( 'API connection (optional)', 'medivot' ), array( __CLASS__, 'section_api' ), self::PAGE ); add_settings_field( 'medivot_api_key', __( 'API key', 'medivot' ), array( __CLASS__, 'field_api_key' ), self::PAGE, 'medivot_api', array( 'label_for' => 'medivot_api_key' ) ); } /** * Sanitise the submitted settings. * * WordPress runs this twice on the very first save (update_option falls * through to add_option), so it must be idempotent: its output is valid input. * * @param mixed $input Submitted values. * @return array */ public static function sanitize( $input ) { static $warned = false; $input = is_array( $input ) ? $input : array(); $current = Medivot_Plugin::settings(); $clean = Medivot_Plugin::defaults(); // API key: a blank field keeps the saved key, the "remove" box clears it. $api_key = isset( $input['api_key'] ) ? self::clean_token( $input['api_key'] ) : ''; if ( ! empty( $input['api_key_remove'] ) ) { $clean['api_key'] = ''; } elseif ( '' !== $api_key ) { $clean['api_key'] = $api_key; } else { $clean['api_key'] = $current['api_key']; } $clean['widget_key'] = isset( $input['widget_key'] ) ? self::clean_token( $input['widget_key'] ) : ''; $clean['chat_enabled'] = ! empty( $input['chat_enabled'] ); $handle = isset( $input['booking_slug'] ) ? Medivot_Plugin::slugs_from( $input['booking_slug'], 'book' ) : array(); $clean['booking_slug'] = isset( $handle[0] ) ? $handle[0] : ''; if ( $clean['chat_enabled'] && '' === $clean['widget_key'] && ! $warned ) { $warned = true; add_settings_error( Medivot_Plugin::OPTION, 'medivot_widget_key_missing', __( 'The chat widget is switched on but has no widget key, so it will not show until you add one.', 'medivot' ), 'warning' ); } return $clean; } /** * Re-check the connection when the API key changes. * * @param mixed $old_value Previous settings. * @param mixed $value New settings. */ public static function on_settings_updated( $old_value, $value ) { $old_key = is_array( $old_value ) && isset( $old_value['api_key'] ) ? $old_value['api_key'] : ''; $new_key = is_array( $value ) && isset( $value['api_key'] ) ? $value['api_key'] : ''; if ( $old_key !== $new_key ) { self::refresh_connection(); } } /** * First save of the settings. * * @param string $option Option name. * @param mixed $value Saved settings. */ public static function on_settings_added( $option, $value ) { if ( is_array( $value ) && ! empty( $value['api_key'] ) ) { self::refresh_connection(); } } /** * Run the connection check with the saved key and store the result. */ public static function refresh_connection() { delete_transient( Medivot_Plugin::EVENT_TYPES_TRANSIENT ); $api_key = (string) Medivot_Plugin::get( 'api_key' ); if ( '' === $api_key ) { delete_option( Medivot_Plugin::CONNECTION_OPTION ); return; } update_option( Medivot_Plugin::CONNECTION_OPTION, Medivot_Api::check_connection( $api_key ) ); } /** * "Check connection" button (admin-post.php). */ public static function handle_check_connection() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Sorry, you are not allowed to manage these settings.', 'medivot' ), '', array( 'response' => 403 ) ); } check_admin_referer( 'medivot_check_connection' ); self::refresh_connection(); wp_safe_redirect( admin_url( 'options-general.php?page=' . self::PAGE ) ); exit; } /** * Render Settings > Medivot. */ public static function render_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } ?>
Medivot' ); ?>
[medivot_booking] [medivot_booking event="intro-call" text="Book a call"] [medivot_form form="contact-us"] Webforms, 2: Calendar > Event Types. Both are menu paths inside Medivot. */ esc_html__( 'Find form slugs in Medivot under %1$s and event type slugs under %2$s.', 'medivot' ), '' . esc_html__( 'CRM > Webforms', 'medivot' ) . '', '' . esc_html__( 'Calendar > Event Types', 'medivot' ) . '' ); ?>
' . esc_html( '' !== $connection['workspace'] ? $connection['workspace'] : __( 'your workspace', 'medivot' ) ) . '',
'' . esc_html( $connection['slug'] ) . ''
);
?>
' . esc_html__( 'Show your Medivot live chat widget on every page of this site. Visitors chat with your team in the Medivot inbox.', 'medivot' ) . ''; } /** * Intro for the booking section. */ public static function section_booking() { echo '
' . esc_html__( 'Booking buttons link visitors to your public Medivot booking page, where they pick a time.', 'medivot' ) . '
'; } /** * Intro for the API section. */ public static function section_api() { echo '' . esc_html__( 'Not required. With an API key the plugin detects your booking page handle and lists your event types in the block editor. Your plan must include API access.', 'medivot' ) . '
'; } /** * Widget key field. */ public static function field_widget_key() { printf( '', esc_attr( Medivot_Plugin::OPTION ), esc_attr( (string) Medivot_Plugin::get( 'widget_key' ) ) ); echo ''; printf( /* translators: %s: Live Chat > Widgets, a menu path inside Medivot. */ esc_html__( 'In Medivot, open %s, choose a widget and copy its widget key (the data-widget-key value in its embed code).', 'medivot' ), '' . esc_html__( 'Live Chat > Widgets', 'medivot' ) . '' ); echo '
'; } /** * Chat toggle field. */ public static function field_chat_enabled() { printf( '', esc_attr( Medivot_Plugin::OPTION ), checked( (bool) Medivot_Plugin::get( 'chat_enabled' ), true, false ), esc_html__( 'Show the chat widget on every page', 'medivot' ) ); } /** * Booking handle field. */ public static function field_booking_slug() { $connection = Medivot_Plugin::connection(); $detected = ! empty( $connection['ok'] ) && ! empty( $connection['slug'] ) ? (string) $connection['slug'] : ''; printf( '', esc_attr( Medivot_Plugin::OPTION ), esc_attr( (string) Medivot_Plugin::get( 'booking_slug' ) ), esc_attr( $detected ) ); echo '';
esc_html_e( 'The part after /book/ in your booking link. You can also paste the whole link.', 'medivot' );
if ( '' !== $detected ) {
echo ' ';
printf(
/* translators: %s: workspace handle detected through the API connection. */
esc_html__( 'Leave blank to use the handle detected from your API key: %s', 'medivot' ),
'' . esc_html( $detected ) . ''
);
}
echo '
'; printf( /* translators: %s: booking page link. */ esc_html__( 'Booking buttons link to %s', 'medivot' ), '' . esc_html( $url ) . '' ); echo '
'; } } /** * API key field. The saved key is never printed back into the page. */ public static function field_api_key() { $has_key = '' !== (string) Medivot_Plugin::get( 'api_key' ); printf( '', esc_attr( Medivot_Plugin::OPTION ), esc_attr( $has_key ? __( 'Saved. Leave blank to keep it.', 'medivot' ) : 'mk_live_...' ) ); if ( $has_key ) { printf( '', esc_attr( Medivot_Plugin::OPTION ), esc_html__( 'Remove the saved API key', 'medivot' ) ); } echo ''; printf( /* translators: %s: API Platform > API Keys, a menu path inside Medivot. */ esc_html__( 'Create a key in Medivot under %s. Read access is enough.', 'medivot' ), '' . esc_html__( 'API Platform > API Keys', 'medivot' ) . '' ); echo '
'; } /** * Keep only characters that appear in Medivot keys. * * @param mixed $value Raw value. * @return string */ private static function clean_token( $value ) { if ( ! is_scalar( $value ) ) { return ''; } return substr( (string) preg_replace( '/[^A-Za-z0-9_.-]/', '', trim( (string) $value ) ), 0, 200 ); } }