Skip to content

Commit a1328d1

Browse files
authored
Merge branch '3.23' into internal/widget-button-markup-ga
2 parents 73284fc + 0d8e786 commit a1328d1

File tree

12 files changed

+180
-13
lines changed

12 files changed

+180
-13
lines changed

assets/dev/js/admin/admin.js

+16
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,22 @@ import FloatingButtonsHandler from 'elementor/modules/floating-buttons/assets/js
118118
} );
119119
} );
120120

121+
$( '.e-notice--cta.e-notice--dismissible[data-notice_id="plugin_image_optimization"] a.e-button--cta' ).on( 'click', function() {
122+
elementorCommon.ajax.addRequest( 'elementor_image_optimization_campaign', {
123+
data: {
124+
source: 'io-wp-media-library-install',
125+
},
126+
} );
127+
} );
128+
129+
$( '.e-a-apps .e-a-item[data-plugin="image-optimization/image-optimization.php"] a.e-btn' ).on( 'click', function() {
130+
elementorCommon.ajax.addRequest( 'elementor_image_optimization_campaign', {
131+
data: {
132+
source: 'io-esetting-addons-install',
133+
},
134+
} );
135+
} );
136+
121137
$( '#elementor-clear-cache-button' ).on( 'click', function( event ) {
122138
event.preventDefault();
123139
var $thisButton = $( this );

assets/dev/js/admin/hints/media.js

+1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
dismissId: event.target.closest( '.e-hint__container' ).dataset.event,
109109
},
110110
} );
111+
111112
this.hideHint( event );
112113
},
113114

assets/dev/js/editor/controls/gallery.js

