true, 'strategy' => 'defer', ) ); add_shortcode( self::SHORTCODE, array( __CLASS__, 'shortcode' ) ); register_block_type( WALLETPB_DIR . 'blocks/add-to-wallet', array( 'render_callback' => array( __CLASS__, 'render_block' ) ) ); } /** * The editor's list of passes for the block's pass picker. */ public static function register_rest_routes() { register_rest_route( 'walletpb/v1', '/passes', array( 'methods' => 'GET', 'permission_callback' => function () { return current_user_can( 'edit_posts' ); }, 'callback' => function () { $passes = self::pass_choices(); if ( is_wp_error( $passes ) ) { return new WP_Error( $passes->get_error_code(), $passes->get_error_message(), array( 'status' => 502 ) ); } return rest_ensure_response( $passes ); }, ) ); } /** * The account's passes as id and title, for pickers. Cached for a few minutes. * * @return array|WP_Error */ public static function pass_choices() { $cached = get_transient( 'walletpb_pass_choices' ); if ( is_array( $cached ) ) { return $cached; } $passes = WalletPB_API::passes(); if ( is_wp_error( $passes ) ) { return $passes; } $choices = array(); foreach ( $passes as $pass ) { if ( empty( $pass['passId'] ) ) { continue; } $title = isset( $pass['passTemplate']['cardTitle'] ) ? (string) $pass['passTemplate']['cardTitle'] : ''; $business = isset( $pass['passTemplate']['logoText'] ) ? (string) $pass['passTemplate']['logoText'] : ''; $choices[] = array( 'id' => (string) $pass['passId'], 'title' => trim( $title . ( '' !== $business ? ' - ' . $business : '' ) ), ); if ( ! empty( $pass['passUrl'] ) ) { set_transient( self::url_key( (string) $pass['passId'] ), esc_url_raw( $pass['passUrl'] ), 12 * HOUR_IN_SECONDS ); } } set_transient( 'walletpb_pass_choices', $choices, 5 * MINUTE_IN_SECONDS ); return $choices; } /** * Transient name for a pass's share link. * * @param string $pass_id Pass id. * @return string */ private static function url_key( $pass_id ) { return 'walletpb_url_' . md5( $pass_id ); } /** * Drops a pass's cached share link and the pass list, after the pass changes. * * @param string $pass_id Pass id. */ public static function forget( $pass_id ) { delete_transient( self::url_key( $pass_id ) ); delete_transient( 'walletpb_pass_choices' ); } /** * A pass's share link, or an empty string if it can't be found. * * @param string $pass_id Pass id; empty means the Pass Template tab's pass. * @return string */ public static function pass_url( $pass_id ) { $template = WalletPB_Template::pass(); if ( '' === $pass_id || ( $template && $template['pass_id'] === $pass_id ) ) { return $template ? $template['pass_url'] : ''; } $cached = get_transient( self::url_key( $pass_id ) ); if ( false !== $cached ) { return (string) $cached; } $pass = WalletPB_API::pass( $pass_id ); $url = ! is_wp_error( $pass ) && ! empty( $pass['passUrl'] ) && 'archived' !== ( isset( $pass['status'] ) ? $pass['status'] : '' ) ? esc_url_raw( $pass['passUrl'] ) : ''; // A missing pass is remembered briefly too, so a broken button doesn't call the API on every page view. set_transient( self::url_key( $pass_id ), $url, '' !== $url ? 12 * HOUR_IN_SECONDS : 5 * MINUTE_IN_SECONDS ); return $url; } /** * The buttons' HTML: the official "Add to Apple Wallet" and "Add to Google Wallet" badges, each * linking straight to that wallet (the pass page's /apple and /google links). * * @param string $pass_id Pass id; empty means the template's pass. * @param string $wallets "both", "apple" or "google". * @param string $align "left", "center" or "right". * @return string */ public static function html( $pass_id, $wallets = 'both', $align = 'left' ) { $url = self::pass_url( $pass_id ); if ( '' === $url ) { // Visitors see nothing; people who can edit the page see why. if ( current_user_can( 'edit_posts' ) ) { return '

' . esc_html__( 'Add to Wallet buttons: choose a pass, or create one on the Pass Template tab under WalletPassBuilder.', 'walletpassbuilder' ) . '

'; } return ''; } wp_enqueue_style( 'walletpb-button' ); wp_enqueue_script( 'walletpb-button' ); return self::badges( untrailingslashit( $url ), $wallets, $align ); } /** * The badge links for a pass page. Each goes straight to its wallet; on a computer, button.js * points them at the pass page instead (data-desktop-href), where there's a QR code to scan. * * @param string $url The pass page, without a trailing slash. * @param string $wallets "both", "apple" or "google". * @param string $align "left", "center" or "right". * @return string */ public static function badges( $url, $wallets, $align ) { $align = in_array( $align, array( 'left', 'center', 'right' ), true ) ? $align : 'left'; $wallets = in_array( $wallets, array( 'both', 'apple', 'google' ), true ) ? $wallets : 'both'; $out = ''; if ( 'google' !== $wallets ) { $out .= sprintf( '%3$s', esc_url( $url . '/apple' ), esc_url( $url ), esc_html__( 'Add to Apple Wallet', 'walletpassbuilder' ) ); } if ( 'apple' !== $wallets ) { $out .= sprintf( '%3$s', esc_url( $url . '/google' ), esc_url( $url ), esc_html__( 'Add to Google Wallet', 'walletpassbuilder' ) ); } return '

' . $out . '

'; } /** * The buttons for an email: the official badges as PNG images (email apps don't show SVG), * both linking to the pass page, which opens the right wallet on any phone. * * @param string $url The card's pass page. * @return string */ public static function email_badges( $url ) { $badge = function ( $file, $alt, $width ) use ( $url ) { return sprintf( '%3$s', esc_url( $url ), esc_url( WALLETPB_URL . 'assets/images/' . $file ), esc_attr( $alt ), (int) $width ); }; return '
' . $badge( 'add-to-apple-wallet.png', __( 'Add to Apple Wallet', 'walletpassbuilder' ), 142 ) . $badge( 'add-to-google-wallet.png', __( 'Add to Google Wallet', 'walletpassbuilder' ), 159 ) . '
'; } /** * [wallet_pass_builder pass="ID" wallets="both" align="left"] * * @param array|string $atts Shortcode attributes. * @return string */ public static function shortcode( $atts ) { $atts = shortcode_atts( array( 'pass' => '', 'wallets' => 'both', 'align' => 'left', ), $atts, self::SHORTCODE ); return self::html( sanitize_text_field( $atts['pass'] ), sanitize_key( $atts['wallets'] ), sanitize_key( $atts['align'] ) ); } /** * The block's front end. * * @param array $attributes Block attributes. * @return string */ public static function render_block( $attributes ) { return self::html( isset( $attributes['passId'] ) ? sanitize_text_field( $attributes['passId'] ) : '', isset( $attributes['wallets'] ) ? sanitize_key( $attributes['wallets'] ) : 'both', isset( $attributes['buttonAlign'] ) ? sanitize_key( $attributes['buttonAlign'] ) : 'left' ); } }