Skip to content

Commit 0f58474

Browse files
committed
fix: elementor widget; onboarding link and css
1 parent 7676f45 commit 0f58474

File tree

7 files changed

+151
-80
lines changed

7 files changed

+151
-80
lines changed

classes/Visualizer/Elementor/Widget.php

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,106 @@
3636
*/
3737
class Visualizer_Elementor_Widget extends \Elementor\Widget_Base {
3838

39+
/**
40+
* Register all Elementor-related hooks for the Visualizer widget.
41+
*
42+
* Called once from index.php on the plugins_loaded action (after Elementor
43+
* itself is confirmed present). Each inner hook fires at its normal time in
44+
* the WordPress lifecycle, so timing is identical to registering them
45+
* directly in visualizer_launch().
46+
*
47+
* @return void
48+
*/
49+
public static function register_hooks() {
50+
// Register the widget with Elementor's widget manager.
51+
add_action(
52+
'elementor/widgets/register',
53+
function ( $widgets_manager ) {
54+
$widgets_manager->register( new self() );
55+
}
56+
);
57+
58+
// Register the Visualizer icon for the Elementor widget panel.
59+
add_action(
60+
'elementor/editor/after_enqueue_styles',
61+
function () {
62+
$icon_url = VISUALIZER_ABSURL . 'images/visualizer-icon.svg';
63+
wp_add_inline_style(
64+
'elementor-icons',
65+
'.visualizer-elementor-icon { display:inline-block; width:1em; height:1em; background:url("' . esc_url( $icon_url ) . '") no-repeat center/contain; }'
66+
);
67+
}
68+
);
69+
70+
// Enqueue Visualizer scripts inside the Elementor preview iframe.
71+
// Elementor serves the preview iframe as a shell page and injects widget HTML via
72+
// JavaScript (innerHTML), so wp_enqueue_script calls inside render() never reach the
73+
// iframe. We load all chart render libraries here so they are available when
74+
// elementor-widget-preview.js triggers visualizer:render:chart:start.
75+
add_action(
76+
'elementor/preview/enqueue_scripts',
77+
function () {
78+
do_action( 'visualizer_enqueue_scripts' );
79+
80+
// ChartJS render library.
81+
if ( ! wp_script_is( 'numeral', 'registered' ) ) {
82+
wp_register_script( 'numeral', VISUALIZER_ABSURL . 'js/lib/numeral.min.js', array(), Visualizer_Plugin::VERSION, true );
83+
}
84+
if ( ! wp_script_is( 'chartjs', 'registered' ) ) {
85+
wp_register_script( 'chartjs', VISUALIZER_ABSURL . 'js/lib/chartjs.min.js', array( 'numeral' ), null, true );
86+
}
87+
wp_enqueue_script( 'visualizer-render-chartjs-lib', VISUALIZER_ABSURL . 'js/render-chartjs.js', array( 'chartjs', 'visualizer-customization' ), Visualizer_Plugin::VERSION, true );
88+
89+
// Google Charts render library.
90+
wp_enqueue_script( 'visualizer-google-jsapi', '//www.gstatic.com/charts/loader.js', array(), null, true );
91+
wp_enqueue_script( 'visualizer-render-google-lib', VISUALIZER_ABSURL . 'js/render-google.js', array( 'visualizer-google-jsapi', 'visualizer-customization' ), Visualizer_Plugin::VERSION, true );
92+
93+
// DataTable render library + styles.
94+
if ( ! wp_script_is( 'visualizer-datatables', 'registered' ) ) {
95+
wp_register_script( 'visualizer-datatables', VISUALIZER_ABSURL . 'js/lib/datatables.min.js', array( 'jquery' ), Visualizer_Plugin::VERSION, true );
96+
}
97+
wp_enqueue_script( 'visualizer-render-datatables-lib', VISUALIZER_ABSURL . 'js/render-datatables.js', array( 'visualizer-datatables', 'visualizer-customization' ), Visualizer_Plugin::VERSION, true );
98+
wp_enqueue_style( 'visualizer-datatables', VISUALIZER_ABSURL . 'css/lib/datatables.min.css', array(), Visualizer_Plugin::VERSION );
99+
100+
// D3 render library (AI charts).
101+
$d3_renderer_asset = VISUALIZER_ABSPATH . '/classes/Visualizer/D3Renderer/build/index.asset.php';
102+
if ( file_exists( $d3_renderer_asset ) && ! wp_script_is( 'visualizer-d3-renderer', 'registered' ) ) {
103+
$d3_asset = include $d3_renderer_asset;
104+
wp_register_script(
105+
'visualizer-d3-renderer',
106+
VISUALIZER_ABSURL . 'classes/Visualizer/D3Renderer/build/index.js',
107+
array_merge( $d3_asset['dependencies'], array( 'jquery' ) ),
108+
$d3_asset['version'],
109+
true
110+
);
111+
}
112+
if ( wp_script_is( 'visualizer-d3-renderer', 'registered' ) ) {
113+
wp_enqueue_script( 'visualizer-d3-renderer' );
114+
wp_localize_script(
115+
'visualizer-d3-renderer',
116+
'vizD3Renderer',
117+
array(
118+
'iframeJsUrl' => VISUALIZER_ABSURL . 'classes/Visualizer/D3Renderer/build/iframe.js',
119+
)
120+
);
121+
}
122+
123+
// Elementor widget preview handler — uses frontend/element_ready hook.
124+
wp_enqueue_script( 'visualizer-elementor-preview', VISUALIZER_ABSURL . 'js/elementor-widget-preview.js', array( 'jquery', 'elementor-frontend' ), Visualizer_Plugin::VERSION, true );
125+
126+
// Prevent Elementor's editor-preview CSS from hiding our widget.
127+
// Elementor marks widgets without a content_template() as elementor-widget-empty
128+
// and adds display:none to .elementor-widget-empty when the panel is hidden
129+
// (.elementor-editor-preview on <body>). Our widget renders async (Google Charts
130+
// loads via callback), so the empty class is always present.
131+
wp_add_inline_style(
132+
'visualizer-datatables',
133+
'.elementor-editor-preview .elementor-widget-visualizer-chart.elementor-widget-empty { display: block !important; }'
134+
);
135+
}
136+
);
137+
}
138+
39139
/**
40140
* Get widget name.
41141
*
@@ -239,7 +339,7 @@ protected function render() {
239339
// via elementor/preview/enqueue_scripts; injecting render-facade.js would add
240340
// a second visualizer:render:chart:start trigger causing duplicate renders.
241341
foreach ( wp_scripts()->queue as $handle ) {
242-
if ( 0 === strpos( $handle, 'visualizer-render-' )
342+
if ( ( 0 === strpos( $handle, 'visualizer-render-' ) || 'visualizer-d3-renderer' === $handle )
243343
&& 'visualizer-render-google-lib' !== $handle
244344
&& 'visualizer-render-chartjs-lib' !== $handle
245345
&& 'visualizer-render-datatables-lib' !== $handle ) {
@@ -301,6 +401,12 @@ protected function render() {
301401
'library' => $library,
302402
);
303403

404+
// D3/AI charts store their rendering code in post meta — include it so
405+
// elementor-widget-preview.js can pass it to the D3 renderer.
406+
if ( 'd3' === $library ) {
407+
$chart_entry['code'] = get_post_meta( $chart_id, Visualizer_Module_AIBuilder::CF_D3_CODE, true );
408+
}
409+
304410
// Elementor injects widget HTML via innerHTML, so <script type="text/javascript">
305411
// tags never execute in the preview iframe. Instead embed the chart data in a
306412
// JSON script element — it is preserved through innerHTML but not executed.

classes/Visualizer/Module/Wizard.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public function __construct( Visualizer_Plugin $plugin ) {
5757
* @access public
5858
*/
5959
public function registerAdminMenu() {
60-
// if ( ! Visualizer_Module::is_pro() && get_option( 'visualizer_fresh_install', false ) ) {
60+
if ( ! Visualizer_Module::is_pro() && get_option( 'visualizer_fresh_install', false ) ) {
6161
$hook = add_submenu_page(
6262
Visualizer_Plugin::NAME,
6363
__( 'Setup Wizard', 'visualizer' ),
@@ -70,7 +70,7 @@ public function registerAdminMenu() {
7070
)
7171
);
7272
add_action( "load-$hook", array( $this, 'visualizer_load_setup_wizard_page' ) );
73-
// }
73+
}
7474
}
7575

7676

classes/Visualizer/Render/Sidebar.php

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -154,15 +154,16 @@ protected function _renderManualConfigDescription() {
154154
* Add the correct example for the manual configuration box.
155155
*/
156156
protected function _renderManualConfigExample() {
157-
return '{
158-
"vAxis": {
159-
"ticks": [5, 10, 15, 20],
160-
"titleTextStyle": {
161-
"color": "red"
162-
},
163-
"textPosition": "in"
164-
}
165-
}';
157+
return json_encode(
158+
[
159+
'vAxis' => [
160+
'ticks' => [ 5, 10, 15, 20 ],
161+
'titleTextStyle' => [ 'color' => 'red' ],
162+
'textPosition' => 'in',
163+
],
164+
],
165+
JSON_PRETTY_PRINT
166+
);
166167
}
167168

168169
/**
@@ -198,9 +199,9 @@ protected function _renderAdvancedSettings() {
198199
'manual',
199200
$this->manual,
200201
sprintf(
201-
// translators: %s - the format.
202-
esc_html__( 'One per line in valid JSON (key:value) format e.g. %s', 'visualizer' ),
203-
'<br><code>' . $this->_renderManualConfigExample() . '</code>'
202+
// translators: %s - JSON example.
203+
esc_html__( 'Provide a valid JSON configuration object. Example: %s', 'visualizer' ),
204+
'<code class="viz-manual-config-example">' . esc_html( $this->_renderManualConfigExample() ) . '</code>'
204205
),
205206
'',
206207
array( 'rows' => 5 )

classes/Visualizer/Render/Sidebar/ChartJS.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,10 +403,13 @@ protected function _renderManualConfigDescription() {
403403
* Add the correct example for the manual configuration box.
404404
*/
405405
protected function _renderManualConfigExample() {
406-
return '{
407-
"cutoutPercentage": 5,
408-
"rotation": 60
409-
}';
406+
return json_encode(
407+
[
408+
'cutoutPercentage' => 5,
409+
'rotation' => 60,
410+
],
411+
JSON_PRETTY_PRINT
412+
);
410413
}
411414

