diff --git a/assets/dev/js/frontend/utils/video-api/youtube-loader.js b/assets/dev/js/frontend/utils/video-api/youtube-loader.js index 5bfed84c9b48..c9555c1650b1 100644 --- a/assets/dev/js/frontend/utils/video-api/youtube-loader.js +++ b/assets/dev/js/frontend/utils/video-api/youtube-loader.js @@ -6,7 +6,7 @@ export default class YoutubeLoader extends BaseLoader { } getURLRegex() { - return /^(?:https?:\/\/)?(?:www\.)?(?:m\.)?(?:youtu\.be\/|youtube\.com\/(?:(?:watch)?\?(?:.*&)?vi?=|(?:embed|v|vi|user)\/))([^?&"'>]+)/; + return /^(?:https?:\/\/)?(?:www\.)?(?:m\.)?(?:youtu\.be\/|youtube\.com\/(?:(?:watch)?\?(?:.*&)?vi?=|(?:embed|v|vi|user|shorts)\/))([^?&"'>]+)/; } isApiLoaded() { diff --git a/assets/dev/scss/frontend/conditionals/e-swiper.scss b/assets/dev/scss/frontend/conditionals/e-swiper.scss index 08d24cb37027..bdda2c7cdc60 100644 --- a/assets/dev/scss/frontend/conditionals/e-swiper.scss +++ b/assets/dev/scss/frontend/conditionals/e-swiper.scss @@ -116,6 +116,14 @@ } } + .elementor-swiper { + position: relative; + } + + .elementor-main-swiper { + position: static; + } + &.elementor-arrows-position- { &outside { diff --git a/changelog.txt b/changelog.txt index d0102aa3c6c7..3b7787300082 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,13 @@ == Changelog == += 3.25.11 - 2024-12-10 = + +* Tweak: Updated `eicons` library to v5.34.0 +* Security Fix: Improved code security enforcement in Image widget +* Security Fix: Improved code security enforcement in Connect process +* Security Fix: Improved code security enforcement in Progress bar widget +* Fix: YouTube video in lightbox is not presented as expected in Video widget ([#29241](https://github.com/elementor/elementor/issues/29241)) + = 3.25.10 - 2024-11-24 = * Security Fix: Improved code security enforcement in Typography control diff --git a/core/common/modules/connect/admin.php b/core/common/modules/connect/admin.php index 228394da8775..41e9daeb1000 100644 --- a/core/common/modules/connect/admin.php +++ b/core/common/modules/connect/admin.php @@ -29,6 +29,12 @@ public function register_admin_menu( Admin_Menu_Manager $admin_menu ) { * @access public */ public function on_load_page() { + if ( ! $this->user_has_enough_permissions() ) { + wp_die( 'You do not have sufficient permissions to access this page.', 'You do not have sufficient permissions to access this page.', [ + 'back_link' => true, + ] ); + } + if ( isset( $_GET['action'], $_GET['app'] ) ) { $manager = Plugin::$instance->common->get_component( 'connect' ); @@ -59,6 +65,18 @@ public function on_load_page() { } } + private function user_has_enough_permissions() { + if ( current_user_can( 'manage_options' ) ) { + return true; + } + + if ( 'library' === Utils::get_super_global_value( $_GET, 'app' ) ) { + return current_user_can( 'edit_posts' ); + } + + return false; + } + /** * @since 2.3.0 * @access public diff --git a/includes/embed.php b/includes/embed.php index 38f19c0d835f..f5579613a751 100644 --- a/includes/embed.php +++ b/includes/embed.php @@ -28,7 +28,7 @@ class Embed { * @var array Provider URL structure regex. */ private static $provider_match_masks = [ - 'youtube' => '/^.*(?:youtu\.be\/|youtube(?:-nocookie)?\.com\/(?:(?:watch)?\?(?:.*&)?vi?=|(?:embed|v|vi|user)\/))([^\?&\"\'>]+)/', + 'youtube' => '/^.*(?:youtu\.be\/|youtube(?:-nocookie)?\.com\/(?:(?:watch)?\?(?:.*&)?vi?=|(?:embed|v|vi|user|shorts)\/))([^\?&\"\'>]+)/', 'vimeo' => '/^.*vimeo\.com\/(?:[a-z]*\/)*([‌​0-9]{6,11})[?]?.*/', 'dailymotion' => '/^.*dailymotion.com\/(?:video|hub)\/([^_]+)[^#]*(#video=([^_&]+))?/', 'videopress' => [ diff --git a/includes/managers/image.php b/includes/managers/image.php index 9b7e2587388d..2d0fe24d5132 100644 --- a/includes/managers/image.php +++ b/includes/managers/image.php @@ -29,7 +29,7 @@ class Images_Manager { * @access public */ public function get_images_details() { - if ( ! current_user_can( Editor::EDITING_CAPABILITY ) ) { + if ( ! current_user_can( 'publish_posts' ) ) { wp_send_json_error( 'Permission denied' ); } diff --git a/includes/widgets/progress.php b/includes/widgets/progress.php index fbc465bb55e0..689d3e6ace78 100644 --- a/includes/widgets/progress.php +++ b/includes/widgets/progress.php @@ -423,13 +423,13 @@ protected function render() { if ( ! Utils::is_empty( $settings['title'] ) ) { ?> < print_render_attribute_string( 'title' ); ?>> - print_unescaped_setting( 'title' ); ?> + >
print_render_attribute_string( 'wrapper' ); ?>>
print_render_attribute_string( 'progress-bar' ); ?>> - print_render_attribute_string( 'inner_text' ); ?>>print_unescaped_setting( 'inner_text' ); ?> + print_render_attribute_string( 'inner_text' ); ?>> % @@ -495,11 +495,11 @@ protected function content_template() { view.addInlineEditingAttributes( 'inner_text' ); #> <# if ( settings.title ) { #> - <{{ title_tag }} {{{ view.getRenderAttributeString( 'title' ) }}}>{{{ settings.title }}} + <{{ title_tag }} {{{ view.getRenderAttributeString( 'title' ) }}}>{{ settings.title }} <# } #>
- {{{ settings.inner_text }}} + {{ settings.inner_text }} <# if ( 'show' === settings.display_percentage ) { #> {{{ progress_percentage }}}% <# } #> diff --git a/modules/ai/module.php b/modules/ai/module.php index a58e8873d27c..b372918e7780 100644 --- a/modules/ai/module.php +++ b/modules/ai/module.php @@ -348,13 +348,6 @@ public function get_product_images_ajax() { ]; } - $supported_post_types = get_option( 'elementor_cpt_support', [] ); - $new_post_type = 'product'; - if ( ! in_array( $new_post_type, $supported_post_types, true ) ) { - $supported_post_types[] = $new_post_type; - update_option( 'elementor_cpt_support', $supported_post_types ); - } - wp_send_json_success( [ 'product_images' => array_slice( $image_ids, 0, 10 ) ] ); wp_die(); diff --git a/modules/editor-events/module.php b/modules/editor-events/module.php index 6c8406f21b92..8d52b6d48e3d 100644 --- a/modules/editor-events/module.php +++ b/modules/editor-events/module.php @@ -53,6 +53,7 @@ private function register_experiment() { 'title' => esc_html__( 'Elementor Editor Events', 'elementor' ), 'description' => esc_html__( 'Editor events processing', 'elementor' ), 'hidden' => true, + 'release_status' => Experiments_Manager::RELEASE_STATUS_ALPHA, 'default' => Experiments_Manager::STATE_INACTIVE, ] ); } diff --git a/modules/home/module.php b/modules/home/module.php index 817bf650b919..700d1065a8c9 100644 --- a/modules/home/module.php +++ b/modules/home/module.php @@ -92,6 +92,7 @@ private function register_layout_experiment(): void { 'title' => esc_html__( 'Elementor Home Screen', 'elementor' ), 'description' => esc_html__( 'Default Elementor menu page.', 'elementor' ), 'hidden' => true, + 'release_status' => Experiments_Manager::RELEASE_STATUS_STABLE, 'default' => Experiments_Manager::STATE_ACTIVE, ] ); } diff --git a/readme.txt b/readme.txt index 7f83a68d60b2..768ec4dd4be3 100644 --- a/readme.txt +++ b/readme.txt @@ -346,6 +346,14 @@ You can also add a new language via [translate.wordpress.org](https://go.element == Changelog == += 3.25.11 - 2024-12-10 = + +* Tweak: Updated `eicons` library to v5.34.0 +* Security Fix: Improved code security enforcement in Image widget +* Security Fix: Improved code security enforcement in Connect process +* Security Fix: Improved code security enforcement in Progress bar widget +* Fix: YouTube video in lightbox is not presented as expected in Video widget ([#29241](https://github.com/elementor/elementor/issues/29241)) + = 3.25.10 - 2024-11-24 = * Security Fix: Improved code security enforcement in Typography control diff --git a/tests/phpunit/elementor/core/common/modules/connect/apps/test-common-app.php b/tests/phpunit/elementor/core/common/modules/connect/apps/test-common-app.php index e8ae948a0aa6..16d560c98a45 100644 --- a/tests/phpunit/elementor/core/common/modules/connect/apps/test-common-app.php +++ b/tests/phpunit/elementor/core/common/modules/connect/apps/test-common-app.php @@ -529,4 +529,39 @@ private function get_connected_user() { return $user; } + + public function test_get_remote_authorize_url_with_plg_data() { + // Arrange + $_GET['utm_source'] = 'test-source'; + $_GET['utm_medium'] = 'test-medium'; + $_GET['utm_campaign'] = 'test-campaign'; + $_GET['utm_not_allowed_param'] = 'test-test'; + + $utm_campaign = [ + 'source' => 'transient-source', + 'medium' => 'transient-medium', + 'campaign' => 'transient-campaign', + ]; + + set_transient( 'elementor_core_campaign', $utm_campaign ); + + // Act + $url = $this->app_stub->proxy_get_remote_authorize_url(); + + // Assert + $parsed_url = parse_url( $url ); + $parsed_query_params = []; + parse_str( $parsed_url['query'], $parsed_query_params ); + + $this->assertEquals( 'my.elementor.com', $parsed_url['host'] ); + $this->assertEquals( '/connect/v1/mock-app', $parsed_url['path'] ); + $this->assertEquals( 'authorize', $parsed_query_params['action'] ); + $this->assertEquals( 'transient-source', $parsed_query_params['utm_source'] ); + $this->assertEquals( 'transient-medium', $parsed_query_params['utm_medium'] ); + $this->assertEquals( 'transient-campaign', $parsed_query_params['utm_campaign'] ); + + $this->assertArrayNotHasKey( 'utm_not_allowed_param', $parsed_query_params ); + $this->assertArrayNotHasKey( 'utm_term', $parsed_query_params ); + $this->assertArrayNotHasKey( 'utm_content', $parsed_query_params ); + } } diff --git a/tests/playwright/pages/elementor-panel-tabs/style.ts b/tests/playwright/pages/elementor-panel-tabs/style.ts deleted file mode 100644 index 21db0ed13656..000000000000 --- a/tests/playwright/pages/elementor-panel-tabs/style.ts +++ /dev/null @@ -1,26 +0,0 @@ -import EditorSelectors from '../../selectors/editor-selectors'; -import { type Page, type TestInfo } from '@playwright/test'; -import EditorPage from '../editor-page'; - -export default class Style { - readonly page: Page; - readonly editor: EditorPage; - - constructor( page: Page, testInfo: TestInfo ) { - this.page = page; - this.editor = new EditorPage( this.page, testInfo ); - } - - async setColorPicker( widget: string, color: string ) { - await this.editor - .getPreviewFrame() - .locator( EditorSelectors.getWidgetByName( widget ) ) - .first() - .click(); - await this.editor.setWidgetTab( 'style' ); - await this.page.getByRole( 'button', { name: 'toggle color picker dialog' } ).click(); - await this.page.getByRole( 'textbox', { name: 'color input field' } ).click(); - await this.page.locator( '.pcr-app.visible input.pcr-result' ).fill( color ); - await this.editor.openElementsPanel(); - } -} diff --git a/tests/playwright/sanity/context-menu.test.ts b/tests/playwright/sanity/context-menu.test.ts index 2b56cdbfb612..2aecca1d94da 100644 --- a/tests/playwright/sanity/context-menu.test.ts +++ b/tests/playwright/sanity/context-menu.test.ts @@ -3,7 +3,6 @@ import { parallelTest as test } from '../parallelTest'; import WpAdminPage from '../pages/wp-admin-page'; import EditorPage from '../pages/editor-page'; import ContextMenu from '../pages/widgets/context-menu'; -import Style from '../pages/elementor-panel-tabs/style'; test.describe( 'Context menu', () => { test( 'Edit widget test', async ( { page, apiRequests }, testInfo ) => { @@ -44,12 +43,12 @@ test.describe( 'Context menu', () => { const editor = new EditorPage( page, testInfo ); const wpAdmin = new WpAdminPage( page, testInfo, apiRequests ); const contextMenu = new ContextMenu( page, testInfo ); - const styleTab = new Style( page, testInfo ); const headingSelector = '.elementor-heading-title'; await wpAdmin.openNewPage(); await editor.addWidget( 'heading' ); - await styleTab.setColorPicker( 'heading', '#E46E6E' ); + await editor.openPanelTab( 'style' ); + await editor.setColorControlValue( 'title_color', '#E46E6E' ); await expect( editor.getPreviewFrame().locator( headingSelector ) ).toHaveCSS( 'color', 'rgb(228, 110, 110)' ); await contextMenu.selectWidgetContextMenuItem( 'heading', 'Reset style' ); await expect( editor.getPreviewFrame().locator( headingSelector ) ).toHaveCSS( 'color', 'rgb(110, 193, 228)' );