Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
45.83% covered (danger)
45.83%
33 / 72
20.00% covered (danger)
20.00%
1 / 5
CRAP
n/a
0 / 0
Automattic\Jetpack\Extensions\Subscriber_Login\register_block
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
42
Automattic\Jetpack\Extensions\Subscriber_Login\get_current_url
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
20
Automattic\Jetpack\Extensions\Subscriber_Login\get_subscriber_login_url
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
3.01
Automattic\Jetpack\Extensions\Subscriber_Login\is_subscriber_logged_in
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
3
Automattic\Jetpack\Extensions\Subscriber_Login\render_block
77.78% covered (warning)
77.78%
21 / 27
0.00% covered (danger)
0.00%
0 / 1
8.70
1<?php
2/**
3 * Subscriber Login Block.
4 *
5 * @since 13.1
6 *
7 * @package automattic/jetpack
8 */
9
10namespace Automattic\Jetpack\Extensions\Subscriber_Login;
11
12use Automattic\Jetpack\Blocks;
13use Automattic\Jetpack\Extensions\Premium_Content\Subscription_Service\Abstract_Token_Subscription_Service;
14use Automattic\Jetpack\Status\Host;
15use Automattic\Jetpack\Status\Request;
16use Jetpack;
17use Jetpack_Gutenberg;
18use Jetpack_Memberships;
19use Jetpack_Options;
20
21if ( ! defined( 'ABSPATH' ) ) {
22    exit( 0 );
23}
24
25require_once __DIR__ . '/class-jetpack-subscription-site.php';
26
27/**
28 * Registers the block for use in Gutenberg
29 * This is done via an action so that we can disable
30 * registration if we need to.
31 */
32function register_block() {
33    if ( ! Jetpack::is_module_active( 'subscriptions' ) ) {
34        Jetpack_Gutenberg::set_extension_unavailable( 'subscriber-login', 'missing_module', array( 'module' => 'subscriptions' ) );
35        return;
36    }
37
38    if (
39        ! class_exists( 'Jetpack_Memberships' ) ||
40        ! class_exists( 'Automattic\Jetpack\Extensions\Premium_Content\Subscription_Service\Abstract_Token_Subscription_Service' )
41    ) {
42        return;
43    }
44
45    Blocks::jetpack_register_block(
46        __DIR__,
47        array( 'render_callback' => __NAMESPACE__ . '\render_block' )
48    );
49
50    add_filter(
51        'jetpack_options_whitelist',
52        function ( $options ) {
53            $options[] = 'jetpack_subscriptions_login_navigation_enabled';
54
55            return $options;
56        }
57    );
58
59    // If called via REST API, we need to register later in the lifecycle
60    if ( ( new Host() )->is_wpcom_platform() && ! Request::is_frontend() ) {
61        add_action(
62            'restapi_theme_init',
63            function () {
64                Jetpack_Subscription_Site::init()->handle_subscriber_login_block_placements();
65            }
66        );
67    } else {
68        Jetpack_Subscription_Site::init()->handle_subscriber_login_block_placements();
69    }
70}
71add_action( 'init', __NAMESPACE__ . '\register_block' );
72
73/**
74 * Returns current URL.
75 *
76 * @return string
77 */
78function get_current_url() {
79    if ( ! isset( $_SERVER['HTTP_HOST'] ) || ! isset( $_SERVER['REQUEST_URI'] ) ) {
80        return '';
81    }
82
83    return ( is_ssl() ? 'https://' : 'http://' ) . wp_unslash( $_SERVER['HTTP_HOST'] ) . wp_unslash( $_SERVER['REQUEST_URI'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
84}
85
86/**
87 * Returns subscriber log in URL.
88 *
89 * @param string $redirect Path to redirect to on login.
90 *
91 * @return string
92 */
93function get_subscriber_login_url( $redirect ) {
94    $redirect = ! empty( $redirect ) ? $redirect : get_site_url();
95
96    if ( ( new Host() )->is_wpcom_simple() ) {
97        // On WPCOM we will redirect immediately
98        return wpcom_logmein_redirect_url( $redirect, false, null, 'link', get_current_blog_id() );
99    }
100
101    // On self-hosted we will save and hide the token.
102    // rawurlencode the redirect before nesting it: it is already percent-encoded
103    // (e.g. an emoji or non-ASCII slug comes through as %F0%9F%8C%91), and add_query_arg
104    // does not encode the values it inserts. Without this extra layer the value is
105    // over-decoded to raw bytes by the time it reaches the subscribers/auth endpoint,
106    // which strips it and 404s. See NL-273.
107    $redirect_url = get_site_url() . '/wp-json/jetpack/v4/subscribers/auth';
108    $redirect_url = add_query_arg( 'redirect_url', rawurlencode( $redirect ), $redirect_url );
109
110    return add_query_arg(
111        array(
112            'site_id'      => intval( Jetpack_Options::get_option( 'id' ) ),
113            'redirect_url' => rawurlencode( $redirect_url ),
114        ),
115        'https://subscribe.wordpress.com/memberships/jwt/'
116    );
117}
118
119/**
120 * Determines whether the visitor has a subscriber session for the login UI.
121 *
122 * WordPress sessions count on Simple; other hosts require the subscriber cookie.
123 * Content access validates the token separately.
124 *
125 * @return bool
126 */
127function is_subscriber_logged_in() {
128    return ( ( new Host() )->is_wpcom_simple() && is_user_logged_in() ) || Abstract_Token_Subscription_Service::has_token_from_cookie();
129}
130
131/**
132 * Renders Subscriber Login block.
133 *
134 * @param array $attributes The block attributes.
135 *
136 * @return string
137 */
138function render_block( $attributes ) {
139    Jetpack_Gutenberg::load_assets_as_required( __DIR__ );
140
141    $block_template             = '<div %1$s><a href="%2$s">%3$s</a></div>';
142    $redirect_url               = ! empty( $attributes['redirectToCurrent'] ) ? get_current_url() : get_site_url();
143    $log_in_label               = ! empty( $attributes['logInLabel'] ) ? sanitize_text_field( $attributes['logInLabel'] ) : esc_html__( 'Log in', 'jetpack' );
144    $log_out_label              = ! empty( $attributes['logOutLabel'] ) ? sanitize_text_field( $attributes['logOutLabel'] ) : esc_html__( 'Log out', 'jetpack' );
145    $show_manage_link           = ! empty( $attributes['showManageSubscriptionsLink'] );
146    $manage_subscriptions_label = ! empty( $attributes['manageSubscriptionsLabel'] ) ? sanitize_text_field( $attributes['manageSubscriptionsLabel'] ) : esc_html__( 'Manage subscription', 'jetpack' );
147
148    if ( ! is_subscriber_logged_in() ) {
149        return sprintf(
150            $block_template,
151            get_block_wrapper_attributes(),
152            get_subscriber_login_url( $redirect_url ),
153            $log_in_label
154        );
155    }
156
157    if ( $show_manage_link && Jetpack_Memberships::is_current_user_subscribed() ) {
158        return sprintf(
159            $block_template,
160            get_block_wrapper_attributes(),
161            'https://wordpress.com/reader/site/subscription/' . Jetpack_Memberships::get_blog_id(),
162            $manage_subscriptions_label
163        );
164    }
165
166    return sprintf(
167        $block_template,
168        get_block_wrapper_attributes(),
169        wp_logout_url( $redirect_url ),
170        $log_out_label
171    );
172}