-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add iframe block add an iframe block that will let publishers to embed an iframe either by its URL or by uploading the iframe archive * chore(iframe block): minor UI changes * style(iframe): fix label text change label text form from a question to normal text * refactor(iframe): show iframe fullscreen notice on editor when adding a fullscreen iframe to a post we'll show a notice saying that the iframe will take over on the content on the post page (we don't want to preview this behavior as it will not let the user user the editor) * fix: rebase onto master * refactor(iframe): change archive folder name to be Newspack related * refactor(iframe): improve iframe archive folder name readability * refactor(iframe): improve editor iframe title * refactor(iframe): edit functions docblock * feat: update sidebar controls * feat: move support link to block description * feat: update preview icon and title * feat(iframe-block): switch UI to follow image Upload block UI set the UI as the Image Upload Block UI and enable getting archive assets from media library * refactor(iframe-block): disable preview by default * feat(iframe-block): enable setting iframe size unit * feat(iframe): display preview button only when src is available * feat: move unit-controls to same row * refactor(iframe-block): add newspack- prefix to class name * style(iframe): wording change change Upload to Embed since we do embed a URL not upload it * fix(iframe): ignore experimental component eslint warning * docs(iframe): separate internal WordPress dependencies from externals * style(iframe): fix indentation * fix(iframe): better error messages when using iframe archive from media * fix(iframe): do not render anything on a blank block * fix(iframe): fix preview toggle Toggle preview display only the first time when we upload an archive zip or embed a URL * fix(iframe): fix error handling on form submit handle only errors with a valid `message` key, else fallback on a generic error message * fix(iframe): better error message when we can't unzip the assets archive * fix(iframe): fix endpoint method delete method should be set as Delete not as a Post/Put/Patch * refactor(iframe): remove unnecessary functions from useEffect deps list * fix(iframe): fix deleting archive folder when needed * fix(iframe): do no render popups when the iframe is fullscreen the iframe will take over the popup prompt so we don't need to render it * refactor(iframe): clean edit from unnecessary states * refactor(iframe): manage block attributes from shared json file * fix(iframe): fix filter callback * style(iframe): remove commented code * fix(iframe): fix typing Iframe URL issue A bug was introduced in 76f9021 where when we type the first letter in the URL field it's submitted, moved the field state to the right place. * style(iframe): format json file for readability Co-authored-by: Thomas Guillot <info@thomasguillot.com>
- Loading branch information
1 parent
4daf27d
commit 08a2712
Showing
14 changed files
with
981 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
{ | ||
"production": [ "author-profile", "carousel", "donate", "homepage-articles", "video-playlist" ] | ||
"production": [ "author-profile", "carousel", "donate", "homepage-articles", "video-playlist", "iframe" ] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{ | ||
"name": "iframe", | ||
"category": "newspack", | ||
"attributes": { | ||
"src": { | ||
"type": "string", | ||
"default": "" | ||
}, | ||
"archiveFolder": { | ||
"type": "string", | ||
"default": "" | ||
}, | ||
"height": { | ||
"type": "string", | ||
"default": "600px" | ||
}, | ||
"width": { | ||
"type": "string", | ||
"default": "100%" | ||
}, | ||
"isFullScreen": { | ||
"type": "boolean", | ||
"default": false | ||
} | ||
} | ||
} |
252 changes: 252 additions & 0 deletions
252
src/blocks/iframe/class-wp-rest-newspack-iframe-controller.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,252 @@ | ||
<?php | ||
/** | ||
* WP_REST_Newspack_Iframe_Controller file. | ||
* | ||
* @package WordPress | ||
*/ | ||
|
||
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound | ||
|
||
/** | ||
* Class WP_REST_Newspack_Iframe_Controller. | ||
*/ | ||
class WP_REST_Newspack_Iframe_Controller extends WP_REST_Controller { | ||
const IFRAME_UPLOAD_DIR = '/newspack_iframes/'; | ||
const IFRAME_ENTRY_FILE = 'index.html'; | ||
|
||
/** | ||
* Constructs the controller. | ||
* | ||
* @access public | ||
*/ | ||
public function __construct() { | ||
$this->namespace = 'newspack-blocks/v1'; | ||
$this->rest_base = 'iframe'; | ||
} | ||
|
||
/** | ||
* Registers the necessary REST API routes. | ||
* | ||
* @access public | ||
*/ | ||
public function register_routes() { | ||
register_rest_route( | ||
$this->namespace, | ||
'/newspack-blocks-iframe-archive', | ||
[ | ||
[ | ||
'methods' => WP_REST_Server::EDITABLE, | ||
'callback' => [ $this, 'import_iframe_archive_from_uploaded_file' ], | ||
'permission_callback' => function() { | ||
return current_user_can( 'edit_posts' ); | ||
}, | ||
], | ||
] | ||
); | ||
|
||
register_rest_route( | ||
$this->namespace, | ||
'/newspack-blocks-iframe-archive-from-media', | ||
[ | ||
[ | ||
'methods' => WP_REST_Server::EDITABLE, | ||
'callback' => [ $this, 'import_iframe_archive_from_media_library' ], | ||
'permission_callback' => function() { | ||
return current_user_can( 'edit_posts' ); | ||
}, | ||
], | ||
] | ||
); | ||
|
||
register_rest_route( | ||
$this->namespace, | ||
'/newspack-blocks-remove-iframe-archive', | ||
[ | ||
[ | ||
'methods' => WP_REST_Server::DELETABLE, | ||
'callback' => [ $this, 'remove_iframe_archive' ], | ||
'permission_callback' => function() { | ||
return current_user_can( 'edit_posts' ); | ||
}, | ||
], | ||
] | ||
); | ||
} | ||
|
||
/** | ||
* Receive the iframe archive, unzip it, and returns the URL and the folder name. | ||
* | ||
* @param WP_REST_Request $request Request object. | ||
* @return WP_REST_Response | ||
*/ | ||
public function import_iframe_archive_from_uploaded_file( $request ) { | ||
$response = []; | ||
$files = $request->get_file_params(); | ||
|
||
if ( count( $files ) > 0 && array_key_exists( 'archive_file', $files ) ) { | ||
$archive_file = $files['archive_file']; | ||
$iframe_folder = pathinfo( $archive_file['name'] )['filename'] . '-' . wp_generate_password( 8, false ); | ||
|
||
$response = $this->process_iframe_archive( $request, $iframe_folder, $archive_file['tmp_name'] ); | ||
} else { | ||
$response = new WP_Error( | ||
'newspack_blocks', | ||
__( 'Could not find the iframe archive on your request.', 'newspack-blocks' ), | ||
[ 'status' => '400' ] | ||
); | ||
} | ||
|
||
return rest_ensure_response( $response ); | ||
} | ||
|
||
/** | ||
* Receive the iframe archive, unzip it, and returns the URL and the folder name. | ||
* | ||
* @param WP_REST_Request $request Request object. | ||
* @return WP_REST_Response | ||
*/ | ||
public function import_iframe_archive_from_media_library( $request ) { | ||
$response = []; | ||
$data = $request->get_body_params(); | ||
|
||
if ( array_key_exists( 'media_id', $data ) ) { | ||
$media = get_post( $data['media_id'] ); | ||
$media_path = get_attached_file( $data['media_id'] ); | ||
|
||
if ( $media_path && 'application/zip' === $media->post_mime_type ) { | ||
$iframe_folder = $media->post_title . '-' . wp_generate_password( 8, false ); | ||
|
||
$response = $this->process_iframe_archive( $request, $iframe_folder, $media_path ); | ||
} else { | ||
$response = new WP_Error( | ||
'newspack_blocks', | ||
__( 'Please choose a valid (.zip) assets archive.', 'newspack-blocks' ), | ||
[ 'status' => '400' ] | ||
); | ||
} | ||
} else { | ||
$response = new WP_Error( | ||
'newspack_blocks', | ||
__( 'Please choose a valid (.zip) assets archive.', 'newspack-blocks' ), | ||
[ 'status' => '400' ] | ||
); | ||
} | ||
|
||
return rest_ensure_response( $response ); | ||
} | ||
|
||
/** | ||
* Process iframe archive from uploaded zip or from media file. | ||
* | ||
* @param WP_REST_REQUEST $request Request object. | ||
* @param string $iframe_folder where to extract the iframe assets. | ||
* @param string $media_path iframe assets zip file path. | ||
* @return WP_REST_Response | ||
*/ | ||
private function process_iframe_archive( $request, $iframe_folder, $media_path ) { | ||
$wp_upload_dir = wp_upload_dir(); | ||
$iframe_upload_dir = $wp_upload_dir['path'] . self::IFRAME_UPLOAD_DIR; | ||
$iframe_path = $iframe_upload_dir . $iframe_folder; | ||
$data = $request->get_body_params(); | ||
|
||
// create iframe directory if not existing. | ||
if ( ! file_exists( $iframe_upload_dir ) ) { | ||
wp_mkdir_p( $iframe_upload_dir ); | ||
} | ||
|
||
// unzip iframe archive. | ||
$zip = new ZipArchive(); | ||
$res = $zip->open( $media_path ); | ||
|
||
if ( true === $res ) { | ||
$zip->extractTo( $iframe_path ); | ||
$zip->close(); | ||
|
||
// check if iframe entry file is there. | ||
if ( file_exists( path_join( $iframe_path, self::IFRAME_ENTRY_FILE ) ) ) { | ||
$response = [ | ||
'src' => $wp_upload_dir['url'] . self::IFRAME_UPLOAD_DIR . $iframe_folder, | ||
'dir' => path_join( $wp_upload_dir['subdir'] . self::IFRAME_UPLOAD_DIR, $iframe_folder ), | ||
]; | ||
|
||
// if we need to remove the previous archive, it's a good place to do it here. | ||
if ( array_key_exists( 'archive_folder', $data ) && ! empty( $data['archive_folder'] ) ) { | ||
$this->remove_folder( $wp_upload_dir['basedir'] . $data['archive_folder'] ); | ||
} | ||
} else { | ||
// check if its not a one folder archive: archive.zip > archive > index.html. | ||
$archive_folders = array_values( | ||
array_filter( | ||
glob( "$iframe_path/*", GLOB_ONLYDIR ), | ||
function( $file ) { | ||
return false === strpos( $file, '__MACOSX' ); | ||
} | ||
) | ||
); | ||
|
||
if ( 1 === count( $archive_folders ) && file_exists( path_join( $archive_folders[0], self::IFRAME_ENTRY_FILE ) ) ) { | ||
$response = [ | ||
'src' => $wp_upload_dir['url'] . self::IFRAME_UPLOAD_DIR . $iframe_folder . DIRECTORY_SEPARATOR . basename( $archive_folders[0] ), | ||
'dir' => path_join( $wp_upload_dir['subdir'] . self::IFRAME_UPLOAD_DIR, $iframe_folder . DIRECTORY_SEPARATOR ), | ||
]; | ||
|
||
// if we need to remove the previous archive, it's a good place to do it here. | ||
if ( array_key_exists( 'archive_folder', $data ) && ! empty( $data['archive_folder'] ) ) { | ||
$this->remove_folder( $wp_upload_dir['basedir'] . $data['archive_folder'] ); | ||
} | ||
} else { | ||
// if not, remove the uploaded archive data and raise an error. | ||
$this->remove_folder( $iframe_path ); | ||
|
||
$response = new WP_Error( | ||
'newspack_blocks', | ||
/* translators: %s: iframe entry file (e.g. index,html) */ | ||
sprintf( __( '%s was not found in the iframe archive.', 'newspack-blocks' ), self::IFRAME_ENTRY_FILE ), | ||
[ 'status' => '400' ] | ||
); | ||
} | ||
} | ||
} else { | ||
$response = new WP_Error( | ||
'newspack_blocks', | ||
__( "Could not unzip the iframe archive, make sure it's a valid .zip archive file.", 'newspack-blocks' ), | ||
[ 'status' => '400' ] | ||
); | ||
} | ||
|
||
return $response; | ||
} | ||
|
||
/** | ||
* Delete iframe archive, this is called when changing the iframe source. | ||
* | ||
* @param WP_REST_Request $request Request object. | ||
* @return WP_REST_Response | ||
*/ | ||
public function remove_iframe_archive( $request ) { | ||
$wp_upload_dir = wp_upload_dir(); | ||
$data = $request->get_json_params(); | ||
|
||
if ( array_key_exists( 'archive_folder', $data ) && ! empty( $data['archive_folder'] ) ) { | ||
$this->remove_folder( $wp_upload_dir['basedir'] . $data['archive_folder'] ); | ||
} | ||
|
||
return rest_ensure_response( [] ); | ||
} | ||
|
||
/** | ||
* Remove a folder. Called to remove the iframe archive folder. | ||
* | ||
* @param string $folder folder path to remove. | ||
* @return void | ||
*/ | ||
private function remove_folder( $folder ) { | ||
if ( ! class_exists( 'WP_Filesystem_Direct' ) ) { | ||
require_once ABSPATH . '/wp-admin/includes/class-wp-filesystem-base.php'; | ||
require_once ABSPATH . '/wp-admin/includes/class-wp-filesystem-direct.php'; | ||
} | ||
|
||
$file_system = new WP_Filesystem_Direct( false ); | ||
$file_system->rmdir( $folder, true ); | ||
} | ||
} |
Oops, something went wrong.