summaryrefslogtreecommitdiff
blob: 26108941e2f0e5a3f9dcc9e7af7b4b8c9f36bb9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
<?php
/**
 * Migration from Jetpack Custom CSS to WordPress' Core CSS.
 *
 * @since 4.4.2
 *
 * @package Jetpack
 */

/**
 * Class Jetpack_Custom_CSS_Data_Migration
 */
class Jetpack_Custom_CSS_Data_Migration {
	/**
	 * Set up assorted actions and filters used by this class.
	 */
	public static function add_hooks() {
		add_action( 'init', array( __CLASS__, 'register_legacy_post_type' ) );
		add_action( 'admin_init', array( __CLASS__, 'do_migration' ) );

		include_once( dirname( __FILE__ ) . '/custom-css.php' );
		if ( ! is_admin() ) {
			add_action( 'init', array( 'Jetpack_Custom_CSS', 'init' ) );
		}
	}

	/**
	 * Do the bulk of the migration.
	 *
	 * @return int|null
	 */
	public static function do_migration() {
		Jetpack_Options::update_option( 'custom_css_4.7_migration', true );
		Jetpack::log( 'custom_css_4.7_migration', 'start' );

		if ( ! post_type_exists( 'safecss' ) ) {
			self::register_legacy_post_type();
		}

		/** This filter is documented in modules/custom-css/custom-css.php */
		$preprocessors      = apply_filters( 'jetpack_custom_css_preprocessors', array() );
		$core_css_post      = wp_get_custom_css_post();
		$jetpack_css_post   = self::get_post();

		if ( ! $jetpack_css_post ) {
			return;
		}

		$revisions          = self::get_all_revisions();

		// Migrate the settings from revision meta to theme mod.
		$options = self::get_options( $jetpack_css_post->ID );
		set_theme_mod( 'jetpack_custom_css', $options );

		if ( empty( $revisions ) || ! is_array( $revisions ) ) {
			if ( $jetpack_css_post instanceof WP_Post ) {
				// Feed in the raw, if the current setting is Sass/LESS, it'll filter it inside.
				kses_remove_filters();
				wp_update_custom_css_post( $jetpack_css_post->post_content );
				kses_init();
				return 1;
			}
			return null;
		}

		$revisions            = array_reverse( $revisions );
		$themes               = Jetpack_Custom_CSS_Enhancements::get_themes();
		$migrated             = array();

		foreach ( $revisions as $post_id => $post ) {
			// Jetpack had stored the theme Name, not the stylesheet directory, for ... reasons.
			// Get the stylesheet.  If null, the theme is no longer available.  Skip.
			$stylesheet = isset( $themes[ $post->post_excerpt ] ) ? $themes[ $post->post_excerpt ] : null;
			if ( empty( $stylesheet ) ) {
				continue;
			}

			$migrated[] = $post->ID;
			$preprocessor = get_post_meta( $post->ID, 'custom_css_preprocessor', true );
			$css = $post->post_content;
			$pre = '';

			// Do a revision by revision parsing.
			if ( $preprocessor && isset( $preprocessors[ $preprocessor ] ) ) {
				$pre = $css;
				$css = call_user_func( $preprocessors[ $preprocessor ]['callback'], $pre );
			}

			kses_remove_filters();
			wp_update_custom_css_post( $css, array(
				'stylesheet'   => $stylesheet,
				'preprocessed' => $pre,
			) );
			kses_init();
		}

		// If we've migrated some CSS for the current theme and there was already something there in the Core dataset ...
		if ( $core_css_post && $jetpack_css_post ) {
			$preprocessor = $options['preprocessor'];

			$css = $core_css_post->post_content;
			$pre = $core_css_post->post_content_filtered;
			if ( $preprocessor ) {
				if ( $pre ) {
					$pre .= "\r\n\r\n/*\r\n\t" . esc_js( __( 'CSS Migrated from Jetpack:', 'jetpack' ) ) . "\r\n*/\r\n\r\n";
				}
				$pre .= $jetpack_css_post->post_content;

				$css .= "\r\n\r\n/*\r\n\t" . esc_js( __( 'CSS Migrated from Jetpack:', 'jetpack' ) ) . "\r\n*/\r\n\r\n";
				$css .= call_user_func( $preprocessors[ $preprocessor ]['callback'], $jetpack_css_post->post_content );
			} else {
				$css .= "\r\n\r\n/*\r\n\t" . esc_js( __( 'CSS Migrated from Jetpack:', 'jetpack' ) ) . "\r\n*/\r\n\r\n";
				$css .= $jetpack_css_post->post_content;
			}

			wp_update_custom_css_post( $css, array(
				'preprocessed' => $pre,
			) );
		}

		Jetpack::log( 'custom_css_4.7_migration', count( $migrated ) . 'revisions migrated' );
		return count( $migrated );
	}

