Skip to content

Commit 9948934

Browse files
committed
Adding widget usage
1 parent d789777 commit 9948934

3 files changed

Lines changed: 200 additions & 16 deletions

File tree

readme.txt

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
=== Solid Dynamics ===
22
Contributors: soliddigital,lukechinworth,peterajtai
33
Tags: elementor, dynamic tags, jet engine, macros
4-
Tested up to: 6.2
5-
Stable tag: 1.5.2
4+
Tested up to: 6.7.1
5+
Stable tag: 1.6.0
66
Requires PHP: 7.0
77
License: GPLv2
88

99
Helpful utilities for Elementor, Jet Engine, and beyond.
1010

1111
== Description ==
1212

13-
This plugin provides several dynamic tags under the "Solid Dynamics" section:
13+
This plugin provides an Admin Page called, "Widget Usage" that shows the individual posts in which a widget is used.
14+
Currently, the Elementor Element Manager only shows the total number of usages of a widget. We're always wondering
15+
where those widgets are being used, and "Widget Usage" is the answer to that question.
16+
17+
Solid Dynamics also provides several dynamic tags under the "Solid Dynamics" section:
1418

1519
- `Custom Callback`: Call any php function. The current post is passed as the first argument.
1620
- `Menu`: Returns comma-separated post ids of a specific menu.
@@ -49,36 +53,37 @@ The code is managed on [github](https://github.com/SolidDigital/solid-dynamics),
4953

5054
== Changelog ==
5155

52-
= 1.5.0 =
53-
- Feature: add `Disable Users REST API`
56+
= 2024-11-23: 1.6.0 =
57+
- Feature: `Widget Usage`
5458

55-
= 1.4.0 =
59+
= 2023-04-08: 1.5.0 =
60+
- Feature: add `Disable Users REST API`
5661
- Feature: add `Post Field` dynamic tag.
5762

58-
= 1.3.4 =
63+
= 2022-12-09: 1.3.4 =
5964
- Fix fatal error on get_class call.
6065

61-
= 1.3.3 =
66+
= 2022-12-09: 1.3.3 =
6267
- Add support for term and user meta to list pluck tag.
6368

64-
= 1.3.2 =
69+
= 2022-12-05: 1.3.2 =
6570
- Add support for wp_options to list pluck tag.
6671

67-
= 1.3.0 =
72+
= 2022-11-01: 1.3.0 =
6873
- Feature: add settings: Disable 404 permalink guessing; Hide the page title from the Hello Elementor theme; Wrap Elementor content with `main#content`; Make Elementor fade in entrance animations more subtle.
6974

70-
= 1.2.0 =
75+
= 2022-09-02: 1.2.0 =
7176
- Feature: add settings page with option to remove elementor's "back to wp editor" button.
7277

73-
= 1.1.3 =
78+
= 2022-08-13: 1.1.3 =
7479
- Bug fix: Do not try to load JetEngine if plugin is not preseent
7580

76-
= 1.1.2 =
81+
= 2022-08-09: 1.1.2 =
7782
- Bug fix: Escape custom callback output with wp_kses_post since it could include html.
7883
- Bug fix: Escape the menu output with esc_html since it should only be comma-separated ids.
7984

80-
= 1.1.0 =
85+
= 2022-03-16: 1.1.0 =
8186
- Feature: Add menu dynamic tag.
8287

83-
= 1.0.0 =
88+
= 2021-06-15: 1.0.0 =
8489
- Feature: Initial release

solid-dynamics.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/**
44
* Plugin Name: Solid Dynamics
55
* Description: Helpful utilities for Elementor, Jet Engine, and beyond.
6-
* Version: 1.5.3
6+
* Version: 1.6.0
77
* Author: Solid Digital
88
* Author URI: https://www.soliddigital.com
99
* License: GPLv2

widget-usage/admin-page.php

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
<?php
2+
namespace Solid;
3+
4+
// Hook to add the admin menu page
5+
add_action('admin_menu', function () {
6+
add_menu_page(
7+
'Elementor Widget Usage', // Page title
8+
'Widget Usage', // Menu title
9+
'manage_options', // Capability
10+
'elementor-widget-usage', // Menu slug
11+
__NAMESPACE__ . '\render_widget_usage_page' // Callback function
12+
);
13+
});
14+
15+
// Function to render the admin page
16+
function render_widget_usage_page() {
17+
$widgets = get_all_elementor_widgets();
18+
19+
?>
20+
<div class="wrap">
21+
<h1>Find Elementor Widget Usage</h1>
22+
<form method="post" id="widget-usage-form">
23+
<label for="widget_name">Select Widget:</label>
24+
<select id="widget_name" name="widget_name" required>
25+
<option value="">-- Select a Widget --</option>
26+
<?php foreach ($widgets as $widget) : ?>
27+
<option value="<?php echo esc_attr($widget); ?>">
28+
<?php echo esc_html($widget); ?>
29+
</option>
30+
<?php endforeach; ?>
31+
</select>
32+
<?php submit_button('Find Usage'); ?>
33+
</form>
34+
35+
<?php
36+
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['widget_name'])) {
37+
$widget_name = sanitize_text_field($_POST['widget_name']);
38+
$results = find_widget_usage($widget_name);
39+
40+
if (!empty($results)) {
41+
// Order results by widget count (highest to lowest)
42+
usort($results, function ($a, $b) {
43+
return $b->widget_count <=> $a->widget_count;
44+
});
45+
46+
$total_instances = array_sum(array_column($results, 'widget_count'));
47+
48+
echo '<h2>Results:</h2>';
49+
echo '<p>Total Instances Across All Posts: ' . $total_instances . '</p>';
50+
echo '<table class="widefat fixed" cellspacing="0">';
51+
echo '<thead><tr><th>#</th><th>Title</th><th>Post Type</th><th>Status</th><th>Count</th></tr></thead>';
52+
echo '<tbody>';
53+
54+
$count = 1; // Initialize instance counter
55+
foreach ($results as $result) {
56+
$edit_link = get_edit_post_link($result->ID);
57+
echo '<tr>';
58+
echo '<td>' . $count . '</td>'; // Display the instance number
59+
echo '<td><a href="' . esc_url($edit_link) . '">' . esc_html($result->post_title) . '</a></td>';
60+
echo '<td>' . esc_html($result->post_type) . '</td>';
61+
echo '<td>' . esc_html($result->post_status) . '</td>';
62+
echo '<td>' . esc_html($result->widget_count) . '</td>';
63+
echo '</tr>';
64+
$count++;
65+
}
66+
67+
echo '</tbody></table>';
68+
} else {
69+
echo '<p>No templates or posts contain this widget.</p>';
70+
}
71+
}
72+
?>
73+
</div>
74+
<?php
75+
}
76+
77+
// Function to get all Elementor widgets
78+
function get_all_elementor_widgets() {
79+
global $wpdb;
80+
81+
// Fetch all `_elementor_data` values
82+
$query = $wpdb->prepare(
83+
"SELECT meta_value
84+
FROM $wpdb->postmeta
85+
WHERE meta_key = %s",
86+
'_elementor_data'
87+
);
88+
89+
$results = $wpdb->get_col($query);
90+
91+
$widgets = [];
92+
93+
foreach ($results as $meta_value) {
94+
$data = json_decode($meta_value, true);
95+
96+
if (is_array($data)) {
97+
collect_widgets_from_data($data, $widgets);
98+
}
99+
}
100+
101+
// Return unique widgets, sorted alphabetically
102+
$widgets = array_unique($widgets);
103+
sort($widgets);
104+
105+
return $widgets;
106+
}
107+
108+
// Helper function to recursively collect widget types
109+
function collect_widgets_from_data($data, &$widgets) {
110+
foreach ($data as $element) {
111+
if (isset($element['elType']) && $element['elType'] === 'widget' && isset($element['widgetType'])) {
112+
$widgets[] = $element['widgetType'];
113+
}
114+
115+
if (isset($element['elements']) && is_array($element['elements'])) {
116+
collect_widgets_from_data($element['elements'], $widgets);
117+
}
118+
}
119+
}
120+
121+
// Function to find widget usage
122+
function find_widget_usage($widget_name) {
123+
global $wpdb;
124+
125+
// Query for all Elementor post meta
126+
$query = $wpdb->prepare(
127+
"SELECT post_id, meta_value
128+
FROM $wpdb->postmeta
129+
WHERE meta_key = %s",
130+
'_elementor_data'
131+
);
132+
133+
$posts = $wpdb->get_results($query);
134+
$results = [];
135+
136+
foreach ($posts as $post) {
137+
$data = json_decode($post->meta_value, true);
138+
139+
if (is_array($data)) {
140+
$widget_count = count_widgets_in_data($data, $widget_name);
141+
if ($widget_count > 0) {
142+
$post_data = get_post($post->post_id);
143+
$results[] = (object) [
144+
'ID' => $post_data->ID,
145+
'post_title' => $post_data->post_title,
146+
'post_type' => $post_data->post_type,
147+
'post_status' => $post_data->post_status,
148+
'widget_count' => $widget_count,
149+
];
150+
}
151+
}
152+
}
153+
154+
return $results;
155+
}
156+
157+
// Helper function to count widget instances in nested data
158+
function count_widgets_in_data($data, $widget_name) {
159+
$count = 0;
160+
161+
foreach ($data as $element) {
162+
// Check if the element is a widget and matches the desired widget name
163+
if (
164+
isset($element['elType']) &&
165+
$element['elType'] === 'widget' &&
166+
isset($element['widgetType']) &&
167+
$element['widgetType'] === $widget_name
168+
) {
169+
$count++;
170+
}
171+
172+
// Recursively check nested elements
173+
if (isset($element['elements']) && is_array($element['elements'])) {
174+
$count += count_widgets_in_data($element['elements'], $widget_name);
175+
}
176+
}
177+
178+
return $count;
179+
}

0 commit comments

Comments
 (0)