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 '';
foreach ( $steps as $step ) {
if ( ! is_array( $step ) || empty( $step['key'] ) ) {
continue;
}
$key = (string) $step['key'];
$done = ! empty( $step['done'] );
echo '- ';
echo ' ';
echo '' . esc_html( self::step_label( $step ) ) . ' ';
if ( $done ) {
echo '' . esc_html__( 'Done', 'egift' ) . '';
} else {
echo ''
. esc_html( self::step_action( $key ) ) . '';
}
echo '
';
}
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' ),
)
);
}
}