	/**
	 * Re-register the legacy CPT so we can play with the content already in the database.
	 */
	public static function register_legacy_post_type() {
		if ( post_type_exists( 'safecss' ) ) {
			return;
		}
		// Register safecss as a custom post_type
		// Explicit capability definitions are largely unnecessary because the posts are manipulated in code via an options page, managing CSS revisions does check the capabilities, so let's ensure that the proper caps are checked.
		register_post_type( 'safecss', array(
			'label'        => 'Custom CSS',
			'supports'     => array( 'revisions' ),
			'can_export'   => false,
			'rewrite'      => false,
			'capabilities' => array(
				'edit_post'          => 'edit_theme_options',
				'read_post'          => 'read',
				'delete_post'        => 'edit_theme_options',
				'edit_posts'         => 'edit_theme_options',
				'edit_others_posts'  => 'edit_theme_options',
				'publish_posts'      => 'edit_theme_options',
				'read_private_posts' => 'read',
			),
		) );
	}

	/**
	 * Get the post used for legacy storage.
	 *
	 * Jetpack used to use a single post for all themes, just blanking it on theme switch.  This gets that post.
	 *
	 * @return array|bool|null|WP_Post
	 */
	public static function get_post() {
		/** This filter is documented in modules/custom-css/custom-css.php */
		$custom_css_post_id = apply_filters( 'jetpack_custom_css_pre_post_id', null );
		if ( ! is_null( $custom_css_post_id ) ) {
			return get_post( $custom_css_post_id );
		}

		$custom_css_post_id = wp_cache_get( 'custom_css_post_id' );

		if ( false === $custom_css_post_id ) {
			$custom_css_posts = get_posts( array(
				'posts_per_page' => 1,
				'post_type'      => 'safecss',
				'post_status'    => 'publish',
				'orderby'        => 'date',
				'order'          => 'DESC',
			) );

			$custom_css_post_id = 0;
			if ( count( $custom_css_posts ) > 0 ) {
				$custom_css_post_id = $custom_css_posts[0]->ID;
			}

			// Save post_id=0 to note that no safecss post exists.
			wp_cache_set( 'custom_css_post_id', $custom_css_post_id );
		}

		if ( ! $custom_css_post_id ) {
			return false;
		}

		return get_post( $custom_css_post_id );
	}

	/**
	 * Get all revisions of the Jetpack CSS CPT entry.
	 *
	 * @return array
	 */
	public static function get_all_revisions() {
		$post = self::get_post();

		if ( ! $post ) {
			return array();
		}

		$revisions = wp_get_post_revisions( $post->ID, array(
			'posts_per_page' => -1,
			'orderby'        => 'date',
			'order'          => 'DESC',
		) );

		return $revisions;
	}

	/**
	 * Get the options stored for a given revision ID.
	 *
	 * Jetpack used to version the settings by storing them as meta on the revision.
	 *
	 * @param integer $post_id Post ID.
	 *
	 * @return array
	 */
	public static function get_options( $post_id = null ) {
		if ( empty( $post_id ) ) {
			$post = self::get_post();
			$post_id = $post->ID;
		}

		$meta = get_post_meta( $post_id );

		$replace = false;
		if ( isset( $meta['custom_css_add'][0] ) && 'no' === $meta['custom_css_add'][0] ) {
			$replace = true;
		}

		return array(
			'preprocessor'  => isset( $meta['custom_css_preprocessor'][0] ) ? $meta['custom_css_preprocessor'][0] : '',
			'replace'       => $replace,
			'content_width' => isset( $meta['content_width'][0] )           ? $meta['content_width'][0]           : '',
		);
	}
}

Jetpack_Custom_CSS_Data_Migration::add_hooks();