PluginProbe ʕ •ᴥ•ʔ
SiteOrigin CSS / 1.2.4
SiteOrigin CSS v1.2.4
1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.10 1.5.11 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 trunk 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2.0
so-css / so-css.php
so-css Last commit date
css 7 years ago inc 9 years ago js 7 years ago lang 7 years ago lib 7 years ago tpl 7 years ago LICENSE 11 years ago readme.txt 6 years ago so-css.php 7 years ago
so-css.php
791 lines
1 <?php
2 /*
3 Plugin Name: SiteOrigin CSS
4 Description: An advanced CSS editor from SiteOrigin.
5 Version: 1.2.4
6 Author: SiteOrigin
7 Author URI: https://siteorigin.com
8 Plugin URI: https://siteorigin.com/css/
9 License: GPL3
10 License URI: https://www.gnu.org/licenses/gpl-3.0.txt
11 Text Domain: so-css
12 */
13
14 // Handle the legacy CSS editor that came with SiteOrigin themes
15 include plugin_dir_path( __FILE__ ) . 'inc/legacy.php';
16
17 define( 'SOCSS_VERSION', '1.2.4' );
18 define( 'SOCSS_JS_SUFFIX', '.min' );
19
20 /**
21 * Class SiteOrigin_CSS The main class for the SiteOrigin CSS Editor
22 */
23 class SiteOrigin_CSS {
24 private $theme;
25 private $snippet_paths;
26
27 function __construct() {
28 $this->theme = basename( get_template_directory() );
29 $this->snippet_paths = array();
30
31 // Main header actions
32 add_action( 'plugins_loaded', array( $this, 'set_plugin_textdomain' ) );
33
34 // Priority 20 is necessary to ensure our CSS takes precedence.
35 add_action( 'wp_head', array( $this, 'enqueue_css' ), 20 );
36
37 // All the admin actions
38 add_action( 'admin_menu', array( $this, 'action_admin_menu' ) );
39 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ), 20 );
40 add_action( 'admin_enqueue_scripts', array( $this, 'dequeue_admin_scripts' ), 19 );
41 add_action( 'load-appearance_page_so_custom_css', array( $this, 'add_help_tab' ) );
42
43 // Add the action links.
44 add_action( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'plugin_action_links' ) );
45
46 // The request to hide the getting started video
47 add_action( 'wp_ajax_socss_hide_getting_started', array( $this, 'admin_action_hide_getting_started' ) );
48
49 add_action( 'wp_ajax_socss_get_post_css', array( $this, 'admin_action_get_post_css' ) );
50 add_action( 'wp_ajax_socss_get_revisions_list', array( $this, 'admin_action_get_revisions_list' ) );
51
52 if ( ! is_admin() ) {
53 if( isset( $_GET['so_css_preview'] ) ) {
54
55 add_action( 'plugins_loaded', array($this, 'disable_ngg_resource_manager') );
56 add_filter( 'show_admin_bar', '__return_false' );
57 add_filter( 'wp_enqueue_scripts', array($this, 'enqueue_inspector_scripts') );
58 add_filter( 'wp_footer', array($this, 'inspector_templates') );
59
60 // We'll be grabbing all the enqueued scripts and outputting them
61 add_action( 'wp_enqueue_scripts', array($this, 'inline_inspector_scripts'), 100 );
62 }
63 }
64 }
65
66 /**
67 * Get a singleton of the SiteOrigin CSS.
68 *
69 * @return SiteOrigin_CSS
70 */
71 static function single() {
72 static $single;
73
74 if ( empty( $single ) ) {
75 $single = new SiteOrigin_CSS();
76 }
77
78 return $single;
79 }
80
81 /**
82 * Retrieve the current custom CSS for a given theme and post id combination.
83 *
84 * @param $theme string The name of the theme for which to retrieve custom CSS.
85 * @param $post_id int The ID of the specific post for which to retrieve custom CSS.
86 *
87 * @return string The custom CSS for the theme and post ID combination.
88 */
89 function get_custom_css( $theme, $post_id = null ) {
90 $css_key = 'siteorigin_custom_css[' . $theme . ']';
91 if ( empty( $post_id ) ) {
92 return get_option( $css_key, '' );
93 }
94
95 return get_post_meta( $post_id, $css_key, true );
96 }
97
98 /**
99 * Save custom CSS for a given theme and post id combination.
100 *
101 * @param $custom_css string The custom CSS to save.
102 * @param $theme string The name of the theme for which to save custom CSS.
103 * @param $post_id int The ID of the specific post for which to save custom CSS.
104 *
105 * @return bool Whether or not saving the custom CSS was successful.
106 */
107 function save_custom_css( $custom_css, $theme, $post_id = null ) {
108 $css_key = 'siteorigin_custom_css[' . $theme . ']';
109 if ( empty( $post_id ) ) {
110 $current = get_option( $css_key );
111 if ( $current === false ) {
112 return add_option( $css_key, $custom_css, '', 'no' );
113 } else {
114 return update_option( $css_key, $custom_css );
115 }
116 }
117
118 if ( metadata_exists( 'post', $post_id, $css_key ) ) {
119 return update_post_meta( $post_id, $css_key, $custom_css );
120 }
121
122 return add_post_meta( $post_id, $css_key, $custom_css );
123 }
124
125 /**
126 * Save custom CSS for a given theme and post id combination to a file in the uploads directory to allow for caching.
127 *
128 * @param $custom_css
129 * @param $theme
130 * @param null $post_id
131 */
132 function save_custom_css_file( $custom_css, $theme, $post_id = null ) {
133 if ( WP_Filesystem() ) {
134 global $wp_filesystem;
135 $upload_dir = wp_upload_dir();
136 $upload_dir_path = $upload_dir['basedir'] . '/so-css/';
137
138 if ( ! $wp_filesystem->is_dir( $upload_dir_path ) ) {
139 $wp_filesystem->mkdir( $upload_dir_path );
140 }
141
142 $css_file_name = 'so-css-' . $theme . ( ! empty( $post_id ) ? '_' . $post_id : '' );
143 $css_file_path = $upload_dir_path . $css_file_name . '.css';
144
145 if ( file_exists( $css_file_path ) ) {
146 $wp_filesystem->delete( $css_file_path );
147 }
148
149 $wp_filesystem->put_contents(
150 $css_file_path,
151 $custom_css
152 );
153 }
154 }
155
156 /**
157 * Retrieve the previous revisions of custom CSS for a given theme and post id combination.
158 *
159 * @param $theme string The name of the theme for which to retrieve custom CSS revisions.
160 * @param $post_id int The ID of the specific post for which to retrieve custom CSS revisions.
161 *
162 * @return array The custom CSS revisions for the theme and post ID combination.
163 */
164 function get_custom_css_revisions( $theme, $post_id = null ) {
165 $css_key = 'siteorigin_custom_css_revisions[' . $theme . ']';
166 if ( empty( $post_id ) ) {
167 return get_option( $css_key, '' );
168 }
169
170 return get_post_meta( $post_id, $css_key, true );
171 }
172
173 /**
174 * Adds a custom CSS revision for a given theme and post id combination.
175 *
176 * @param $custom_css string The custom CSS to add as a revision.
177 * @param $theme string The name of the theme for which to save custom CSS.
178 * @param $post_id int The ID of the specific post for which to save custom CSS.
179 *
180 * @return bool Whether or not adding the custom CSS revision was successful.
181 */
182 function add_custom_css_revision( $custom_css, $theme, $post_id = null ) {
183 $revisions = $this->get_custom_css_revisions( $this->theme, $post_id );
184
185 $css_key = 'siteorigin_custom_css_revisions[' . $theme . ']';
186
187 if ( empty( $revisions ) ) {
188 $revisions = array();
189 if ( empty( $post_id ) ) {
190 add_option( $css_key, $revisions, '', 'no' );
191 } else {
192 add_post_meta( $post_id, $css_key, $revisions );
193 }
194 }
195 $revisions[ time() ] = $custom_css;
196
197 // Sort the revisions and cut off any old ones.
198 krsort( $revisions );
199 $revisions = array_slice( $revisions, 0, 15, true );
200
201 if ( empty( $post_id ) ) {
202 return update_option( $css_key, $revisions );
203 }
204
205 return update_post_meta( $post_id, $css_key, $revisions );
206 }
207
208 /**
209 * Enqueue or print inline CSS.
210 */
211 function enqueue_css() {
212
213 $this->enqueue_custom_css( $this->theme );
214
215 if ( is_singular() ) {
216 $this->enqueue_custom_css( $this->theme, get_the_ID() );
217 }
218
219 }
220
221 /**
222 * Enqueue the custom CSS for the given theme and post id combination.
223 *
224 * @param $theme string The name of the theme for which to enqueue custom CSS.
225 * @param $post_id int The ID of the specific post for which to enqueue custom CSS.
226 *
227 */
228 function enqueue_custom_css( $theme, $post_id = null ) {
229
230 $upload_dir = wp_upload_dir();
231 $upload_dir_path = $upload_dir['basedir'] . '/so-css/';
232
233 $css_id = $theme . ( ! empty( $post_id ) ? '_' . $post_id : '' );
234 $css_file_name = 'so-css-' . $css_id;
235 $css_file_path = $upload_dir_path . $css_file_name . '.css';
236
237 if ( empty( $_GET['so_css_preview'] ) && ! is_admin() && file_exists( $css_file_path ) ) {
238 wp_enqueue_style(
239 'so-css-' . $css_id,
240 set_url_scheme( $upload_dir['baseurl'] . '/so-css/' . $css_file_name . '.css' ),
241 array(),
242 $this->get_latest_revision_timestamp()
243 );
244 } else {
245 $custom_css = $this->get_custom_css( $theme, $post_id );
246 // We just need to enqueue a dummy style
247 if ( ! empty( $custom_css ) ) {
248 echo "<style id='" . sanitize_html_class( $css_id ) . "-custom-css' class='siteorigin-custom-css' type='text/css'>\n";
249 echo self::sanitize_css( $custom_css ) . "\n";
250 echo "</style>\n";
251 }
252 }
253 }
254
255 function set_plugin_textdomain() {
256 load_plugin_textdomain( 'so-css', false, plugin_dir_path( __FILE__ ) . 'lang/' );
257 }
258
259 /**
260 * Action to run on the admin action.
261 */
262 function action_admin_menu() {
263 add_theme_page( __( 'Custom CSS', 'so-css' ), __( 'Custom CSS', 'so-css' ), 'edit_theme_options', 'so_custom_css', array(
264 $this,
265 'display_admin_page'
266 ) );
267
268 if ( current_user_can( 'edit_theme_options' ) && isset( $_POST['siteorigin_custom_css_save'] ) ) {
269 check_admin_referer( 'custom_css', '_sononce' );
270
271 // Sanitize CSS input. Should keep most tags, apart from script and style tags.
272 $custom_css = self::sanitize_css( filter_input( INPUT_POST, 'custom_css' ) );
273 $socss_post_id = filter_input( INPUT_GET, 'socss_post_id', FILTER_VALIDATE_INT );
274
275 $current = $this->get_custom_css( $this->theme, $socss_post_id );
276 $this->save_custom_css( $custom_css, $this->theme, $socss_post_id );
277
278 // If this has changed, then add a revision.
279 if ( $current != $custom_css ) {
280 $this->add_custom_css_revision( $custom_css, $this->theme, $socss_post_id );
281
282 $this->save_custom_css_file( $custom_css, $this->theme, $socss_post_id );
283 }
284 }
285 }
286
287 /**
288 * Display the help tab
289 */
290 function add_help_tab() {
291 $screen = get_current_screen();
292 $screen->add_help_tab( array(
293 'id' => 'custom-css',
294 'title' => __( 'Custom CSS', 'so-css' ),
295 'content' => '<p>'
296 . sprintf( __( "SiteOrigin CSS adds any custom CSS you enter here into your site's header. ", 'so-css' ) )
297 . __( "These changes will persist across updates so it's best to make all your changes here. ", 'so-css' )
298 . '</p>'
299 ) );
300 }
301
302 function enqueue_admin_scripts( $page ) {
303 if ( $page != 'appearance_page_so_custom_css' ) {
304 return;
305 }
306
307 // Core WordPress stuff that we use
308 wp_enqueue_media();
309
310 // Enqueue the codemirror scripts. Call Underscore and Backbone dependencies so they're enqueued first to prevent conflicts.
311 wp_enqueue_script( 'socss-codemirror', plugin_dir_url( __FILE__ ) . 'lib/codemirror/lib/codemirror' . SOCSS_JS_SUFFIX . '.js', array(
312 'underscore',
313 'backbone'
314 ), '5.2.0' );
315 wp_enqueue_script( 'socss-codemirror-mode-css', plugin_dir_url( __FILE__ ) . 'lib/codemirror/mode/css/css' . SOCSS_JS_SUFFIX . '.js', array(), '5.2.0' );
316
317 // Add in all the linting libs
318 wp_enqueue_script( 'socss-codemirror-lint', plugin_dir_url( __FILE__ ) . 'lib/codemirror/addon/lint/lint' . SOCSS_JS_SUFFIX . '.js', array( 'socss-codemirror' ), '5.2.0' );
319 wp_enqueue_script( 'socss-codemirror-lint-css', plugin_dir_url( __FILE__ ) . 'lib/codemirror/addon/lint/css-lint' . SOCSS_JS_SUFFIX . '.js', array(
320 'socss-codemirror',
321 'socss-codemirror-lint-css-lib'
322 ), '5.2.0' );
323 wp_enqueue_script( 'socss-codemirror-lint-css-lib', plugin_dir_url( __FILE__ ) . 'js/csslint' . SOCSS_JS_SUFFIX . '.js', array(), '0.10.0' );
324
325 // The CodeMirror autocomplete library
326 wp_enqueue_script( 'socss-codemirror-show-hint', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/hint/show-hint' . SOCSS_JS_SUFFIX . '.js', array( 'socss-codemirror' ), '5.2.0' );
327
328 // CodeMirror search and dialog addons
329 wp_enqueue_script( 'socss-codemirror-dialog', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/dialog/dialog' . SOCSS_JS_SUFFIX . '.js', array( 'socss-codemirror' ), '5.2.0' );
330
331 wp_enqueue_script( 'socss-codemirror-search', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/search/search' . SOCSS_JS_SUFFIX . '.js', array( 'socss-codemirror' ), '5.37.0' );
332 wp_enqueue_script( 'socss-codemirror-search-searchcursor', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/search/searchcursor' . SOCSS_JS_SUFFIX . '.js', array( 'socss-codemirror', 'socss-codemirror-search' ), '5.37.0' );
333 wp_enqueue_script( 'socss-codemirror-search-match-cursor', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/search/match-highlighter' . SOCSS_JS_SUFFIX . '.js', array( 'socss-codemirror', 'socss-codemirror-search' ), '5.37.0' );
334 wp_enqueue_script( 'socss-codemirror-search-matchesonscrollbar', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/search/matchesonscrollbar' . SOCSS_JS_SUFFIX . '.js', array( 'socss-codemirror', 'socss-codemirror-search' ), '5.37.0' );
335 wp_enqueue_script( 'socss-codemirror-scroll-annotatescrollbar', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/scroll/annotatescrollbar' . SOCSS_JS_SUFFIX . '.js', array( 'socss-codemirror', 'socss-codemirror-search', 'socss-codemirror-search-matchesonscrollbar' ), '5.37.0' );
336 wp_enqueue_script( 'socss-codemirror-jump-to-line', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/search/jump-to-line' . SOCSS_JS_SUFFIX . '.js', array( 'socss-codemirror', 'socss-codemirror-search' ), '5.37.0' );
337
338 // All the CodeMirror styles
339 wp_enqueue_style( 'socss-codemirror', plugin_dir_url( __FILE__ ) . 'lib/codemirror/lib/codemirror.css', array(), '5.2.0' );
340 wp_enqueue_style( 'socss-codemirror-theme-neat', plugin_dir_url( __FILE__ ) . 'lib/codemirror/theme/neat.css', array(), '5.2.0' );
341 wp_enqueue_style( 'socss-codemirror-lint-css', plugin_dir_url( __FILE__ ) . 'lib/codemirror/addon/lint/lint.css', array(), '5.2.0' );
342 wp_enqueue_style( 'socss-codemirror-show-hint', plugin_dir_url( __FILE__ ) . 'lib/codemirror/addon/hint/show-hint.css', array(), '5.2.0' );
343 wp_enqueue_style( 'socss-codemirror-dialog', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/dialog/dialog.css', '5.2.0' );
344 wp_enqueue_style( 'socss-codemirror-search-matchesonscrollbar', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/search/matchesonscrollbar.css', array(), '5.37.0' );
345
346 // Enqueue the scripts for theme CSS processing
347 wp_enqueue_script( 'siteorigin-css-parser-lib', plugin_dir_url( __FILE__ ) . 'js/css' . SOCSS_JS_SUFFIX . '.js', array( 'jquery' ), SOCSS_VERSION );
348
349 // There are conflicts between CSS linting and the built in WordPress color picker, so use something else
350 wp_enqueue_style( 'siteorigin-custom-css-minicolors', plugin_dir_url( __FILE__ ) . 'lib/minicolors/jquery.minicolors.css', array(), '2.1.7' );
351 wp_enqueue_script( 'siteorigin-custom-css-minicolors', plugin_dir_url( __FILE__ ) . 'lib/minicolors/jquery.minicolors' . SOCSS_JS_SUFFIX . '.js', array( 'jquery' ), '2.1.7' );
352
353 // We need Font Awesome
354 wp_enqueue_style( 'siteorigin-custom-css-font-awesome', plugin_dir_url( __FILE__ ) . 'lib/fontawesome/css/font-awesome.min.css', array(), SOCSS_VERSION );
355
356 // URI parsing for preview navigation
357 wp_enqueue_script( 'siteorigin-uri', plugin_dir_url( __FILE__ ) . 'js/URI' . SOCSS_JS_SUFFIX . '.js', array(), SOCSS_VERSION, true );
358
359 // All the custom SiteOrigin CSS stuff
360 wp_enqueue_script( 'siteorigin-custom-css', plugin_dir_url(__FILE__) . 'js/editor' . SOCSS_JS_SUFFIX . '.js', array( 'jquery', 'underscore', 'backbone', 'siteorigin-css-parser-lib', 'socss-codemirror' ), SOCSS_VERSION, true );
361 wp_enqueue_style( 'siteorigin-custom-css', plugin_dir_url(__FILE__) . 'css/admin.css', array( ), SOCSS_VERSION );
362
363
364 // Pretty confusing, but it seems we should be using `home_url` and NOT `site_url`
365 // as described here => https://wordpress.stackexchange.com/a/50605
366 $init_url = home_url();
367
368 if ( ! empty( $socss_post_id ) && is_int( $socss_post_id ) ) {
369 $init_url = set_url_scheme( get_permalink( $socss_post_id ) );
370 }
371
372 $open_visual_editor = ! empty( $_REQUEST['open_visual_editor'] );
373
374 $home_url = add_query_arg( 'so_css_preview', '1', $init_url );
375
376 wp_localize_script( 'siteorigin-custom-css', 'socssOptions', array(
377 'themeCSS' => SiteOrigin_CSS::single()->get_theme_css(),
378 'homeURL' => $home_url,
379 'postCssUrlRoot' => wp_nonce_url( admin_url('admin-ajax.php?action=socss_get_post_css'), 'get_post_css' ),
380 'getRevisionsListAjaxUrl' => wp_nonce_url( admin_url('admin-ajax.php?action=socss_get_revisions_list'), 'get_revisions_list' ),
381 'openVisualEditor' => $open_visual_editor,
382
383 'propertyControllers' => apply_filters( 'siteorigin_css_property_controllers', $this->get_property_controllers() ),
384
385 'loc' => array(
386 'unchanged' => __( 'Unchanged', 'so-css' ),
387 'select' => __( 'Select', 'so-css' ),
388 'select_image' => __( 'Select Image', 'so-css' ),
389 'leave' => __( 'Are you sure you want to leave without saving?', 'so-css' ),
390 )
391 ) );
392
393 // This is for the templates required by the CSS editor. Ideally this would be out in the footer, but we need
394 // it earlier for dependent scripts.
395 include plugin_dir_path( __FILE__ ) . 'tpl/js-templates.php';
396 }
397
398 /**
399 * @param $page
400 */
401 function dequeue_admin_scripts( $page ) {
402 if ( $page != 'appearance_page_so_custom_css' ) {
403 return;
404 }
405
406 // Dequeue the core WordPress color picker on the custom CSS page.
407 // This script causes conflicts and other plugins seem to be enqueueing it on the SO CSS admin page.
408 wp_dequeue_script( 'wp-color-picker' );
409 wp_dequeue_style( 'wp-color-picker' );
410 }
411
412 /**
413 * Get all the available property controllers
414 */
415 function get_property_controllers() {
416 return include plugin_dir_path( __FILE__ ) . 'inc/controller-config.php';
417 }
418
419 function plugin_action_links( $links ) {
420 if ( isset( $links['edit'] ) ) {
421 unset( $links['edit'] );
422 }
423 $links['css_editor'] = '<a href="' . admin_url( 'themes.php?page=so_custom_css' ) . '">' . __( 'CSS Editor', 'so-css' ) . '</a>';
424 $links['support'] = '<a href="https://siteorigin.com/thread/" target="_blank">' . __( 'Support', 'so-css' ) . '</a>';
425
426 return $links;
427 }
428
429 function display_admin_page() {
430
431 $socss_post_id = filter_input( INPUT_GET, 'socss_post_id', FILTER_VALIDATE_INT );
432 $theme = filter_input( INPUT_GET, 'theme' );
433 $time = filter_input( INPUT_GET, 'time', FILTER_VALIDATE_INT );
434
435 $page_title = __( 'SiteOrigin CSS', 'so-css' );
436 $theme_obj = wp_get_theme();
437 $theme_name = $theme_obj->get( 'Name' );
438 $editor_description = sprintf( __( 'Changes apply to %s and its child themes', 'so-css' ), $theme_name );
439 $save_button_label = __( 'Save CSS', 'so-css' );
440 $form_save_url = admin_url( 'themes.php?page=so_custom_css' );
441
442 if ( ! empty( $socss_post_id ) ) {
443 $selected_post = get_post( $socss_post_id );
444
445 $page_title = sprintf(
446 __( 'Editing CSS for: %s', 'so-css' ),
447 $selected_post->post_title
448 );
449
450 $editor_description = sprintf(
451 __( 'Changes apply to the %s %s when the current theme is %s or its child themes', 'so-css' ),
452 $selected_post->post_type,
453 $selected_post->post_title,
454 $theme_name
455 );
456 $post_type_obj = get_post_type_object( $selected_post->post_type );
457 $post_type_labels = $post_type_obj->labels;
458 $save_button_label = sprintf( __( 'Save %s CSS', 'so-css' ), $post_type_labels->singular_name );
459 $form_save_url = add_query_arg( 'socss_post_id', urlencode( $socss_post_id ), $form_save_url );
460 }
461 $custom_css = $this->get_custom_css( $this->theme, $socss_post_id );
462 $custom_css_revisions = $this->get_custom_css_revisions( $this->theme, $socss_post_id );
463 $current_revision = 0;
464
465 if ( ! empty( $theme ) && $theme == $this->theme && ! empty( $time ) && ! empty( $custom_css_revisions[ $time ] ) ) {
466 $current_revision = $time;
467 $custom_css = $custom_css_revisions[ $time ];
468 }
469
470 if ( ! empty ( $current_revision ) ) {
471 $save_button_label = __( 'Revert to this revision', 'so-css' );
472 }
473
474 if ( ! empty( $custom_css_revisions ) ) {
475 krsort( $custom_css_revisions );
476 }
477
478 $theme = basename( get_template_directory() );
479
480 include plugin_dir_path( __FILE__ ) . 'tpl/page.php';
481 }
482
483
484 function display_teaser() {
485 return apply_filters( 'siteorigin_premium_upgrade_teaser', true ) &&
486 ! defined( 'SITEORIGIN_PREMIUM_VERSION' );
487 }
488
489 /**
490 * Generates the url to edit the custom CSS for a post.
491 */
492 function get_edit_css_link( $post ) {
493 $url = admin_url( 'themes.php?page=so_custom_css' );
494 if ( ! is_int( $post ) ) {
495 $post = get_post( $post );
496 $post = $post->ID;
497 }
498
499 return empty( $post ) ? $url : add_query_arg( array(
500 'socss_post_id' => urlencode( $post ),
501 'open_visual_editor' => 1,
502 ), $url );
503 }
504 /**
505 *
506 */
507 function admin_action_hide_getting_started() {
508 if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'hide' ) ) {
509 return;
510 }
511
512 $user = wp_get_current_user();
513 if ( ! empty( $user ) ) {
514 update_user_meta( $user->ID, 'socss_hide_gs', true );
515 }
516 }
517
518 /**
519 * Retrieves the post specific CSS for the supplied postId.
520 */
521 function admin_action_get_post_css() {
522 if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'get_post_css' ) ) {
523 wp_die(
524 __( 'The supplied nonce is invalid.', 'siteorigin-panels' ),
525 __( 'Invalid nonce.', 'siteorigin-panels' ),
526 403
527 );
528 }
529
530 $post_id = filter_input( INPUT_GET, 'postId', FILTER_VALIDATE_INT );
531
532 $current = $this->get_custom_css( $this->theme, $post_id );
533
534 $url = empty( $post_id ) ? home_url() : set_url_scheme( get_permalink( $post_id ) );
535
536 wp_send_json( array( 'css' => empty( $current ) ? '' : $current, 'postUrl' => $url ) );
537 }
538
539 /**
540 * Retrieves the past revisions of post specific CSS for the supplied postId.
541 */
542 function admin_action_get_revisions_list() {
543 if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'get_revisions_list' ) ) {
544 wp_die(
545 __( 'The supplied nonce is invalid.', 'siteorigin-panels' ),
546 __( 'Invalid nonce.', 'siteorigin-panels' ),
547 403
548 );
549 }
550
551 $post_id = filter_input( INPUT_GET, 'postId', FILTER_VALIDATE_INT );
552
553 $this->custom_css_revisions_list( $this->theme, $post_id );
554
555 wp_die();
556 }
557
558 function custom_css_revisions_list( $theme, $post_id = null, $current_revision = null ) {
559
560 $revisions = $this->get_custom_css_revisions( $theme, $post_id );
561
562 if ( is_array( $revisions ) && ! empty( $revisions ) ) {
563 $i = 0;
564 foreach ( $revisions as $time => $css ) {
565 $is_current = ( empty( $current_revision ) && $i == 0 ) || ( ! empty( $current_revision ) && $time == $current_revision );
566 $query_args = array( 'theme' => $theme, 'time' => $time, 'open_visual_editor' => false );
567 if ( ! empty( $post_id ) ) {
568 $query_args['socss_post_id'] = $post_id;
569 }
570 ?>
571 <li>
572 <?php if ( ! $is_current ) : ?>
573 <a href="<?php echo esc_url( add_query_arg( $query_args, admin_url( 'themes.php?page=so_custom_css' ) ) ) ?>"
574 class="load-css-revision">
575 <?php endif; ?>
576 <?php echo date('j F Y @ H:i:s', $time + get_option('gmt_offset') * 60 * 60) ?>
577 <?php if ( ! $is_current ) : ?>
578 </a>
579 <?php endif; ?>
580 (<?php printf( __('%d chars', 'so-css'), strlen( $css ) ) ?>)<?php if ( $i == 0 ) : ?> (<?php _e( 'Latest', 'so-css' ) ?>)<?php endif; ?>
581 </li>
582 <?php
583 $i++;
584 }
585 } else {
586 printf( '<em>%s</em>', __( 'No revisions yet.', 'so-css' ) );
587 }
588 }
589
590 /**
591 * Add one or more paths to the registered snippet paths
592 *
593 * @param string|array $path
594 */
595 function register_snippet_path( $path ) {
596 $this->snippet_paths = array_merge( $this->snippet_paths, (array) $path );
597 }
598
599 /**
600 * Get all the available snippets
601 *
602 * @return array|bool
603 */
604 function get_snippets() {
605 // Get the snippet paths
606 $snippet_paths = apply_filters( 'siteorigin_css_snippet_paths', $this->snippet_paths );
607 if ( empty( $snippet_paths ) ) {
608 return array();
609 }
610
611 static $snippets = array();
612 if ( ! empty( $snippets ) ) {
613 return $snippets;
614 }
615
616 if ( ! WP_Filesystem() ) {
617 return false;
618 }
619 global $wp_filesystem;
620 foreach ( $snippet_paths as $path ) {
621 foreach ( glob( $path . '/*.css' ) as $css_file ) {
622 $data = get_file_data( $css_file, array(
623 'Name' => 'Name',
624 'Description' => 'Description',
625 ) );
626
627 // Get the CSS and strip out the first header
628 $css = $wp_filesystem->get_contents( $css_file );
629 $css = preg_replace( '!/\*.*?\*/!s', '', $css, 1 );
630
631 $snippets[] = wp_parse_args( $data, array(
632 'css' => str_replace( "\t", ' ', trim( $css ) ),
633 ) );
634 }
635 }
636
637 usort( $snippets, array( $this, 'sort_snippet_callback' ) );
638
639 return $snippets;
640 }
641
642 /**
643 * Sort snippets by name.
644 *
645 * @param $a
646 * @param $b
647 *
648 * @return int
649 */
650 static function sort_snippet_callback( $a, $b ) {
651 return $a['Name'] > $b['Name'] ? 1 : - 1;
652 }
653
654 /**
655 * A very simple CSS sanitization function.
656 *
657 * @param $css
658 *
659 * @return string
660 */
661 static function sanitize_css( $css ) {
662 return trim( strip_tags( $css ) );
663 }
664
665 /**
666 * Get all the available theme CSS
667 */
668 function get_theme_css() {
669 $css = '';
670 if ( file_exists( get_template_directory() . '/style.css' ) ) {
671 $css .= file_get_contents( get_template_directory() . '/style.css' );
672 }
673
674 if ( is_child_theme() ) {
675 $css .= file_get_contents( get_stylesheet_directory() . '/style.css' );
676 }
677
678 // Remove all CSS comments
679 $regex = array(
680 "`^([\t\s]+)`ism" => '',
681 "`^\/\*(.+?)\*\/`ism" => "",
682 "`([\n\A;]+)\/\*(.+?)\*\/`ism" => "$1",
683 "`([\n\A;\s]+)//(.+?)[\n\r]`ism" => "$1\n",
684 "`(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+`ism" => "\n"
685 );
686 $css = preg_replace( array_keys( $regex ), $regex, $css );
687 $css = preg_replace( '/\s+/', ' ', $css );
688
689 return $css;
690 }
691
692 function enqueue_inspector_scripts() {
693 if ( ! current_user_can( 'edit_theme_options' ) ) {
694 return;
695 }
696
697 wp_enqueue_style( 'dashicons' );
698
699 wp_enqueue_script( 'siteorigin-css-parser-lib', plugin_dir_url( __FILE__ ) . 'js/css' . SOCSS_JS_SUFFIX . '.js', array( 'jquery' ), SOCSS_VERSION );
700
701 wp_enqueue_script( 'siteorigin-css-sizes', plugin_dir_url( __FILE__ ) . 'js/jquery.sizes' . SOCSS_JS_SUFFIX . '.js', array( 'jquery' ), '0.33' );
702 wp_enqueue_script( 'siteorigin-css-specificity', plugin_dir_url( __FILE__ ) . 'js/specificity' . SOCSS_JS_SUFFIX . '.js', array() );
703 wp_enqueue_script( 'siteorigin-css-inspector', plugin_dir_url( __FILE__ ) . 'js/inspector' . SOCSS_JS_SUFFIX . '.js', array(
704 'jquery',
705 'underscore',
706 'backbone'
707 ), SOCSS_VERSION, true );
708 wp_enqueue_style( 'siteorigin-css-inspector', plugin_dir_url( __FILE__ ) . 'css/inspector.css', array(), SOCSS_VERSION );
709
710 wp_localize_script( 'siteorigin-css-inspector', 'socssOptions', array() );
711 }
712
713 function inspector_templates() {
714 if ( ! current_user_can( 'edit_theme_options' ) ) {
715 return;
716 }
717
718 include plugin_dir_path( __FILE__ ) . 'tpl/inspector-templates.php';
719 }
720
721 /**
722 * Change the stylesheets to all be inline
723 */
724 function inline_inspector_scripts() {
725 if ( ! current_user_can( 'edit_theme_options' ) ) {
726 return;
727 }
728
729 $regex = array(
730 "`^([\t\s]+)`ism" => '',
731 "`^\/\*(.+?)\*\/`ism" => "",
732 "`([\n\A;]+)\/\*(.+?)\*\/`ism" => "$1",
733 "`([\n\A;\s]+)//(.+?)[\n\r]`ism" => "$1\n",
734 "`(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+`ism" => "\n"
735 );
736
737 global $wp_styles;
738 if ( empty( $wp_styles->queue ) ) {
739 return;
740 }
741
742 // Make each of the scripts inline
743 foreach ( $wp_styles->queue as $handle ) {
744 if ( $handle === 'siteorigin-css-inspector' || $handle === 'dashicons' ) {
745 continue;
746 }
747 $style = $wp_styles->registered[ $handle ];
748 if ( empty( $style->src ) || substr( $style->src, 0, 4 ) !== 'http' ) {
749 continue;
750 }
751 $response = wp_remote_get( $style->src );
752 if ( is_wp_error( $response ) || $response['response']['code'] !== 200 || empty( $response['body'] ) ) {
753 continue;
754 }
755
756 $css = $response['body'];
757 $css = preg_replace( array_keys( $regex ), $regex, $css );
758
759 ?>
760 <script type="text/css" class="socss-theme-styles"
761 id="socss-inlined-style-<?php echo sanitize_html_class( $handle ) ?>">
762 <?php echo strip_tags( $css ); ?>
763 </script>
764 <?php
765 }
766 }
767
768 function disable_ngg_resource_manager() {
769 if ( ! current_user_can( 'edit_theme_options' ) ) {
770 return;
771 }
772
773 //The NextGen Gallery plugin does some weird interfering with the output buffer.
774 define( 'NGG_DISABLE_RESOURCE_MANAGER', true );
775 }
776
777 private function get_latest_revision_timestamp() {
778 $revisions = $this->get_custom_css_revisions( $this->theme );
779 if ( empty( $revisions ) ) {
780 return false;
781 }
782 krsort( $revisions );
783 $revision_times = array_keys( $revisions );
784
785 return $revision_times[0];
786 }
787 }
788
789 // Initialize the single
790 SiteOrigin_CSS::single();
791