';
return 'data:image/svg+xml;base64,' . base64_encode( $svg ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
}
/**
* Screens: key => [ slug suffix, title ].
*
* @return array
*/
public static function screens() {
$screens = array(
'dashboard' => array( '', __( 'Dashboard', 'returnkit' ) ),
'requests' => array( '-requests', __( 'Requests', 'returnkit' ) ),
'settings' => array( '-settings', __( 'Settings', 'returnkit' ) ),
'help' => array( '-help', __( 'Help', 'returnkit' ) ),
);
/**
* Filters the ReturnKit admin screens (Pro adds Insights).
*
* @param array $screens key => [ slug suffix, title ].
*/
$screens = (array) apply_filters( 'rtkt_admin_screens', $screens );
if ( ! Gate::is_pro() ) {
$screens['pro'] = array( '-pro', __( 'Go Pro', 'returnkit' ) );
}
return $screens;
}
/**
* Register menu pages.
*
* @return void
*/
public static function menu() {
$pending = Requests::count( array( 'status' => 'pending' ) );
$bubble = $pending ? ' ' . esc_html( number_format_i18n( $pending ) ) . '' : '';
add_menu_page(
__( 'ReturnKit', 'returnkit' ),
__( 'Returns', 'returnkit' ) . $bubble,
self::CAP,
RTKT_MENU_SLUG,
array( __CLASS__, 'screen_dashboard' ),
self::menu_icon(),
'56.6'
);
foreach ( self::screens() as $key => $screen ) {
$label = $screen[1];
if ( 'pro' === $key ) {
$label = '' . esc_html( $screen[1] ) . '';
} elseif ( 'requests' === $key ) {
$label .= $bubble;
}
$callback = method_exists( __CLASS__, 'render_' . $key ) ? array( __CLASS__, 'screen_' . $key ) : static function () use ( $key ) {
/**
* Render a screen added through rtkt_admin_screens.
*/
do_action( 'rtkt_admin_screen_' . $key );
};
add_submenu_page( RTKT_MENU_SLUG, $screen[1], $label, self::CAP, RTKT_MENU_SLUG . $screen[0], $callback );
}
}
/**
* URL of a screen.
*
* @param string $screen Screen key.
* @param array $args Extra query args.
* @return string
*/
public static function url( $screen = 'dashboard', array $args = array() ) {
$screens = self::screens();
$suffix = isset( $screens[ $screen ] ) ? $screens[ $screen ][0] : '-' . sanitize_key( $screen );
$args = array_filter(
$args,
static function ( $v ) {
return '' !== (string) $v;
}
);
return add_query_arg( array_merge( array( 'page' => RTKT_MENU_SLUG . $suffix ), $args ), admin_url( 'admin.php' ) );
}
/**
* URL of a request in the admin.
*
* @param int $id Request ID.
* @return string
*/
public static function request_url( $id ) {
return self::url( 'requests', array( 'request' => (int) $id ) );
}
/**
* Is the current screen one of ours?
*
* @return bool
*/
public static function is_our_screen() {
$page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return 0 === strpos( $page, RTKT_MENU_SLUG );
}
/**
* Body class.
*
* @param string $classes Classes.
* @return string
*/
public static function body_class( $classes ) {
return self::is_our_screen() ? $classes . ' rtkt-screen' : $classes;
}
/**
* Enqueue assets on our screens.
*
* @return void
*/
public static function assets() {
wp_add_inline_style( 'common', '#adminmenu .rtkt-menu-pro{color:#fbbf24;font-weight:600}' );
if ( ! self::is_our_screen() ) {
return;
}
wp_enqueue_style( 'rtkt-admin', RTKT_URL . 'assets/css/admin.css', array(), rtkt_asset_version( 'assets/css/admin.css' ) );
wp_enqueue_script( 'rtkt-admin', RTKT_URL . 'assets/js/admin.js', array(), rtkt_asset_version( 'assets/js/admin.js' ), true );
wp_localize_script(
'rtkt-admin',
'ReturnKit',
array(
'defaults' => Settings::defaults(),
'keep' => Settings::personal_keys(),
'i18n' => array(
'unsaved' => __( 'You have unsaved changes', 'returnkit' ),
'resetDone' => __( 'Recommended values filled in. Save to apply them.', 'returnkit' ),
'confirmReject' => __( 'Decline this request? The customer is emailed your reason.', 'returnkit' ),
'confirmRefund' => __( 'Refund this amount now? This can\'t be undone.', 'returnkit' ),
'confirmDelete' => __( 'Delete this request and its history permanently?', 'returnkit' ),
),
)
);
/**
* Fires after the ReturnKit admin assets are enqueued (Pro adds its own).
*/
do_action( 'rtkt_admin_assets' );
}
/**
* Redirect to the dashboard after a single-plugin activation.
*
* @return void
*/
public static function activation_redirect() {
if ( ! get_transient( Installer::REDIRECT_KEY ) ) {
return;
}
delete_transient( Installer::REDIRECT_KEY );
if ( wp_doing_ajax() || is_network_admin() || isset( $_GET['activate-multi'] ) || ! current_user_can( self::CAP ) || ! ( rtkt_fs() instanceof Stub ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return;
}
wp_safe_redirect( self::url( 'dashboard' ) );
exit;
}
/**
* Plugins-list links.
*
* @param array $links Links.
* @return array
*/
public static function action_links( $links ) {
$ours = array(
'' . esc_html__( 'Requests', 'returnkit' ) . '',
'' . esc_html__( 'Settings', 'returnkit' ) . '',
);
if ( ! Gate::is_pro() ) {
$ours[] = '' . esc_html__( 'Go Pro', 'returnkit' ) . '';
}
return array_merge( $ours, (array) $links );
}
/**
* Docs and support links under the plugin description.
*
* @param array $meta Row meta.
* @param string $file Plugin file.
* @return array
*/
public static function row_meta( $meta, $file ) {
if ( RTKT_BASENAME === $file ) {
$meta[] = '' . esc_html__( 'Documentation', 'returnkit' ) . '';
$meta[] = '' . esc_html__( 'Support', 'returnkit' ) . '';
}
return $meta;
}
/* ------------------------------------------------------------------
* Data
* ------------------------------------------------------------------ */
/**
* Withdrawal compliance checklist: [ label, ok (true|false|null = check by hand), hint, link ].
*
* @return array[]
*/
public static function compliance() {
$s = Settings::all();
$page = Access::withdrawal_base();
$emails = get_option( 'woocommerce_rtkt_customer_withdrawal_settings', array() );
$ack_on = ! is_array( $emails ) || ! isset( $emails['enabled'] ) || 'no' !== $emails['enabled'];
$in_menu = $page && self::page_in_menu( (int) $s['withdrawal_page'] );
$settings = self::url( 'settings' );
return array(
array( __( 'Withdrawal function switched on', 'returnkit' ), (bool) $s['withdrawal_enabled'], '', $settings . '#rtkt-withdrawal' ),
array( __( 'Withdrawal page published', 'returnkit' ), '' !== $page, __( 'Create the pages from Settings → Pages.', 'returnkit' ), $settings . '#rtkt-pages' ),
array(
__( '"Withdraw from contract here" link on every page', 'returnkit' ),
$s['withdrawal_in_footer'] || $in_menu ? true : null,
__( 'Turn on the footer link, add the page to your footer menu, or place [returnkit_withdrawal_button] in your footer. Then check it shows.', 'returnkit' ),
$settings . '#rtkt-withdrawal',
),
array( __( 'Acknowledgement email enabled', 'returnkit' ), $ack_on, __( 'Turn on "Withdrawal acknowledgement" in WooCommerce → Settings → Emails.', 'returnkit' ), admin_url( 'admin.php?page=wc-settings&tab=email§ion=rtkt_customer_withdrawal' ) ),
array( __( 'Withdrawal links in My Account and order emails', 'returnkit' ), $s['withdrawal_in_account'] && $s['withdrawal_in_emails'], '', $settings . '#rtkt-withdrawal' ),
array( __( 'Only one withdrawal form active', 'returnkit' ), ! CoreWithdrawal::enabled(), __( 'WooCommerce\'s own withdrawal form is also on.', 'returnkit' ), CoreWithdrawal::settings_url() ),
);
}
/**
* Is a page linked in any navigation menu?
*
* @param int $page_id Page ID.
* @return bool
*/
private static function page_in_menu( $page_id ) {
if ( ! $page_id ) {
return false;
}
foreach ( wp_get_nav_menus() as $menu ) {
foreach ( (array) wp_get_nav_menu_items( $menu->term_id ) as $item ) {
if ( 'page' === $item->object && (int) $item->object_id === $page_id ) {
return true;
}
}
}
// Block themes: navigation blocks linking the page.
$nav = get_posts(
array(
'post_type' => 'wp_navigation',
'posts_per_page' => 20,
'post_status' => 'publish',
)
);
foreach ( $nav as $post ) {
if ( false !== strpos( (string) $post->post_content, '"id":' . $page_id ) || false !== strpos( (string) $post->post_content, 'returnkit_withdrawal_button' ) ) {
return true;
}
}
return false;
}
/**
* A flash message from a redirect, as [ text, is_error ].
*
* @return array|null
*/
public static function flash() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
$msg = isset( $_GET['rtkt_msg'] ) ? sanitize_key( wp_unslash( $_GET['rtkt_msg'] ) ) : '';
// phpcs:enable
if ( 'error' === $msg ) {
$key = 'rtkt_flash_' . get_current_user_id();
$error = (string) get_transient( $key );
delete_transient( $key );
return '' !== $error ? array( $error, true ) : null;
}
$map = array(
'saved' => array( __( 'Settings saved', 'returnkit' ), false ),
'pages' => array( __( 'Pages created', 'returnkit' ), false ),
'approved' => array( __( 'Request approved and the customer emailed', 'returnkit' ), false ),
'rejected' => array( __( 'Request declined and the customer emailed', 'returnkit' ), false ),
'received' => array( __( 'Marked as received', 'returnkit' ), false ),
'refunded' => array( __( 'Refund issued and the request completed', 'returnkit' ), false ),
'completed' => array( __( 'Request completed', 'returnkit' ), false ),
'noted' => array( __( 'Note added', 'returnkit' ), false ),
'messaged' => array( __( 'Message sent to the customer', 'returnkit' ), false ),
'deleted' => array( __( 'Request deleted', 'returnkit' ), false ),
'linked' => array( __( 'Request linked to the order', 'returnkit' ), false ),
);
/**
* Filters the admin flash messages (Pro adds its own).
*
* @param array $map key => [ text, is_error ].
*/
$map = (array) apply_filters( 'rtkt_admin_flash', $map );
return isset( $map[ $msg ] ) ? $map[ $msg ] : null;
}
/* ------------------------------------------------------------------
* Screens
* ------------------------------------------------------------------ */
/**
* Admin page callbacks (screen_dashboard …): render guarded, so an error
* shows a notice instead of a "critical error" page.
*
* @param string $name Method name.
* @param array $args Arguments.
* @return void
*/
public static function __callStatic( $name, $args ) {
unset( $args );
if ( 0 !== strpos( $name, 'screen_' ) ) {
return;
}
$method = 'render_' . substr( $name, 7 );
if ( ! method_exists( __CLASS__, $method ) ) {
return;
}
$level = ob_get_level();
try {
call_user_func( array( __CLASS__, $method ) );
} catch ( \Throwable $e ) {
while ( ob_get_level() > $level ) {
ob_end_clean();
}
Safe::report( $e, 'admin screen ' . substr( $name, 7 ) );
echo '
' . esc_html__( 'This ReturnKit screen could not be shown. Your store is not affected. Details:', 'returnkit' ) . ' ' . esc_html( $e->getMessage() ) . '