Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
97.60% |
325 / 333 |
|
70.59% |
12 / 17 |
CRAP | |
0.00% |
0 / 1 |
| Jetpack_Offline_Mode_Features | |
98.19% |
325 / 331 |
|
70.59% |
12 / 17 |
41 | |
0.00% |
0 / 1 |
| get_dashboard_data | |
98.28% |
57 / 58 |
|
0.00% |
0 / 1 |
5 | |||
| get_recommended_modules | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
1 | |||
| get_partial_features | |
100.00% |
35 / 35 |
|
100.00% |
1 / 1 |
2 | |||
| get_always_available_features | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
1 | |||
| get_requires_connection_features | |
97.06% |
33 / 34 |
|
0.00% |
0 / 1 |
7 | |||
| allow_partial_module_in_offline_mode | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
| get_groups | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
1 | |||
| is_boost_available | |
86.67% |
13 / 15 |
|
0.00% |
0 / 1 |
6.09 | |||
| get_offline_module_features | |
96.00% |
24 / 25 |
|
0.00% |
0 / 1 |
6 | |||
| get_limited_offline_modules | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
| get_requires_connection_non_module_features | |
100.00% |
26 / 26 |
|
100.00% |
1 / 1 |
1 | |||
| get_requires_connection_feature | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
1 | |||
| get_requires_connection_description | |
100.00% |
25 / 25 |
|
100.00% |
1 / 1 |
1 | |||
| get_requires_connection_name | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
| get_documentation_url | |
100.00% |
32 / 32 |
|
100.00% |
1 / 1 |
1 | |||
| get_module_name_fallback | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| get_module_group | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
3 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * Offline Mode feature registry. |
| 4 | * |
| 5 | * @package automattic/jetpack |
| 6 | */ |
| 7 | |
| 8 | use Automattic\Jetpack\Redirect; |
| 9 | |
| 10 | if ( ! defined( 'ABSPATH' ) ) { |
| 11 | exit( 0 ); |
| 12 | } |
| 13 | |
| 14 | /** |
| 15 | * Provides feature data for the Jetpack Offline Mode dashboard. |
| 16 | */ |
| 17 | class Jetpack_Offline_Mode_Features { |
| 18 | const TYPE_MODULE = 'module'; |
| 19 | const TYPE_PARTIAL = 'partial'; |
| 20 | const TYPE_ALWAYS_AVAILABLE = 'always_available'; |
| 21 | const TYPE_REQUIRES_CONNECTION = 'requires_connection'; |
| 22 | |
| 23 | /** |
| 24 | * Get dashboard data for the Offline Mode screen. |
| 25 | * |
| 26 | * @return array |
| 27 | */ |
| 28 | public static function get_dashboard_data() { |
| 29 | $features = array_merge( |
| 30 | self::get_offline_module_features(), |
| 31 | array_values( self::get_partial_features() ), |
| 32 | array_values( self::get_always_available_features() ) |
| 33 | ); |
| 34 | |
| 35 | $group_order = array_flip( array_keys( self::get_groups() ) ); |
| 36 | |
| 37 | usort( |
| 38 | $features, |
| 39 | function ( $a, $b ) use ( $group_order ) { |
| 40 | $a_group = $group_order[ $a['group'] ] ?? PHP_INT_MAX; |
| 41 | $b_group = $group_order[ $b['group'] ] ?? PHP_INT_MAX; |
| 42 | |
| 43 | if ( $a['group'] === $b['group'] ) { |
| 44 | return strcasecmp( $a['name'], $b['name'] ); |
| 45 | } |
| 46 | |
| 47 | if ( $a_group === $b_group ) { |
| 48 | return strcasecmp( $a['group'], $b['group'] ); |
| 49 | } |
| 50 | |
| 51 | return ( $a_group < $b_group ) ? -1 : 1; |
| 52 | } |
| 53 | ); |
| 54 | |
| 55 | return array( |
| 56 | 'features' => $features, |
| 57 | 'groups' => self::get_groups(), |
| 58 | 'recommended' => self::get_recommended_modules(), |
| 59 | 'requires_connection' => self::get_requires_connection_features(), |
| 60 | 'counts' => array( |
| 61 | 'offline_safe' => count( |
| 62 | array_filter( |
| 63 | $features, |
| 64 | function ( $feature ) { |
| 65 | return self::TYPE_MODULE === $feature['type']; |
| 66 | } |
| 67 | ) |
| 68 | ), |
| 69 | 'enabled' => count( |
| 70 | array_filter( |
| 71 | $features, |
| 72 | function ( $feature ) { |
| 73 | return ! empty( $feature['active'] ) && ! empty( $feature['toggleable'] ); |
| 74 | } |
| 75 | ) |
| 76 | ), |
| 77 | 'partial' => count( |
| 78 | array_filter( |
| 79 | $features, |
| 80 | function ( $feature ) { |
| 81 | return self::TYPE_PARTIAL === $feature['type']; |
| 82 | } |
| 83 | ) |
| 84 | ), |
| 85 | 'always_available' => count( |
| 86 | array_filter( |
| 87 | $features, |
| 88 | function ( $feature ) { |
| 89 | return self::TYPE_ALWAYS_AVAILABLE === $feature['type']; |
| 90 | } |
| 91 | ) |
| 92 | ), |
| 93 | ), |
| 94 | ); |
| 95 | } |
| 96 | |
| 97 | /** |
| 98 | * Get recommended module slugs for local development. |
| 99 | * |
| 100 | * @return array |
| 101 | */ |
| 102 | public static function get_recommended_modules() { |
| 103 | return array( |
| 104 | 'contact-form', |
| 105 | 'blocks', |
| 106 | 'shortcodes', |
| 107 | 'tiled-gallery', |
| 108 | 'carousel', |
| 109 | 'widgets', |
| 110 | 'widget-visibility', |
| 111 | 'markdown', |
| 112 | 'copy-post', |
| 113 | 'sharedaddy', |
| 114 | 'sitemaps', |
| 115 | 'seo-tools', |
| 116 | ); |
| 117 | } |
| 118 | |
| 119 | /** |
| 120 | * Get curated partial offline features. |
| 121 | * |
| 122 | * @return array |
| 123 | */ |
| 124 | public static function get_partial_features() { |
| 125 | $module = Jetpack::get_module( 'subscriptions' ); |
| 126 | |
| 127 | $features = array( |
| 128 | 'newsletter' => array( |
| 129 | 'slug' => 'newsletter', |
| 130 | 'module' => 'subscriptions', |
| 131 | 'name' => __( 'Newsletter', 'jetpack' ), |
| 132 | 'description' => $module['description'] ?? __( 'Grow your subscriber list and deliver your content directly to their email inbox.', 'jetpack' ), |
| 133 | 'type' => self::TYPE_PARTIAL, |
| 134 | 'group' => 'audience', |
| 135 | 'active' => Jetpack::is_module_active( 'subscriptions' ), |
| 136 | 'available' => true, |
| 137 | 'recommended' => false, |
| 138 | 'toggleable' => true, |
| 139 | 'limitation' => __( 'Local editor, theme, and plugin integration can be enabled. Email delivery, subscriber sync, and WordPress.com-backed flows still require a connection.', 'jetpack' ), |
| 140 | 'underlying_module' => 'subscriptions', |
| 141 | 'documentation_url' => self::get_documentation_url( 'newsletter' ), |
| 142 | ), |
| 143 | ); |
| 144 | |
| 145 | if ( self::is_boost_available() ) { |
| 146 | $features['boost'] = array( |
| 147 | 'slug' => 'boost', |
| 148 | 'module' => '', |
| 149 | 'name' => __( 'Boost', 'jetpack' ), |
| 150 | 'description' => __( 'Use Jetpack Boost performance tools that can run on a local site.', 'jetpack' ), |
| 151 | 'type' => self::TYPE_PARTIAL, |
| 152 | 'group' => 'performance', |
| 153 | 'active' => true, |
| 154 | 'available' => true, |
| 155 | 'recommended' => false, |
| 156 | 'toggleable' => false, |
| 157 | 'limitation' => __( 'Image Guide, Concatenate CSS, Concatenate JS, Defer Non-Essential JavaScript, Page Cache, Speculation Rules, and manual Critical CSS generation can run locally. Speed scores, Image CDN, LCP analysis, Cloud CSS, and cloud-backed history require a publicly reachable site and/or WordPress.com services.', 'jetpack' ), |
| 158 | 'underlying_module' => '', |
| 159 | 'documentation_url' => self::get_documentation_url( 'boost' ), |
| 160 | ); |
| 161 | } |
| 162 | |
| 163 | return $features; |
| 164 | } |
| 165 | |
| 166 | /** |
| 167 | * Get local features that are loaded in Offline Mode without module toggles. |
| 168 | * |
| 169 | * @return array |
| 170 | */ |
| 171 | public static function get_always_available_features() { |
| 172 | return array( |
| 173 | 'theme-tools' => array( |
| 174 | 'slug' => 'theme-tools', |
| 175 | 'module' => '', |
| 176 | 'name' => __( 'Theme tools', 'jetpack' ), |
| 177 | 'description' => __( 'Use Jetpack theme integrations that are loaded automatically for local development.', 'jetpack' ), |
| 178 | 'type' => self::TYPE_ALWAYS_AVAILABLE, |
| 179 | 'group' => 'theme', |
| 180 | 'active' => true, |
| 181 | 'available' => true, |
| 182 | 'recommended' => false, |
| 183 | 'toggleable' => false, |
| 184 | 'limitation' => __( 'Responsive videos, featured content, social menus, breadcrumbs, site logo tools, and content options are loaded automatically when Jetpack is in Offline Mode.', 'jetpack' ), |
| 185 | 'underlying_module' => '', |
| 186 | 'documentation_url' => self::get_documentation_url( 'theme-tools' ), |
| 187 | ), |
| 188 | ); |
| 189 | } |
| 190 | |
| 191 | /** |
| 192 | * Get connection-required features for the informational section. |
| 193 | * |
| 194 | * @return array |
| 195 | */ |
| 196 | public static function get_requires_connection_features() { |
| 197 | $features = array(); |
| 198 | $partial_modules = wp_list_pluck( self::get_partial_features(), 'module' ); |
| 199 | |
| 200 | foreach ( Jetpack::get_available_modules( false, false, true, null ) as $module_slug ) { |
| 201 | if ( in_array( $module_slug, $partial_modules, true ) ) { |
| 202 | continue; |
| 203 | } |
| 204 | |
| 205 | $module = Jetpack::get_module( $module_slug ); |
| 206 | if ( ! $module ) { |
| 207 | continue; |
| 208 | } |
| 209 | |
| 210 | $module_name = isset( $module['name'] ) && '' !== $module['name'] ? $module['name'] : self::get_module_name_fallback( $module_slug ); |
| 211 | $feature_name = self::get_requires_connection_name( $module_slug, $module_name ); |
| 212 | $features[ $module_slug ] = array( |
| 213 | 'slug' => $module_slug, |
| 214 | 'module' => $module_slug, |
| 215 | 'name' => $feature_name, |
| 216 | 'description' => self::get_requires_connection_description( $module_slug, $module['description'] ?? $module_name ), |
| 217 | 'type' => self::TYPE_REQUIRES_CONNECTION, |
| 218 | 'group' => self::get_module_group( $module_slug ), |
| 219 | 'active' => Jetpack::is_module_active( $module_slug ), |
| 220 | 'available' => false, |
| 221 | 'recommended' => false, |
| 222 | 'toggleable' => false, |
| 223 | 'limitation' => __( 'This feature requires a WordPress.com connection and is unavailable in Offline Mode.', 'jetpack' ), |
| 224 | 'underlying_module' => $module_slug, |
| 225 | 'documentation_url' => self::get_documentation_url( $module_slug ), |
| 226 | ); |
| 227 | } |
| 228 | |
| 229 | foreach ( self::get_requires_connection_non_module_features() as $feature ) { |
| 230 | $features[ $feature['slug'] ] = $feature; |
| 231 | } |
| 232 | |
| 233 | uasort( |
| 234 | $features, |
| 235 | function ( $a, $b ) { |
| 236 | return strcasecmp( $a['name'], $b['name'] ); |
| 237 | } |
| 238 | ); |
| 239 | |
| 240 | return array_values( $features ); |
| 241 | } |
| 242 | |
| 243 | /** |
| 244 | * Allow curated partial modules to activate and load in Offline Mode. |
| 245 | * |
| 246 | * @param bool $allow Whether the module is already allowed. |
| 247 | * @param string $module Module slug. |
| 248 | * @param array $_module_data Module metadata. |
| 249 | * @return bool |
| 250 | */ |
| 251 | public static function allow_partial_module_in_offline_mode( $allow, $module, $_module_data = array() ) { |
| 252 | unset( $_module_data ); |
| 253 | |
| 254 | if ( $allow ) { |
| 255 | return true; |
| 256 | } |
| 257 | |
| 258 | $partial_modules = wp_list_pluck( self::get_partial_features(), 'module' ); |
| 259 | return in_array( $module, $partial_modules, true ); |
| 260 | } |
| 261 | |
| 262 | /** |
| 263 | * Get dashboard groups. |
| 264 | * |
| 265 | * @return array |
| 266 | */ |
| 267 | public static function get_groups() { |
| 268 | return array( |
| 269 | 'content' => __( 'Content and editor', 'jetpack' ), |
| 270 | 'audience' => __( 'Audience and engagement', 'jetpack' ), |
| 271 | 'media' => __( 'Media', 'jetpack' ), |
| 272 | 'performance' => __( 'Performance', 'jetpack' ), |
| 273 | 'traffic' => __( 'Traffic and discovery', 'jetpack' ), |
| 274 | 'theme' => __( 'Theme enhancements', 'jetpack' ), |
| 275 | 'other' => __( 'Other local features', 'jetpack' ), |
| 276 | ); |
| 277 | } |
| 278 | |
| 279 | /** |
| 280 | * Check whether Jetpack Boost is active or loaded. |
| 281 | * |
| 282 | * @return bool |
| 283 | */ |
| 284 | private static function is_boost_available() { |
| 285 | if ( defined( 'JETPACK_BOOST_VERSION' ) || class_exists( 'Automattic\Jetpack_Boost\Jetpack_Boost' ) ) { |
| 286 | return true; |
| 287 | } |
| 288 | |
| 289 | $boost_plugins = array( |
| 290 | 'boost/jetpack-boost.php', |
| 291 | 'jetpack-boost/jetpack-boost.php', |
| 292 | 'jetpack-boost-dev/jetpack-boost.php', |
| 293 | ); |
| 294 | |
| 295 | $active_plugins = (array) get_option( 'active_plugins', array() ); |
| 296 | if ( array_intersect( $boost_plugins, $active_plugins ) ) { |
| 297 | return true; |
| 298 | } |
| 299 | |
| 300 | $network_active_plugins = (array) get_site_option( 'active_sitewide_plugins', array() ); |
| 301 | foreach ( $boost_plugins as $boost_plugin ) { |
| 302 | if ( isset( $network_active_plugins[ $boost_plugin ] ) ) { |
| 303 | return true; |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | return false; |
| 308 | } |
| 309 | |
| 310 | /** |
| 311 | * Get fully offline module feature data. |
| 312 | * |
| 313 | * @return array |
| 314 | */ |
| 315 | private static function get_offline_module_features() { |
| 316 | $features = array(); |
| 317 | $recommended_modules = self::get_recommended_modules(); |
| 318 | $limited_modules = self::get_limited_offline_modules(); |
| 319 | |
| 320 | foreach ( Jetpack::get_available_modules( false, false, false, null ) as $module_slug ) { |
| 321 | $module = Jetpack::get_module( $module_slug ); |
| 322 | if ( ! $module ) { |
| 323 | continue; |
| 324 | } |
| 325 | |
| 326 | $module_name = isset( $module['name'] ) && '' !== $module['name'] ? $module['name'] : self::get_module_name_fallback( $module_slug ); |
| 327 | $limitation = $limited_modules[ $module_slug ] ?? ''; |
| 328 | |
| 329 | $features[] = array( |
| 330 | 'slug' => $module_slug, |
| 331 | 'module' => $module_slug, |
| 332 | 'name' => $module_name, |
| 333 | 'description' => $module['description'] ?? $module_name, |
| 334 | 'type' => $limitation ? self::TYPE_PARTIAL : self::TYPE_MODULE, |
| 335 | 'group' => self::get_module_group( $module_slug ), |
| 336 | 'active' => Jetpack::is_module_active( $module_slug ), |
| 337 | 'available' => true, |
| 338 | 'recommended' => in_array( $module_slug, $recommended_modules, true ), |
| 339 | 'toggleable' => true, |
| 340 | 'limitation' => $limitation, |
| 341 | 'underlying_module' => $module_slug, |
| 342 | 'documentation_url' => self::get_documentation_url( $module_slug ), |
| 343 | ); |
| 344 | } |
| 345 | |
| 346 | return $features; |
| 347 | } |
| 348 | |
| 349 | /** |
| 350 | * Get connection-free modules with mixed offline support. |
| 351 | * |
| 352 | * @return array |
| 353 | */ |
| 354 | private static function get_limited_offline_modules() { |
| 355 | return array( |
| 356 | 'blocks' => __( 'The Blocks module loads local editor support in Offline Mode. Blocks and editor tools that require WordPress.com services, such as AI, stats, likes, social publishing, payments, Instagram, and related content, remain unavailable.', 'jetpack' ), |
| 357 | 'shortcodes' => __( 'Most shortcode embeds can be tested locally. Instagram and Twitter oEmbed proxy helpers require a WordPress.com connection and are not loaded in Offline Mode.', 'jetpack' ), |
| 358 | 'widgets' => __( 'Most Jetpack widgets can be tested locally. Widgets that depend on Stats, followers, community data, or WordPress.com APIs are unavailable in Offline Mode.', 'jetpack' ), |
| 359 | ); |
| 360 | } |
| 361 | |
| 362 | /** |
| 363 | * Get connection-required non-module features. |
| 364 | * |
| 365 | * @return array |
| 366 | */ |
| 367 | private static function get_requires_connection_non_module_features() { |
| 368 | return array( |
| 369 | 'activity-log' => self::get_requires_connection_feature( |
| 370 | 'activity-log', |
| 371 | __( 'Activity Log', 'jetpack' ), |
| 372 | __( 'Requires a WordPress.com connection to collect, sync, and display site activity history.', 'jetpack' ), |
| 373 | 'security' |
| 374 | ), |
| 375 | 'jetpack-ai' => self::get_requires_connection_feature( |
| 376 | 'jetpack-ai', |
| 377 | __( 'Jetpack AI', 'jetpack' ), |
| 378 | __( 'Requires a WordPress.com connection to generate, process, and manage AI content.', 'jetpack' ), |
| 379 | 'content' |
| 380 | ), |
| 381 | 'payments' => self::get_requires_connection_feature( |
| 382 | 'payments', |
| 383 | __( 'Payments and paid content', 'jetpack' ), |
| 384 | __( 'Requires a WordPress.com connection for payment accounts, paid plans, subscriber authentication, and checkout flows.', 'jetpack' ), |
| 385 | 'audience' |
| 386 | ), |
| 387 | 'scan' => self::get_requires_connection_feature( |
| 388 | 'scan', |
| 389 | __( 'Jetpack Scan', 'jetpack' ), |
| 390 | __( 'Requires a WordPress.com connection to scan site files and receive security results.', 'jetpack' ), |
| 391 | 'security' |
| 392 | ), |
| 393 | ); |
| 394 | } |
| 395 | |
| 396 | /** |
| 397 | * Build a connection-required non-module feature entry. |
| 398 | * |
| 399 | * @param string $slug Feature slug. |
| 400 | * @param string $name Feature name. |
| 401 | * @param string $description Feature description. |
| 402 | * @param string $group Feature group. |
| 403 | * @return array |
| 404 | */ |
| 405 | private static function get_requires_connection_feature( $slug, $name, $description, $group ) { |
| 406 | return array( |
| 407 | 'slug' => $slug, |
| 408 | 'module' => '', |
| 409 | 'name' => $name, |
| 410 | 'description' => $description, |
| 411 | 'type' => self::TYPE_REQUIRES_CONNECTION, |
| 412 | 'group' => $group, |
| 413 | 'active' => false, |
| 414 | 'available' => false, |
| 415 | 'recommended' => false, |
| 416 | 'toggleable' => false, |
| 417 | 'limitation' => __( 'This feature requires a WordPress.com connection and is unavailable in Offline Mode.', 'jetpack' ), |
| 418 | 'underlying_module' => '', |
| 419 | 'documentation_url' => self::get_documentation_url( $slug ), |
| 420 | ); |
| 421 | } |
| 422 | |
| 423 | /** |
| 424 | * Get connection-required description for a module. |
| 425 | * |
| 426 | * @param string $module Module slug. |
| 427 | * @param string $fallback_description Module description. |
| 428 | * @return string |
| 429 | */ |
| 430 | private static function get_requires_connection_description( $module, $fallback_description ) { |
| 431 | $descriptions = array( |
| 432 | 'comments' => __( 'Requires a WordPress.com connection for the enhanced Jetpack comment form and its WordPress.com API-backed flows.', 'jetpack' ), |
| 433 | 'comment-likes' => __( 'Requires a WordPress.com connection so visitors can like individual comments.', 'jetpack' ), |
| 434 | 'json-api' => __( 'Requires a WordPress.com connection to expose site data through the WordPress.com REST API.', 'jetpack' ), |
| 435 | 'monitor' => __( 'Requires a WordPress.com connection to monitor uptime and send downtime alerts.', 'jetpack' ), |
| 436 | 'notes' => __( 'Requires a connected WordPress.com user to receive notifications across devices.', 'jetpack' ), |
| 437 | 'photon' => __( 'Requires a WordPress.com connection to resize, optimize, and serve images through Jetpack Image CDN.', 'jetpack' ), |
| 438 | 'post-by-email' => __( 'Requires a connected WordPress.com user to generate and use a private posting email address.', 'jetpack' ), |
| 439 | 'protect' => __( 'Requires a WordPress.com connection to check login attempts against Jetpack protection services.', 'jetpack' ), |
| 440 | 'publicize' => __( 'Requires a connected WordPress.com user and social accounts to publish posts to social networks.', 'jetpack' ), |
| 441 | 'related-posts' => __( 'Requires a WordPress.com connection to index content and calculate related posts.', 'jetpack' ), |
| 442 | 'search' => __( 'Requires a WordPress.com connection to index site content for Jetpack Search.', 'jetpack' ), |
| 443 | 'shortlinks' => __( 'Requires a WordPress.com connection to create and resolve WP.me shortlinks.', 'jetpack' ), |
| 444 | 'sso' => __( 'Requires a connected WordPress.com user for WordPress.com Secure Sign On.', 'jetpack' ), |
| 445 | 'stats' => __( 'Requires a WordPress.com connection to collect and display site traffic data.', 'jetpack' ), |
| 446 | 'vaultpress' => __( 'Requires a WordPress.com connection to store backups and manage restores.', 'jetpack' ), |
| 447 | 'videopress' => __( 'Requires a WordPress.com connection to upload, process, host, and serve videos.', 'jetpack' ), |
| 448 | 'waf' => __( 'Requires a WordPress.com connection to manage Jetpack firewall rules and updates.', 'jetpack' ), |
| 449 | 'woocommerce-analytics' => __( 'Requires a WordPress.com connection to sync and display WooCommerce analytics data.', 'jetpack' ), |
| 450 | 'wordads' => __( 'Requires a WordPress.com connection to configure ads, consent management, and revenue reporting.', 'jetpack' ), |
| 451 | ); |
| 452 | |
| 453 | return $descriptions[ $module ] ?? sprintf( |
| 454 | /* translators: %s: Jetpack feature description. */ |
| 455 | __( '%s This feature requires a WordPress.com connection and is unavailable in Offline Mode.', 'jetpack' ), |
| 456 | $fallback_description |
| 457 | ); |
| 458 | } |
| 459 | |
| 460 | /** |
| 461 | * Get display name for a connection-required module. |
| 462 | * |
| 463 | * @param string $module Module slug. |
| 464 | * @param string $fallback_name Module name. |
| 465 | * @return string |
| 466 | */ |
| 467 | private static function get_requires_connection_name( $module, $fallback_name ) { |
| 468 | $names = array( |
| 469 | 'comments' => __( 'Jetpack Comments', 'jetpack' ), |
| 470 | ); |
| 471 | |
| 472 | return $names[ $module ] ?? $fallback_name; |
| 473 | } |
| 474 | |
| 475 | /** |
| 476 | * Get the Jetpack Redirect URL for a feature's documentation. |
| 477 | * |
| 478 | * @param string $feature Feature or module slug. |
| 479 | * @return string |
| 480 | */ |
| 481 | private static function get_documentation_url( $feature ) { |
| 482 | $redirect_sources = array( |
| 483 | 'blocks' => 'jetpack-support-blocks', |
| 484 | 'boost' => 'jetpack-support-boost', |
| 485 | 'canonical-urls' => 'jetpack-support-canonical-urls', |
| 486 | 'carousel' => 'jetpack-support-carousel', |
| 487 | 'contact-form' => 'jetpack-support-contact-form', |
| 488 | 'copy-post' => 'jetpack-support-copy-post', |
| 489 | 'custom-content-types' => 'jetpack-support-custom-content-types', |
| 490 | 'google-fonts' => 'jetpack-support-google-fonts', |
| 491 | 'gravatar-hovercards' => 'jetpack-support-gravatar-hovercards', |
| 492 | 'infinite-scroll' => 'jetpack-support-infinite-scroll', |
| 493 | 'jetpack-ai' => 'jetpack-ai', |
| 494 | 'latex' => 'jetpack-support-beautiful-math-with-latex', |
| 495 | 'markdown' => 'jetpack-support-markdown', |
| 496 | 'newsletter' => 'https://jetpack.com/support/newsletter', |
| 497 | 'payments' => 'jetpack-support-payments', |
| 498 | 'photon-cdn' => 'jetpack-support-asset-cdn', |
| 499 | 'post-list' => 'jetpack-support-post-list', |
| 500 | 'scan' => 'jetpack-support-scan', |
| 501 | 'sharedaddy' => 'jetpack-support-sharing', |
| 502 | 'shortcodes' => 'jetpack-support-shortcode-embeds', |
| 503 | 'seo-tools' => 'jetpack-support-seo-tools', |
| 504 | 'sitemaps' => 'jetpack-support-sitemaps', |
| 505 | 'theme-tools' => 'jetpack-support-theme-tools', |
| 506 | 'tiled-gallery' => 'jetpack-support-tiled-galleries', |
| 507 | 'verification-tools' => 'jetpack-support-site-verification-tools', |
| 508 | 'widget-visibility' => 'jetpack-support-widget-visibility', |
| 509 | 'widgets' => 'jetpack-support-extra-sidebar-widgets', |
| 510 | 'wpcom-reader' => 'jetpack-support-reader', |
| 511 | ); |
| 512 | |
| 513 | $source = $redirect_sources[ $feature ] ?? 'jetpack-support-' . $feature; |
| 514 | return Redirect::get_url( $source ); |
| 515 | } |
| 516 | |
| 517 | /** |
| 518 | * Get a readable module name from a module slug. |
| 519 | * |
| 520 | * @param string $module Module slug. |
| 521 | * @return string |
| 522 | */ |
| 523 | private static function get_module_name_fallback( $module ) { |
| 524 | return ucwords( str_replace( '-', ' ', $module ) ); |
| 525 | } |
| 526 | |
| 527 | /** |
| 528 | * Map module slugs to developer dashboard groups. |
| 529 | * |
| 530 | * @param string $module Module slug. |
| 531 | * @return string |
| 532 | */ |
| 533 | private static function get_module_group( $module ) { |
| 534 | $groups = array( |
| 535 | 'content' => array( 'blocks', 'contact-form', 'copy-post', 'custom-content-types', 'latex', 'markdown', 'shortcodes' ), |
| 536 | 'audience' => array( 'gravatar-hovercards', 'sharedaddy', 'wpcom-reader' ), |
| 537 | 'media' => array( 'carousel', 'photon-cdn', 'tiled-gallery' ), |
| 538 | 'traffic' => array( 'canonical-urls', 'seo-tools', 'sitemaps', 'verification-tools' ), |
| 539 | 'theme' => array( 'google-fonts', 'infinite-scroll', 'post-list', 'widget-visibility', 'widgets' ), |
| 540 | ); |
| 541 | |
| 542 | foreach ( $groups as $group => $modules ) { |
| 543 | if ( in_array( $module, $modules, true ) ) { |
| 544 | return $group; |
| 545 | } |
| 546 | } |
| 547 | |
| 548 | return 'other'; |
| 549 | } |
| 550 | } |