@@ -65,6 +65,100 @@ public function init() {
6565 add_action ( 'wp_ajax_nopriv_skip_subscribe ' , array ( $ this , 'skip_subscribe ' ) );
6666
6767 $ this ->register_feedback_settings ();
68+
69+ $ this ->register_prevent_clone_hooks ();
70+ }
71+
72+ /**
73+ * Register hooks to prevent meta cloning for the templates.
74+ * This is needed because the template id is unique, and we don't want to clone it.
75+ * @return void
76+ */
77+ public function register_prevent_clone_hooks () {
78+ $ allowed_post_types = Editor::get_allowed_post_types ();
79+ if ( empty ( $ allowed_post_types ) ) {
80+ return ;
81+ }
82+ foreach ( $ allowed_post_types as $ post_type ) {
83+ add_filter (
84+ 'update_ ' . $ post_type . '_metadata ' ,
85+ function ( $ value , $ post_id , $ meta_key , $ meta_value , $ prev_value ) use ( $ post_type ) {
86+ if ( $ this ->check_unique_template_id_on_meta_change ( $ post_id , $ meta_key , $ post_type , $ meta_value ) ) {
87+ return true ;
88+ }
89+ return $ value ;
90+ },
91+ 10 ,
92+ 5
93+ );
94+ add_filter (
95+ 'add_ ' . $ post_type . '_metadata ' ,
96+ function ( $ value , $ post_id , $ meta_key , $ meta_value , $ unique ) use ( $ post_type ) {
97+ if ( $ this ->check_unique_template_id_on_meta_change ( $ post_id , $ meta_key , $ post_type , $ meta_value ) ) {
98+ return true ;
99+ }
100+ return $ value ;
101+ },
102+ 10 ,
103+ 5
104+ );
105+ }
106+ }
107+
108+ /**
109+ * Check that the meta value is unique for the allowed post types that support Templates Cloud.
110+ *
111+ * @param int $post_id The post ID.
112+ * @param string $meta_key The meta key.
113+ * @param string $meta_type The meta type. The post type ( post, page, neve_custom_layouts etc. ).
114+ * @param string $meta_value The meta value.
115+ *
116+ * @return bool
117+ */
118+ public function check_unique_template_id_on_meta_change ( $ post_id , $ meta_key , $ meta_type , $ meta_value ) {
119+ // Skip check if the meta key is not one of the allowed ones.
120+ if ( ! in_array (
121+ $ meta_key ,
122+ array (
123+ '_ti_tpc_template_sync ' ,
124+ '_ti_tpc_template_id ' ,
125+ '_ti_tpc_screenshot_url ' ,
126+ '_ti_tpc_site_slug ' ,
127+ '_ti_tpc_published ' ,
128+ ),
129+ true
130+ )
131+ ) {
132+ return false ;
133+ }
134+
135+ if ( empty ( $ meta_value ) ) {
136+ return false ;
137+ }
138+
139+ $ template_id = get_post_meta ( $ post_id , '_ti_tpc_template_id ' , true );
140+ if ( empty ( $ template_id ) && $ meta_key === '_ti_tpc_template_id ' ) {
141+ $ template_id = $ meta_value ;
142+ }
143+
144+ // Check if the template ID is used on any other posts or pages
145+ // exclude the current post from the query
146+ $ args = array (
147+ 'post_type ' => $ meta_type ,
148+ 'meta_key ' => '_ti_tpc_template_id ' ,
149+ 'meta_value ' => $ template_id ,
150+ 'post__not_in ' => array ( $ post_id ),
151+ 'posts_per_page ' => 1 ,
152+ 'fields ' => 'ids ' ,
153+ );
154+ $ query = new \WP_Query ( $ args );
155+ $ duplicate_id = $ query ->get_posts ();
156+
157+ if ( ! empty ( $ duplicate_id ) ) {
158+ // The template ID is already used on another post
159+ return true ;
160+ }
161+ return false ;
68162 }
69163
70164 /**
@@ -253,11 +347,11 @@ public function enqueue() {
253347
254348 $ dependencies = ( include TIOB_PATH . 'assets/build/app.asset.php ' );
255349
256- wp_register_style ( 'tiob ' , TIOB_URL . '/ assets/build/style-app.css ' , array ( 'wp-components ' ), $ dependencies ['version ' ] );
350+ wp_register_style ( 'tiob ' , TIOB_URL . 'assets/build/style-app.css ' , array ( 'wp-components ' ), $ dependencies ['version ' ] );
257351 wp_style_add_data ( 'tiob ' , 'rtl ' , 'replace ' );
258352 wp_enqueue_style ( 'tiob ' );
259353
260- wp_register_script ( 'tiob ' , TIOB_URL . '/ assets/build/app.js ' , array_merge ( $ dependencies ['dependencies ' ], array ( 'updates ' ) ), $ dependencies ['version ' ], true );
354+ wp_register_script ( 'tiob ' , TIOB_URL . 'assets/build/app.js ' , array_merge ( $ dependencies ['dependencies ' ], array ( 'updates ' ) ), $ dependencies ['version ' ], true );
261355 wp_localize_script ( 'tiob ' , 'tiobDash ' , apply_filters ( 'neve_dashboard_page_data ' , $ this ->get_localization () ) );
262356 wp_enqueue_script ( 'tiob ' );
263357 }
@@ -287,7 +381,7 @@ private function get_localization() {
287381 return array (
288382 'version ' => TIOB_VERSION ,
289383 'nonce ' => wp_create_nonce ( 'wp_rest ' ),
290- 'assets ' => TIOB_URL . '/ assets/ ' ,
384+ 'assets ' => TIOB_URL . 'assets/ ' ,
291385 'upgradeURL ' => $ upgrade_url ,
292386 'upgradeURLTpc ' => $ upgrade_url_tpc ,
293387 'strings ' => array (
@@ -519,8 +613,8 @@ private function get_migrateable( $theme_support ) {
519613
520614 $ options = array (
521615 'theme_name ' => ! empty ( $ data [ $ old_theme ]['theme_name ' ] ) ? esc_html ( $ data [ $ old_theme ]['theme_name ' ] ) : '' ,
522- 'screenshot ' => TIOB_URL . '/ migration/ ' . $ folder_name . '/ ' . $ data [ $ old_theme ]['template ' ] . '.png ' ,
523- 'template ' => TIOB_PATH . '/ migration/ ' . $ folder_name . '/ ' . $ data [ $ old_theme ]['template ' ] . '.json ' ,
616+ 'screenshot ' => TIOB_URL . 'migration/ ' . $ folder_name . '/ ' . $ data [ $ old_theme ]['template ' ] . '.png ' ,
617+ 'template ' => TIOB_PATH . 'migration/ ' . $ folder_name . '/ ' . $ data [ $ old_theme ]['template ' ] . '.json ' ,
524618 'template_name ' => $ data [ $ old_theme ]['template ' ],
525619 'heading ' => $ data [ $ old_theme ]['heading ' ],
526620 'description ' => $ data [ $ old_theme ]['description ' ],
0 commit comments