PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.7
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.7
16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 All 506 releases
jetpack / jetpack_vendor / automattic / jetpack-ads / src / class-analytics-dashboard.php

class-analytics-dashboard.php in Jetpack – WP Security, Backup, Speed, & Growth 16.3-a.7, at jetpack_vendor/automattic/jetpack-ads/src/class-analytics-dashboard.php

205 lines 6.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The Ads section and widgets of the Premium Analytics dashboard.
4 *
5 * @package automattic/jetpack-ads
6 */
7
8 namespace Automattic\Jetpack\WordAds;
9
10 use Automattic\Jetpack\PremiumAnalytics\Capabilities;
11 use function Automattic\Jetpack\PremiumAnalytics\get_dashboard_default_widget_instance;
12 use function Automattic\Jetpack\PremiumAnalytics\register_dashboard_section;
13 use function Automattic\Jetpack\PremiumAnalytics\register_widget_types_from_manifest;
14 use const Automattic\Jetpack\PremiumAnalytics\DASHBOARD_NAME;
15
16 /**
17 * Registers the Ads section, its default layout and its widget types on the Premium Analytics
18 * dashboard.
19 *
20 * The package decides nothing about who gets Ads: the WordAds module of the Jetpack plugin calls
21 * `init()` outside the WordPress.com platform, jetpack-mu-wpcom calls the registrants on Simple
22 * and Atomic where the plan includes WordAds and the site has it on. Everything registers when the dashboard's registries
23 * hydrate, so a call on a site without the dashboard is inert.
24 *
25 * @since 0.1.0
26 */
27 class Analytics_Dashboard {
28
29 const PACKAGE_VERSION = '0.1.1';
30
31 /**
32 * Namespaced section identifier. Its slug, `ads`, keys the section's URL and stored layouts.
33 */
34 const SECTION_ID = 'wordads/ads';
35
36 /**
37 * Widget type names the package builds, from `widgets/*\/widget.json`.
38 */
39 const CHART_TABS_TYPE = 'wordads/chart-tabs';
40 const HIGHLIGHTS_TYPE = 'wordads/highlights';
41 const EARNINGS_HISTORY_TYPE = 'wordads/earnings-history';
42
43 /**
44 * Registry actions of the dashboard package.
45 */
46 const REGISTER_SECTIONS_ACTION = 'jetpack_premium_analytics_register_dashboard_sections';
47 const REGISTER_WIDGET_TYPES_ACTION = 'jetpack_premium_analytics_register_widget_types';
48
49 /**
50 * Text domain of the widget metadata and of the built widget bundles.
51 */
52 const TEXTDOMAIN = 'jetpack-ads-pkg';
53
54 /**
55 * Hook both registrants on the dashboard's registry actions.
56 *
57 * Priority 20, after the dashboard package's own registrants: an older package that still
58 * registers the section itself is found by slug and left alone.
59 *
60 * @return void
61 */
62 public static function init() {
63 add_action( self::REGISTER_SECTIONS_ACTION, array( __CLASS__, 'register_section' ), 20 );
64 add_action( self::REGISTER_WIDGET_TYPES_ACTION, array( __CLASS__, 'register_widget_types' ), 20 );
65 }
66
67 /**
68 * Register the Ads section unless another owner already holds the `ads` slug.
69 *
70 * Also skipped when the dashboard's widget contract moved past this build: a tab whose every
71 * widget is unavailable is worse than no tab.
72 *
73 * @param object $registry The section registry being hydrated.
74 * @return void
75 */
76 public static function register_section( $registry ) {
77 if ( self::widget_contract_moved_on() || self::dashboard_has_section_slug( $registry, DASHBOARD_NAME, 'ads' ) ) {
78 return;
79 }
80
81 register_dashboard_section(
82 DASHBOARD_NAME,
83 self::SECTION_ID,
84 array(
85 'label' => __( 'Ads', 'jetpack-ads-pkg' ),
86 'title' => __( 'Ads performance', 'jetpack-ads-pkg' ),
87 'order' => 50,
88 'is_available' => array( Capabilities::class, 'current_user_can_view_ad_reports' ),
89 // Only the chart supports dates, so it owns the control. No Ads widget
90 // supports comparison.
91 'date_filter_options' => array(
92 'with_date_comparison' => false,
93 'with_header_date_control' => false,
94 ),
95 'default_layout' => array( __CLASS__, 'get_default_layout' ),
96 )
97 );
98 }
99
100 /**
101 * The default layout of the Ads section: chart on top, balance, then earnings history.
102 *
103 * @return array[] Widget instances, as `get_dashboard_default_widget_instance()` builds them.
104 */
105 public static function get_default_layout() {
106 return array(
107 get_dashboard_default_widget_instance( 'default-wordads-chart-tabs-widget-instance', self::CHART_TABS_TYPE, 0, 3, 2 ),
108 get_dashboard_default_widget_instance( 'default-wordads-highlights-widget-instance', self::HIGHLIGHTS_TYPE, 1, 3, 1 ),
109 get_dashboard_default_widget_instance( 'default-wordads-earnings-history-widget-instance', self::EARNINGS_HISTORY_TYPE, 2, 1, 2 ),
110 );
111 }
112
113 /**
114 * Register the widget types from the package's build manifest.
115 *
116 * Loads the generated build first: after `init` it registers the widget script modules on the
117 * spot, so they reach the page import map the same request.
118 *
119 * @param object $registry The widget type registry being hydrated.
120 * @return void
121 */
122 public static function register_widget_types( $registry ) {
123 if ( ! defined( 'Automattic\\Jetpack\\PremiumAnalytics\\WIDGET_API_VERSION' ) || self::widget_contract_moved_on() ) {
124 return;
125 }
126
127 self::load_build();
128 if ( ! function_exists( 'jetpack_ads_get_registered_widget_modules' ) ) {
129 return;
130 }
131
132 register_widget_types_from_manifest(
133 jetpack_ads_get_registered_widget_modules(),
134 array(
135 'textdomain' => self::TEXTDOMAIN,
136 'i18n_manifest' => add_query_arg( 'ver', self::PACKAGE_VERSION, plugins_url( 'i18n-manifest.json', self::build_dir() . '/build.php' ) ),
137 ),
138 $registry
139 );
140 }
141
142 /**
143 * Whether the dashboard's widget contract moved to a major this package was not built against.
144 *
145 * Undefined is not a mismatch: the sections REST route hydrates the section registry before
146 * the dashboard loads the file that defines the version.
147 *
148 * @return bool
149 */
150 private static function widget_contract_moved_on() {
151 return defined( 'Automattic\\Jetpack\\PremiumAnalytics\\WIDGET_API_VERSION' )
152 && version_compare( \Automattic\Jetpack\PremiumAnalytics\WIDGET_API_VERSION, '2', '>=' );
153 }
154
155 /**
156 * Load the generated build once. Guarded by symbol, not by path: on WordPress.com Simple two
157 * copies of the package can share a request.
158 *
159 * @return void
160 */
161 private static function load_build() {
162 if ( function_exists( 'jetpack_ads_get_registered_widget_modules' ) ) {
163 return;
164 }
165 $loader = self::build_dir() . '/build.php';
166 if ( file_exists( $loader ) ) {
167 require_once $loader;
168 }
169 }
170
171 /**
172 * Directory of the wp-build output.
173 *
174 * @return string
175 */
176 private static function build_dir() {
177 return dirname( __DIR__ ) . '/build';
178 }
179
180 /**
181 * Whether a section with the slug is registered on the dashboard.
182 *
183 * Reads the registry through the slug lookup when the package offers it, and through the full
184 * list otherwise: the package and this one ship on different cadences.
185 *
186 * @param object $registry The registry being hydrated.
187 * @param string $dashboard_name Dashboard identifier.
188 * @param string $slug Section slug.
189 * @return bool
190 */
191 private static function dashboard_has_section_slug( $registry, $dashboard_name, $slug ) {
192 if ( method_exists( $registry, 'get_registered_by_slug' ) ) {
193 return null !== $registry->get_registered_by_slug( $dashboard_name, $slug );
194 }
195
196 foreach ( $registry->get_all_registered( $dashboard_name ) as $section ) {
197 if ( $section->slug === $slug ) {
198 return true;
199 }
200 }
201
202 return false;
203 }
204 }
205