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