Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
65.85% |
27 / 41 |
|
60.87% |
14 / 23 |
CRAP | |
0.00% |
0 / 1 |
| Environment | |
65.85% |
27 / 41 |
|
60.87% |
14 / 23 |
125.62 | |
0.00% |
0 / 1 |
| is_block_theme | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| is_simple_site | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| sharing_module_running | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
| legacy_sharing_switched_off | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 | |||
| legacy_sharing_supported | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
3 | |||
| settings_screen_supported | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| jetpack_blocks_load | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
4 | |||
| likes_supported | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
3 | |||
| is_connected | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| is_connection_ready | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| is_offline_mode | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| likes_module_running | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
| legacy_likes_switched_off | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
| comment_likes_module_running | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
| comment_likes_enabled | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
| comment_likes_follow_likes_settings | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
| likes_settings_in_use | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
| twitter_site_tag_used | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| module_active | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
| sharing_block_registered | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| like_block_registered | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| single_template_editor_url | |
90.91% |
10 / 11 |
|
0.00% |
0 / 1 |
5.02 | |||
| block_is_registered | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * Reads the site state that Settings > Sharing branches on. |
| 4 | * |
| 5 | * @package automattic/jetpack-sharing-likes |
| 6 | */ |
| 7 | |
| 8 | declare( strict_types = 1 ); |
| 9 | |
| 10 | namespace Automattic\Jetpack\Sharing_Likes\Settings; |
| 11 | |
| 12 | use Automattic\Jetpack\Connection\Manager as Connection_Manager; |
| 13 | use Automattic\Jetpack\Modules; |
| 14 | use Automattic\Jetpack\Sharing_Likes\Block_Names; |
| 15 | use Automattic\Jetpack\Status; |
| 16 | use Automattic\Jetpack\Status\Host; |
| 17 | |
| 18 | /** |
| 19 | * The facts Settings > Sharing branches on, read in one place so the sections |
| 20 | * and the state resolver stay free of environment lookups. |
| 21 | */ |
| 22 | final class Environment { |
| 23 | |
| 24 | /** |
| 25 | * Memoised Site Editor URL, since resolving the template hits the theme's files. |
| 26 | * |
| 27 | * @var string|null |
| 28 | */ |
| 29 | private static $single_template_editor_url = null; |
| 30 | |
| 31 | /** |
| 32 | * Whether the active theme is a block theme. |
| 33 | */ |
| 34 | public static function is_block_theme(): bool { |
| 35 | return wp_is_block_theme(); |
| 36 | } |
| 37 | |
| 38 | /** |
| 39 | * Whether this is a WordPress.com Simple site. |
| 40 | */ |
| 41 | public static function is_simple_site(): bool { |
| 42 | return ( new Host() )->is_wpcom_simple(); |
| 43 | } |
| 44 | |
| 45 | /** |
| 46 | * Whether sharing buttons can still produce output. |
| 47 | */ |
| 48 | public static function sharing_module_running(): bool { |
| 49 | return self::legacy_sharing_supported() && self::module_active( 'sharedaddy' ); |
| 50 | } |
| 51 | |
| 52 | /** |
| 53 | * Whether every sharing service has been removed, so sharedaddy renders nothing. |
| 54 | * |
| 55 | * An absent option is not that: `Sharing_Service::get_blog_services()` falls |
| 56 | * back to its default services when the option was never saved. |
| 57 | */ |
| 58 | public static function legacy_sharing_switched_off(): bool { |
| 59 | $services = get_option( 'sharing-services' ); |
| 60 | |
| 61 | if ( ! is_array( $services ) ) { |
| 62 | return false; |
| 63 | } |
| 64 | |
| 65 | return empty( $services['visible'] ) && empty( $services['hidden'] ); |
| 66 | } |
| 67 | |
| 68 | /** |
| 69 | * Whether this site can have legacy sharing buttons at all. |
| 70 | * |
| 71 | * The module needs no connection, but `Jetpack::load_modules()` includes |
| 72 | * nothing on a site that is neither connected nor in offline mode, and |
| 73 | * `Modules::activate()` refuses there too: an active module renders no |
| 74 | * buttons, and offering to turn it on would do nothing. Simple loads |
| 75 | * sharedaddy from `post-flair.php` without either. |
| 76 | */ |
| 77 | public static function legacy_sharing_supported(): bool { |
| 78 | return self::is_simple_site() || self::is_connected() || self::is_offline_mode(); |
| 79 | } |
| 80 | |
| 81 | /** |
| 82 | * Whether Settings > Sharing has anything to offer this site. |
| 83 | * |
| 84 | * Neither the legacy features nor their blocks load on a site that is neither |
| 85 | * connected nor in offline mode. Checking sharing alone is enough: any site |
| 86 | * that can have Like buttons (connected, or Simple) passes that check too. |
| 87 | */ |
| 88 | public static function settings_screen_supported(): bool { |
| 89 | return self::legacy_sharing_supported(); |
| 90 | } |
| 91 | |
| 92 | /** |
| 93 | * Whether Jetpack's blocks load on this site, as `Jetpack_Gutenberg::should_load()` decides: |
| 94 | * a ready connection or offline mode, then the Blocks module, which its `jetpack_gutenberg` filter can override. |
| 95 | * |
| 96 | * True on Simple without asking for modules or a connection, both of which it lacks. |
| 97 | */ |
| 98 | public static function jetpack_blocks_load(): bool { |
| 99 | if ( ! self::is_simple_site() && ! self::is_connection_ready() && ! self::is_offline_mode() ) { |
| 100 | return false; |
| 101 | } |
| 102 | |
| 103 | /** This filter is documented in projects/plugins/jetpack/class.jetpack-gutenberg.php */ |
| 104 | return (bool) apply_filters( 'jetpack_gutenberg', self::module_active( 'blocks' ) ); |
| 105 | } |
| 106 | |
| 107 | /** |
| 108 | * Whether this site can have Like buttons at all. |
| 109 | * |
| 110 | * The Likes module declares `Requires Connection: Yes`, so without a |
| 111 | * WordPress.com connection it cannot be activated and its buttons cannot |
| 112 | * render: the widget is keyed on the blog ID a connection provides. |
| 113 | * Offline mode keeps a connected site's tokens, but `Jetpack::load_modules()` |
| 114 | * skips every module that requires a connection until it ends. |
| 115 | */ |
| 116 | public static function likes_supported(): bool { |
| 117 | return self::is_simple_site() || ( self::is_connected() && ! self::is_offline_mode() ); |
| 118 | } |
| 119 | |
| 120 | /** |
| 121 | * Whether the site holds a WordPress.com connection. |
| 122 | */ |
| 123 | private static function is_connected(): bool { |
| 124 | return ( new Connection_Manager( 'jetpack' ) )->is_connected(); |
| 125 | } |
| 126 | |
| 127 | /** |
| 128 | * Whether the connection is ready for Jetpack's modules and blocks, as `Jetpack::is_connection_ready()` decides. |
| 129 | * |
| 130 | * WordPress.com's Atomic hosting filters it off on a site whose connection has no owner. |
| 131 | */ |
| 132 | private static function is_connection_ready(): bool { |
| 133 | $manager = new Connection_Manager( 'jetpack' ); |
| 134 | |
| 135 | /** This filter is documented in projects/plugins/jetpack/class.jetpack.php */ |
| 136 | return (bool) apply_filters( 'jetpack_is_connection_ready', $manager->is_connected(), $manager ); |
| 137 | } |
| 138 | |
| 139 | /** |
| 140 | * Whether the site is in offline mode, where it cannot connect to WordPress.com either. |
| 141 | */ |
| 142 | public static function is_offline_mode(): bool { |
| 143 | return ( new Status() )->is_offline_mode(); |
| 144 | } |
| 145 | |
| 146 | /** |
| 147 | * Whether Like buttons can still produce output. |
| 148 | * |
| 149 | * The module can be left active in the options through a disconnect, |
| 150 | * which is why support is checked too. |
| 151 | */ |
| 152 | public static function likes_module_running(): bool { |
| 153 | return self::likes_supported() && self::module_active( 'likes' ); |
| 154 | } |
| 155 | |
| 156 | /** |
| 157 | * Whether Simple's posts show neither a Like nor a Reblog button, bar those that opted in individually. |
| 158 | * |
| 159 | * Both count because the legacy widget renders for either. Jetpack and Atomic never |
| 160 | * render Reblog, and switch to the block by turning the module off instead. |
| 161 | */ |
| 162 | public static function legacy_likes_switched_off(): bool { |
| 163 | return self::is_simple_site() |
| 164 | && ! Likes_Options::likes_enabled_sitewide() |
| 165 | && ! Likes_Options::reblogs_enabled_sitewide(); |
| 166 | } |
| 167 | |
| 168 | /** |
| 169 | * Whether comments can still be liked. |
| 170 | * |
| 171 | * Comment Likes is its own module, but it reads the Likes settings: both |
| 172 | * `disabled_likes` and the shared placement gate `is_likes_visible()`. So a |
| 173 | * site running it without the Likes module still needs those controls. |
| 174 | */ |
| 175 | public static function comment_likes_module_running(): bool { |
| 176 | return self::likes_supported() && self::module_active( 'comment-likes' ); |
| 177 | } |
| 178 | |
| 179 | /** |
| 180 | * Whether Comment Likes are switched on for this site. |
| 181 | * |
| 182 | * - On WordPress.com Simple, which has no modules: the `jetpack_comment_likes_enabled` option. |
| 183 | * - On Atomic and self-hosted Jetpack sites: the Comment Likes module, which never reads that option. |
| 184 | */ |
| 185 | public static function comment_likes_enabled(): bool { |
| 186 | return self::is_simple_site() ? Likes_Options::comment_likes_enabled() : self::comment_likes_module_running(); |
| 187 | } |
| 188 | |
| 189 | /** |
| 190 | * Whether Comment Likes read the Likes settings: the sitewide default and placement. Simple's do not. |
| 191 | */ |
| 192 | public static function comment_likes_follow_likes_settings(): bool { |
| 193 | return ! self::is_simple_site() && self::comment_likes_module_running(); |
| 194 | } |
| 195 | |
| 196 | /** |
| 197 | * Whether anything on this site still reads the Likes settings. |
| 198 | * |
| 199 | * Both features are gated on `disabled_likes` and the shared placement, so |
| 200 | * either one running makes the Likes placement defaults the ones that apply. |
| 201 | */ |
| 202 | public static function likes_settings_in_use(): bool { |
| 203 | return self::likes_module_running() || self::comment_likes_module_running(); |
| 204 | } |
| 205 | |
| 206 | /** |
| 207 | * Whether anything on this site reads the Twitter Site Tag option. |
| 208 | * |
| 209 | * Twitter Cards read it, and through them the Sharing Buttons block's X `via`. |
| 210 | * Simple's Twitter Cards read `twitter_via`, which wpcom serves and saves this option from. |
| 211 | */ |
| 212 | public static function twitter_site_tag_used(): bool { |
| 213 | /** This filter is documented in projects/plugins/jetpack/class.jetpack.php */ |
| 214 | return ! apply_filters( 'jetpack_disable_twitter_cards', false ); |
| 215 | } |
| 216 | |
| 217 | /** |
| 218 | * Whether a module is active. |
| 219 | * |
| 220 | * Simple has no modules: wpcom loads both features on every request, so |
| 221 | * every module counts as active there whatever the option holds. |
| 222 | * |
| 223 | * @param string $slug Module slug. |
| 224 | */ |
| 225 | private static function module_active( string $slug ): bool { |
| 226 | return self::is_simple_site() || ( new Modules() )->is_active( $slug ); |
| 227 | } |
| 228 | |
| 229 | /** |
| 230 | * Whether the Sharing Buttons block is available to offer as an alternative. |
| 231 | */ |
| 232 | public static function sharing_block_registered(): bool { |
| 233 | return self::block_is_registered( Block_Names::SHARING_BUTTONS ); |
| 234 | } |
| 235 | |
| 236 | /** |
| 237 | * Whether the Like block is available to offer as an alternative. |
| 238 | */ |
| 239 | public static function like_block_registered(): bool { |
| 240 | return self::block_is_registered( Block_Names::LIKE ); |
| 241 | } |
| 242 | |
| 243 | /** |
| 244 | * Site Editor URL for the active theme's single post template. |
| 245 | * |
| 246 | * Empty when the theme has no `single` template, which callers treat as |
| 247 | * "offer no Site Editor link" rather than linking somewhere that 404s: a |
| 248 | * block theme shipping only `index.html` is the case that hits this. |
| 249 | */ |
| 250 | public static function single_template_editor_url(): string { |
| 251 | if ( null !== self::$single_template_editor_url ) { |
| 252 | return self::$single_template_editor_url; |
| 253 | } |
| 254 | |
| 255 | $stylesheet = get_stylesheet(); |
| 256 | $template = $stylesheet ? $stylesheet . '//single' : ''; |
| 257 | |
| 258 | if ( ! $template || ! get_block_template( $template ) ) { |
| 259 | self::$single_template_editor_url = ''; |
| 260 | |
| 261 | return self::$single_template_editor_url; |
| 262 | } |
| 263 | |
| 264 | // `add_query_arg()` does not encode, and the Site Editor router wants `p` percent-encoded. |
| 265 | self::$single_template_editor_url = admin_url( |
| 266 | 'site-editor.php?p=' . rawurlencode( '/wp_template/' . $template ) . '&canvas=edit' |
| 267 | ); |
| 268 | |
| 269 | return self::$single_template_editor_url; |
| 270 | } |
| 271 | |
| 272 | /** |
| 273 | * Whether a block is registered, and so available to add to a template. |
| 274 | * |
| 275 | * Registration happens on `init`, well before this screen renders. |
| 276 | * |
| 277 | * @param string $name Fully qualified block name. |
| 278 | */ |
| 279 | private static function block_is_registered( string $name ): bool { |
| 280 | return \WP_Block_Type_Registry::get_instance()->is_registered( $name ); |
| 281 | } |
| 282 | } |