+7
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,13 @@ ControlMediaItemView = ControlBaseDataView.extend( {
258258
if ( actionURL ) {
259259
window.open( actionURL, '_blank' );
260260
}
261+
262+
elementorCommon.ajax.addRequest( 'elementor_image_optimization_campaign', {
263+
data: {
264+
source: 'io-editor-gallery-install',
265+
},
266+
} );
267+
261268
this.hidePromotion();
262269
},
263270

assets/dev/js/editor/controls/media.js

+7
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,13 @@ ControlMediaItemView = ControlMultipleBaseItemView.extend( {
221221
if ( ! eventName ) {
222222
eventName = this.getDismissPromotionEventName();
223223
}
224+
225+
elementorCommon.ajax.addRequest( 'elementor_image_optimization_campaign', {
226+
data: {
227+
source: 'io-editor-image-install',
228+
},
229+
} );
230+
224231
// Prevent opening the same promotion again in current editor session.
225232
elementor.config.user.dismissed_editor_notices.push( eventName );
226233
},

core/admin/admin.php

+20
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,8 @@ public function __construct() {
878878
add_action( 'in_plugin_update_message-' . ELEMENTOR_PLUGIN_BASE, function( $plugin_data ) {
879879
$this->version_update_warning( ELEMENTOR_VERSION, $plugin_data['new_version'] );
880880
} );
881+
882+
add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_hints' ] );
881883
}
882884

883885
/**
@@ -987,4 +989,22 @@ private function maybe_enqueue_hints() {
987989

988990
wp_enqueue_script( 'media-hints' );
989991
}
992+
993+
public function register_ajax_hints( $ajax_manager ) {
994+
$ajax_manager->register_ajax_action( 'elementor_image_optimization_campaign', [ $this, 'ajax_set_image_optimization_campaign' ] );
995+
}
996+
997+
public function ajax_set_image_optimization_campaign( $request ) {
998+
if ( empty( $request['source'] ) ) {
999+
return;
1000+
}
1001+
1002+
$campaign_data = [
1003+
'source' => sanitize_key( $request['source'] ),
1004+
'campaign' => 'io-plg',
1005+
'medium' => 'wp-dash',
1006+
];
1007+
1008+
set_transient( 'elementor_image_optimization_campaign', $campaign_data, 30 * DAY_IN_SECONDS );
1009+
}
9901010
}

modules/ai/assets/js/editor/api/index.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
const request = ( endpoint, data = {}, immediately = false, signal ) => {
22
if ( Object.keys( data ).length ) {
3-
data.context = window.elementorAiCurrentContext;
3+
if ( window.elementorAiCurrentContext ) {
4+
data.context = window.elementorAiCurrentContext;
5+
} else {
6+
data.context = window.elementorWpAiCurrentContext;
7+
}
48
}
59

610
return new Promise( ( resolve, reject ) => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { useState } from '@wordpress/element';
2+
import { __ } from '@wordpress/i18n';
3+
import { AiText } from './text-with-ai';
4+
import { AIIcon } from '@elementor/icons';
5+
import React from 'react';
6+
const { ToolbarButton } = wp.components;
7+
const { BlockControls } = wp.blockEditor;
8+
9+
export const EditTextWithAi = ( props ) => {
10+
const [ shouldRenderAiApp, setShouldRenderAiApp ] = useState( false );
11+
const BlockEdit = props.blockEdit;
12+
13+
const supportedBlocks = [ 'core/paragraph', 'core/heading' ];
14+
15+
if ( ! supportedBlocks.includes( props.name ) ) {
16+
return <BlockEdit { ...props } />;
17+
}
18+
19+
if ( shouldRenderAiApp ) {
20+
return <AiText onClose={ () => setShouldRenderAiApp( false ) }
21+
blockName={ props.name }
22+
initialValue={ props.attributes.content ? String( props.attributes.content ) : '' }
23+
blockClientId={ props.clientId }
24+
/>;
25+
}
26+
27+
return (
28+
<>
29+
<BlockControls>
30+
<ToolbarButton
31+
icon={ <AIIcon color="secondary" /> }
32+
label={ __( 'Edit with Elementor AI', 'elementor' ) }
33+
onClick={ () => setShouldRenderAiApp( true ) }
34+
/>
35+
</BlockControls>
36+
{ <BlockEdit { ...props } /> }
37+
</>
38+
);
39+
};
40+
41+
EditTextWithAi.propTypes = {
42+
name: PropTypes.string,
43+
blockEdit: PropTypes.func,
44+
attributes: PropTypes.object,
45+
clientId: PropTypes.string,
46+
};
47+

modules/ai/assets/js/gutenberg/excerpt.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const GenerateExcerptWithAI = () => {
2626
};
2727

2828
return (
29-
<div style={ { paddingBottom: '0.6em' } }>
29+
<div style={ { paddingTop: '0.6em' } }>
3030
<RequestIdsProvider>
3131
<Icon className={ 'eicon-ai' } />
3232
<AiLink onClick={ handleButtonClick }>{ __( 'Generate with Elementor AI', 'elementor' ) }</AiLink>

modules/ai/assets/js/gutenberg/index.js

+61-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { createRoot } from '@wordpress/element';
22
import GenerateExcerptWithAI from './excerpt';
33
import GenerateFeaturedImageWithAI from './featured-image';
44
import { GenerateTextWithAi } from './text-with-ai';
5+
import React from 'react';
6+
import { EditTextWithAi } from './edit-text-with-ai';
57

68
( function() {
79
'use strict';
@@ -48,14 +50,16 @@ import { GenerateTextWithAi } from './text-with-ai';
4850
}
4951
};
5052

51-
const addTextWithAI = ( blockName ) => {
52-
const textPanel = document.querySelector( '.block-editor-block-card__content' );
53-
if ( textPanel && ! document.querySelector( '.e-text-ai' ) ) {
53+
const addTextWithAI = ( blockName, blockClientId ) => {
54+
const textPanel = document.querySelector( '.block-editor-block-card__description, .block-editor-block-card__content' );
55+
if ( textPanel && ! document.querySelector( `.e-text-ai[data-client-id="${ blockClientId }"]` ) ) {
56+
removeAiIndicator();
5457
const rootElement = document.createElement( 'div' );
5558
rootElement.classList.add( 'e-text-ai' );
59+
rootElement.setAttribute( 'data-client-id', blockClientId );
5660
textPanel.appendChild( rootElement );
5761
const root = createRoot( rootElement );
58-
root.render( <GenerateTextWithAi blockName={ blockName } /> );
62+
root.render( <GenerateTextWithAi blockName={ blockName } blockClientId={ blockClientId } /> );
5963
}
6064
};
6165

@@ -78,7 +82,7 @@ import { GenerateTextWithAi } from './text-with-ai';
7882
const addAiIndicatorToTextBlock = ( blockNames ) => {
7983
const selectedBlock = wp.data.select( 'core/block-editor' )?.getSelectedBlock();
8084
if ( selectedBlock && blockNames.some( ( name ) => selectedBlock.name.includes( name ) ) ) {
81-
addTextWithAI( selectedBlock.name );
85+
addTextWithAI( selectedBlock.name, selectedBlock.clientId );
8286
} else {
8387
removeAiIndicator();
8488
}
@@ -89,5 +93,57 @@ import { GenerateTextWithAi } from './text-with-ai';
8993
addAiIndicator( 'featured-image', addGenerateFeaturedImageWithAI );
9094
addAiIndicatorToTextBlock( [ 'paragraph', 'heading' ] );
9195
} );
96+
97+
const observer = new MutationObserver( ( mutationsList ) => {
98+
for ( const mutation of mutationsList ) {
99+
if ( 'childList' === mutation.type ) {
100+
if ( document.querySelector( '.editor-post-excerpt' ) ) {
101+
addGenerateExcerptWithAI();
102+
}
103+
}
104+
}
105+
} );
106+
107+
observer.observe( document.body, { childList: true, subtree: true } );
108+
window.addEventListener( 'beforeunload', () => {
109+
observer.disconnect();
110+
} );
92111
} );
93112
} )( jQuery );
113+
114+
( function( wp ) {
115+
const { addFilter } = wp.hooks;
116+
117+
const addAiButtonToToolbar = ( BlockEdit ) => {
118+
return ( props ) => {
119+
return <EditTextWithAi { ...props } blockEdit={ BlockEdit } />;
120+
};
121+
};
122+
123+
addFilter( 'editor.BlockEdit', 'elementor-ai-toolbar-button', addAiButtonToToolbar );
124+
} )( window.wp );
125+
126+
( function() {
127+
'use strict';
128+
129+
const setElementorWpAiCurrentContext = () => {
130+
const selectedBlock = wp.data.select( 'core/block-editor' ).getSelectedBlock();
131+
if ( selectedBlock ) {
132+
const blockName = 'core/heading' === selectedBlock.name ? 'heading' : selectedBlock.name;
133+
window.elementorWpAiCurrentContext = {
134+
widgetType: blockName,
135+
controlName: blockName,
136+
};
137+
} else {
138+
window.elementorWpAiCurrentContext = null;
139+
}
140+
};
141+
142+
wp.data.subscribe( setElementorWpAiCurrentContext );
143+
144+
const clearElementorAiCurrentContext = () => {
145+
window.elementorWpAiCurrentContext = null;
146+
};
147+
148+
window.addEventListener( 'beforeunload', clearElementorAiCurrentContext );
149+
} )();

modules/ai/assets/js/gutenberg/text-with-ai.js

+10-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import PropTypes from 'prop-types';
99
const { useDispatch, useSelect } = wp.data;
1010
const { createBlock } = wp.blocks;
1111

12-
const AiText = ( { onClose, blockName } ) => {
12+
export const AiText = ( { onClose, blockName, initialValue = '', blockClientId = '' } ) => {
1313
const { replaceBlocks, insertBlocks } = useDispatch( 'core/block-editor' );
1414
const insertTextIntoParagraph = ( text ) => {
1515
if ( paragraphBlock ) {
@@ -31,7 +31,7 @@ const AiText = ( { onClose, blockName } ) => {
3131

3232
const { paragraphBlock } = useSelect( ( ) => {
3333
const currentBlocks = wp.data.select( 'core/block-editor' )?.getBlocks();
34-
const foundParagraphBlock = currentBlocks.find( ( block ) => blockName === block.name );
34+
const foundParagraphBlock = currentBlocks.find( ( block ) => blockName === block.name && blockClientId === block.clientId );
3535
return {
3636
blocks: currentBlocks,
3737
paragraphBlock: foundParagraphBlock,
@@ -44,7 +44,9 @@ const AiText = ( { onClose, blockName } ) => {
4444
<>
4545
<App
4646
type={ appType }
47-
getControlValue={ () => {} }
47+
getControlValue={ () => {
48+
return initialValue;
49+
} }
4850
setControlValue={ ( value ) => {
4951
insertTextIntoParagraph( value );
5052
} }
@@ -59,9 +61,11 @@ const AiText = ( { onClose, blockName } ) => {
5961
AiText.propTypes = {
6062
onClose: PropTypes.func.isRequired,
6163
blockName: PropTypes.string.isRequired,
64+
initialValue: PropTypes.string,
65+
blockClientId: PropTypes.string,
6266
};
6367

64-
export const GenerateTextWithAi = ( { blockName } ) => {
68+
export const GenerateTextWithAi = ( { blockName, blockClientId } ) => {
6569
const [ isOpen, setIsOpen ] = useState( false );
6670

6771
const handleButtonClick = () => {
@@ -77,11 +81,12 @@ export const GenerateTextWithAi = ( { blockName } ) => {
7781
<RequestIdsProvider>
7882
<Icon className={ 'eicon-ai' } />
7983
<AiLink onClick={ handleButtonClick }>{ __( 'Generate with Elementor AI', 'elementor' ) }</AiLink>
80-
{ isOpen && <AiText onClose={ handleClose } blockName={ blockName } /> }
84+
{ isOpen && <AiText onClose={ handleClose } blockName={ blockName } blockClientId={ blockClientId } /> }
8185
</RequestIdsProvider>
8286
</div> );
8387
};
8488

8589
GenerateTextWithAi.propTypes = {
8690
blockName: PropTypes.string.isRequired,
91+
blockClientId: PropTypes.string.isRequired,
8792
};

modules/ai/module.php

+4
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ public function __construct() {
119119
'wp-element',
120120
'wp-editor',
121121
'wp-data',
122+
'wp-components',
123+
'wp-compose',
124+
'wp-i18n',
125+
'wp-hooks',
122126
],
123127
ELEMENTOR_VERSION, true );
124128

modules/apps/admin-apps-page.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ private static function is_elementor_pro_installed() {
163163

164164
private static function render_plugin_item( $plugin ) {
165165
?>
166-
<div class="e-a-item">
166+
<div class="e-a-item"<?php echo ! empty( $plugin['file_path'] ) ? ' data-plugin="' . esc_attr( $plugin['file_path'] ) . '"' : ''; ?>>
167167
<div class="e-a-heading">
168168
<img class="e-a-img" src="<?php echo esc_url( $plugin['image'] ); ?>" alt="<?php echo esc_attr( $plugin['name'] ); ?>">
169169
<?php if ( ! empty( $plugin['badge'] ) ) : ?>

0 commit comments

Comments
 (0)