412415
/**

css/frame.css

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,6 +1609,19 @@ span.viz-section-error {
16091609
/******************************************************************************/
16101610
/************************ manual config JSON editor *************************/
16111611
/******************************************************************************/
1612+
code.viz-manual-config-example {
1613+
display: block;
1614+
white-space: pre;
1615+
background: #f5f5f5;
1616+
border: 1px solid #e0e0e0;
1617+
border-radius: 3px;
1618+
padding: 6px 8px;
1619+
margin-top: 6px;
1620+
font-size: 11px;
1621+
line-height: 1.5;
1622+
}
1623+
1624+
16121625
textarea[name="manual"] + .CodeMirror {
16131626
background: #282923;
16141627
color: #f8f8f2;

css/library.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
box-sizing: border-box;
66
}
77

8+
body {
9+
height: auto;
10+
}
11+
812
#visualizer-icon {
913
background-image: url("../images/icon.png");
1014
}

index.php

Lines changed: 5 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -113,69 +113,13 @@ function visualizer_launch() {
113113
}}
114114
);
115115

116-
// register Elementor widget
116+
// register Elementor widget and related hooks
117+
// Use elementor/init so Elementor's autoloader is registered and Widget_Base is resolvable.
117118
add_action(
118-
'elementor/widgets/register',
119-
function ( $widgets_manager ) {
120-
require_once VISUALIZER_ABSPATH . '/classes/Visualizer/Elementor/Widget.php';
121-
$widgets_manager->register( new Visualizer_Elementor_Widget() );
122-
}
123-
);
124-
125-
// Register the Visualizer icon for the Elementor widget panel.
126-
add_action(
127-
'elementor/editor/after_enqueue_styles',
119+
'elementor/init',
128120
function () {
129-
$icon_url = VISUALIZER_ABSURL . 'images/visualizer-icon.svg';
130-
wp_add_inline_style(
131-
'elementor-icons',
132-
'.visualizer-elementor-icon { display:inline-block; width:1em; height:1em; background:url("' . esc_url( $icon_url ) . '") no-repeat center/contain; }'
133-
);
134-
}
135-
);
136-
137-
// Enqueue Visualizer scripts inside the Elementor preview iframe.
138-
// Elementor serves the preview iframe as a shell page and injects widget HTML via
139-
// JavaScript (innerHTML), so wp_enqueue_script calls inside render() never reach the
140-
// iframe. We load all chart render libraries here so they are available when
141-
// elementor-widget-preview.js triggers visualizer:render:chart:start.
142-
add_action(
143-
'elementor/preview/enqueue_scripts',
144-
function () {
145-
do_action( 'visualizer_enqueue_scripts' );
146-
147-
// ChartJS render library.
148-
if ( ! wp_script_is( 'numeral', 'registered' ) ) {
149-
wp_register_script( 'numeral', VISUALIZER_ABSURL . 'js/lib/numeral.min.js', array(), Visualizer_Plugin::VERSION, true );
150-
}
151-
if ( ! wp_script_is( 'chartjs', 'registered' ) ) {
152-
wp_register_script( 'chartjs', VISUALIZER_ABSURL . 'js/lib/chartjs.min.js', array( 'numeral' ), null, true );
153-
}
154-
wp_enqueue_script( 'visualizer-render-chartjs-lib', VISUALIZER_ABSURL . 'js/render-chartjs.js', array( 'chartjs', 'visualizer-customization' ), Visualizer_Plugin::VERSION, true );
155-
156-
// Google Charts render library.
157-
wp_enqueue_script( 'visualizer-google-jsapi', '//www.gstatic.com/charts/loader.js', array(), null, true );
158-
wp_enqueue_script( 'visualizer-render-google-lib', VISUALIZER_ABSURL . 'js/render-google.js', array( 'visualizer-google-jsapi', 'visualizer-customization' ), Visualizer_Plugin::VERSION, true );
159-
160-
// DataTable render library + styles.
161-
if ( ! wp_script_is( 'visualizer-datatables', 'registered' ) ) {
162-
wp_register_script( 'visualizer-datatables', VISUALIZER_ABSURL . 'js/lib/datatables.min.js', array( 'jquery' ), Visualizer_Plugin::VERSION, true );
163-
}
164-
wp_enqueue_script( 'visualizer-render-datatables-lib', VISUALIZER_ABSURL . 'js/render-datatables.js', array( 'visualizer-datatables', 'visualizer-customization' ), Visualizer_Plugin::VERSION, true );
165-
wp_enqueue_style( 'visualizer-datatables', VISUALIZER_ABSURL . 'css/lib/datatables.min.css', array(), Visualizer_Plugin::VERSION );
166-
167-
// Elementor widget preview handler — uses frontend/element_ready hook.
168-
wp_enqueue_script( 'visualizer-elementor-preview', VISUALIZER_ABSURL . 'js/elementor-widget-preview.js', array( 'jquery', 'elementor-frontend' ), Visualizer_Plugin::VERSION, true );
169-
170-
// Prevent Elementor's editor-preview CSS from hiding our widget.
171-
// Elementor marks widgets without a content_template() as elementor-widget-empty
172-
// and adds display:none to .elementor-widget-empty when the panel is hidden
173-
// (.elementor-editor-preview on <body>). Our widget renders async (Google Charts
174-
// loads via callback), so the empty class is always present.
175-
wp_add_inline_style(
176-
'visualizer-datatables',
177-
'.elementor-editor-preview .elementor-widget-visualizer-chart.elementor-widget-empty { display: block !important; }'
178-
);
121+
require_once VISUALIZER_ABSPATH . '/classes/Visualizer/Elementor/Widget.php';
122+
Visualizer_Elementor_Widget::register_hooks();
179123
}
180124
);
181125

0 commit comments

Comments
 (0)