Skip to content

Commit 45c253e

Browse files
authored
release: small fixes
- Fix: Admin paths consistency - Fix: Prevent cloned posts to inherit template metadata - Fix: Improve compatibility for LifterLMS
2 parents bcce702 + 003db68 commit 45c253e

File tree

5 files changed

+232
-14
lines changed

5 files changed

+232
-14
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ artifact
66
vendor
77
languages/*.pot
88
**/build/*
9-
**/.DS_Store
9+
**/.DS_Store
10+
.phpunit.result.cache

composer.lock

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

includes/Admin.php

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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'],

includes/Importers/Helpers/Helper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ private function remap_host( $url ) {
105105
* @return string
106106
*/
107107
public function cleanup_page_slug( $slug, $demo_slug ) {
108-
$unhashed = array( 'shop', 'my-account', 'checkout', 'cart', 'blog', 'news', 'lifter-courses', 'courses', 'dashboard', 'my-courses' );
108+
$unhashed = array( 'shop', 'my-account', 'checkout', 'cart', 'blog', 'news', 'lifter-courses', 'courses', 'dashboard', 'my-courses', 'memberships' );
109109
$slug = str_replace( $demo_slug, '', $slug );
110110
$slug = str_replace( 'demo', '', $slug );
111111
$slug = ltrim( $slug, '-' );

tests/post-clone-test.php

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
/**
3+
* Post clone tests.
4+
*
5+
* @author Bogdan Preda <[email protected]>
6+
* @package templates-patterns-collection
7+
*/
8+
9+
use TIOB\Admin;
10+
11+
/**
12+
* Class Post_Clone_Test
13+
*/
14+
class Post_Clone_Test extends WP_UnitTestCase {
15+
16+
private $post_id;
17+
private $template_id = 'tpc_template_source_ID';
18+
19+
/**
20+
* Create a post with _ti_tpc_template_id meta.
21+
*/
22+
public function setUp(): void {
23+
parent::setUp();
24+
25+
$admin = new Admin();
26+
// Only Hook the save_post action from the Admin class.
27+
$admin->register_prevent_clone_hooks();
28+
}
29+
30+
/**
31+
* Check meta value is true. Utility function for better readability.
32+
*
33+
* @param mixed $value The meta value.
34+
*
35+
* @return bool
36+
*/
37+
private function meta_value_is_true( $value ) {
38+
return $value === '1' || $value === 'true' || $value === true;
39+
}
40+
41+
/**
42+
* Create a post with meta.
43+
* Utility function to create a post with meta.
44+
*
45+
* @param string $post_title The post title.
46+
* @param string $template_id The template id.
47+
*
48+
* @return int
49+
*/
50+
private function create_post_with_meta( $post_title = 'A test Post', $template_id = 'tpc_template_test_ID', $published = true ) {
51+
$post_id = $this->factory()->post->create(
52+
array(
53+
'post_title' => $post_title,
54+
'post_type' => 'post',
55+
)
56+
);
57+
update_post_meta( $post_id, '_ti_tpc_template_id', $template_id );
58+
update_post_meta( $post_id, '_ti_tpc_template_sync', $published );
59+
update_post_meta( $post_id, '_ti_tpc_published', $published );
60+
return $post_id;
61+
}
62+
63+
/**
64+
* Clone a post and its meta.
65+
* Utility function to clone a post and its meta.
66+
*
67+
* @return int
68+
*/
69+
private function clone_post_and_meta() {
70+
$post = get_post( $this->post_id );
71+
$new_post_id = wp_insert_post(
72+
array(
73+
'post_title' => $post->post_title,
74+
'post_content' => $post->post_content,
75+
'post_status' => 'publish',
76+
'post_type' => $post->post_type,
77+
)
78+
);
79+
$meta_keys = get_post_custom_keys( $this->post_id );
80+
foreach ( $meta_keys as $meta_key ) {
81+
$meta_values = get_post_custom_values( $meta_key, $this->post_id );
82+
foreach ( $meta_values as $meta_value ) {
83+
$meta_value = maybe_unserialize( $meta_value );
84+
add_post_meta( $new_post_id, $meta_key, $meta_value );
85+
}
86+
}
87+
return $new_post_id;
88+
}
89+
90+
/**
91+
* Test that the post has the meta defined and if cloned the meta is not the same.
92+
*/
93+
final public function test_post_meta_and_clone() {
94+
$this->post_id = $this->create_post_with_meta( 'The Original Post source', $this->template_id );
95+
96+
$this->assertTrue( get_post_meta( $this->post_id, '_ti_tpc_template_id', true ) === $this->template_id );
97+
$this->assertTrue( $this->meta_value_is_true( get_post_meta( $this->post_id, '_ti_tpc_template_sync', true ) ) );
98+
$this->assertTrue( $this->meta_value_is_true( get_post_meta( $this->post_id, '_ti_tpc_published', true ) ) );
99+
100+
$clone_post_id = $this->clone_post_and_meta();
101+
102+
// assert that the new cloned post does not have the same meta as the original.
103+
$this->assertTrue( $clone_post_id !== $this->post_id );
104+
$this->assertTrue( get_post_meta( $clone_post_id, '_ti_tpc_template_id', true ) !== $this->template_id );
105+
$this->assertTrue( ! $this->meta_value_is_true( get_post_meta( $clone_post_id, '_ti_tpc_template_sync', true ) ) );
106+
$this->assertTrue( ! $this->meta_value_is_true( get_post_meta( $clone_post_id, '_ti_tpc_published', true ) ) );
107+
}
108+
109+
final public function test_create_new_post_check_meta_is_not_stripped() {
110+
$template_id = 'tpcs_new_template_ID_' . time();
111+
$new_post_id = $this->create_post_with_meta( 'The New Post', $template_id, true );
112+
$this->assertTrue( get_post_meta( $new_post_id, '_ti_tpc_template_id', true ) === $template_id );
113+
$this->assertTrue( $this->meta_value_is_true( get_post_meta( $new_post_id, '_ti_tpc_template_sync', true ) ) );
114+
$this->assertTrue( $this->meta_value_is_true( get_post_meta( $new_post_id, '_ti_tpc_published', true ) ) );
115+
116+
// attempt to create a post with same template id.
117+
$new_test_post = $this->create_post_with_meta( 'The New Manual Post', $template_id, true );
118+
$this->assertTrue( get_post_meta( $new_test_post, '_ti_tpc_template_id', true ) !== $template_id );
119+
$this->assertTrue( ! $this->meta_value_is_true( get_post_meta( $new_test_post, '_ti_tpc_template_sync', true ) ) );
120+
$this->assertTrue( ! $this->meta_value_is_true( get_post_meta( $new_test_post, '_ti_tpc_published', true ) ) );
121+
}
122+
123+
}

0 commit comments

Comments
 (0)