Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
21.99% |
64 / 291 |
|
27.59% |
8 / 29 |
CRAP | |
0.00% |
0 / 1 |
| Admin_UI | |
21.99% |
64 / 291 |
|
27.59% |
8 / 29 |
2008.28 | |
0.00% |
0 / 1 |
| init | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
| maybe_load_wp_build | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
20 | |||
| get_dashboard_render_callback | |
66.67% |
2 / 3 |
|
0.00% |
0 / 1 |
3.33 | |||
| enable_menu | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
| enable_dashboard_menu | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
1 | |||
| init_inactive_menu | |
66.67% |
2 / 3 |
|
0.00% |
0 / 1 |
2.15 | |||
| enable_inactive_menu | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
4 | |||
| add_wp_admin_submenu | |
15.38% |
2 / 13 |
|
0.00% |
0 / 1 |
8.45 | |||
| get_admin_page_url | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| get_allowed_video_extensions | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
1 | |||
| admin_init | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| plugin_settings_page | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| remove_jetpack_hooks | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
| can_use_analytics | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| enqueue_admin_scripts | |
0.00% |
0 / 30 |
|
0.00% |
0 / 1 |
56 | |||
| render_initial_state | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| initial_state | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
12 | |||
| edit_video_link | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
42 | |||
| get_logo_svg | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| attachment_details_two_column_template | |
0.00% |
0 / 46 |
|
0.00% |
0 / 1 |
2 | |||
| attachment_details_template | |
0.00% |
0 / 52 |
|
0.00% |
0 / 1 |
2 | |||
| attachment_info_template_part | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
| load_wp_build | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
6 | |||
| maybe_strip_chapters_editor_routes | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
4 | |||
| strip_chapters_editor_routes | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
2 | |||
| alias_screen_id_for_wp_build | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| is_modernized | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| is_chapters_editor_enabled | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| is_videopress_admin_request | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * The initializer class for Admin UI elements |
| 4 | * |
| 5 | * @package automattic/jetpack-videopress |
| 6 | */ |
| 7 | |
| 8 | namespace Automattic\Jetpack\VideoPress; |
| 9 | |
| 10 | use Automattic\Jetpack\Admin_UI\Admin_Menu; |
| 11 | use Automattic\Jetpack\Assets; |
| 12 | use Automattic\Jetpack\Connection\Initial_State as Connection_Initial_State; |
| 13 | use Automattic\Jetpack\Connection\Manager as Connection_Manager; |
| 14 | use Automattic\Jetpack\Current_Plan; |
| 15 | use Automattic\Jetpack\My_Jetpack\Initializer as My_Jetpack_Initializer; |
| 16 | use Automattic\Jetpack\My_Jetpack\Products as My_Jetpack_Products; |
| 17 | use Automattic\Jetpack\Status; |
| 18 | use Automattic\Jetpack\Status\Host; |
| 19 | use Automattic\Jetpack\Terms_Of_Service; |
| 20 | use Automattic\Jetpack\Tracking; |
| 21 | use Automattic\Jetpack\VideoPress\Status as VideoPress_Status; |
| 22 | |
| 23 | /** |
| 24 | * Initialized the VideoPress package |
| 25 | */ |
| 26 | class Admin_UI { |
| 27 | |
| 28 | const JETPACK_VIDEOPRESS_PKG_NAMESPACE = 'jetpack-videopress-pkg'; |
| 29 | |
| 30 | const ADMIN_PAGE_SLUG = 'jetpack-videopress'; |
| 31 | |
| 32 | /** |
| 33 | * The My Jetpack interstitial where VideoPress can be activated, relative to wp-admin. |
| 34 | * |
| 35 | * Used as the target of the "Jetpack > VideoPress" menu item when VideoPress |
| 36 | * is not active. |
| 37 | */ |
| 38 | const MY_JETPACK_ADD_VIDEOPRESS_URI = 'admin.php?page=my-jetpack#/add-videopress'; |
| 39 | |
| 40 | /** |
| 41 | * Filter name that gates the wp-build–based dashboard. |
| 42 | * |
| 43 | * When this filter returns true, "Jetpack > VideoPress" renders the new |
| 44 | * wp-build dashboard instead of the legacy React app. |
| 45 | */ |
| 46 | const MODERNIZATION_FILTER = 'rsm_jetpack_ui_modernization_videopress'; |
| 47 | |
| 48 | /** |
| 49 | * Filter name that gates the chapters editor. |
| 50 | * |
| 51 | * The chapters editor is generally available, so this defaults to true and |
| 52 | * the filter serves as a kill switch: returning false withdraws it from both |
| 53 | * places it lives — the dashboard's Editor tab (and the `/video/$id/editor` |
| 54 | * route behind it) and the block editor's chapter manager modal. |
| 55 | */ |
| 56 | const CHAPTERS_EDITOR_FILTER = 'jetpack_videopress_chapters_editor'; |
| 57 | |
| 58 | /** |
| 59 | * Route paths that belong to the chapters editor. |
| 60 | * |
| 61 | * Kept in sync with the wp-build route registry (`build/routes/registry.php`); |
| 62 | * entries with these paths are stripped from the registry when the chapters |
| 63 | * editor filter is off, so the routes never register. |
| 64 | */ |
| 65 | const CHAPTERS_EDITOR_ROUTE_PATHS = array( '/video/$id/editor' ); |
| 66 | |
| 67 | /** |
| 68 | * Initializes the Admin UI of VideoPress |
| 69 | * |
| 70 | * This method is called only once by the Initializer class |
| 71 | * |
| 72 | * @return void |
| 73 | */ |
| 74 | public static function init() { |
| 75 | |
| 76 | // Load the wp-build dashboard assets on the VideoPress admin page, on every |
| 77 | // host. Registered before enable_menu() below — both hook admin_menu:1, and |
| 78 | // same-priority callbacks fire in registration order — so the render function |
| 79 | // and SCRIPT_HANDLE exist by the time the menu callback is selected: on |
| 80 | // standalone/Atomic by enable_menu(), on wpcom Simple by add_wp_admin_submenu() |
| 81 | // (wpcom-admin-menu.php, admin_menu:999999). maybe_load_wp_build() self-gates |
| 82 | // to the VideoPress admin request, so it's inert on every other page. |
| 83 | add_action( 'admin_menu', array( __CLASS__, 'maybe_load_wp_build' ), 1 ); |
| 84 | |
| 85 | // On WordPress.com Simple the standalone menu system (Admin_Menu) is not used: |
| 86 | // the Jetpack parent menu is created late (admin_menu priority 999999) by |
| 87 | // wpcom-admin-menu.php, which registers the VideoPress submenu directly via |
| 88 | // Admin_UI::add_wp_admin_submenu(). So on Simple we skip enable_menu() and the |
| 89 | // Jetpack/Atomic media-library hooks below — the media hooks are Phase 3 media |
| 90 | // parity, out of scope for menu + boot, and would patch a media library wpcom |
| 91 | // owns (their VideoPress branches are inert on Simple anyway: videos keep their |
| 92 | // original mime, never video/videopress). |
| 93 | if ( ( new Host() )->is_wpcom_simple() ) { |
| 94 | return; |
| 95 | } |
| 96 | |
| 97 | add_action( 'admin_menu', array( __CLASS__, 'enable_menu' ), 1 ); // Akismet uses 4, so we use 1 to ensure both menus are added when only they exist. |
| 98 | |
| 99 | add_action( 'admin_footer-upload.php', array( __CLASS__, 'attachment_details_two_column_template' ) ); |
| 100 | add_action( 'admin_footer-post.php', array( __CLASS__, 'attachment_details_template' ), 20 ); |
| 101 | |
| 102 | add_filter( 'get_edit_post_link', array( __CLASS__, 'edit_video_link' ), 10, 3 ); |
| 103 | |
| 104 | add_action( 'admin_init', array( __CLASS__, 'remove_jetpack_hooks' ) ); |
| 105 | } |
| 106 | |
| 107 | /** |
| 108 | * Load the wp-build dashboard assets when modernization is enabled and the current |
| 109 | * request targets the VideoPress admin page. |
| 110 | * |
| 111 | * The single wp-build load path on every host, hooked at admin_menu:1 from init(). |
| 112 | * Requiring build.php here defines the render function that enable_menu() / |
| 113 | * add_wp_admin_submenu() select later in the same hook, and registers the |
| 114 | * SCRIPT_HANDLE that Initial_State::enqueue() hydrates from. |
| 115 | * |
| 116 | * @return void |
| 117 | */ |
| 118 | public static function maybe_load_wp_build() { |
| 119 | if ( ! self::is_modernized() || ! self::is_videopress_admin_request() ) { |
| 120 | return; |
| 121 | } |
| 122 | |
| 123 | self::load_wp_build(); |
| 124 | |
| 125 | // wp-build registers standalone modules (e.g. the init module) on |
| 126 | // wp_default_scripts, which has already fired by admin_menu. Register them |
| 127 | // directly so the init module makes it into the import map. |
| 128 | if ( function_exists( 'jetpack_videopress_register_script_modules' ) ) { |
| 129 | jetpack_videopress_register_script_modules(); // @phan-suppress-current-line PhanUndeclaredFunction -- Checked with function_exists(); defined in the generated build/modules.php, which Phan excludes. |
| 130 | } |
| 131 | |
| 132 | add_action( 'current_screen', array( __CLASS__, 'alias_screen_id_for_wp_build' ) ); |
| 133 | } |
| 134 | |
| 135 | /** |
| 136 | * Select the dashboard render callback: the modernized wp-build render function |
| 137 | * when modernization is on and it's available (loaded by maybe_load_wp_build()), |
| 138 | * otherwise the legacy React root. Shared by enable_menu() (standalone/Atomic) |
| 139 | * and add_wp_admin_submenu() (wpcom Simple). |
| 140 | * |
| 141 | * @return string|array Callback for Admin_Menu::add_menu()/add_submenu_page(). |
| 142 | */ |
| 143 | private static function get_dashboard_render_callback() { |
| 144 | return self::is_modernized() && function_exists( 'jetpack_videopress_jetpack_videopress_dashboard_wp_admin_render_page' ) |
| 145 | ? 'jetpack_videopress_jetpack_videopress_dashboard_wp_admin_render_page' |
| 146 | : array( __CLASS__, 'plugin_settings_page' ); |
| 147 | } |
| 148 | |
| 149 | /** |
| 150 | * Register the "Jetpack > VideoPress" menu item, choosing its target dynamically. |
| 151 | * |
| 152 | * Hooked on admin_menu from both init() and init_inactive_menu(), so the item |
| 153 | * reflects the module state when the menu renders rather than when the package |
| 154 | * initialized: when VideoPress is active it opens the VideoPress library |
| 155 | * (admin.php?page=jetpack-videopress); when it is not, it links to the |
| 156 | * My Jetpack interstitial where VideoPress can be activated. |
| 157 | * |
| 158 | * Registered separately to init due to translations needing to run early for |
| 159 | * the page suffix. |
| 160 | * |
| 161 | * @return void |
| 162 | */ |
| 163 | public static function enable_menu() { |
| 164 | if ( VideoPress_Status::is_active() ) { |
| 165 | self::enable_dashboard_menu(); |
| 166 | return; |
| 167 | } |
| 168 | |
| 169 | self::enable_inactive_menu(); |
| 170 | } |
| 171 | |
| 172 | /** |
| 173 | * Register the VideoPress library dashboard page and its menu item. |
| 174 | * |
| 175 | * @return void |
| 176 | */ |
| 177 | private static function enable_dashboard_menu() { |
| 178 | $callback = self::get_dashboard_render_callback(); |
| 179 | |
| 180 | $page_suffix = Admin_Menu::add_menu( |
| 181 | // "VideoPress" is a product name, do not translate. |
| 182 | 'Jetpack VideoPress', |
| 183 | 'VideoPress', |
| 184 | 'manage_options', |
| 185 | self::ADMIN_PAGE_SLUG, |
| 186 | $callback, |
| 187 | 3 |
| 188 | ); |
| 189 | add_action( 'load-' . $page_suffix, array( __CLASS__, 'admin_init' ) ); |
| 190 | } |
| 191 | |
| 192 | /** |
| 193 | * Initializes the "Jetpack > VideoPress" menu item when VideoPress is not active. |
| 194 | * |
| 195 | * This method is called by the Initializer class instead of init() when the |
| 196 | * VideoPress module is not active. It hooks the same enable_menu() callback as |
| 197 | * init(), which picks the item's target from the module state at admin_menu |
| 198 | * time — so if the state changed since package initialization, the rendered |
| 199 | * link is still correct. |
| 200 | * |
| 201 | * @return void |
| 202 | */ |
| 203 | public static function init_inactive_menu() { |
| 204 | // On WordPress.com Simple the standalone menu system (Admin_Menu) is not used; |
| 205 | // the Jetpack menu is fully managed by wpcom-admin-menu.php. See init(). |
| 206 | if ( ( new Host() )->is_wpcom_simple() ) { |
| 207 | return; |
| 208 | } |
| 209 | |
| 210 | add_action( 'admin_menu', array( __CLASS__, 'enable_menu' ), 1 ); |
| 211 | } |
| 212 | |
| 213 | /** |
| 214 | * Register the inactive-state menu item: a direct link to the My Jetpack |
| 215 | * "add VideoPress" interstitial. |
| 216 | * |
| 217 | * A slug that is not a registered page makes WordPress render the item as a |
| 218 | * plain link to that URI (same mechanism as the "Upgrade Jetpack" menu item). |
| 219 | * |
| 220 | * @return void |
| 221 | */ |
| 222 | public static function enable_inactive_menu() { |
| 223 | // Activating VideoPress from My Jetpack requires a connected user, so only |
| 224 | // offer the item to users with their own Jetpack connection. Checked here, |
| 225 | // at admin_menu time, so the item starts rendering as soon as the current |
| 226 | // user connects. |
| 227 | $connection = new Connection_Manager(); |
| 228 | if ( ! $connection->is_connected() || ! $connection->is_user_connected() ) { |
| 229 | return; |
| 230 | } |
| 231 | |
| 232 | // The link targets My Jetpack; don't render a dead link when that page |
| 233 | // is not registered (e.g. offline mode). |
| 234 | if ( ! My_Jetpack_Initializer::should_initialize() ) { |
| 235 | return; |
| 236 | } |
| 237 | |
| 238 | Admin_Menu::add_menu( |
| 239 | // "VideoPress" is a product name, do not translate. |
| 240 | 'Jetpack VideoPress', |
| 241 | 'VideoPress', |
| 242 | 'manage_options', |
| 243 | self::MY_JETPACK_ADD_VIDEOPRESS_URI, |
| 244 | null, |
| 245 | 3 |
| 246 | ); |
| 247 | } |
| 248 | |
| 249 | /** |
| 250 | * Add the VideoPress submenu directly under the Jetpack menu on wpcom Simple. |
| 251 | * |
| 252 | * Called from wpcom-admin-menu.php at a late priority (999999), once the Jetpack |
| 253 | * parent menu exists. On Simple enable_menu() is skipped (see init()), so this is |
| 254 | * the only place the submenu is registered there. The callback mirrors enable_menu(): |
| 255 | * the wp-build render function when modernized and available (loaded by |
| 256 | * maybe_load_wp_build() at admin_menu:1, which runs first), otherwise the legacy root. |
| 257 | * |
| 258 | * @return void |
| 259 | */ |
| 260 | public static function add_wp_admin_submenu() { |
| 261 | // Unlike standalone/Atomic, Simple has no working fallback: the legacy |
| 262 | // React dashboard's data layer rides videopress/v1, which never reaches |
| 263 | // the REST dispatcher there. With modernization off (e.g. a site outside |
| 264 | // the staged rollout), register no menu rather than a dead page. The |
| 265 | // function_exists half of the callback selection can't gate this — the |
| 266 | // wp-build render function is only loaded on the VideoPress page itself, |
| 267 | // and the menu must register on every admin page. |
| 268 | if ( ! self::is_modernized() ) { |
| 269 | return; |
| 270 | } |
| 271 | |
| 272 | $callback = self::get_dashboard_render_callback(); |
| 273 | |
| 274 | $page_suffix = add_submenu_page( |
| 275 | 'jetpack', |
| 276 | // "VideoPress" is a product name, do not translate. |
| 277 | 'Jetpack VideoPress', |
| 278 | 'VideoPress', |
| 279 | 'manage_options', |
| 280 | self::ADMIN_PAGE_SLUG, |
| 281 | $callback |
| 282 | ); |
| 283 | |
| 284 | if ( $page_suffix ) { |
| 285 | add_action( 'load-' . $page_suffix, array( __CLASS__, 'admin_init' ) ); |
| 286 | } |
| 287 | } |
| 288 | |
| 289 | /** |
| 290 | * Gets the URL for the VideoPress admin page |
| 291 | * |
| 292 | * @return string |
| 293 | */ |
| 294 | public static function get_admin_page_url() { |
| 295 | return admin_url( 'admin.php?page=' . self::ADMIN_PAGE_SLUG ); |
| 296 | } |
| 297 | |
| 298 | /** |
| 299 | * Gets the list of allowed video extensions |
| 300 | * |
| 301 | * @return array |
| 302 | */ |
| 303 | public static function get_allowed_video_extensions() { |
| 304 | return array( |
| 305 | '3g2' => 'video/3gpp2', |
| 306 | '3gp' => 'video/3gpp', |
| 307 | '3gp2' => 'video/3gpp2', |
| 308 | '3gpp' => 'video/3gpp', |
| 309 | 'avi' => 'video/avi', |
| 310 | 'm4v' => 'video/mp4', |
| 311 | 'mov' => 'video/quicktime', |
| 312 | 'mp4' => 'video/mp4', |
| 313 | 'mpe' => 'video/mpeg', |
| 314 | 'mpeg' => 'video/mpeg', |
| 315 | 'mpg' => 'video/mpeg', |
| 316 | 'ogv' => 'video/ogg', |
| 317 | 'wmv' => 'video/x-ms-wmv', |
| 318 | ); |
| 319 | } |
| 320 | |
| 321 | /** |
| 322 | * Initialize the admin resources. |
| 323 | */ |
| 324 | public static function admin_init() { |
| 325 | add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_admin_scripts' ) ); |
| 326 | } |
| 327 | |
| 328 | /** |
| 329 | * Main plugin settings page. |
| 330 | */ |
| 331 | public static function plugin_settings_page() { |
| 332 | ?> |
| 333 | <div id="jetpack-videopress-root"></div> |
| 334 | <?php |
| 335 | } |
| 336 | |
| 337 | /** |
| 338 | * Remove extra fields from Attachment details modal |
| 339 | * |
| 340 | * @return void |
| 341 | */ |
| 342 | public static function remove_jetpack_hooks() { |
| 343 | if ( class_exists( '\VideoPress_Edit_Attachment' ) ) { |
| 344 | $edit_attachment = \VideoPress_Edit_Attachment::init(); |
| 345 | remove_filter( 'attachment_fields_to_edit', array( $edit_attachment, 'fields_to_edit' ) ); |
| 346 | remove_filter( 'attachment_fields_to_save', array( $edit_attachment, 'save_fields' ) ); |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | /** |
| 351 | * Returns whether we are in condition to track to use |
| 352 | * Analytics functionality like Tracks, MC, or GA. |
| 353 | */ |
| 354 | public static function can_use_analytics() { |
| 355 | $status = new Status(); |
| 356 | $connection = new Connection_Manager(); |
| 357 | $tracking = new Tracking( 'jetpack', $connection ); |
| 358 | |
| 359 | return $tracking->should_enable_tracking( new Terms_Of_Service(), $status ); |
| 360 | } |
| 361 | |
| 362 | /** |
| 363 | * Enqueue plugin admin scripts and styles. |
| 364 | */ |
| 365 | public static function enqueue_admin_scripts() { |
| 366 | // This callback is registered via `load-{$page_suffix}` in `enable_menu()`, |
| 367 | // so it only fires on the VideoPress admin page — no need to re-check the page here. |
| 368 | if ( self::is_modernized() ) { |
| 369 | // Page-level shell stylesheet: scopes the shared `jetpack-admin-page-layout` |
| 370 | // mixin to the dashboard body so every route inherits the proper |
| 371 | // scrollable chrome (fixed `#wpbody-content`, scrollable middle, pinned |
| 372 | // footer) regardless of whether it uses DashboardLayout. Without this, |
| 373 | // non-tabbed routes (e.g. Video details) would only get the layout |
| 374 | // after a sibling route's chunk happened to inject the same CSS. |
| 375 | // Pick the flipped build ourselves on RTL locales rather than leaning on |
| 376 | // `wp_style_add_data( …, 'rtl', 'replace' )`: core resolves that by |
| 377 | // rewriting `index.css` to `index-rtl.css` (hyphenated) *and* dropping |
| 378 | // the LTR tag, but webpack emits the flipped file as `index.rtl.css` |
| 379 | // (dotted, the same convention `Assets::register_script()`'s `css_path` |
| 380 | // follows). The hyphenated file never exists, so RTL sites used to load |
| 381 | // no shell stylesheet at all — the layout flex chain never formed and |
| 382 | // the dashboard rendered as a blank page. |
| 383 | $shell_dir = dirname( __DIR__ ) . '/build/dashboard-shell/'; |
| 384 | $shell_file = is_rtl() && file_exists( $shell_dir . 'index.rtl.css' ) ? 'index.rtl.css' : 'index.css'; |
| 385 | if ( file_exists( $shell_dir . $shell_file ) ) { |
| 386 | wp_register_style( |
| 387 | 'jetpack-videopress-dashboard-shell', |
| 388 | plugins_url( 'build/dashboard-shell/' . $shell_file, __DIR__ ), |
| 389 | array(), |
| 390 | (string) filemtime( $shell_dir . $shell_file ) |
| 391 | ); |
| 392 | wp_enqueue_style( 'jetpack-videopress-dashboard-shell' ); |
| 393 | } |
| 394 | |
| 395 | // The Video details screen's thumbnail editor opens the WordPress |
| 396 | // media library (via window.wp.media) for the "Upload image" |
| 397 | // action, so the media scripts must be present here too. |
| 398 | wp_enqueue_media(); |
| 399 | |
| 400 | // The i18n loader is registered on every admin page by jetpack-assets but |
| 401 | // only enqueued when depended on; the esbuild bundles don't pull it in. |
| 402 | if ( wp_script_is( 'wp-jp-i18n-loader', 'registered' ) ) { |
| 403 | wp_enqueue_script( 'wp-jp-i18n-loader' ); |
| 404 | } |
| 405 | |
| 406 | // Beyond the shell stylesheet and the media library, wp-build |
| 407 | // manages its own enqueue pipeline. The legacy script, initial |
| 408 | // state, and tracking are all intentionally skipped for the |
| 409 | // wp-build dashboard. |
| 410 | return; |
| 411 | } |
| 412 | |
| 413 | Assets::register_script( |
| 414 | self::JETPACK_VIDEOPRESS_PKG_NAMESPACE, |
| 415 | '../build/admin/index.js', |
| 416 | __FILE__, |
| 417 | array( |
| 418 | 'in_footer' => true, |
| 419 | 'textdomain' => 'jetpack-videopress-pkg', |
| 420 | ) |
| 421 | ); |
| 422 | Assets::enqueue_script( self::JETPACK_VIDEOPRESS_PKG_NAMESPACE ); |
| 423 | |
| 424 | // Required for Media Library access |
| 425 | wp_enqueue_media(); |
| 426 | |
| 427 | // Required for Analytics. |
| 428 | if ( self::can_use_analytics() ) { |
| 429 | Tracking::register_tracks_functions_scripts( true ); |
| 430 | } |
| 431 | |
| 432 | // Initial JS state including JP Connection data. |
| 433 | Connection_Initial_State::render_script( self::JETPACK_VIDEOPRESS_PKG_NAMESPACE ); |
| 434 | wp_add_inline_script( self::JETPACK_VIDEOPRESS_PKG_NAMESPACE, self::render_initial_state(), 'before' ); |
| 435 | } |
| 436 | |
| 437 | /** |
| 438 | * Render the initial state into a JavaScript variable. |
| 439 | * |
| 440 | * @return string |
| 441 | */ |
| 442 | public static function render_initial_state() { |
| 443 | return 'var jetpackVideoPressInitialState=' . wp_json_encode( self::initial_state(), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ) . ';'; |
| 444 | } |
| 445 | |
| 446 | /** |
| 447 | * Get the initial state data for hydrating the React UI. |
| 448 | * |
| 449 | * @return array |
| 450 | */ |
| 451 | public static function initial_state() { |
| 452 | return array( |
| 453 | 'apiRoot' => esc_url_raw( rest_url() ), |
| 454 | 'apiNonce' => wp_create_nonce( 'wp_rest' ), |
| 455 | 'registrationNonce' => wp_create_nonce( 'jetpack-registration-nonce' ), |
| 456 | 'adminUrl' => self::get_admin_page_url(), |
| 457 | 'adminUri' => 'admin.php?page=' . self::ADMIN_PAGE_SLUG, |
| 458 | 'paidFeatures' => array( |
| 459 | 'isVideoPressSupported' => Current_Plan::supports( 'videopress' ), |
| 460 | // Check videopress-1tb-storage (Jetpack) or videopress (WordPress.com). |
| 461 | 'isVideoPress1TBSupported' => Current_Plan::supports( 'videopress-1tb-storage' ) |
| 462 | || ( ( new Host() )->is_wpcom_platform() && wpcom_site_has_feature( 'videopress' ) ), |
| 463 | 'isVideoPressUnlimitedSupported' => Current_Plan::supports( 'videopress-unlimited-storage' ), |
| 464 | ), |
| 465 | 'siteSuffix' => ( new Status() )->get_site_suffix(), |
| 466 | 'productData' => Plan::get_product(), |
| 467 | 'productPrice' => Plan::get_product_price(), |
| 468 | 'siteProductData' => My_Jetpack_Products::get_product( 'videopress' ), |
| 469 | 'allowedVideoExtensions' => self::get_allowed_video_extensions(), |
| 470 | 'initialState' => Data::get_initial_state(), |
| 471 | 'contentNonce' => wp_create_nonce( 'videopress-content-nonce' ), |
| 472 | ); |
| 473 | } |
| 474 | |
| 475 | /** |
| 476 | * Replaces the edit link for videopress videos |
| 477 | * |
| 478 | * @param string $link - the post link. |
| 479 | * @param int $post_id - the post ID. |
| 480 | * @param string $context - the context. |
| 481 | * |
| 482 | * @return string |
| 483 | */ |
| 484 | public static function edit_video_link( $link, $post_id, $context ) { |
| 485 | $post_id = (int) $post_id; |
| 486 | if ( ! $post_id ) { |
| 487 | return $link; |
| 488 | } |
| 489 | |
| 490 | $post = get_post( $post_id ); |
| 491 | if ( ! $post ) { |
| 492 | return $link; |
| 493 | } |
| 494 | |
| 495 | if ( 'attachment' !== $post->post_type || 'video/videopress' !== $post->post_mime_type ) { |
| 496 | return $link; |
| 497 | } |
| 498 | |
| 499 | $url = add_query_arg( 'p', sprintf( '/video/%d', $post_id ), self::get_admin_page_url() ); |
| 500 | |
| 501 | if ( 'display' === $context ) { |
| 502 | return esc_url( $url ); |
| 503 | } |
| 504 | |
| 505 | return esc_url_raw( $url ); |
| 506 | } |
| 507 | |
| 508 | /** |
| 509 | * Gets the SVG for the sub brand Jetpack VideoPress logo |
| 510 | * |
| 511 | * @return string |
| 512 | */ |
| 513 | protected static function get_logo_svg() { |
| 514 | return '<svg width="212" height="27" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M110.441 16.294c.479-1.458.995-2.93 1.547-4.414l2.545-6.87h1.687l-5.09 13.361h-1.427l-5.09-13.361h1.687l2.545 6.87a109.628 109.628 0 0 1 1.556 4.414h.04ZM117.919 18.371V8.884h1.547v9.487h-1.547Zm-.04-11.694V4.95h1.627v1.727h-1.627ZM123.331 13.728c0 .546.06 1.042.179 1.488.127.439.306.815.539 1.128.233.306.519.543.858.71.34.166.729.249 1.168.249.326 0 .622-.044.888-.13.266-.087.503-.196.709-.33a3.045 3.045 0 0 0 .898-.838V11.04a3.706 3.706 0 0 0-1.108-.779c-.419-.2-.871-.3-1.357-.3a2.83 2.83 0 0 0-.928.17 2.26 2.26 0 0 0-.898.59c-.273.286-.499.672-.679 1.158-.179.48-.269 1.095-.269 1.848Zm-1.617.02c0-.66.063-1.242.19-1.748.133-.513.306-.959.519-1.338.212-.38.462-.696.748-.949.286-.26.582-.47.888-.629.306-.16.616-.273.928-.34.32-.073.619-.11.898-.11.579 0 1.082.097 1.507.29.426.193.809.476 1.148.85h.03V3.91h1.547v14.46h-1.168l-.319-1.058h-.04c-.12.153-.26.31-.419.47-.16.152-.349.292-.569.419a2.83 2.83 0 0 1-.749.3 3.57 3.57 0 0 1-.978.119 4.63 4.63 0 0 1-1.526-.26 3.666 3.666 0 0 1-1.338-.849c-.386-.392-.698-.895-.938-1.507-.239-.62-.359-1.372-.359-2.257ZM136.626 9.963c-.352 0-.682.07-.988.21a2.57 2.57 0 0 0-.788.569c-.226.24-.409.522-.549.849-.14.32-.226.662-.259 1.028h4.79c0-.373-.05-.719-.15-1.038a2.474 2.474 0 0 0-.419-.85 1.935 1.935 0 0 0-.689-.559 2.046 2.046 0 0 0-.948-.21Zm.849 7.31c.512 0 .978-.04 1.397-.12a8.775 8.775 0 0 0 1.267-.36v1.289c-.339.166-.758.296-1.257.39-.499.1-1.035.149-1.607.149a6.871 6.871 0 0 1-1.916-.26 4.108 4.108 0 0 1-1.557-.838c-.446-.387-.798-.89-1.058-1.508-.253-.626-.379-1.379-.379-2.257 0-.866.12-1.615.359-2.247.24-.64.559-1.172.958-1.598.4-.426.859-.746 1.378-.959a4.238 4.238 0 0 1 1.626-.32c.532 0 1.028.09 1.487.27.466.173.868.45 1.208.83.339.379.605.868.798 1.467.2.6.299 1.318.299 2.157v.21c0 .053-.003.18-.009.38h-6.507c0 .605.09 1.121.269 1.547.187.42.436.763.749 1.029.319.26.692.45 1.117.57.426.119.885.179 1.378.179ZM149.623 13.638c0-.586-.074-1.105-.22-1.558a3.288 3.288 0 0 0-.599-1.159 2.421 2.421 0 0 0-.908-.718 2.674 2.674 0 0 0-1.157-.25c-.42 0-.806.083-1.158.25a2.5 2.5 0 0 0-.918.719c-.253.312-.453.699-.599 1.158-.14.453-.21.972-.21 1.558 0 .579.07 1.098.21 1.558.146.452.349.835.609 1.148.259.313.565.553.918.72.352.159.738.239 1.157.239.42 0 .802-.08 1.148-.24a2.56 2.56 0 0 0 .908-.719c.26-.313.459-.696.599-1.148.146-.46.22-.979.22-1.558Zm1.616 0a6.17 6.17 0 0 1-.319 2.037 4.617 4.617 0 0 1-.908 1.578 3.987 3.987 0 0 1-1.407 1.009c-.552.24-1.171.359-1.857.359-.705 0-1.337-.12-1.896-.36a4.09 4.09 0 0 1-1.417-1.008 4.562 4.562 0 0 1-.888-1.578 6.361 6.361 0 0 1-.309-2.037c0-.752.106-1.435.319-2.047a4.697 4.697 0 0 1 .898-1.578c.393-.44.865-.78 1.417-1.019a4.69 4.69 0 0 1 1.867-.36c.698 0 1.327.12 1.886.36.559.24 1.031.58 1.417 1.019.386.44.682.965.888 1.578.206.612.309 1.295.309 2.047ZM155.204 18.371h-1.627V5.01h3.703c.552 0 1.061.033 1.527.1.472.066.905.17 1.297.309.798.286 1.404.716 1.816 1.288.413.566.619 1.265.619 2.097 0 .68-.136 1.279-.409 1.798a3.473 3.473 0 0 1-1.168 1.288c-.512.346-1.137.61-1.876.79-.732.172-1.563.259-2.495.259-.446 0-.908-.02-1.387-.06v5.492Zm0-6.98a12.234 12.234 0 0 0 1.367.08c.765 0 1.417-.06 1.956-.18.539-.12.978-.293 1.318-.52.339-.232.585-.512.738-.838.153-.333.23-.71.23-1.129 0-.519-.127-.945-.38-1.278-.246-.333-.598-.586-1.057-.759a4.097 4.097 0 0 0-.988-.22 10.59 10.59 0 0 0-1.298-.07h-1.886v4.914ZM169.62 10.143h-.12c-.365 0-.725.033-1.077.1a4.45 4.45 0 0 0-.998.309c-.306.133-.586.3-.839.5a2.74 2.74 0 0 0-.618.708v6.611h-1.547V8.884h1.197l.3 1.508h.03c.153-.246.339-.476.559-.689.226-.213.479-.4.758-.56a3.72 3.72 0 0 1 .918-.369c.333-.093.682-.14 1.048-.14.067 0 .133.004.2.01.073 0 .136.004.189.01v1.489ZM174.673 9.963c-.353 0-.682.07-.988.21-.3.14-.562.33-.789.569-.226.24-.409.522-.549.849-.139.32-.226.662-.259 1.028h4.79c0-.373-.05-.719-.149-1.038a2.476 2.476 0 0 0-.42-.85 1.931 1.931 0 0 0-.688-.559 2.052 2.052 0 0 0-.948-.21Zm.848 7.31c.512 0 .978-.04 1.397-.12a8.824 8.824 0 0 0 1.268-.36v1.289c-.34.166-.759.296-1.258.39-.499.1-1.034.149-1.607.149a6.876 6.876 0 0 1-1.916-.26 4.108 4.108 0 0 1-1.557-.838c-.445-.387-.798-.89-1.057-1.508-.253-.626-.38-1.379-.38-2.257 0-.866.12-1.615.36-2.247.239-.64.559-1.172.958-1.598a3.9 3.9 0 0 1 1.377-.959 4.243 4.243 0 0 1 1.627-.32c.532 0 1.027.09 1.487.27.465.173.868.45 1.207.83.339.379.606.868.798 1.467.2.6.3 1.318.3 2.157v.21c0 .053-.003.18-.01.38h-6.507c0 .605.09 1.121.27 1.547.186.42.435.763.748 1.029.319.26.692.45 1.118.57.426.119.885.179 1.377.179ZM181.831 11.41c0 .26.056.473.17.64.113.166.262.303.449.41.193.1.412.182.658.25.253.066.513.126.779.179.366.08.712.17 1.038.27.326.093.625.236.898.429.279.193.502.456.668.789.173.326.26.752.26 1.278 0 .48-.093.906-.28 1.278a2.64 2.64 0 0 1-.788.929 3.66 3.66 0 0 1-1.217.56c-.473.132-.992.199-1.557.199-.346 0-.662-.02-.948-.06a5.2 5.2 0 0 1-.749-.14 4.56 4.56 0 0 1-.549-.17 3.646 3.646 0 0 1-.379-.17v-1.297c.399.16.795.286 1.188.379.392.093.825.14 1.297.14.373 0 .709-.034 1.008-.1.299-.067.555-.163.768-.29.22-.133.386-.296.499-.489.12-.2.18-.43.18-.69 0-.265-.053-.485-.16-.658a1.315 1.315 0 0 0-.429-.43 2.582 2.582 0 0 0-.629-.28 9.795 9.795 0 0 0-.738-.199c-.339-.073-.685-.16-1.038-.26-.346-.1-.662-.24-.948-.419a2.102 2.102 0 0 1-.699-.729c-.173-.313-.259-.712-.259-1.198 0-.5.09-.932.269-1.299.18-.366.423-.669.729-.908.306-.24.662-.42 1.068-.54.406-.12.835-.18 1.287-.18.526 0 1.011.05 1.457.15.453.1.862.227 1.228.38v1.318a8.85 8.85 0 0 0-1.218-.37 5.61 5.61 0 0 0-1.257-.16c-.366 0-.679.037-.938.11a1.78 1.78 0 0 0-.639.31c-.166.127-.289.28-.369.46a1.46 1.46 0 0 0-.11.579ZM189.787 11.41c0 .26.057.473.17.64.113.166.263.303.449.41.193.1.413.182.659.25.253.066.512.126.778.179.366.08.712.17 1.038.27.326.093.626.236.898.429.28.193.503.456.669.789.173.326.259.752.259 1.278 0 .48-.093.906-.279 1.278a2.64 2.64 0 0 1-.788.929c-.34.246-.746.433-1.218.56-.472.132-.991.199-1.557.199-.346 0-.662-.02-.948-.06a5.185 5.185 0 0 1-.748-.14 4.56 4.56 0 0 1-.549-.17 3.552 3.552 0 0 1-.379-.17v-1.297c.399.16.795.286 1.187.379.393.093.825.14 1.298.14.372 0 .708-.034 1.007-.1.3-.067.556-.163.769-.29.219-.133.386-.296.499-.489.12-.2.18-.43.18-.69 0-.265-.054-.485-.16-.658a1.334 1.334 0 0 0-.429-.43 2.6 2.6 0 0 0-.629-.28 9.925 9.925 0 0 0-.738-.199c-.34-.073-.686-.16-1.038-.26-.346-.1-.662-.24-.948-.419a2.102 2.102 0 0 1-.699-.729c-.173-.313-.259-.712-.259-1.198 0-.5.089-.932.269-1.299.18-.366.422-.669.729-.908a3.16 3.16 0 0 1 1.067-.54c.406-.12.835-.18 1.288-.18.525 0 1.011.05 1.457.15.452.1.861.227 1.227.38v1.318a8.837 8.837 0 0 0-1.217-.37 5.612 5.612 0 0 0-1.258-.16 3.49 3.49 0 0 0-.938.11 1.797 1.797 0 0 0-.639.31c-.166.127-.289.28-.369.46-.073.173-.11.366-.11.579Z" fill="#000"/><path d="M13.491 27c7.451 0 13.492-6.044 13.492-13.5 0-7.457-6.04-13.5-13.492-13.5C6.041 0 0 6.044 0 13.5 0 20.957 6.04 27 13.491 27Z" fill="#069E08"/><path d="M14.16 11.233v13.088l6.746-13.088H14.16ZM12.798 15.742V2.679l-6.72 13.063h6.72Z" fill="#fff"/><path d="M34.834 22.414c-.387-.593-.747-1.184-1.107-1.751 1.905-1.16 2.548-2.087 2.548-3.84V6.699h-2.24V4.767H38.8v11.542c0 2.937-.85 4.586-3.965 6.105ZM54.787 15.51c0 .979.695 1.082 1.159 1.082.464 0 1.133-.155 1.647-.31v1.804c-.72.232-1.467.412-2.497.412-1.236 0-2.678-.464-2.678-2.628v-5.308h-1.313v-1.83h1.313V6.029h2.369v2.706h2.986v1.83h-2.986v4.946ZM59.73 23.316V8.708h2.266v.876c.901-.696 1.906-1.134 3.141-1.134 2.137 0 3.837 1.494 3.837 4.715 0 3.195-1.853 5.307-4.918 5.307-.746 0-1.338-.103-1.957-.232v5.05h-2.368v.026Zm4.789-12.908c-.695 0-1.57.335-2.395 1.057v4.973a8.59 8.59 0 0 0 1.777.18c1.673 0 2.626-1.057 2.626-3.272 0-2.036-.695-2.938-2.008-2.938ZM78.294 18.266H76.08V17.21h-.052c-.772.592-1.725 1.236-3.14 1.236-1.237 0-2.576-.902-2.576-2.731 0-2.447 2.086-2.911 3.553-3.117l2.085-.283v-.283c0-1.289-.514-1.7-1.725-1.7-.593 0-1.982.18-3.115.643l-.206-1.906a11.91 11.91 0 0 1 3.63-.618c2.317 0 3.811.928 3.811 3.684v6.131h-.05Zm-2.369-4.457-1.957.31c-.592.076-1.21.437-1.21 1.313 0 .773.438 1.21 1.081 1.21.696 0 1.442-.411 2.085-.875v-1.958h.001ZM88.079 17.957c-.978.335-1.853.541-2.961.541-3.553 0-4.97-2.035-4.97-4.998 0-3.117 1.958-5.05 5.124-5.05 1.184 0 1.905.207 2.703.465v2.01c-.695-.259-1.7-.542-2.677-.542-1.442 0-2.678.773-2.678 2.989 0 2.447 1.236 3.195 2.806 3.195.747 0 1.571-.155 2.678-.593v1.983h-.025ZM92.558 12.83c.205-.231.36-.463 3.346-4.096h3.09l-3.863 4.535 4.222 5.023h-3.089l-3.681-4.535v4.535h-2.368V4.767h2.369v8.064h-.026ZM49.328 17.957c-1.236.387-2.292.541-3.528.541-3.038 0-4.917-1.52-4.917-5.076 0-2.602 1.596-4.972 4.66-4.972 3.038 0 4.094 2.112 4.094 4.122 0 .67-.052 1.03-.077 1.416h-6.128c.052 2.087 1.236 2.577 3.013 2.577.978 0 1.853-.232 2.858-.593v1.983h.025v.002Zm-2.162-5.54c0-1.159-.387-2.164-1.647-2.164-1.184 0-1.906.85-2.06 2.165h3.707Z" fill="#000"/></svg>'; |
| 515 | } |
| 516 | |
| 517 | // phpcs:disable WordPress.Security.EscapeOutput.UnsafePrintingFunction |
| 518 | // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped |
| 519 | |
| 520 | /** |
| 521 | * Overwrites the backbone template for the attachment details modal |
| 522 | * |
| 523 | * This template is originally added in WP core in wp-includes/media-templates.php |
| 524 | * |
| 525 | * We override the initialize method of the TwoColumn view class (located at core's js/media/view/attachment/detail-two-column.js) |
| 526 | * and use the custom template only for VideoPress videos. |
| 527 | * |
| 528 | * @return void |
| 529 | */ |
| 530 | public static function attachment_details_two_column_template() { |
| 531 | |
| 532 | ?> |
| 533 | <script type="text/html" id="tmpl-videopress_iframe_vnext"> |
| 534 | <iframe class="videopress-iframe" style="display: block; max-width: 100%; max-height: 100%;" width="{{ data.width }}" height="{{ data.height }}" src="https://videopress.com/embed/{{ data.guid }}?{{ data.urlargs }}" frameborder='0' allowfullscreen></iframe> |
| 535 | </script> |
| 536 | <script type="text/html" id="tmpl-attachment-details-two-column-videopress"> |
| 537 | <div class="attachment-media-view {{ data.orientation }}"> |
| 538 | <h2 class="screen-reader-text"><?php _e( 'Attachment Preview', 'jetpack-videopress-pkg' ); ?></h2> |
| 539 | <div class="thumbnail thumbnail-{{ data.type }}"> |
| 540 | </div> |
| 541 | </div> |
| 542 | <div class="attachment-info"> |
| 543 | <h2> |
| 544 | <?php echo self::get_logo_svg(); ?> |
| 545 | </h2> |
| 546 | <?php self::attachment_info_template_part(); ?> |
| 547 | </div> |
| 548 | </script> |
| 549 | <script> |
| 550 | jQuery(document).ready( function($) { |
| 551 | if( typeof wp.media.view.Attachment.Details.TwoColumn != 'undefined' ){ |
| 552 | var TwoColumn = wp.media.view.Attachment.Details.TwoColumn, |
| 553 | old_render = TwoColumn.prototype.render, |
| 554 | vp_template = wp.template('videopress_iframe_vnext'); |
| 555 | |
| 556 | TwoColumn.prototype.initialize = function() { |
| 557 | if ( 'video' === this.model.attributes.type && 'videopress' === this.model.attributes.subtype ) { |
| 558 | this.template = wp.template( 'attachment-details-two-column-videopress' ); |
| 559 | } else { |
| 560 | this.template = wp.template( 'attachment-details-two-column' ); |
| 561 | } |
| 562 | // From this point on, we are just copying the function from core. |
| 563 | this.controller.on( 'content:activate:edit-details', _.bind( this.editAttachment, this ) ); |
| 564 | wp.media.view.Attachment.Details.prototype.initialize.apply( this, arguments ); |
| 565 | } |
| 566 | |
| 567 | // Add the VideoPress player |
| 568 | TwoColumn.prototype.render = function() { |
| 569 | // Have the original renderer run first. |
| 570 | old_render.apply( this, arguments ); |
| 571 | |
| 572 | // Now our stuff! |
| 573 | if ( 'video' === this.model.get('type') ) { |
| 574 | if ( this.model.get('videopress_guid') ) { |
| 575 | this.$('.attachment-media-view .thumbnail-video').html( vp_template( { |
| 576 | guid : this.model.get('videopress_guid'), |
| 577 | width : this.model.get('width') > 0 ? this.model.get('width') : '100%', |
| 578 | height : this.model.get('height') > 0 ? this.model.get('height') : '100%' |
| 579 | })); |
| 580 | } |
| 581 | } |
| 582 | }; |
| 583 | } |
| 584 | }); |
| 585 | </script> |
| 586 | <?php |
| 587 | } |
| 588 | |
| 589 | /** |
| 590 | * Overwrites the backbone template for the attachment details modal |
| 591 | * |
| 592 | * This template is originally added in WP core in wp-includes/media-templates.php |
| 593 | * |
| 594 | * We override the initialize method of the TwoColumn view class (located at core's js/media/view/attachment/detail-two-column.js) |
| 595 | * and use the custom template only for VideoPress videos. |
| 596 | * |
| 597 | * @return void |
| 598 | */ |
| 599 | public static function attachment_details_template() { |
| 600 | ?> |
| 601 | <script type="text/html" id="tmpl-videopress_iframe_vnext"> |
| 602 | <iframe class="videopress-iframe" style="display: block; max-width: 100%; max-height: 180px;" width="{{ data.width }}" height="{{ data.height }}" src="https://videopress.com/embed/{{ data.guid }}?{{ data.urlargs }}" frameborder='0' allowfullscreen></iframe> |
| 603 | </script> |
| 604 | <script type="text/html" id="tmpl-attachment-details-videopress"> |
| 605 | <h2> |
| 606 | <?php echo self::get_logo_svg(); ?> |
| 607 | </h2> |
| 608 | <div class="attachment-info"> |
| 609 | <div class="wp-media-wrapper wp-video"> |
| 610 | </div> |
| 611 | <?php self::attachment_info_template_part(); ?> |
| 612 | </div> |
| 613 | </script> |
| 614 | <script> |
| 615 | jQuery(document).ready( function($) { |
| 616 | if( typeof wp.media.view.Attachment.Details != 'undefined' ){ |
| 617 | var DetailsTemplate = wp.media.view.Attachment.Details, |
| 618 | old_render = DetailsTemplate.prototype.render, |
| 619 | vp_template = wp.template('videopress_iframe_vnext'); |
| 620 | |
| 621 | DetailsTemplate.prototype.initialize = function() { |
| 622 | if ( 'video' === this.model.attributes.type && 'videopress' === this.model.attributes.subtype ) { |
| 623 | this.template = wp.template( 'attachment-details-videopress' ); |
| 624 | } else { |
| 625 | this.template = wp.template( 'attachment-details' ); |
| 626 | } |
| 627 | // From this point on, we are just copying the function from core. |
| 628 | this.options = _.defaults( this.options, { |
| 629 | rerenderOnModelChange: false |
| 630 | }); |
| 631 | |
| 632 | // Call 'initialize' directly on the parent class. |
| 633 | wp.media.view.Attachment.prototype.initialize.apply( this, arguments ); |
| 634 | |
| 635 | this.copyAttachmentDetailsURLClipboard(); |
| 636 | } |
| 637 | |
| 638 | // Add the VideoPress player |
| 639 | DetailsTemplate.prototype.render = function() { |
| 640 | // Have the original renderer run first. |
| 641 | old_render.apply( this, arguments ); |
| 642 | |
| 643 | // Now our stuff! |
| 644 | if ( 'video' === this.model.get('type') ) { |
| 645 | if ( this.model.get('videopress_guid') ) { |
| 646 | this.$('.attachment-info .wp-video').html( vp_template( { |
| 647 | guid : this.model.get('videopress_guid'), |
| 648 | // width : this.model.get('width') > 0 ? this.model.get('width') : '100%', |
| 649 | // height : this.model.get('height') > 0 ? this.model.get('height') : '100%' |
| 650 | })); |
| 651 | } |
| 652 | } |
| 653 | }; |
| 654 | } |
| 655 | }); |
| 656 | </script> |
| 657 | <?php |
| 658 | } |
| 659 | |
| 660 | /** |
| 661 | * Echoes the piece of the custom template that is shared between the two templates above |
| 662 | * |
| 663 | * @return void |
| 664 | */ |
| 665 | protected static function attachment_info_template_part() { |
| 666 | ?> |
| 667 | <span class="setting" data-setting="title"> |
| 668 | <label for="attachment-details-title" class="name"><?php _e( 'Title', 'jetpack-videopress-pkg' ); ?></label> |
| 669 | <input type="text" id="attachment-details-title" value="{{ data.title }}" readonly /> |
| 670 | </span> |
| 671 | <span class="setting" data-setting="filename"> |
| 672 | <label for="attachment-details-filename" class="name"><?php _e( 'File name', 'jetpack-videopress-pkg' ); ?></label> |
| 673 | <input type="text" id="attachment-details-filename" value="{{ data.filename }}" readonly /> |
| 674 | </span> |
| 675 | <span class="setting" data-setting="fileurl"> |
| 676 | <label for="attachment-details-copy-link" class="name"><?php _e( 'File URL:', 'jetpack-videopress-pkg' ); ?></label> |
| 677 | <input type="text" class="attachment-details-copy-link" id="attachment-details-copy-link" value="{{ data.url }}" readonly /> |
| 678 | <div class="copy-to-clipboard-container"> |
| 679 | <button type="button" class="button button-small copy-attachment-url" data-clipboard-target="#attachment-details-copy-link"><?php _e( 'Copy URL to clipboard', 'jetpack-videopress-pkg' ); ?></button> |
| 680 | <span class="success hidden" aria-hidden="true"><?php _e( 'Copied!', 'jetpack-videopress-pkg' ); ?></span> |
| 681 | </div> |
| 682 | </span> |
| 683 | <p><a href="{{ data.editLink }}" class="button button-medium" target="_blank"><?php _e( 'Edit video details', 'jetpack-videopress-pkg' ); ?></a></p> |
| 684 | <?php |
| 685 | } |
| 686 | // phpcs:enable WordPress.Security.EscapeOutput.UnsafePrintingFunction |
| 687 | // phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped |
| 688 | |
| 689 | /** |
| 690 | * Load the wp-build entry file and register its polyfills. |
| 691 | * |
| 692 | * Only called on `?page=jetpack-videopress` admin requests when the |
| 693 | * modernization filter is enabled. Keeps wp-build off every other request. |
| 694 | * |
| 695 | * @return void |
| 696 | */ |
| 697 | private static function load_wp_build() { |
| 698 | $build_index = dirname( __DIR__ ) . '/build/build.php'; |
| 699 | |
| 700 | if ( ! file_exists( $build_index ) ) { |
| 701 | return; |
| 702 | } |
| 703 | |
| 704 | require_once $build_index; |
| 705 | |
| 706 | // Defer the chapters-editor route stripping to the page init actions, at a |
| 707 | // priority ahead of the `build/routes.php` readers (default 10). Those |
| 708 | // actions fire from the page's `admin_enqueue_scripts` callback, one |
| 709 | // priority before `Initial_State` mirrors the chapters-editor filter to |
| 710 | // the client (priority 11), so both evaluations of the filter happen at |
| 711 | // the same request stage and a filter registered after this method |
| 712 | // runs (`init`, `admin_init`, …) is honored consistently by both. |
| 713 | add_action( 'jetpack-videopress-dashboard_init', array( __CLASS__, 'maybe_strip_chapters_editor_routes' ), 5 ); |
| 714 | add_action( 'jetpack-videopress-dashboard-wp-admin_init', array( __CLASS__, 'maybe_strip_chapters_editor_routes' ), 5 ); |
| 715 | |
| 716 | \Automattic\Jetpack\WP_Build_Polyfills\WP_Build_Polyfills::register( |
| 717 | 'jetpack-videopress', |
| 718 | array_merge( |
| 719 | \Automattic\Jetpack\WP_Build_Polyfills\WP_Build_Polyfills::SCRIPT_HANDLES, |
| 720 | \Automattic\Jetpack\WP_Build_Polyfills\WP_Build_Polyfills::MODULE_IDS |
| 721 | ) |
| 722 | ); |
| 723 | } |
| 724 | |
| 725 | /** |
| 726 | * Remove the chapters editor routes from the generated route registry when |
| 727 | * the chapters editor filter is off. |
| 728 | * |
| 729 | * The wp-build routes loader (`build/routes.php`) stores each page's route |
| 730 | * list in `$GLOBALS['jetpack_videopress_jetpack_videopress_dashboard_routes_data']` |
| 731 | * and reads it back on the page init hooks at default priority, so |
| 732 | * `load_wp_build()` hooks this on those same actions at priority 5 — |
| 733 | * filtering the global just before it is consumed keeps the chapters editor |
| 734 | * route modules from ever being registered. |
| 735 | * |
| 736 | * @since 0.45.0 |
| 737 | * |
| 738 | * @internal Only public so the wp-build page init actions can invoke it. |
| 739 | * |
| 740 | * @return void |
| 741 | */ |
| 742 | public static function maybe_strip_chapters_editor_routes() { |
| 743 | if ( self::is_chapters_editor_enabled() ) { |
| 744 | return; |
| 745 | } |
| 746 | |
| 747 | $global_name = 'jetpack_videopress_jetpack_videopress_dashboard_routes_data'; |
| 748 | |
| 749 | // Guard against a build change renaming the generated global: the |
| 750 | // chapters editor route would leak, but nothing fatals. |
| 751 | if ( empty( $GLOBALS[ $global_name ] ) || ! is_array( $GLOBALS[ $global_name ] ) ) { |
| 752 | return; |
| 753 | } |
| 754 | |
| 755 | $GLOBALS[ $global_name ] = self::strip_chapters_editor_routes( $GLOBALS[ $global_name ] ); |
| 756 | } |
| 757 | |
| 758 | /** |
| 759 | * Filter the chapters editor route entries out of a wp-build route registry array. |
| 760 | * |
| 761 | * Pure helper extracted from `maybe_strip_chapters_editor_routes()` so the |
| 762 | * filtering logic is unit-testable without the generated global. |
| 763 | * |
| 764 | * @since 0.45.0 |
| 765 | * |
| 766 | * @internal For use by `maybe_strip_chapters_editor_routes()` and tests only. |
| 767 | * |
| 768 | * @param array $routes Route entries as generated by `build/routes.php`, each an array with a `path` key. |
| 769 | * @return array Route entries with the chapters editor paths removed. |
| 770 | */ |
| 771 | public static function strip_chapters_editor_routes( $routes ) { |
| 772 | return array_values( |
| 773 | array_filter( |
| 774 | $routes, |
| 775 | static function ( $route ) { |
| 776 | return ! isset( $route['path'] ) || ! in_array( $route['path'], self::CHAPTERS_EDITOR_ROUTE_PATHS, true ); |
| 777 | } |
| 778 | ) |
| 779 | ); |
| 780 | } |
| 781 | |
| 782 | /** |
| 783 | * Alias the current screen ID to satisfy wp-build's auto-generated enqueue check. |
| 784 | * |
| 785 | * Wp-build's `<page>-wp-admin` enqueue callback enqueues only when the screen ID |
| 786 | * matches the wp-build page slug (`jetpack-videopress-dashboard`). Our WP-admin |
| 787 | * menu slug stays `jetpack-videopress`, so we mutate the screen object in place |
| 788 | * to make the check pass without changing the user-facing URL. |
| 789 | * |
| 790 | * Hooked only when modernization is on AND we're on the VideoPress admin page, |
| 791 | * so this never affects any other request. |
| 792 | * |
| 793 | * @param \WP_Screen|null $screen The current screen object (passed by WP). |
| 794 | * @return void |
| 795 | */ |
| 796 | public static function alias_screen_id_for_wp_build( $screen ) { |
| 797 | if ( ! is_object( $screen ) ) { |
| 798 | return; |
| 799 | } |
| 800 | |
| 801 | $screen->id = 'jetpack-videopress-dashboard'; |
| 802 | } |
| 803 | |
| 804 | /** |
| 805 | * Returns true when the wp-build modernization filter is enabled. |
| 806 | * |
| 807 | * @return bool |
| 808 | */ |
| 809 | public static function is_modernized() { |
| 810 | return (bool) apply_filters( self::MODERNIZATION_FILTER, true ); |
| 811 | } |
| 812 | |
| 813 | /** |
| 814 | * Returns true when the chapters editor feature filter is enabled. |
| 815 | * |
| 816 | * Note the default is true: the dashboard Editor tab, the |
| 817 | * `/video/$id/editor` route, the Details-tab deep link, and the block |
| 818 | * editor's "Manage chapters" toolbar button are all available unless a site |
| 819 | * explicitly opts out via the filter. |
| 820 | * |
| 821 | * @since 0.45.0 |
| 822 | * |
| 823 | * @return bool |
| 824 | */ |
| 825 | public static function is_chapters_editor_enabled() { |
| 826 | /** |
| 827 | * Whether the VideoPress chapters editor UI is available. |
| 828 | * |
| 829 | * Gates UI only — the chapters REST surface stays registered either way. |
| 830 | * |
| 831 | * @since 0.45.0 |
| 832 | * |
| 833 | * @param bool $enabled Whether the chapters editor UI is enabled. Default true. |
| 834 | */ |
| 835 | return (bool) apply_filters( self::CHAPTERS_EDITOR_FILTER, true ); |
| 836 | } |
| 837 | |
| 838 | /** |
| 839 | * Returns true when the current request targets the VideoPress admin page. |
| 840 | * |
| 841 | * Used to scope wp-build loading to the one page that needs it. The |
| 842 | * `$_GET['page']` value is populated by wp-admin/admin.php before any of |
| 843 | * our hooks fire, so this check is reliable from `init()` onwards. |
| 844 | * |
| 845 | * @return bool |
| 846 | */ |
| 847 | private static function is_videopress_admin_request() { |
| 848 | if ( ! is_admin() || ! isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended |
| 849 | return false; |
| 850 | } |
| 851 | |
| 852 | return sanitize_text_field( wp_unslash( $_GET['page'] ) ) === self::ADMIN_PAGE_SLUG; // phpcs:ignore WordPress.Security.NonceVerification.Recommended |
| 853 | } |
| 854 | } |