PluginProbe
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant / 2.3.2
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant v2.3.2
2.3.2 2.3.1 2.3.0 2.2.8 2.2.7 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.11.0 1.11.1 1.11.2 1.6 1.7 1.8 1.8.1 1.8.2 1.8.3 1.9.0 1.9.1 1.9.10 1.9.11 All 60 releases
← All changes | inc/modules/class-add-module.php +197 -44 1.11.02.3.2 View file →
@@ -36,8 +36,18 @@
36 36 */
37 37 public $module_data = array();
38 38
39 39 /**
40 + * AI prompt examples shown in the "Ask AI" popup for this module.
41 + *
42 + * Subclasses set this in their constructor with a 'blurb' string
43 + * and a 'prompts' array of example prompts.
44 + *
45 + * @var array
46 + */
47 + protected $ai_examples = array();
48 +
49 + /**
40 50 * Module options.
41 51 *
42 52 */
43 53 public $module_options_path = '';
@@ -48,9 +58,66 @@
48 58 * @var bool
49 59 */
50 60 public $has_shortcode = false;
51 61
62 + protected $has_analytics = false;
63 +
52 64 /**
65 + * Option group definitions cache.
66 + *
67 + * @var array<int, array<string, mixed>>|null
68 + */
69 + protected $option_groups = null;
70 +
71 + /**
72 + * Initialize the module's option group definitions.
73 + *
74 + * Subclasses override this to define their settings panels.
75 + * Each element in the returned array corresponds to one settings
76 + * section in the admin UI.
77 + *
78 + * @return array<int, array<string, mixed>> Array of option group arrays, each with 'module', 'title', and 'fields' keys.
79 + */
80 + protected function init_option_groups() {
81 + return array();
82 + }
83 +
84 + /**
85 + * Get the module's option group definitions.
86 + *
87 + * Returns cached definitions if available. On first call,
88 + * initializes from the subclass and applies the filter for
89 + * third-party extensibility.
90 + *
91 + * @return array<int, array<string, mixed>> Filtered option group definitions.
92 + */
93 + public function get_option_groups() {
94 + if ( $this->option_groups !== null ) {
95 + return $this->option_groups;
96 + }
97 +
98 + $groups = $this->init_option_groups();
99 +
100 + /**
101 + * Filter a module's option group definitions.
102 + *
103 + * Allows third-party plugins to add, remove, or modify
104 + * the field definitions for any module.
105 + *
106 + * @param array<int, array<string, mixed>> $groups Array of option group arrays.
107 + *
108 + * @since 2.3.0
109 + */
110 + $this->option_groups = apply_filters(
111 + "merchant_{$this->module_id}_option_groups",
112 + $groups
113 + );
114 +
115 + return $this->option_groups;
116 + }
117 +
118 +
119 + /**
53 120 * Constructor.
54 121 *
55 122 */
56 123 public function __construct() {
@@ -69,11 +136,79 @@
69 136 if ( $this->has_shortcode ) {
70 137 add_action( 'wp', array( $this, 'setup_product_object' ) );
71 138 add_shortcode( 'merchant_module_' . str_replace( '-', '_', $this->module_id ), array( $this, 'shortcode_handler' ) );
72 139 }
140 +
141 + // Remove merchant shortcodes from Botiga product card short description
142 + add_filter( 'botiga_loop_product_elements', function( $elements ) {
143 + add_filter( 'get_the_excerpt', function( $excerpt ) {
144 + return preg_replace( '/\[merchant_[^]]+]/', '', $excerpt );
145 + } );
146 +
147 + return $elements;
148 + } );
73 149 }
74 150
75 151 /**
152 + * Check if the module has analytics.
153 + *
154 + * @return bool
155 + */
156 + public function has_analytics() {
157 + return $this->has_analytics;
158 + }
159 +
160 + /**
161 + * Get the module's AI prompt examples.
162 + *
163 + * @return array Array with 'blurb' and 'prompts' keys, or an empty array if the module has none.
164 + */
165 + public function get_ai_examples() {
166 + /**
167 + * Filter a module's AI prompt examples.
168 + *
169 + * @param array $ai_examples Array with 'blurb' and 'prompts' keys.
170 + *
171 + * @since 2.3.0
172 + */
173 + return apply_filters( "merchant_{$this->module_id}_ai_examples", $this->ai_examples );
174 + }
175 +
176 + /**
177 + * Get all analytics metrics and allow modules to filter them.
178 + *
179 + * @return array List of available metrics.
180 + */
181 + public function analytics_metrics() {
182 + /**
183 + * Hook: merchant_analytics_module_metrics
184 + *
185 + * @param array $metrics List of available metrics.
186 + * @param string $module_id Module ID.
187 + *
188 + * @since 2.0
189 + */
190 + return apply_filters( 'merchant_analytics_module_metrics', $this->default_analytics_metrics(), $this->module_id, $this );
191 + }
192 +
193 + /**
194 + * Get analytics metrics.
195 + *
196 + * @return array List of available metrics.
197 + */
198 + protected function default_analytics_metrics() {
199 + return array(
200 + 'campaigns' => true,
201 + 'impressions' => true,
202 + 'clicks' => true,
203 + 'ctr' => true,
204 + 'revenue' => true,
205 + 'orders_count' => true,
206 + 'aov' => true,
207 + );
208 + }
209 +
210 + /**
76 211 * Active modules class handler.
77 212 *
78 213 */
79 214 public function add_module_activation_status_class( $classes ) {
@@ -119,9 +254,9 @@
119 254 * Get module settings.
120 255 *
121 256 */
122 257 public function get_module_settings() {
123 - $settings = get_option( 'merchant' ) ? get_option( 'merchant' ) : array();
258 + $settings = get_option( 'merchant', array() );
124 259
125 260 // Default settings.
126 261 $defaults = $this->module_default_settings;
127 262
@@ -146,54 +281,30 @@
146 281 return $settings;
147 282 }
148 283
149 284 /**
150 - * Get preview URL
285 + * Update module settings.
151 286 *
152 - * @param array $args
287 + * @param array $module_settings
153 288 *
154 - * @return string
289 + * @return void
155 290 */
156 - public function set_module_preview_url( $args = array() ) {
157 - // Mount preview url.
158 - $preview_url = site_url( '/' );
291 + public function update_module_settings( $module_settings ) {
292 + $settings = get_option( 'merchant', array() );
159 293
160 - // Type based preview url
161 - if ( isset( $args['type'] ) ) {
162 - switch ( $args['type'] ) {
163 - case 'shop':
164 - if ( function_exists( 'wc_get_page_id' ) ) {
165 - $preview_url = get_permalink( wc_get_page_id( 'shop' ) );
166 - }
167 - break;
294 + $settings[ $this->module_id ] = $module_settings;
168 295
169 - case 'product':
170 - $query_args = array(
171 - 'post_type' => 'product',
172 - 'posts_per_page' => 1,
173 - );
296 + /**
297 + * Hook: merchant_module_settings_update
298 + *
299 + * @param array $settings Module settings.
300 + * @param string $module_id Module ID.
301 + *
302 + * @since 2.0.0
303 + */
304 + $settings = apply_filters( 'merchant_module_settings_update', $settings, $this->module_id );
174 305
175 - if ( isset( $args['query'] ) ) {
176 - $products = ( new WP_Query( wp_parse_args( $args['query'], $query_args ) ) )->get_posts();
177 -
178 - // If no results can be found with the custom query,
179 - // then use the default args
180 - if ( empty( $products ) || ! isset( $products[0] ) ) {
181 - $products = ( new WP_Query( $query_args ) )->get_posts();
182 - }
183 - } else {
184 - $products = ( new WP_Query( $query_args ) )->get_posts();
185 - }
186 -
187 - if ( ! empty( $products ) && isset( $products[0] ) ) {
188 - $preview_url = get_permalink( $products[0] );
189 - }
190 -
191 - break;
192 - }
193 - }
194 -
195 - return $preview_url;
306 + update_option( 'merchant', $settings );
196 307 }
197 308
198 309 /**
199 310 * Add module.
@@ -207,16 +318,58 @@
207 318
208 319 /**
209 320 * Add module options.
210 321 *
322 + * For migrated modules (those with option groups defined),
323 + * renders settings directly from get_option_groups().
324 + * Unmigrated modules fall back to including $module_options_path.
325 + *
326 + * @param string $module_path Default file path.
327 + * @param string $merchant_module Module ID being rendered.
328 + *
329 + * @return string File path to include, or empty string if already rendered.
211 330 */
212 331 public function add_module_options( $module_path, $merchant_module ) {
213 - if ( $this->module_id === $merchant_module ) {
214 - return $this->module_options_path;
332 + if ( $this->module_id !== $merchant_module ) {
333 + return $module_path;
215 334 }
216 335
217 - return $module_path;
336 + $groups = $this->get_option_groups();
337 +
338 + if ( ! empty( $groups ) ) {
339 + $this->before_render_option_groups();
340 +
341 + foreach ( $groups as $group ) {
342 + Merchant_Admin_Options::create( $group );
343 + }
344 +
345 + $this->after_render_option_groups();
346 +
347 + return '';
348 + }
349 +
350 + return $this->module_options_path;
218 351 }
352 +
353 + /**
354 + * Called before option groups are rendered in the admin.
355 + *
356 + * Override in subclasses that need to fire actions
357 + * before settings fields (e.g., help banners).
358 + *
359 + * @return void
360 + */
361 + protected function before_render_option_groups() {}
362 +
363 + /**
364 + * Called after option groups are rendered in the admin.
365 + *
366 + * Override in subclasses that need to fire actions
367 + * after settings fields.
368 + *
369 + * @return void
370 + */
371 + protected function after_render_option_groups() {}
219 372
220 373 /**
221 374 * Display error message if the shortcode is placed in the wrong place.
222 375 *