PluginProbe
Testimonial Customer Feedback / trunk
Testimonial Customer Feedback vtrunk
1.2.8 1.2.7 1.1.14 1.1.15 1.1.16 1.1.17 1.1.18 1.1.19 1.1.2 1.1.20 1.1.21 1.1.22 1.1.23 1.1.24 1.1.25 1.1.26 1.1.27 1.1.28 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 All 76 releases
testimonial-maker / testimonial-maker.php

testimonial-maker.php in Testimonial Customer Feedback trunk, at testimonial-maker.php

920 lines 33.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) {
3 exit; // Exit if accessed directly
4 }
5 /**
6 @package Testimonial Maker
7 * Plugin Name: Testimonial Maker
8 * Plugin URI: https://awplife.com/wordpress-plugins/testimonial-wordpress-plugin/
9 * Description: A very easy Plugin for make testimonials.
10 * Version: 1.2.8
11 * Requires at least: 5.0
12 * Requires PHP: 7.0
13 * Author: A WP Life
14 * Author URI: https://profiles.wordpress.org/awordpresslife
15 * License: GPL v2 or later
16 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
17 * Text Domain: testimonial-maker
18 * Domain Path: /languages
19 * License: GPL2
20
21 Testimonial Maker is free software: you can redistribute it and/or modify
22 it under the terms of the GNU General Public License as published by
23 the Free Software Foundation, either version 2 of the License, or
24 any later version.
25
26 Testimonial Maker is distributed in the hope that it will be useful,
27 but WITHOUT ANY WARRANTY; without even the implied warranty of
28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 GNU General Public License for more details.
30
31 You should have received a copy of the GNU General Public License
32 along with Testimonial Maker. If not, see https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html.
33 */
34 if (!class_exists('tml_or_testimonial')) {
35 class tml_or_testimonial
36 {
37
38 public function __construct()
39 {
40 $this->_constants();
41 $this->_hooks();
42 }
43
44 protected function _constants()
45 {
46 // Version Type (PRO/FREE toggle)
47 define('TML_IS_PRO', false);
48
49 //Plugin Version
50 define('TML_PLUGIN_VER', '1.2.8');
51
52 //Plugin Text Domain
53 define('TML_TXTDM', 'testimonial-maker');
54
55 //Plugin Name
56 define('TML_PLUGIN_NAME', 'Testimonial Maker');
57
58 //Plugin Slug
59 define('TML_PLUGIN_SLUG', 'testimonial-maker');
60
61 //Plugin Directory Path
62 define('TML_PLUGIN_DIR', plugin_dir_path(__FILE__));
63
64 //Plugin Directory URL
65 define('TML_PLUGIN_URL', plugin_dir_url(__FILE__));
66
67 define('TML_SECURE_KEY', md5(NONCE_KEY));
68
69 } // end of constructor function
70
71 protected function _hooks()
72 {
73 //Load text domain
74 //add_action('plugins_loaded', array($this, 'load_textdomain'));
75
76 //add testimonial menu item, change menu filter for multisite
77 add_action('admin_menu', array($this, 'tmonial_menu'), 101);
78
79 // Register Admin Scripts
80 add_action('admin_enqueue_scripts', array($this, 'tml_admin_enqueue_scripts'));
81
82 //Create testimonial Filter testimonial Custom Post
83 add_action('init', array($this, 'Testimonial'));
84 add_action('init', array($this, 'tml_run_v2_migration'));
85 add_action('init', array($this, 'tml_auto_create_default_shortcode'));
86
87 //Add meta box to custom post
88 add_action('add_meta_boxes', array($this, 'admin_add_meta_box'));
89
90 //loaded during admin init
91 add_action('admin_init', array($this, 'admin_add_meta_box'));
92
93 add_action('save_post', array(&$this, '_tml_save_settings'));
94 add_action('save_post', array(&$this, 'tml_save_shortcode_meta'));
95 add_action('save_post', array(&$this, 'tml_save_form_meta'));
96
97 //Shortcode Compatibility in Text Widgets
98 add_action('widget_text', 'do_shortcode');
99
100 // Gutenberg Block Assets
101 add_action('enqueue_block_editor_assets', array($this, 'tml_gutenberg_block_assets'));
102 add_action('init', array($this, 'tml_register_gutenberg_blocks'));
103 add_filter('block_categories_all', array($this, 'tml_block_category'), 10, 2);
104
105 // Register Scripts
106 add_action('wp_enqueue_scripts', array($this, 'awplife_tml_register_scripts'));
107
108
109
110 // AJAX Live Preview Handler
111 add_action('wp_ajax_tml_save_preview_settings', array($this, 'ajax_save_preview_settings'));
112
113 // AJAX Reset to Defaults Handler
114 add_action('wp_ajax_tml_reset_shortcode_settings', array($this, 'ajax_reset_shortcode_settings'));
115
116 // Allow data: protocol for SVG inline avatars in esc_url()
117 add_filter('kses_allowed_protocols', array($this, 'tml_allow_data_protocol'));
118
119 // Custom columns for Shortcodes post list
120 add_filter('manage_tml-shortcode_posts_columns', array($this, 'tml_shortcode_posts_columns'));
121 add_action('manage_tml-shortcode_posts_custom_column', array($this, 'tml_shortcode_posts_custom_column'), 10, 2);
122
123 // Duplicate shortcode action and row actions
124 add_action('admin_action_tml_duplicate_shortcode', array($this, 'tml_duplicate_shortcode_handler'));
125 add_filter('post_row_actions', array($this, 'tml_shortcode_row_actions'), 10, 2);
126 add_filter('page_row_actions', array($this, 'tml_shortcode_row_actions'), 10, 2);
127 add_action('admin_notices', array($this, 'tml_duplicate_admin_notice'));
128 } // end of hook function
129
130 public function load_textdomain()
131 {
132 // phpcs:ignore PluginCheck.CodeAnalysis.DiscouragedFunctions.load_plugin_textdomainFound
133 load_plugin_textdomain(TML_TXTDM, false, dirname(plugin_basename(__FILE__)) . '/languages');
134 }
135
136 public function tmonial_menu()
137 {
138 add_submenu_page('edit.php?post_type=' . TML_PLUGIN_SLUG, __('Import/Export', 'testimonial-maker'), __('Import/Export', 'testimonial-maker'), 'administrator', 'tml-import-export', array($this, '_tml_import_export_page'));
139 add_submenu_page('edit.php?post_type=' . TML_PLUGIN_SLUG, __('Analytics', 'testimonial-maker'), __('Analytics', 'testimonial-maker'), 'administrator', 'tml-analytics', array($this, '_tml_analytics_page'));
140 add_submenu_page('edit.php?post_type=' . TML_PLUGIN_SLUG, __('Docs', 'testimonial-maker'), __('Docs', 'testimonial-maker'), 'administrator', 'tml-docs', array($this, '_tml_docs_page'));
141 add_submenu_page('edit.php?post_type=' . TML_PLUGIN_SLUG, __('Free Plugins', 'testimonial-maker'), __('Free Plugins', 'testimonial-maker'), 'administrator', 'tml-free-plugins', array($this, '_tml_free_plugins_page'));
142 add_submenu_page('edit.php?post_type=' . TML_PLUGIN_SLUG, __('Free Themes', 'testimonial-maker'), __('Free Themes', 'testimonial-maker'), 'administrator', 'tml-free-themes', array($this, '_tml_free_themes_page'));
143 }
144
145 public function _tml_import_export_page()
146 {
147 require_once(TML_PLUGIN_DIR . 'include/import-export.php');
148 }
149
150 public function _tml_analytics_page()
151 {
152 require_once(TML_PLUGIN_DIR . 'include/analytics.php');
153 }
154
155 public function Testimonial()
156 {
157 // register testimonial custom post type
158 $cpt_name = __('Testimonial Maker', 'testimonial-maker');
159 $labels = array(
160 'name' => $cpt_name,
161 'singular_name' => $cpt_name,
162 'menu_name' => $cpt_name,
163 'name_admin_bar' => $cpt_name,
164 'add_new' => __('Add New Testimonial', 'testimonial-maker'),
165 'add_new_item' => __('Add New Testimonial', 'testimonial-maker'),
166 'new_item' => __('New Testimonial', 'testimonial-maker'),
167 'edit_item' => __('Edit Testimonial', 'testimonial-maker'),
168 'view_item' => __('View Testimonial', 'testimonial-maker'),
169 'all_items' => __('All Testimonial', 'testimonial-maker'),
170 'search_items' => __('Search Testimonial', 'testimonial-maker'),
171 'parent_item_colon' => __('Parent Testimonial:', 'testimonial-maker'),
172 'not_found' => __('No Testimonial found', 'testimonial-maker'),
173 'not_found_in_trash' => __('No Testimonial found in Trash', 'testimonial-maker')
174 );
175
176 $args = array(
177 'labels' => __('Testimonial', 'testimonial-maker'),
178 'description' => __('Description', 'testimonial-maker'),
179 'labels' => $labels,
180 'public' => true,
181 'publicly_queryable' => true,
182 'show_ui' => true,
183 'show_in_menu' => true,
184 'query_var' => true,
185 'rewrite' => array('slug' => false),
186 'capability_type' => 'page',
187 'has_archive' => true,
188 'hierarchical' => false,
189 'menu_icon' => 'dashicons-format-status',
190 'menu_position' => null,
191 'supports' => array('title', 'editor', 'thumbnail', ),
192 'taxonomies' => array('testimonial-categories'),
193 );
194
195 register_post_type('testimonial-maker', $args);
196
197 // register custom taxonomy for testimonial custom post type
198 $labels = array(
199 'name' => __('Categories', 'testimonial-maker'),
200 'singular_name' => __('Category', 'testimonial-maker'),
201 'search_items' => __('Search Categories', 'testimonial-maker'),
202 'all_items' => __('All Categories', 'testimonial-maker'),
203 'parent_item' => __('Parent Categories', 'testimonial-maker'),
204 'parent_item_colon' => __('Parent Categories:', 'testimonial-maker'),
205 'edit_item' => __('Edit Categories', 'testimonial-maker'),
206 'update_item' => __('Update Categories', 'testimonial-maker'),
207 'add_new_item' => __('Add New Categories', 'testimonial-maker'),
208 'new_item_name' => __('New Category Name', 'testimonial-maker'),
209 'menu_name' => __('Categories', 'testimonial-maker'),
210 );
211
212 $args = array(
213 'hierarchical' => true,
214 'labels' => $labels,
215 'show_ui' => true,
216 'show_admin_column' => true,
217 'query_var' => true,
218 'rewrite' => array('slug' => 'testimonial-categories'),
219 );
220
221 register_taxonomy('testimonial-categories', array('testimonial-maker'), $args);
222
223 // Register Shortcode Generator CPT
224 $shortcode_labels = array(
225 'name' => __('Shortcode Generator', 'testimonial-maker'),
226 'singular_name' => __('Shortcode', 'testimonial-maker'),
227 'menu_name' => __('Shortcodes', 'testimonial-maker'),
228 'name_admin_bar' => __('Shortcode', 'testimonial-maker'),
229 'add_new' => __('Add New', 'testimonial-maker'),
230 'add_new_item' => __('Add New Shortcode', 'testimonial-maker'),
231 'new_item' => __('New Shortcode', 'testimonial-maker'),
232 'edit_item' => __('Edit Shortcode', 'testimonial-maker'),
233 'view_item' => __('View Shortcode', 'testimonial-maker'),
234 'all_items' => __('Shortcodes', 'testimonial-maker'),
235 'search_items' => __('Search Shortcodes', 'testimonial-maker'),
236 'not_found' => __('No shortcodes found.', 'testimonial-maker'),
237 'not_found_in_trash' => __('No shortcodes found in Trash.', 'testimonial-maker')
238 );
239
240 $shortcode_args = array(
241 'labels' => $shortcode_labels,
242 'public' => false,
243 'show_ui' => true,
244 'show_in_menu' => 'edit.php?post_type=' . TML_PLUGIN_SLUG,
245 'capability_type' => 'post',
246 'hierarchical' => false,
247 'supports' => array('title'),
248 );
249 register_post_type('tml-shortcode', $shortcode_args);
250
251 // Register Form Builder CPT
252 $form_labels = array(
253 'name' => __('Form Builder', 'testimonial-maker'),
254 'singular_name' => __('Form', 'testimonial-maker'),
255 'menu_name' => __('Form Builder', 'testimonial-maker'),
256 'name_admin_bar' => __('Form', 'testimonial-maker'),
257 'add_new' => __('Add New Form', 'testimonial-maker'),
258 'add_new_item' => __('Add New Form', 'testimonial-maker'),
259 'new_item' => __('New Form', 'testimonial-maker'),
260 'edit_item' => __('Edit Form', 'testimonial-maker'),
261 'view_item' => __('View Form', 'testimonial-maker'),
262 'all_items' => __('Form Builder', 'testimonial-maker'),
263 'search_items' => __('Search Forms', 'testimonial-maker'),
264 'not_found' => __('No forms found.', 'testimonial-maker'),
265 'not_found_in_trash' => __('No forms found in Trash.', 'testimonial-maker')
266 );
267
268 $form_args = array(
269 'labels' => $form_labels,
270 'public' => false,
271 'show_ui' => true,
272 'show_in_menu' => 'edit.php?post_type=' . TML_PLUGIN_SLUG,
273 'capability_type' => 'post',
274 'hierarchical' => false,
275 'supports' => array('title'),
276 );
277 register_post_type('tml-form', $form_args);
278 }
279 public function admin_add_meta_box()
280 {
281 add_meta_box('', __('Add Client Detail', 'testimonial-maker'), array(&$this, 'tml_testimonial_upload'), 'testimonial-maker', 'normal', 'default');
282 add_meta_box('tml_shortcode_settings_box', __('Testimonial Settings', 'testimonial-maker'), array(&$this, 'tml_shortcode_settings_cb'), 'tml-shortcode', 'normal', 'high');
283 add_meta_box('tml_shortcode_display_box', __('Shortcode', 'testimonial-maker'), array(&$this, 'tml_shortcode_display_cb'), 'tml-shortcode', 'side', 'high');
284 // For Form Builder
285 add_meta_box('tml_form_builder_box', __('Form Configuration', 'testimonial-maker'), array(&$this, 'tml_form_builder_cb'), 'tml-form', 'normal', 'high');
286 }
287
288 public function tml_form_builder_cb($post)
289 {
290 wp_nonce_field('tml_save_form_settings', 'tml_form_nonce');
291 require_once('include/form-builder.php');
292 }
293 public function tml_testimonial_upload($post)
294 {
295 require_once(TML_PLUGIN_DIR . 'include/metabox-testimonial.php');
296 }
297
298 public function _tml_save_settings($post_id)
299 {
300 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
301 return;
302 if (!current_user_can('edit_post', $post_id))
303 return;
304
305 $nonce = isset($_POST['tml_save_nonce']) ? sanitize_text_field(wp_unslash($_POST['tml_save_nonce'])) : '';
306 if (!empty($nonce)) {
307 if (!wp_verify_nonce($nonce, 'tml_save_settings')) {
308 print 'Sorry, your nonce did not verify.';
309 exit;
310 } else {
311 $website_link = isset($_POST['website_link']) ? esc_url_raw(wp_unslash($_POST['website_link'])) : '';
312 $designation = isset($_POST['designation']) ? sanitize_text_field(wp_unslash($_POST['designation'])) : '';
313 $star_rating = isset($_POST['star_rating']) ? sanitize_text_field(wp_unslash($_POST['star_rating'])) : '5';
314
315 $testimonial_post_settings = array(
316 'website_link' => $website_link,
317 'designation' => $designation,
318 'star_rating' => $star_rating,
319 );
320 $awl_testimonial_shortcode_setting = "awl_testimonial" . $post_id;
321 update_post_meta($post_id, $awl_testimonial_shortcode_setting, $testimonial_post_settings);
322 }
323 }// end save setting
324 }
325 public function tml_shortcode_settings_cb($post)
326 {
327 wp_nonce_field('tml_save_shortcode_settings', 'tml_shortcode_nonce');
328 require_once('include/testimonial-setting.php');
329 }
330
331 public function tml_shortcode_display_cb($post)
332 {
333 $shortcode = '[TML id="' . $post->ID . '"]';
334 ?>
335 <div class="tml-shortcode-side-box" style="text-align: center;">
336 <p style="color:#666; margin-top:0; margin-bottom:10px;">
337 <?php esc_html_e('Copy and paste this shortcode into any Page, Post, or Widget.', 'testimonial-maker'); ?>
338 </p>
339 <input type="text" value="<?php echo esc_attr($shortcode); ?>" readonly onclick="this.select();"
340 style="width: 100%; text-align: center; font-size: 14px; padding: 10px; font-weight: bold; background: #f0f0f1; border-color: #8c8f94; box-shadow: inset 0 1px 2px rgba(0,0,0,.07);">
341 </div>
342 <?php
343 }
344
345
346
347 public function tml_save_shortcode_meta($post_id)
348 {
349 require_once(TML_PLUGIN_DIR . 'include/save-shortcode-meta.php');
350 }
351
352 public function tml_save_form_meta($post_id)
353 {
354 require_once(TML_PLUGIN_DIR . 'include/save-form-meta.php');
355 }
356
357 public function _tml_testimonial_settings()
358 {
359 require_once('include/testimonial-setting.php');
360 }
361
362 public function _tml_free_plugins_page()
363 {
364 require_once(TML_PLUGIN_DIR . 'our-plugins.php');
365 }
366
367 public function _tml_free_themes_page()
368 {
369 require_once(TML_PLUGIN_DIR . 'our-themes.php');
370 }
371
372 public function _tml_docs_page()
373 {
374 require_once(TML_PLUGIN_DIR . 'include/docs.php');
375 }
376
377 public function tml_admin_enqueue_scripts($hook)
378 {
379 if (isset($_GET['page']) && ($_GET['page'] === 'tml-free-plugins' || $_GET['page'] === 'tml-free-themes')) {
380 wp_enqueue_style('tml-our-plugins-style', TML_PLUGIN_URL . 'assets/css/our-plugins-style.css', array(), TML_PLUGIN_VER);
381 add_thickbox();
382 }
383 }
384 public function tml_gutenberg_block_assets()
385 {
386 wp_enqueue_script(
387 'tml-gutenberg-block',
388 TML_PLUGIN_URL . 'assets/js/tml-gutenberg-blocks.js',
389 array('wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-data'),
390 TML_PLUGIN_VER,
391 true
392 );
393
394 // Fetch shortcodes
395 $shortcodes = get_posts(array(
396 'post_type' => 'tml-shortcode',
397 'posts_per_page' => -1,
398 'post_status' => 'any'
399 ));
400 $shortcode_options = array();
401 foreach ($shortcodes as $s) {
402 $shortcode_options[] = array(
403 'label' => $s->post_title . ' (ID: ' . $s->ID . ')',
404 'value' => (string) $s->ID,
405 );
406 }
407
408 wp_localize_script('tml-gutenberg-block', 'tmlBlockData', array(
409 'shortcodes' => $shortcode_options,
410 ));
411 }
412
413 public function tml_register_gutenberg_blocks()
414 {
415 if (!function_exists('register_block_type')) {
416 return;
417 }
418
419 register_block_type('tml-shortcode/block', array(
420 'render_callback' => array($this, 'tml_render_shortcode_block'),
421 ));
422 }
423
424 public function tml_render_shortcode_block($attributes)
425 {
426 if (empty($attributes['shortcodeId'])) {
427 return '<p style="border:1px dashed #2271b1; padding:15px; text-align:center; color:#2271b1;">' . __('Please select a Testimonial Shortcode in block settings.', 'testimonial-maker') . '</p>';
428 }
429 return do_shortcode('[TML id="' . esc_attr($attributes['shortcodeId']) . '"]');
430 }
431
432 public function tml_block_category($categories, $post)
433 {
434 return array_merge(
435 array(
436 array(
437 'slug' => 'testimonial-maker',
438 'title' => __('Testimonial Maker', 'testimonial-maker'),
439 'icon' => 'format-status',
440 ),
441 ),
442 $categories
443 );
444 }
445
446
447 public function awplife_tml_register_scripts()
448 {
449 wp_enqueue_script('jquery');
450 wp_enqueue_style('tml-bootstrap-css', TML_PLUGIN_URL . 'assets/css/tml-frontend-bootstrap.css', array(), TML_PLUGIN_VER);
451 wp_enqueue_style('tml-font-awesome-css', TML_PLUGIN_URL . 'assets/css/font-awesome.min.css', array(), TML_PLUGIN_VER);
452
453 wp_enqueue_style('tml-owl-carousel-css', TML_PLUGIN_URL . 'assets/css/owl.carousel.css', array(), TML_PLUGIN_VER);
454 wp_enqueue_style('tml-owl-theme-css', TML_PLUGIN_URL . 'assets/css/owl.theme.default.css', array(), TML_PLUGIN_VER);
455 wp_enqueue_style('tml-owl-animate-css', TML_PLUGIN_URL . 'assets/css/animate.css', array(), TML_PLUGIN_VER);
456 }
457
458
459
460
461 public function ajax_save_preview_settings()
462 {
463 if (!current_user_can('edit_posts')) {
464 wp_send_json_error(array('message' => 'Unauthorized user.'));
465 }
466
467 // Verify nonce
468 $nonce = isset($_POST['tml_shortcode_nonce']) ? sanitize_text_field(wp_unslash($_POST['tml_shortcode_nonce'])) : '';
469 if (empty($nonce) || !wp_verify_nonce($nonce, 'tml_save_shortcode_settings')) {
470 wp_send_json_error(array('message' => 'Security check failed.'));
471 }
472
473 $post_data = wp_unslash($_POST);
474
475 $post_id = isset($post_data['post_ID']) ? intval($post_data['post_ID']) : 0;
476 if (!$post_id) {
477 wp_send_json_error(array('message' => 'Invalid shortcode ID.'));
478 }
479
480 // Verify the post is a tml-shortcode CPT
481 $post = get_post($post_id);
482 if (!$post || $post->post_type !== 'tml-shortcode') {
483 wp_send_json_error(array('message' => 'Invalid post type.'));
484 }
485
486 // Start with current saved settings as base (so unlisted fields don't go missing)
487 $testimonial_settings = get_post_meta($post_id, 'testimonial_settings', true);
488 if (!is_array($testimonial_settings)) {
489 $testimonial_settings = array();
490 }
491
492 // Override with current form $_POST values — NO SAVE TO DATABASE
493 $text_fields = array(
494 'tml_active_tab',
495 'tml_active_vtab',
496 'tml_active_stab',
497 'tml_active_subtab',
498 'tml_layout_preset',
499 'testimonial_carousel_design',
500 'tml_animateOut_effect',
501 'tml_animateIn_effect',
502 'tml_testimonial_loop',
503 'auto_play_carousel',
504 'tml_slide_speed',
505 'tml_timeout_speed',
506 'tml_hover_pause',
507 'tml_nav',
508 'tml_pagination',
509 'tml_pagination_mobile_hide',
510 'tml_auto_hight',
511 'tml_post_order',
512 'tml_rtl',
513 'tml_mouse_control',
514 'tml_nav_mobile_hide',
515 'tml_autoplay_mobile',
516 'tml_show_star_rating',
517 'tml_image_shape',
518 'tml_mouse_draggable',
519 'tml_limit',
520 'tml_order_by',
521 'tml_random_order',
522 'tml_filter_category',
523 'tml_col_ld',
524 'tml_col_d',
525 'tml_col_l',
526 'tml_col_t',
527 'tml_col_m',
528 'tml_gap',
529 'tml_vgap',
530 'tml_ds_section_title',
531 'tml_ds_preloader',
532 'tml_ds_card_shadow',
533 'tml_ds_field_order',
534 'tml_ds_content_show',
535 'tml_ds_content_type',
536 'tml_ds_content_length',
537 'tml_ds_content_length_type',
538 'tml_ds_rating_default_color',
539 'tml_ds_rating_pos',
540 'tml_ds_name_show',
541 'tml_ds_designation_show',
542 'tml_ds_website_show',
543 'tml_ds_rating_size',
544 'tml_ds_rating_gap',
545 'tml_ds_image_show',
546 'tml_ds_image_dim',
547 'tml_ds_image_shape',
548 'tml_ds_image_size',
549 'tml_ds_image_fallback',
550 'tml_ds_avg_rating',
551 'tml_ds_ajax_search',
552 'tml_ds_ajax_search_width',
553 'tml_ds_ajax_search_shape',
554 'tml_nav_color',
555 'tml_nav_bg_color',
556 'tml_nav_size',
557 'tml_nav_arrow_style',
558 'tml_title_color',
559 'tml_description_color',
560 'tml_designation_color',
561 'tml_background_color',
562 'tml_ds_section_title_text',
563 'tml_star_rating_color',
564 'tml_star_rating_alignment',
565 );
566
567 foreach ($text_fields as $field) {
568 if (isset($post_data[$field])) {
569 $testimonial_settings[$field] = sanitize_text_field($post_data[$field]);
570 }
571 }
572
573 // Handle array fields
574 if (isset($post_data['tml_selected_categories'])) {
575 $testimonial_settings['tml_selected_categories'] = map_deep($post_data['tml_selected_categories'], 'sanitize_text_field');
576 }
577 if (isset($post_data['tml_selected_ratings'])) {
578 $testimonial_settings['tml_selected_ratings'] = array_map('intval', (array) $post_data['tml_selected_ratings']);
579 }
580
581 // �
582 PREVIEW ONLY — Do NOT save. Temporarily inject settings via WP metadata filter.
583 $preview_settings = $testimonial_settings;
584 $preview_post_id = $post_id;
585
586 $filter_fn = function ($value, $object_id, $meta_key, $single) use ($preview_settings, $preview_post_id) {
587 if ((int) $object_id === (int) $preview_post_id && $meta_key === 'testimonial_settings') {
588 // ALWAYS wrap in array.
589 // WP does: if ($single && is_array($check)) return $check[0]
590 // So $check[0] = $preview_settings (our full settings array) �
591
592 return array($preview_settings);
593 }
594 return $value;
595 };
596
597 // Attach temporary filter — priority 99 overrides WP object cache reads too
598 add_filter('get_post_metadata', $filter_fn, 99, 4);
599
600 $paged = isset($post_data['paged']) ? intval($post_data['paged']) : 1;
601 $is_ajax_request = isset($post_data['is_ajax_request']) ? sanitize_text_field($post_data['is_ajax_request']) : 'false';
602 $preview_html = do_shortcode('[TML id="' . $preview_post_id . '" paged="' . $paged . '" is_ajax_request="' . esc_attr($is_ajax_request) . '"]');
603
604 // Remove filter immediately after rendering
605 remove_filter('get_post_metadata', $filter_fn, 99);
606
607 wp_send_json_success(array('html' => $preview_html));
608 }
609
610 public function ajax_reset_shortcode_settings()
611 {
612 if (!current_user_can('edit_posts')) {
613 wp_send_json_error(array('message' => 'Unauthorized.'));
614 }
615
616 // Verify nonce
617 $nonce = isset($_POST['tml_shortcode_nonce']) ? sanitize_text_field(wp_unslash($_POST['tml_shortcode_nonce'])) : '';
618 if (empty($nonce) || !wp_verify_nonce($nonce, 'tml_save_shortcode_settings')) {
619 wp_send_json_error(array('message' => 'Security check failed.'));
620 }
621
622 $post_id = isset($_POST['post_ID']) ? intval(wp_unslash($_POST['post_ID'])) : 0;
623 if (!$post_id) {
624 wp_send_json_error(array('message' => 'Invalid post ID.'));
625 }
626
627 $post = get_post($post_id);
628 if (!$post || $post->post_type !== 'tml-shortcode') {
629 wp_send_json_error(array('message' => 'Invalid post type.'));
630 }
631
632 // Delete all settings — next load will use plugin defaults
633 delete_post_meta($post_id, 'testimonial_settings');
634
635 wp_send_json_success(array('message' => 'Settings have been reset to defaults.'));
636 }
637
638 public function tml_allow_data_protocol($protocols)
639 {
640 if (!in_array('data', $protocols)) {
641 $protocols[] = 'data';
642 }
643 return $protocols;
644 }
645
646 public function tml_shortcode_posts_columns($columns)
647 {
648 $new_columns = array();
649 foreach ($columns as $key => $title) {
650 $new_columns[$key] = $title;
651 if ($key === 'title') {
652 $new_columns['tml_shortcode'] = __('Shortcode', 'testimonial-maker');
653 $new_columns['tml_preset'] = __('Layout Preset', 'testimonial-maker');
654 }
655 }
656 return $new_columns;
657 }
658
659 public function tml_shortcode_posts_custom_column($column, $post_id)
660 {
661 if ($column === 'tml_shortcode') {
662 static $script_printed = false;
663 if (!$script_printed) {
664 $script_printed = true;
665 ?>
666 <style>
667 .tml-duplicate-shortcode-btn {
668 display: inline-flex;
669 align-items: center;
670 justify-content: center;
671 gap: 4px;
672 height: 24px;
673 padding: 0 10px;
674 background: #10b981;
675 border: 1px solid #10b981;
676 color: #fff;
677 border-radius: 4px;
678 font-weight: 600;
679 cursor: pointer;
680 font-size: 11px;
681 transition: all 0.2s ease;
682 outline: none;
683 box-sizing: border-box;
684 text-decoration: none;
685 }
686
687 .tml-duplicate-shortcode-btn:hover {
688 background: #059669;
689 border-color: #059669;
690 color: #fff;
691 box-shadow: 0 2px 4px rgba(16, 185, 129, 0.3);
692 }
693
694 .tml-copy-shortcode-btn:hover {
695 opacity: 0.9;
696 box-shadow: 0 2px 4px rgba(98, 0, 238, 0.3);
697 }
698 </style>
699 <script>
700 jQuery(document).ready(function ($) {
701 $(document).on('click', '.tml-copy-shortcode-btn', function (e) {
702 e.preventDefault();
703 var $btn = $(this);
704 var shortcodeText = $btn.attr('data-shortcode');
705
706 var $temp = $("<input>");
707 $("body").append($temp);
708 $temp.val(shortcodeText).select();
709 document.execCommand("copy");
710 $temp.remove();
711
712 var originalHtml = $btn.html();
713 $btn.html('<span class="dashicons dashicons-yes" style="font-size:14px; width:14px; height:14px; margin-top:2px; color:#fff;"></span> Copied!').css({
714 'background': '#2e7d32',
715 'border-color': '#2e7d32',
716 'box-shadow': '0 2px 4px rgba(46,125,50,0.3)'
717 });
718 setTimeout(function () {
719 $btn.html(originalHtml).css({
720 'background': '#6200ee',
721 'border-color': '#6200ee',
722 'box-shadow': 'none'
723 });
724 }, 2000);
725 });
726 });
727 </script>
728 <?php
729 }
730 $shortcode = '[TML id="' . $post_id . '"]';
731 ?>
732 <div class="tml-shortcode-copy-container" style="display:inline-flex; align-items:center; gap:8px;">
733 <code
734 style="background:#f1f3f5; padding:4px 8px; border-radius:4px; border:1px solid #dcdfe3; font-family:Consolas, Monaco, monospace; font-size:11px; color:#1a1a1a; user-select:all; font-weight:500;">[TML id="<?php echo esc_attr($post_id); ?>"]</code>
735 <button class="tml-copy-shortcode-btn" data-shortcode='[TML id="<?php echo esc_attr($post_id); ?>"]'
736 style="display:inline-flex; align-items:center; justify-content:center; gap:4px; height:24px; padding:0 10px; background:#6200ee; border:1px solid #6200ee; color:#fff; border-radius:4px; font-weight:600; cursor:pointer; font-size:11px; transition:all 0.2s ease; outline:none; box-sizing:border-box;">
737 <span class="dashicons dashicons-admin-page"
738 style="font-size:12px; width:12px; height:12px; margin-top:2px;"></span> Copy
739 </button>
740 <a href="<?php echo esc_url(wp_nonce_url(admin_url('admin.php?action=tml_duplicate_shortcode&post=' . $post_id), 'tml_duplicate_' . $post_id)); ?>"
741 class="tml-duplicate-shortcode-btn">
742 <span class="dashicons dashicons-welcome-add-page"
743 style="font-size:12px; width:12px; height:12px; margin-top:2px;"></span> Duplicate
744 </a>
745 </div>
746 <?php
747 } elseif ($column === 'tml_preset') {
748 $settings = get_post_meta($post_id, 'testimonial_settings', true);
749 $preset = isset($settings['tml_layout_preset']) ? $settings['tml_layout_preset'] : 'slider';
750 $preset_titles = array(
751 'slider' => 'Slider',
752 'carousel' => 'Carousel',
753 'grid' => 'Grid',
754 'masonry' => 'Masonry',
755 'isotope' => 'Isotope',
756 'list' => 'List'
757 );
758 $title = isset($preset_titles[$preset]) ? $preset_titles[$preset] : 'Slider';
759
760 $bg_color = '#e8f0fe';
761 $color = '#1a73e8';
762 if ($preset === 'grid') {
763 $bg_color = '#e6f4ea';
764 $color = '#137333';
765 } elseif ($preset === 'masonry') {
766 $bg_color = '#fef7e0';
767 $color = '#b06000';
768 } elseif ($preset === 'isotope') {
769 $bg_color = '#f3e8fd';
770 $color = '#7c25e9';
771 } elseif ($preset === 'list') {
772 $bg_color = '#fce8e6';
773 $color = '#c5221f';
774 } elseif ($preset === 'carousel') {
775 $bg_color = '#f3e8fd';
776 $color = '#9334e6';
777 }
778 ?>
779 <span class="tml-preset-badge"
780 style="display:inline-flex; align-items:center; background:<?php echo esc_attr($bg_color); ?>; color:<?php echo esc_attr($color); ?>; font-weight:600; font-size:11px; padding:3px 10px; border-radius:12px; text-transform:capitalize; border:1px solid rgba(0,0,0,0.04);">
781 <?php echo esc_html($title); ?>
782 </span>
783 <?php
784 }
785 }
786
787 public function tml_shortcode_row_actions($actions, $post)
788 {
789 if ($post->post_type === 'tml-shortcode') {
790 $actions['duplicate'] = '<a href="' . esc_url(wp_nonce_url(admin_url('admin.php?action=tml_duplicate_shortcode&post=' . $post->ID), 'tml_duplicate_' . $post->ID)) . '" title="' . esc_attr__('Duplicate this shortcode', 'testimonial-maker') . '">' . __('Duplicate', 'testimonial-maker') . '</a>';
791 }
792 return $actions;
793 }
794
795 public function tml_duplicate_shortcode_handler()
796 {
797 if (!current_user_can('edit_posts')) {
798 wp_die(esc_html__('You do not have permission to duplicate this shortcode.', 'testimonial-maker'));
799 }
800
801 $post_id = isset($_GET['post']) ? intval($_GET['post']) : 0;
802 if (!$post_id) {
803 wp_die(esc_html__('No shortcode ID was provided.', 'testimonial-maker'));
804 }
805
806 // Verify nonce
807 $nonce = isset($_GET['_wpnonce']) ? sanitize_text_field(wp_unslash($_GET['_wpnonce'])) : '';
808 if (!wp_verify_nonce($nonce, 'tml_duplicate_' . $post_id)) {
809 wp_die(esc_html__('Security check failed.', 'testimonial-maker'));
810 }
811
812 $post = get_post($post_id);
813 if (!$post || $post->post_type !== 'tml-shortcode') {
814 wp_die(esc_html__('Invalid shortcode CPT.', 'testimonial-maker'));
815 }
816
817 // Create duplicate post
818 $new_post = array(
819 'post_title' => $post->post_title . ' (Duplicate)',
820 'post_status' => 'draft',
821 'post_type' => 'tml-shortcode',
822 );
823
824 $new_post_id = wp_insert_post($new_post);
825
826 if (!is_wp_error($new_post_id)) {
827 // Copy all post meta
828 $meta_keys = get_post_custom_keys($post_id);
829 if (!empty($meta_keys)) {
830 foreach ($meta_keys as $key) {
831 if (in_array($key, array('_edit_lock', '_edit_last'))) {
832 continue;
833 }
834 $values = get_post_meta($post_id, $key);
835 foreach ($values as $value) {
836 add_post_meta($new_post_id, $key, $value);
837 }
838 }
839 }
840
841 // Redirect back to list
842 wp_safe_redirect(admin_url('edit.php?post_type=tml-shortcode&tml_duplicated=1'));
843 exit;
844 } else {
845 wp_die(esc_html__('Failed to create duplicate shortcode.', 'testimonial-maker'));
846 }
847 }
848
849 public function tml_duplicate_admin_notice()
850 {
851 global $pagenow;
852 // phpcs:disable WordPress.Security.NonceVerification.Recommended
853 if ($pagenow === 'edit.php' && isset($_GET['post_type']) && $_GET['post_type'] === 'tml-shortcode' && isset($_GET['tml_duplicated'])) {
854 ?>
855 <div class="notice notice-success is-dismissible">
856 <p><?php esc_html_e('Shortcode duplicated successfully.', 'testimonial-maker'); ?></p>
857 </div>
858 <?php
859 }
860 // phpcs:enable WordPress.Security.NonceVerification.Recommended
861 }
862
863 public function tml_run_v2_migration()
864 {
865 if (get_option('tml_premium_migrated_to_v2') !== 'yes') {
866 // 1. Migrate Global Settings
867 $global_settings = get_option('testimonial_settings');
868 if (is_array($global_settings)) {
869 $global_settings['testimonial_carousel_design'] = 1;
870 update_option('testimonial_settings', $global_settings);
871 }
872
873 // 2. Migrate Showcase Settings (Custom Post Meta)
874 $showcases = get_posts(array(
875 'post_type' => 'testimonial-maker',
876 'posts_per_page' => -1,
877 'post_status' => 'any',
878 'fields' => 'ids',
879 ));
880 if (!empty($showcases)) {
881 foreach ($showcases as $showcase_id) {
882 $settings = get_post_meta($showcase_id, 'testimonial_settings', true);
883 if (is_array($settings)) {
884 $settings['testimonial_carousel_design'] = 1;
885 update_post_meta($showcase_id, 'testimonial_settings', $settings);
886 }
887 }
888 }
889
890 // 3. Mark migration as completed
891 update_option('tml_premium_migrated_to_v2', 'yes');
892 }
893 }
894
895 public function tml_auto_create_default_shortcode()
896 {
897 $default_id = get_option('tml_default_shortcode_id');
898 if (empty($default_id) || !get_post($default_id)) {
899 $default_id = wp_insert_post(array(
900 'post_title' => 'Default Shortcode',
901 'post_status' => 'publish',
902 'post_type' => 'tml-shortcode',
903 ));
904 if (!is_wp_error($default_id)) {
905 update_option('tml_default_shortcode_id', $default_id);
906 $default_settings = get_option('testimonial_settings');
907 if (is_array($default_settings)) {
908 update_post_meta($default_id, 'testimonial_settings', $default_settings);
909 }
910 }
911 }
912 }
913 }
914
915 $new_testimonial_object = new tml_or_testimonial();
916 require_once('shortcode.php');
917 require_once('include/frontend-form.php');
918 require_once('include/user-dashboard.php');
919 }
920 ?>