@elementor/elementor-mcp-common 4.1.0-754

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,158 @@
1
+ import { ensureElementorFrontend, isGutenbergEditor } from './editor-detection';
2
+ import { get$e, getElementor, getElementorFrontend, getWp } from './utils';
3
+
4
+ interface GutenbergBlockEditorDispatch {
5
+ updateBlockAttributes: ( clientId: string, attributes: Record< string, unknown > ) => void;
6
+ }
7
+
8
+ interface GutenbergBlockEditorSelect {
9
+ getBlock: ( clientId: string ) => { name: string } | null;
10
+ }
11
+
12
+ interface GutenbergBlock {
13
+ name: string;
14
+ }
15
+
16
+ export function injectElementCSS( elementId: string, css: string ): void {
17
+ const style = document.createElement( 'style' );
18
+ style.id = elementId;
19
+ style.appendChild( document.createTextNode( css ) );
20
+
21
+ ensureElementorFrontend();
22
+ const frontend = getElementorFrontend() as { elements: { $body: HTMLElement[] } } | undefined;
23
+ if ( frontend ) {
24
+ frontend.elements.$body[ 0 ].appendChild( style );
25
+ }
26
+ }
27
+
28
+ export function removeElementCSS( elementId: string ): void {
29
+ ensureElementorFrontend();
30
+ const frontend = getElementorFrontend() as { elements: { $body: HTMLElement[] } } | undefined;
31
+ if ( ! frontend ) {
32
+ return;
33
+ }
34
+
35
+ const bodyElement = frontend.elements.$body[ 0 ];
36
+ const styleTags = bodyElement.querySelectorAll( `#${ CSS.escape( elementId ) }` );
37
+
38
+ if ( styleTags?.length > 0 ) {
39
+ styleTags.forEach( ( tag: Element ) => {
40
+ bodyElement.removeChild( tag );
41
+ } );
42
+ }
43
+ }
44
+
45
+ export async function updateElementSettings( {
46
+ id,
47
+ settings,
48
+ }: {
49
+ id: string;
50
+ settings: Record< string, unknown >;
51
+ } ): Promise< unknown > {
52
+ const containerToUpdateSettings = getElementor()?.getContainer( id );
53
+ if ( ! containerToUpdateSettings ) {
54
+ throw new Error( `Element with ID "${ id }" not found.` );
55
+ }
56
+
57
+ const updateResult = await get$e()?.run( 'document/elements/settings', {
58
+ container: containerToUpdateSettings,
59
+ settings,
60
+ options: {
61
+ external: true,
62
+ render: true,
63
+ },
64
+ } );
65
+
66
+ const frontend = getElementorFrontend() as { elements: { $body: { resize: () => void } } } | undefined;
67
+ frontend?.elements.$body.resize();
68
+
69
+ return updateResult;
70
+ }
71
+
72
+ export function getElementSettings( id: string ): unknown {
73
+ const container = getElementor()?.getContainer( id );
74
+ if ( ! container ) {
75
+ throw new Error( `Element with ID "${ id }" not found.` );
76
+ }
77
+ return container.settings;
78
+ }
79
+
80
+ export function getGutenbergBlockEditorApis(): {
81
+ blockEditorDispatch: GutenbergBlockEditorDispatch;
82
+ blockEditorSelect: GutenbergBlockEditorSelect;
83
+ } {
84
+ const wp = getWp();
85
+ if ( ! isGutenbergEditor() || ! wp ) {
86
+ throw new Error( 'WordPress editor API is not available' );
87
+ }
88
+
89
+ const blockEditorDispatch = wp.data.dispatch( 'core/block-editor' ) as unknown as GutenbergBlockEditorDispatch;
90
+ const blockEditorSelect = wp.data.select( 'core/block-editor' ) as unknown as GutenbergBlockEditorSelect;
91
+
92
+ if ( ! blockEditorDispatch || ! blockEditorSelect ) {
93
+ throw new Error( 'Block editor API is not available' );
94
+ }
95
+
96
+ return { blockEditorDispatch, blockEditorSelect };
97
+ }
98
+
99
+ export function validateAndGetGutenbergBlock(
100
+ blockEditorSelect: GutenbergBlockEditorSelect,
101
+ blockId: string
102
+ ): GutenbergBlock {
103
+ const block = blockEditorSelect.getBlock( blockId );
104
+ if ( ! block ) {
105
+ throw new Error( `Block with ID "${ blockId }" not found` );
106
+ }
107
+ return block;
108
+ }
109
+
110
+ export function updateGutenbergBlockAttributes(
111
+ blockId: string,
112
+ attributes: Record< string, unknown >
113
+ ): { blockId: string; blockName: string; updatedAttributes: string[] } {
114
+ const { blockEditorDispatch, blockEditorSelect } = getGutenbergBlockEditorApis();
115
+ const block = validateAndGetGutenbergBlock( blockEditorSelect, blockId );
116
+
117
+ blockEditorDispatch.updateBlockAttributes( blockId, attributes );
118
+
119
+ return {
120
+ blockId,
121
+ blockName: block.name,
122
+ updatedAttributes: Object.keys( attributes ),
123
+ };
124
+ }
125
+
126
+ export function extractElementImageData(
127
+ targetElementId: string,
128
+ fallbackImageId = '',
129
+ fallbackImageUrl = ''
130
+ ): { imageId: string; imageUrl: string } {
131
+ let extractedImageId = fallbackImageId;
132
+ let extractedImageUrl = fallbackImageUrl;
133
+
134
+ if ( targetElementId && ( ! extractedImageId || ! extractedImageUrl ) ) {
135
+ const targetContainer = getElementor()?.getContainer?.( targetElementId );
136
+ if ( targetContainer ) {
137
+ const imageData = targetContainer.settings.get( 'image' );
138
+ if ( imageData && typeof imageData === 'object' ) {
139
+ const imageObj = imageData as { id?: string | number; url?: string };
140
+ extractedImageId = extractedImageId || imageObj.id?.toString() || '';
141
+ extractedImageUrl = extractedImageUrl || imageObj.url || '';
142
+ }
143
+ }
144
+ }
145
+
146
+ return {
147
+ imageId: extractedImageId,
148
+ imageUrl: extractedImageUrl,
149
+ };
150
+ }
151
+
152
+ export function isSelectAllCheckbox( input: HTMLInputElement ): boolean {
153
+ if ( ( input.id && input.id.includes( 'select-all' ) ) || ( input.name && input.name.includes( 'select-all' ) ) ) {
154
+ return true;
155
+ }
156
+
157
+ return false;
158
+ }
package/src/index.ts ADDED
@@ -0,0 +1,52 @@
1
+ export {
2
+ isGutenbergEditor,
3
+ isElementorEditor,
4
+ isElementorAIActive,
5
+ hasGutenbergUI,
6
+ ensureElementorFrontend,
7
+ isElementorEditorReady,
8
+ waitForElementorEditor,
9
+ waitForElementor,
10
+ whenElementorReady,
11
+ } from './editor-detection';
12
+
13
+ export {
14
+ injectElementCSS,
15
+ removeElementCSS,
16
+ updateElementSettings,
17
+ getElementSettings,
18
+ getGutenbergBlockEditorApis,
19
+ validateAndGetGutenbergBlock,
20
+ updateGutenbergBlockAttributes,
21
+ extractElementImageData,
22
+ isSelectAllCheckbox,
23
+ } from './elements';
24
+
25
+ export { callWpApi, extractJSONFromResponse } from './rest-client';
26
+
27
+ export { initNonceRefresh, refreshNonce, isNonceError } from './nonce-refresh';
28
+
29
+ export type {
30
+ ElementorChannels,
31
+ ElementorCommandsInstance,
32
+ ElementorCommonInstance,
33
+ ElementorContainer,
34
+ ElementorDocument,
35
+ ElementorFrontendInstance,
36
+ ElementorInstance,
37
+ JQuery,
38
+ WpApiSettings,
39
+ WpDataInstance,
40
+ } from './types';
41
+
42
+ export {
43
+ get$e,
44
+ getAjaxUrl,
45
+ getElementor,
46
+ getElementorAiConfig,
47
+ getElementorCommon,
48
+ getElementorFrontend,
49
+ getJQuery,
50
+ getWp,
51
+ getWpApiSettings,
52
+ } from './utils';
@@ -0,0 +1,76 @@
1
+ import type { WpApiSettings } from './types';
2
+ import { getAjaxUrl, getJQuery, getWpApiSettings } from './utils';
3
+
4
+ type HeartbeatTickData = {
5
+ angie_nonce?: string;
6
+ };
7
+
8
+ let isNonceRefreshInitialized = false;
9
+ let nonceRefreshPromise: Promise< string > | null = null;
10
+
11
+ export function initNonceRefresh(): void {
12
+ const jQuery = getJQuery();
13
+ const wpApiSettings = getWpApiSettings();
14
+ if ( isNonceRefreshInitialized || typeof jQuery === 'undefined' || ! wpApiSettings ) {
15
+ return;
16
+ }
17
+
18
+ isNonceRefreshInitialized = true;
19
+
20
+ jQuery?.( document ).on( 'heartbeat-tick.angieNonceRefresh', ( _event: unknown, data: unknown ) => {
21
+ try {
22
+ const tickData = data as HeartbeatTickData;
23
+ const currentSettings = getWpApiSettings() as WpApiSettings | undefined;
24
+ if ( tickData.angie_nonce && currentSettings && currentSettings.nonce !== tickData.angie_nonce ) {
25
+ currentSettings.nonce = tickData.angie_nonce;
26
+ }
27
+ } catch ( error ) {
28
+ // eslint-disable-next-line no-console
29
+ console.error( 'Failed to refresh nonce:', error );
30
+ }
31
+ } );
32
+ }
33
+
34
+ export async function refreshNonce(): Promise< string > {
35
+ if ( nonceRefreshPromise ) {
36
+ return nonceRefreshPromise;
37
+ }
38
+
39
+ nonceRefreshPromise = fetchFreshNonce();
40
+
41
+ try {
42
+ return await nonceRefreshPromise;
43
+ } finally {
44
+ nonceRefreshPromise = null;
45
+ }
46
+ }
47
+
48
+ async function fetchFreshNonce(): Promise< string > {
49
+ const ajaxUrl = new URL( getAjaxUrl() || '/wp-admin/admin-ajax.php', window.location.origin );
50
+ ajaxUrl.searchParams.set( 'action', 'rest-nonce' );
51
+ const response = await fetch( ajaxUrl.toString(), {
52
+ credentials: 'same-origin',
53
+ } );
54
+
55
+ if ( ! response.ok ) {
56
+ throw new Error( `Failed to refresh nonce: HTTP ${ response.status }` );
57
+ }
58
+
59
+ const nonce = await response.text();
60
+
61
+ if ( ! nonce || nonce === '0' ) {
62
+ throw new Error( 'Session expired — received invalid nonce' );
63
+ }
64
+
65
+ const wpApiSettings = getWpApiSettings() as WpApiSettings | undefined;
66
+ if ( ! wpApiSettings ) {
67
+ throw new Error( 'wpApiSettings not available — cannot refresh nonce' );
68
+ }
69
+
70
+ wpApiSettings.nonce = nonce;
71
+ return nonce;
72
+ }
73
+
74
+ export function isNonceError( status: number, responseText: string ): boolean {
75
+ return status === 403 && responseText.includes( 'rest_cookie_invalid_nonce' );
76
+ }
@@ -0,0 +1,163 @@
1
+ import { isNonceError, refreshNonce } from './nonce-refresh';
2
+ import { getWpApiSettings } from './utils';
3
+
4
+ type WpApiResponse = unknown;
5
+
6
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS';
7
+
8
+ type CallWpApiOptions = {
9
+ binaryData?: ArrayBufferLike;
10
+ customHeaders?: Record< string, string >;
11
+ };
12
+
13
+ type CallWpApiResult< T > = {
14
+ data: T;
15
+ totalItems?: number;
16
+ totalPages?: number;
17
+ };
18
+
19
+ export async function callWpApi< T = WpApiResponse >(
20
+ endpoint: string,
21
+ method: HttpMethod,
22
+ data?: Record< string, unknown >,
23
+ options?: CallWpApiOptions
24
+ ): Promise< CallWpApiResult< T > > {
25
+ return executeWpApiCall< T >( endpoint, method, data, options, true );
26
+ }
27
+
28
+ async function executeWpApiCall< T = WpApiResponse >(
29
+ endpoint: string,
30
+ method: HttpMethod,
31
+ data?: Record< string, unknown >,
32
+ options?: CallWpApiOptions,
33
+ allowNonceRetry = false
34
+ ): Promise< CallWpApiResult< T > > {
35
+ const wpApiSettings = getWpApiSettings();
36
+ if ( ! wpApiSettings?.nonce || ! wpApiSettings.root ) {
37
+ throw new Error( 'wpApiSettings not available' );
38
+ }
39
+
40
+ const baseUrl = wpApiSettings.root;
41
+ const urlObject = new URL( baseUrl );
42
+ const endpointUrl = new URL( endpoint, baseUrl );
43
+
44
+ urlObject.searchParams.set( 'rest_route', endpointUrl.pathname );
45
+
46
+ for ( const [ key, value ] of endpointUrl.searchParams.entries() ) {
47
+ urlObject.searchParams.append( key, value );
48
+ }
49
+
50
+ const url = urlObject.toString();
51
+
52
+ const headers: Record< string, string > = {
53
+ 'X-WP-Nonce': wpApiSettings.nonce,
54
+ ...( options?.customHeaders || {} ),
55
+ };
56
+
57
+ if ( ! options?.binaryData && ! options?.customHeaders?.[ 'Content-Type' ] ) {
58
+ headers[ 'Content-Type' ] = 'application/json';
59
+ }
60
+
61
+ const requestOptions: RequestInit = {
62
+ method,
63
+ headers,
64
+ credentials: 'same-origin',
65
+ };
66
+
67
+ if ( options?.binaryData ) {
68
+ requestOptions.body = options.binaryData as ArrayBuffer;
69
+ } else if ( data && ( method === 'POST' || method === 'PUT' || method === 'PATCH' ) ) {
70
+ requestOptions.body = JSON.stringify( data );
71
+ }
72
+
73
+ const response = await fetch( url, requestOptions );
74
+
75
+ if ( ! response.ok ) {
76
+ const responseText = await response.text();
77
+
78
+ if ( allowNonceRetry && isNonceError( response.status, responseText ) ) {
79
+ await refreshNonce();
80
+ return executeWpApiCall< T >( endpoint, method, data, options, false );
81
+ }
82
+
83
+ throw new Error( `HTTP error ${ response.status }: ${ responseText }` );
84
+ }
85
+
86
+ const responseText = await response.text();
87
+ const json = extractJSONFromResponse( responseText );
88
+
89
+ if ( json === null ) {
90
+ throw new Error( `Invalid response: no JSON found in: ${ responseText.substring( 0, 200 ) }` );
91
+ }
92
+
93
+ const jsonObj = json as { success?: boolean };
94
+ if ( jsonObj?.success !== undefined && ! jsonObj.success ) {
95
+ throw new Error( `API errors: ${ JSON.stringify( json ) }` );
96
+ }
97
+
98
+ const totalItemsHeader = response.headers.get( 'X-WP-Total' );
99
+ const totalPagesHeader = response.headers.get( 'X-WP-TotalPages' );
100
+ const totalItems: number | undefined = totalItemsHeader ? parseInt( totalItemsHeader, 10 ) : undefined;
101
+ const totalPages: number | undefined = totalPagesHeader ? parseInt( totalPagesHeader, 10 ) : undefined;
102
+
103
+ return {
104
+ data: json as T,
105
+ totalItems,
106
+ totalPages,
107
+ };
108
+ }
109
+
110
+ export function extractJSONFromResponse( responseText: string ): unknown {
111
+ const objectStart = responseText.indexOf( '{' );
112
+ const arrayStart = responseText.indexOf( '[' );
113
+
114
+ let startIndex = -1;
115
+ let isArray = false;
116
+
117
+ if ( objectStart === -1 && arrayStart === -1 ) {
118
+ return null;
119
+ }
120
+
121
+ if ( objectStart === -1 ) {
122
+ startIndex = arrayStart;
123
+ isArray = true;
124
+ } else if ( arrayStart === -1 ) {
125
+ startIndex = objectStart;
126
+ isArray = false;
127
+ } else if ( arrayStart < objectStart ) {
128
+ startIndex = arrayStart;
129
+ isArray = true;
130
+ } else {
131
+ startIndex = objectStart;
132
+ isArray = false;
133
+ }
134
+
135
+ let delimiterCount = 0;
136
+ let endIndex = -1;
137
+ const openChar = isArray ? '[' : '{';
138
+ const closeChar = isArray ? ']' : '}';
139
+
140
+ for ( let i = startIndex; i < responseText.length; i++ ) {
141
+ if ( responseText[ i ] === openChar ) {
142
+ delimiterCount++;
143
+ } else if ( responseText[ i ] === closeChar ) {
144
+ delimiterCount--;
145
+ if ( delimiterCount === 0 ) {
146
+ endIndex = i;
147
+ break;
148
+ }
149
+ }
150
+ }
151
+
152
+ if ( endIndex === -1 ) {
153
+ return null;
154
+ }
155
+
156
+ const jsonString = responseText.substring( startIndex, endIndex + 1 );
157
+
158
+ try {
159
+ return JSON.parse( jsonString );
160
+ } catch {
161
+ return null;
162
+ }
163
+ }
package/src/types.ts ADDED
@@ -0,0 +1,186 @@
1
+ export interface WpApiSettings {
2
+ nonce: string;
3
+ root: string;
4
+ }
5
+
6
+ export interface ElementorContainer {
7
+ id: string;
8
+ model: {
9
+ id: string;
10
+ get: ( key: string ) => unknown;
11
+ attributes?: Record< string, unknown >;
12
+ editor_settings?: { title?: string };
13
+ };
14
+ settings: {
15
+ get: ( key: string ) => unknown;
16
+ attributes?: Record< string, unknown >;
17
+ controls?: Record< string, unknown >;
18
+ };
19
+ children?: ElementorContainer[];
20
+ view?: {
21
+ el: HTMLElement;
22
+ };
23
+ parent?: ElementorContainer;
24
+ }
25
+
26
+ export interface ElementorDocument {
27
+ id: string;
28
+ container: ElementorContainer;
29
+ config?: {
30
+ type?: string;
31
+ settings?: Record< string, unknown >;
32
+ };
33
+ editor?: {
34
+ status?: string;
35
+ isChanged?: boolean;
36
+ };
37
+ history?: {
38
+ active?: boolean;
39
+ setActive?: ( active: boolean ) => void;
40
+ };
41
+ }
42
+
43
+ export interface ElementorChannels {
44
+ deviceMode?: {
45
+ request: ( key?: string ) => unknown;
46
+ };
47
+ dataEditMode?: {
48
+ request: ( key?: string ) => unknown;
49
+ };
50
+ }
51
+
52
+ export interface ElementorInstance {
53
+ documents: {
54
+ getCurrent: () => ElementorDocument | null;
55
+ get?: ( id: string | number ) => ElementorDocument | null;
56
+ };
57
+ getContainer: ( id: string ) => ElementorContainer | null;
58
+ getCurrentElement: () => { model: { id: string } } | null;
59
+ on: ( event: string, callback: () => void ) => void;
60
+ config?: {
61
+ responsive?: {
62
+ breakpoints?: Record< string, unknown >;
63
+ };
64
+ controls?: Record< string, unknown >;
65
+ v4Promotions?: Record< string, unknown >;
66
+ default_schemes?: Record< string, unknown >;
67
+ atomicDynamicTags?: {
68
+ tags?: Record< string, unknown >;
69
+ groups?: Record< string, unknown >;
70
+ };
71
+ };
72
+ helpers?: {
73
+ hasPro?: () => boolean;
74
+ enqueueFont?: ( font: string ) => void;
75
+ };
76
+ $preview?: [ HTMLIFrameElement ];
77
+ selection?: {
78
+ elements?: Record< string, unknown >;
79
+ getElements?: () => unknown[];
80
+ };
81
+ hooks?: {
82
+ addFilter: ( name: string, callback: ( ...args: unknown[] ) => unknown ) => void;
83
+ };
84
+ dynamicTags?: {
85
+ getConfig: ( key: string ) => Record< string, unknown >;
86
+ tagDataToTagText: ( id: string, name: string, settings: Record< string, unknown > ) => string;
87
+ createTag?: ( options: Record< string, unknown > ) => unknown;
88
+ loadTagDataFromCache?: ( tag: unknown, key: string ) => unknown;
89
+ refreshCacheFromServer?: ( tag: unknown, callback: () => void ) => void;
90
+ };
91
+ widgetsCache?: Record<
92
+ string,
93
+ {
94
+ controls?: Record< string, unknown >;
95
+ title?: string;
96
+ atomic_controls?: unknown[];
97
+ }
98
+ >;
99
+ channels?: ElementorChannels;
100
+ getPanelView?: () => {
101
+ getHeaderView?: () => {
102
+ setTitle?: ( title: string ) => void;
103
+ };
104
+ getCurrentPageView?: () => unknown;
105
+ };
106
+ getPreferences?: ( key: string ) => unknown;
107
+ changeEditMode?: ( mode: string ) => void;
108
+ modules?: Record< string, unknown >;
109
+ }
110
+
111
+ export interface ElementorFrontendInstance {
112
+ elements: {
113
+ $body: JQuery & HTMLElement[];
114
+ };
115
+ on: ( event: string, callback: () => void ) => void;
116
+ config?: {
117
+ responsive?: {
118
+ activeBreakpoints?: Record< string, unknown >;
119
+ };
120
+ kit?: {
121
+ active_breakpoints?: string[];
122
+ };
123
+ experimentalFeatures?: Record< string, boolean >;
124
+ is_rtl?: boolean;
125
+ };
126
+ }
127
+
128
+ export interface ElementorCommandsInstance {
129
+ run: ( command: string, args?: Record< string, unknown > ) => Promise< unknown >;
130
+ components: {
131
+ get: ( name: string ) => {
132
+ getCommands?: () => {
133
+ open?: { registerConfig: { command: string } };
134
+ close?: { registerConfig: { command: string } };
135
+ };
136
+ getNamespace?: () => string;
137
+ } | null;
138
+ getAll?: () => string[];
139
+ };
140
+ routes?: {
141
+ getAll?: () => string[];
142
+ isPartOf?: ( route: string ) => boolean;
143
+ to?: ( route: string, args?: Record< string, unknown > ) => void;
144
+ register?: ( route: string, callback: () => void ) => void;
145
+ saveState?: ( namespace: string ) => void;
146
+ back?: ( namespace: string ) => void;
147
+ getComponent?: ( route: string ) => { getNamespace: () => string };
148
+ };
149
+ data?: {
150
+ get?: ( key: string ) => Promise< unknown >;
151
+ };
152
+ modules?: {
153
+ hookData?: Record< string, unknown >;
154
+ };
155
+ }
156
+
157
+ export interface WpDataInstance {
158
+ select: ( store: string ) => Record< string, unknown > | undefined;
159
+ dispatch: ( store: string ) => Record< string, unknown >;
160
+ }
161
+
162
+ export interface JQuery {
163
+ resize: () => void;
164
+ [ index: number ]: HTMLElement;
165
+ }
166
+
167
+ export interface ElementorCommonInstance {
168
+ eventsManager?: {
169
+ dispatchEvent?: ( name: string, data: unknown, options?: Record< string, unknown > ) => void;
170
+ canSendEvents?: () => boolean;
171
+ initializeMixpanel?: ( onLoaded: ( mpInstance?: unknown ) => void ) => void;
172
+ config?: Record< string, unknown >;
173
+ };
174
+ config?: {
175
+ isRTL?: boolean;
176
+ version?: string;
177
+ experimentalFeatures?: Record< string, boolean >;
178
+ urls?: Record< string, string >;
179
+ };
180
+ helpers?: {
181
+ getUniqueId?: () => number | string;
182
+ };
183
+ ajax?: {
184
+ addRequest?: ( endpoint: string, options: { success?: ( data: unknown ) => void } ) => Promise< void >;
185
+ };
186
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,46 @@
1
+ import type {
2
+ ElementorCommandsInstance,
3
+ ElementorCommonInstance,
4
+ ElementorFrontendInstance,
5
+ ElementorInstance,
6
+ WpApiSettings,
7
+ WpDataInstance,
8
+ } from './types';
9
+
10
+ interface McpWindow {
11
+ elementor?: ElementorInstance;
12
+ elementorFrontend?: ElementorFrontendInstance;
13
+ $e?: ElementorCommandsInstance;
14
+ elementorCommon?: ElementorCommonInstance;
15
+ wpApiSettings?: WpApiSettings;
16
+ ajaxurl?: string;
17
+ wp?: {
18
+ data: WpDataInstance;
19
+ };
20
+ jQuery?: ( selector: unknown ) => {
21
+ on: ( event: string, callback: ( event: unknown, data: unknown ) => void ) => void;
22
+ get?: ( index: number ) => HTMLElement;
23
+ };
24
+ ElementorAiConfig?: Record< string, unknown >;
25
+ }
26
+
27
+ export const getElementor = (): ElementorInstance | undefined => ( window as unknown as McpWindow ).elementor;
28
+
29
+ export const getElementorFrontend = (): ElementorFrontendInstance | undefined =>
30
+ ( window as unknown as McpWindow ).elementorFrontend;
31
+
32
+ export const get$e = (): ElementorCommandsInstance | undefined => ( window as unknown as McpWindow ).$e;
33
+
34
+ export const getElementorCommon = (): ElementorCommonInstance | undefined =>
35
+ ( window as unknown as McpWindow ).elementorCommon;
36
+
37
+ export const getWpApiSettings = (): WpApiSettings | undefined => ( window as unknown as McpWindow ).wpApiSettings;
38
+
39
+ export const getAjaxUrl = (): string | undefined => ( window as unknown as McpWindow ).ajaxurl;
40
+
41
+ export const getWp = (): { data: WpDataInstance } | undefined => ( window as unknown as McpWindow ).wp;
42
+
43
+ export const getJQuery = (): McpWindow[ 'jQuery' ] => ( window as unknown as McpWindow ).jQuery;
44
+
45
+ export const getElementorAiConfig = (): Record< string, unknown > | undefined =>
46
+ ( window as unknown as McpWindow ).ElementorAiConfig;