Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 112
0.00% covered (danger)
0.00%
0 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
Settings
0.00% covered (danger)
0.00%
0 / 112
0.00% covered (danger)
0.00%
0 / 11
650
0.00% covered (danger)
0.00%
0 / 1
 init
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 expose_to_users
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 is_subscriptions_active
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 init_hooks
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
 add_wp_admin_menu
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
42
 add_wp_admin_submenu
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
 admin_init
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 load_admin_scripts
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
2
 get_subscriber_management_url
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
 get_settings_data
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
6
 render
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * A class that adds a newsletter settings screen to wp-admin.
4 *
5 * @package automattic/jetpack-newsletter
6 */
7
8namespace Automattic\Jetpack\Newsletter;
9
10use Automattic\Jetpack\Admin_UI\Admin_Menu;
11use Automattic\Jetpack\Assets;
12use Automattic\Jetpack\Connection\Manager as Connection_Manager;
13use Automattic\Jetpack\Modules;
14use Automattic\Jetpack\Paths;
15use Automattic\Jetpack\Redirect;
16use Automattic\Jetpack\Status\Host;
17use Jetpack_Tracks_Client;
18
19/**
20 * A class responsible for adding a newsletter settings screen to wp-admin.
21 */
22class Settings {
23
24    const PACKAGE_VERSION = '0.5.0';
25    /**
26     * Whether the class has been initialized
27     *
28     * @var boolean
29     */
30    private static $initialized = false;
31
32    /**
33     * Init Newsletter Settings if it wasn't already.
34     */
35    public static function init() {
36        if ( ! self::$initialized ) {
37            self::$initialized = true;
38            ( new self() )->init_hooks();
39        }
40    }
41
42    /**
43     * Determine whether to expose the new settings UI to users.
44     *
45     * @return bool
46     */
47    private function expose_to_users() {
48        /**
49         * Enables the new in-development newsletter settings UI in wp-admin.
50         *
51         * @since 15.3.0
52         *
53         * @param bool $enabled Whether to enable the new newsletter settings UI. Default false.
54         */
55        return apply_filters( 'jetpack_wp_admin_newsletter_settings_enabled', false );
56    }
57
58    /**
59     * Check if the subscriptions module is active.
60     *
61     * @return bool
62     */
63    private function is_subscriptions_active() {
64        return ( new Modules() )->is_active( 'subscriptions' );
65    }
66
67    /**
68     * Subscribe to necessary hooks.
69     */
70    public function init_hooks() {
71        if ( ! $this->expose_to_users() ) {
72            return;
73        }
74
75        $host = new Host();
76
77        // On wpcom Simple, the Jetpack menu is created at priority 999999 by wpcom-admin-menu.php,
78        // which will call add_wp_admin_submenu() directly. Skip adding the menu here to avoid
79        // trying to add a submenu before the parent menu exists.
80        if ( $host->is_wpcom_simple() ) {
81            return;
82        }
83
84        // Add admin menu item.
85        add_action( 'admin_menu', array( $this, 'add_wp_admin_menu' ), 1000 );
86
87        // Hijack the config URLs to point to our settings page.
88        // Customize the configuration URL to lead to the Subscriptions settings.
89        add_filter(
90            'jetpack_module_configuration_url_subscriptions',
91            function () {
92                return ( new Paths() )->admin_url( array( 'page' => 'jetpack-newsletter' ) );
93            }
94        );
95    }
96
97    /**
98     * Add the newsletter settings submenu to the Jetpack menu.
99     *
100     * Note: This method is NOT called on wpcom Simple sites. Simple sites use
101     * add_wp_admin_submenu() called from wpcom-admin-menu.php instead.
102     *
103     * Menu visibility rules:
104     * - wpcom Atomic: Show under 'jetpack' if module active, hidden if inactive.
105     * - Standalone Jetpack: Show under 'jetpack' if module active, hidden if inactive.
106     */
107    public function add_wp_admin_menu() {
108        if ( ! $this->expose_to_users() ) {
109            return;
110        }
111
112        $host             = new Host();
113        $is_module_active = $this->is_subscriptions_active();
114
115        // Show in Jetpack menu if module active, hidden page if inactive.
116        $parent_slug = $is_module_active ? 'jetpack' : '';
117
118        // On Atomic, use add_submenu_page. On standalone Jetpack, use Admin_Menu when active.
119        $use_jetpack_menu = ! $host->is_woa_site() && $is_module_active;
120
121        // Register menu item.
122        if ( $use_jetpack_menu ) {
123            $page_suffix = Admin_Menu::add_menu(
124                /** "Newsletter" is a product name, do not translate. */
125                'Newsletter',
126                'Newsletter',
127                'manage_options',
128                'jetpack-newsletter',
129                array( $this, 'render' ),
130                10
131            );
132        } else {
133            $page_suffix = add_submenu_page(
134                $parent_slug,
135                /** "Newsletter" is a product name, do not translate. */
136                'Newsletter',
137                'Newsletter',
138                'manage_options',
139                'jetpack-newsletter',
140                array( $this, 'render' )
141            );
142        }
143
144        if ( $page_suffix ) {
145            add_action( 'load-' . $page_suffix, array( $this, 'admin_init' ) );
146        }
147    }
148
149    /**
150     * Add the newsletter settings submenu directly under the Jetpack menu.
151     *
152     * This method is called from wpcom-admin-menu.php on Simple sites at late priority
153     * (999999) when the Jetpack menu already exists.
154     *
155     * Similar to Subscribers_Dashboard::add_wp_admin_submenu().
156     */
157    public function add_wp_admin_submenu() {
158        if ( ! $this->expose_to_users() ) {
159            return;
160        }
161
162        $page_suffix = add_submenu_page(
163            'jetpack',
164            /** "Newsletter" is a product name, do not translate. */
165            'Newsletter',
166            'Newsletter',
167            'manage_options',
168            'jetpack-newsletter',
169            array( $this, 'render' )
170        );
171
172        if ( $page_suffix ) {
173            add_action( 'load-' . $page_suffix, array( $this, 'admin_init' ) );
174        }
175    }
176
177    /**
178     * Admin init actions.
179     */
180    public function admin_init() {
181        add_action( 'admin_enqueue_scripts', array( $this, 'load_admin_scripts' ) );
182    }
183
184    /**
185     * Load the admin scripts.
186     */
187    public function load_admin_scripts() {
188        Assets::register_script(
189            'jetpack-newsletter',
190            '../build/newsletter.js',
191            __FILE__,
192            array(
193                'in_footer'  => true,
194                'textdomain' => 'jetpack-newsletter',
195                'enqueue'    => true,
196            )
197        );
198
199        wp_add_inline_script(
200            'jetpack-newsletter',
201            'window.jetpackNewsletterSettings = ' . wp_json_encode( $this->get_settings_data(), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ) . ';',
202            'before'
203        );
204
205        // Enqueue the Tracks script for analytics.
206        wp_enqueue_script( 'jp-tracks', '//stats.wp.com/w.js', array(), gmdate( 'YW' ), true );
207    }
208
209    /**
210     * Get the subscriber management URL based on site type and filter settings.
211     *
212     * - If jetpack_wp_admin_subscriber_management_enabled filter is true: wp-admin subscribers page
213     * - If filter is false AND wpcom simple site: wordpress.com/subscribers/$domain
214     * - If filter is false AND Jetpack site: jetpack.com redirect URL
215     *
216     * @param bool   $wp_admin_enabled Whether wp-admin subscriber management is enabled.
217     * @param bool   $is_wpcom_simple  Whether this is a wpcom simple site.
218     * @param string $site_raw_url     The site URL without protocol.
219     * @param int    $blog_id          The blog ID.
220     * @return string The subscriber management URL.
221     */
222    private function get_subscriber_management_url( $wp_admin_enabled, $is_wpcom_simple, $site_raw_url, $blog_id ) {
223        // If wp-admin subscriber management is enabled, use the wp-admin page.
224        if ( $wp_admin_enabled ) {
225            return admin_url( 'admin.php?page=subscribers' );
226        }
227
228        // For wpcom simple sites, use the wordpress.com URL.
229        if ( $is_wpcom_simple ) {
230            return 'https://wordpress.com/subscribers/' . $site_raw_url;
231        }
232
233        // For Jetpack sites, use the jetpack.com redirect URL.
234        $site_id = $blog_id ? $blog_id : Connection_Manager::get_site_id();
235        return Redirect::get_url(
236            'jetpack-settings-jetpack-manage-subscribers',
237            array( 'site' => $site_id )
238        );
239    }
240
241    /**
242     * Get the data to be passed to the newsletter settings page.
243     *
244     * @return array
245     */
246    private function get_settings_data() {
247        $current_user = wp_get_current_user();
248        $theme        = wp_get_theme();
249
250        $site_url     = get_site_url();
251        $site_raw_url = preg_replace( '(^https?://)', '', $site_url );
252
253        $host                   = new Host();
254        $blog_id                = (int) $host->get_wpcom_site_id();
255        $is_wpcom               = $host->is_wpcom_platform();
256        $is_wpcom_simple        = $host->is_wpcom_simple();
257        $setup_payment_plan_url = ( $is_wpcom_simple ? 'https://wordpress.com/earn/payments/' : 'https://cloud.jetpack.com/monetize/payments/' ) . rawurlencode( $site_raw_url );
258
259        $wp_admin_subscriber_management_enabled = apply_filters( 'jetpack_wp_admin_subscriber_management_enabled', false );
260
261        return array(
262            'isBlockTheme'                    => wp_is_block_theme(),
263            'siteAdminUrl'                    => admin_url(),
264            'themeStylesheet'                 => $theme->get_stylesheet(),
265            'blogID'                          => $blog_id,
266            'email'                           => $current_user->user_email,
267            'gravatar'                        => get_avatar_url( $current_user->ID ),
268            'displayName'                     => $current_user->display_name,
269            'dateExample'                     => gmdate( get_option( 'date_format' ), time() ),
270            'subscriberManagementUrl'         => $this->get_subscriber_management_url( $wp_admin_subscriber_management_enabled, $is_wpcom_simple, $site_raw_url, $blog_id ),
271            'isSubscriptionSiteEditSupported' => wp_is_block_theme(),
272            'setupPaymentPlansUrl'            => $setup_payment_plan_url,
273            'isSitePublic'                    => (int) get_option( 'blog_public' ) === 1,
274            'isWpcomPlatform'                 => $is_wpcom,
275            'isWpcomSimple'                   => $is_wpcom_simple,
276            'restApiRoot'                     => esc_url_raw( rest_url() ),
277            'restApiNonce'                    => wp_create_nonce( 'wp_rest' ),
278            'siteName'                        => get_bloginfo( 'name' ),
279            'tracksUserData'                  => Jetpack_Tracks_Client::get_connected_user_tracks_identity(),
280        );
281    }
282
283    /**
284     * Render the newsletter settings page.
285     */
286    public function render() {
287        ?>
288        <div id="newsletter-settings-root"></div>
289        <?php
290    }
291}