eGift. The Merchant pastes their code or merchant id once; the page then shows * "Gekoppeld met " and what is still missing before their bonpagina is Public ready. */ class Egift_Settings { const OPTION = 'egift_settings'; const PAGE = 'egift'; const CONNECT_ACTION = 'egift_connect'; // The query parameter that carries the outcome of the connect form over its redirect. const NOTICE = 'egift_notice'; // The Registration origin eGift records for an account created through this plugin's link. const REGISTRATION_ORIGIN = 'WordPressPlugin'; /** * Hooks the page into wp-admin. */ public static function init() { add_action( 'admin_menu', array( __CLASS__, 'add_page' ) ); add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_assets' ) ); add_action( 'admin_post_' . self::CONNECT_ACTION, array( __CLASS__, 'handle_connect' ) ); add_filter( 'plugin_action_links_' . plugin_basename( EGIFT_PLUGIN_FILE ), array( __CLASS__, 'add_action_link' ) ); } /** * One plugin setting. All of them live in one array option: merchant_id and the company_name * seen at connect time, page_id of the "Cadeaubon" page, and for the webshop part the * webshopsleutel with the webshopsleutel_name and webshopsleutel_company eGift answered, and * diagnostics. * * @param string $name The setting. * @return mixed The stored value, or null when it is not set. */ public static function get( $name ) { $settings = self::all(); return isset( $settings[ $name ] ) ? $settings[ $name ] : null; } /** * Changes plugin settings in one save, which also sends the status report (Egift_Status_Report). * * @param array $changes Setting names and their new values; null removes a setting. */ public static function update( array $changes ) { $settings = self::all(); foreach ( $changes as $name => $value ) { if ( null === $value ) { unset( $settings[ $name ] ); } else { $settings[ $name ] = $value; } } update_option( self::OPTION, $settings ); } /** * The connected merchant id, or '' when this site is not connected. * * @return string */ public static function merchant_id() { return (string) self::get( 'merchant_id' ); } /** * The saved Webshopsleutel, or '' when there is none. * * @return string */ public static function webshopsleutel() { return (string) self::get( 'webshopsleutel' ); } /** * Settings > eGift, where every section of the plugin's settings lives. * * @return string */ public static function page_url() { return admin_url( 'options-general.php?page=' . self::PAGE ); } /** * Back to Settings > eGift with a notice, the usual post/redirect/get. Each section carries its * outcome in its own query parameter and shows it itself. * * @param string $param The section's notice parameter, for example egift_notice. * @param string $notice A short key the section knows. */ public static function redirect_with_notice( $param, $notice ) { wp_safe_redirect( add_query_arg( $param, $notice, self::page_url() ) ); exit; } /** * The option with every setting. * * @return array */ private static function all() { $settings = get_option( self::OPTION, array() ); return is_array( $settings ) ? $settings : array(); } /** * Adds Settings > eGift. */ public static function add_page() { add_options_page( 'eGift', 'eGift', 'manage_options', self::PAGE, array( __CLASS__, 'render_page' ) ); } /** * Loads the page's stylesheet on this page only. * * @param string $hook_suffix The current admin page. */ public static function enqueue_assets( $hook_suffix ) { if ( 'settings_page_' . self::PAGE !== $hook_suffix ) { return; } wp_enqueue_style( 'egift-admin', plugins_url( 'assets/admin.css', EGIFT_PLUGIN_FILE ), array(), EGIFT_VERSION ); } /** * Adds a "Settings" link next to the plugin on the Plugins screen. * * @param array $links The plugin's action links. * @return array */ public static function add_action_link( $links ) { array_unshift( $links, '' . esc_html__( 'Settings', 'egift' ) . '' ); return $links; } /** * Saves the pasted code. Only a code eGift recognises is stored; a refused one leaves the * settings as they were. An empty field disconnects the site. */ public static function handle_connect() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Sorry, you are not allowed to change these settings.', 'egift' ), 403 ); } check_admin_referer( self::CONNECT_ACTION ); // Not sanitized as text on purpose: that would strip the snippet's HTML tag and the id in // it. Only the merchant id matched by a strict GUID pattern is ever kept. $pasted = isset( $_POST['egift_code'] ) ? (string) wp_unslash( $_POST['egift_code'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( '' === trim( $pasted ) ) { if ( '' === self::merchant_id() ) { self::redirect_with_notice( self::NOTICE, 'malformed' ); } self::update( array( 'merchant_id' => null, 'company_name' => null, ) ); self::redirect_with_notice( self::NOTICE, 'disconnected' ); } $merchant_id = Egift_Api::extract_merchant_id( $pasted ); if ( '' === $merchant_id ) { self::redirect_with_notice( self::NOTICE, 'malformed' ); } $lookup = Egift_Api::lookup_merchant( $merchant_id ); if ( is_wp_error( $lookup ) ) { self::redirect_with_notice( self::NOTICE, 'unreachable' ); } if ( null === $lookup ) { self::redirect_with_notice( self::NOTICE, 'unknown' ); } self::update( array( 'merchant_id' => $merchant_id, 'company_name' => sanitize_text_field( isset( $lookup['companyName'] ) ? (string) $lookup['companyName'] : '' ), ) ); // Also when the saved value did not change, which fires no option hook. Egift_Status_Report::send(); self::redirect_with_notice( self::NOTICE, 'connected' ); } /** * Renders Settings > eGift. */ public static function render_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } $merchant_id = self::merchant_id(); // Looked up on every visit: the Merchant comes back here right after finishing a step in // the portal, and expects the checklist to show it. $lookup = '' === $merchant_id ? null : Egift_Api::lookup_merchant( $merchant_id ); ?>

' . esc_html__( 'No eGift account yet?', 'egift' ) . ' ' . esc_html__( 'Create a free account', 'egift' ) . '

'; } /** * Shows which merchant this site is connected to and the Public ready checklist. * * @param array|null|WP_Error $lookup The fresh merchant lookup. */ private static function render_connection( $lookup ) { if ( null === $lookup ) { // Connected earlier, but eGift no longer knows the merchant (removed or blocked). wp_admin_notice( esc_html__( 'eGift no longer finds an account for this code. Paste the code from the "Bon op uw eigen website" page again.', 'egift' ), array( 'type' => 'warning', 'additional_classes' => array( 'inline' ), ) ); return; } $company_name = is_wp_error( $lookup ) ? (string) self::get( 'company_name' ) : ( isset( $lookup['companyName'] ) ? (string) $lookup['companyName'] : '' ); ?>

' . esc_html( $company_name ) . '' ); ?>

'warning', 'additional_classes' => array( 'inline' ), ) ); return; } self::render_checklist( $lookup ); } /** * The Public ready steps (company details, logo, banner), each with a link to the portal. * * @param array $lookup The merchant lookup. */ private static function render_checklist( array $lookup ) { if ( ! empty( $lookup['hidden'] ) ) { // Verborgen: only eGift can make the bonpagina visible again. echo '

' . esc_html__( 'Your eGift account is hidden, so buyers cannot find your gift voucher page.', 'egift' ) . ' ' . esc_html__( 'Contact eGift', 'egift' ) . '

'; } elseif ( ! empty( $lookup['publicReady'] ) ) { echo '

' . esc_html__( 'Your gift voucher page is ready: buyers can buy your gift vouchers.', 'egift' ) . '

'; } else { echo '

' . esc_html__( 'Finish these steps in the eGift portal so buyers can buy your gift vouchers:', 'egift' ) . '

'; } $steps = isset( $lookup['steps'] ) && is_array( $lookup['steps'] ) ? $lookup['steps'] : array(); echo ''; } /** * The step's name. A step this release does not know yet shows eGift's own Dutch label. * * @param array $step One step from the lookup. * @return string */ private static function step_label( array $step ) { switch ( $step['key'] ) { case 'companyData': return __( 'Company details', 'egift' ); case 'logo': return __( 'Logo', 'egift' ); case 'banner': return __( 'Banner', 'egift' ); default: return isset( $step['label'] ) ? (string) $step['label'] : (string) $step['key']; } } /** * The link text that sends the Merchant to the portal to finish a step. * * @param string $key The step key. * @return string */ private static function step_action( $key ) { switch ( $key ) { case 'companyData': return __( 'Complete in the eGift portal', 'egift' ); case 'logo': case 'banner': return __( 'Upload in the eGift portal', 'egift' ); default: return __( 'Open the eGift portal', 'egift' ); } } /** * The portal page for a step. eGift returns a relative path, since only the plugin knows the * address the Merchant's browser uses. * * @param array $step One step from the lookup. * @return string */ private static function portal_url( array $step ) { $path = isset( $step['portalPath'] ) ? (string) $step['portalPath'] : ''; return Egift_Api::public_url() . ( 0 === strpos( $path, '/' ) ? $path : '/' ); } /** * Shows the outcome of the last save, carried over the redirect as a short key. */ private static function render_notice() { // Display only, nothing is changed here; the save itself checked the nonce. $notice = isset( $_GET['egift_notice'] ) ? sanitize_key( wp_unslash( $_GET['egift_notice'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $notices = array( 'connected' => array( 'success', __( 'Your code was saved.', 'egift' ) ), 'disconnected' => array( 'success', __( 'This site is no longer connected to eGift.', 'egift' ) ), 'malformed' => array( 'error', __( 'That is not a valid code. Paste the full code from the "Bon op uw eigen website" page in the eGift portal, or your merchant ID.', 'egift' ) ), 'unknown' => array( 'error', __( 'No eGift merchant was found for this code. Check that you copied the full code.', 'egift' ) ), 'unreachable' => array( 'error', __( 'eGift cannot be reached right now. Please try again later.', 'egift' ) ), ); if ( ! isset( $notices[ $notice ] ) ) { return; } wp_admin_notice( esc_html( $notices[ $notice ][1] ), array( 'type' => $notices[ $notice ][0], 'dismissible' => true, 'additional_classes' => array( 'egift-notice' ), ) ); } }