PluginProbe ʕ •ᴥ•ʔ
SiteOrigin CSS / 1.1.4
SiteOrigin CSS v1.1.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 9 years ago inc 9 years ago js 9 years ago lang 9 years ago lib 9 years ago tpl 9 years ago LICENSE 11 years ago readme.txt 8 years ago so-css.php 9 years ago
so-css.php
445 lines
1 <?php
2 /*
3 Plugin Name: SiteOrigin CSS
4 Description: An advanced CSS editor from SiteOrigin.
5 Version: 1.1.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.1.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 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 add_action( 'admin_footer', array($this, 'action_admin_footer') );
41
42 // Add the action links.
43 add_action( 'plugin_action_links_' . plugin_basename(__FILE__), array($this, 'plugin_action_links') );
44
45 // The request to hide the getting started video
46 add_action( 'wp_ajax_socss_hide_getting_started', array( $this, 'admin_action_hide_getting_started' ) );
47
48 if( isset($_GET['so_css_preview']) && !is_admin() ) {
49
50 add_action( 'plugins_loaded', array($this, 'disable_ngg_resource_manager') );
51 add_filter( 'show_admin_bar', '__return_false' );
52 add_filter( 'wp_enqueue_scripts', array($this, 'enqueue_inspector_scripts') );
53 add_filter( 'wp_footer', array($this, 'inspector_templates') );
54
55 // We'll be grabbing all the enqueued scripts and outputting them
56 add_action( 'wp_enqueue_scripts', array($this, 'inline_inspector_scripts'), 100 );
57 }
58 }
59
60 /**
61 * Get a singleton of the SiteOrigin CSS.
62 *
63 * @return SiteOrigin_CSS
64 */
65 static function single(){
66 static $single;
67
68 if( empty($single) ) {
69 $single = new SiteOrigin_CSS();
70 }
71
72 return $single;
73 }
74
75 /**
76 * Display the custom CSS in the header.
77 */
78 function action_wp_head(){
79 $custom_css = get_option( 'siteorigin_custom_css[' . $this->theme . ']', '' );
80 if ( empty( $custom_css ) ) return;
81
82 // We just need to enqueue a dummy style
83 echo "<style id='" . sanitize_html_class($this->theme) . "-custom-css' class='siteorigin-custom-css' type='text/css'>\n";
84 echo self::sanitize_css( $custom_css ) . "\n";
85 echo "</style>\n";
86 }
87
88 function set_plugin_textdomain(){
89 load_plugin_textdomain( 'so-css', false, plugin_dir_path( __FILE__ ) . 'lang/' );
90 }
91
92 /**
93 * Action to run on the admin action.
94 */
95 function action_admin_menu(){
96 add_theme_page( __( 'Custom CSS', 'so-css' ), __( 'Custom CSS', 'so-css' ), 'edit_theme_options', 'so_custom_css', array( $this, 'display_admin_page' ) );
97
98 if ( current_user_can('edit_theme_options') && isset( $_POST['siteorigin_custom_css_save'] ) ) {
99 check_admin_referer( 'custom_css', '_sononce' );
100 $theme = basename( get_template_directory() );
101
102 // Sanitize CSS input. Should keep most tags, apart from script and style tags.
103 $custom_css = self::sanitize_css( filter_input(INPUT_POST, 'custom_css' ) );
104
105 $current = get_option('siteorigin_custom_css[' . $theme . ']');
106 if( $current === false ) {
107 add_option( 'siteorigin_custom_css[' . $theme . ']', $custom_css , '', 'no' );
108 }
109 else {
110 update_option( 'siteorigin_custom_css[' . $theme . ']', $custom_css );
111 }
112
113 // If this has changed, then add a revision.
114 if ( $current != $custom_css ) {
115 $revisions = get_option( 'siteorigin_custom_css_revisions[' . $theme . ']' );
116 if ( empty( $revisions ) ) {
117 add_option( 'siteorigin_custom_css_revisions[' . $theme . ']', array(), '', 'no' );
118 $revisions = array();
119 }
120 $revisions[ time() ] = $custom_css;
121
122 // Sort the revisions and cut off any old ones.
123 krsort($revisions);
124 $revisions = array_slice($revisions, 0, 15, true);
125
126 update_option( 'siteorigin_custom_css_revisions[' . $theme . ']', $revisions );
127 }
128 }
129 }
130
131 /**
132 * Display the help tab
133 */
134 function add_help_tab(){
135 $screen = get_current_screen();
136 $screen->add_help_tab( array(
137 'id' => 'custom-css',
138 'title' => __( 'Custom CSS', 'so-css' ),
139 'content' => '<p>'
140 . sprintf( __( "SiteOrigin CSS adds any custom CSS you enter here into your site's header. ", 'so-css' ) )
141 . __( "These changes will persist across updates so it's best to make all your changes here. ", 'so-css' )
142 . '</p>'
143 ) );
144 }
145
146 function enqueue_admin_scripts( $page ){
147 if( $page != 'appearance_page_so_custom_css' ) return;
148
149 // Core WordPress stuff that we use
150 wp_enqueue_media();
151
152 // Enqueue the codemirror scripts. Call Underscore and Backbone dependencies so they're enqueued first to prevent conflicts.
153 wp_enqueue_script( 'codemirror', plugin_dir_url(__FILE__) . 'lib/codemirror/lib/codemirror' . SOCSS_JS_SUFFIX . '.js', array( 'underscore', 'backbone' ), '5.2.0' );
154 wp_enqueue_script( 'codemirror-mode-css', plugin_dir_url(__FILE__) . 'lib/codemirror/mode/css/css' . SOCSS_JS_SUFFIX . '.js', array(), '5.2.0' );
155
156 // Add in all the linting libs
157 wp_enqueue_script( 'codemirror-lint', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/lint/lint' . SOCSS_JS_SUFFIX . '.js', array( 'codemirror' ), '5.2.0' );
158 wp_enqueue_script( 'codemirror-lint-css', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/lint/css-lint' . SOCSS_JS_SUFFIX . '.js', array( 'codemirror', 'codemirror-lint-css-lib' ), '5.2.0' );
159 wp_enqueue_script( 'codemirror-lint-css-lib', plugin_dir_url(__FILE__) . 'js/csslint' . SOCSS_JS_SUFFIX . '.js', array(), '0.10.0' );
160
161 // The CodeMirror autocomplete library
162 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' );
163
164 // All the CodeMirror styles
165 wp_enqueue_style( 'codemirror', plugin_dir_url(__FILE__) . 'lib/codemirror/lib/codemirror.css', array(), '5.2.0' );
166 wp_enqueue_style( 'codemirror-theme-neat', plugin_dir_url(__FILE__) . 'lib/codemirror/theme/neat.css', array(), '5.2.0' );
167 wp_enqueue_style( 'codemirror-lint-css', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/lint/lint.css', array(), '5.2.0' );
168 wp_enqueue_style( 'codemirror-show-hint', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/hint/show-hint.css', array( ), '5.2.0' );
169
170 // Enqueue the scripts for theme CSS processing
171 wp_enqueue_script( 'siteorigin-css-parser-lib', plugin_dir_url(__FILE__) . 'js/css' . SOCSS_JS_SUFFIX . '.js', array( 'jquery' ), SOCSS_VERSION );
172
173 // There are conflicts between CSS linting and the built in WordPress color picker, so use something else
174 wp_enqueue_style('siteorigin-custom-css-minicolors', plugin_dir_url(__FILE__) . 'lib/minicolors/jquery.minicolors.css', array(), '2.1.7' );
175 wp_enqueue_script('siteorigin-custom-css-minicolors', plugin_dir_url(__FILE__) . 'lib/minicolors/jquery.minicolors' . SOCSS_JS_SUFFIX . '.js', array('jquery'), '2.1.7' );
176
177 // We need Font Awesome
178 wp_enqueue_style( 'siteorigin-custom-css-font-awesome', plugin_dir_url(__FILE__) . 'lib/fontawesome/css/font-awesome.min.css', array( ), SOCSS_VERSION );
179
180 // URI parsing for preview navigation
181 wp_enqueue_script( 'siteorigin-uri', plugin_dir_url(__FILE__) . 'js/URI' . SOCSS_JS_SUFFIX . '.js', array( ), SOCSS_VERSION, true );
182
183 // All the custom SiteOrigin CSS stuff
184 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 );
185 wp_enqueue_style( 'siteorigin-custom-css', plugin_dir_url(__FILE__) . 'css/admin.css', array( ), SOCSS_VERSION );
186
187 wp_localize_script( 'siteorigin-custom-css', 'socssOptions', array(
188 'themeCSS' => SiteOrigin_CSS::single()->get_theme_css(),
189 'homeURL' => add_query_arg( 'so_css_preview', '1', site_url() ),
190 'snippets' => $this->get_snippets(),
191
192 'propertyControllers' => apply_filters( 'siteorigin_css_property_controllers', $this->get_property_controllers() ),
193
194 'loc' => array(
195 'unchanged' => __('Unchanged', 'so-css'),
196 'select' => __('Select', 'so-css'),
197 'select_image' => __('Select Image', 'so-css'),
198 'leave' => __('Are you sure you want to leave without saving?', 'so-css'),
199 )
200 ) );
201
202 // This is for the templates required by the CSS editor
203 add_action( 'admin_footer', array($this, 'action_admin_footer') );
204 }
205
206 /**
207 * @param $page
208 */
209 function dequeue_admin_scripts( $page ) {
210 if( $page != 'appearance_page_so_custom_css' ) return;
211
212 // Dequeue the core WordPress color picker on the custom CSS page.
213 // This script causes conflicts and other plugins seem to be enqueueing it on the SO CSS admin page.
214 wp_dequeue_script('wp-color-picker');
215 wp_dequeue_style('wp-color-picker');
216 }
217
218 /**
219 * Get all the available property controllers
220 */
221 function get_property_controllers() {
222 return include plugin_dir_path( __FILE__ ) . 'inc/controller-config.php';
223 }
224
225 /**
226 * Display the templates for the CSS Editor
227 */
228 function action_admin_footer(){
229 include plugin_dir_path( __FILE__ ) . 'tpl/js-templates.php';
230 }
231
232 function plugin_action_links( $links ){
233 if( isset($links['edit']) ) unset( $links['edit'] );
234 $links['css_editor'] = '<a href="' . admin_url('themes.php?page=so_custom_css') . '">'.__('CSS Editor', 'so-css').'</a>';
235 $links['support'] = '<a href="https://siteorigin.com/thread/" target="_blank">'.__('Support', 'so-css').'</a>';
236 return $links;
237 }
238
239 function display_admin_page(){
240 $theme = basename( get_template_directory() );
241
242 $custom_css = get_option( 'siteorigin_custom_css[' . $theme . ']', '' );
243 $custom_css_revisions = get_option('siteorigin_custom_css_revisions[' . $theme . ']');
244
245 if( !empty( $_GET['theme'] ) && $_GET['theme'] == $theme && !empty( $_GET['time'] ) && !empty( $custom_css_revisions[$_GET['time']] ) ) {
246 $custom_css = $custom_css_revisions[$_GET['time']];
247 $revision = true;
248 }
249
250 include plugin_dir_path( __FILE__ ) . 'tpl/page.php';
251 }
252
253
254 function display_teaser(){
255 return apply_filters( 'siteorigin_premium_upgrade_teaser', true ) &&
256 ! defined( 'SITEORIGIN_PREMIUM_VERSION' );
257 }
258
259 /**
260 *
261 */
262 function admin_action_hide_getting_started(){
263 if( !isset($_GET['_wpnonce']) || !wp_verify_nonce( $_GET['_wpnonce'], 'hide' ) ) return;
264
265 $user = wp_get_current_user();
266 if( !empty( $user ) ) {
267 update_user_meta( $user->ID, 'socss_hide_gs', true );
268 }
269 }
270
271 /**
272 * Add one or more paths to the registered snippet paths
273 *
274 * @param string|array $path
275 */
276 function register_snippet_path( $path ){
277 $this->snippet_paths = array_merge( $this->snippet_paths, (array) $path );
278 }
279
280 /**
281 * Get all the available snippets
282 *
283 * @return array|bool
284 */
285 function get_snippets(){
286 // Get the snippet paths
287 $snippet_paths = apply_filters( 'siteorigin_css_snippet_paths', $this->snippet_paths );
288 if( empty($snippet_paths) ) return array();
289
290 static $snippets = array();
291 if( !empty($snippets) ) return $snippets;
292
293 if( !WP_Filesystem() ) return false;
294 global $wp_filesystem;
295 foreach( $snippet_paths as $path ) {
296 foreach( glob($path . '/*.css') as $css_file ) {
297 $data = get_file_data( $css_file, array(
298 'Name' => 'Name',
299 'Description' => 'Description',
300 ) );
301
302 // Get the CSS and strip out the first header
303 $css = $wp_filesystem->get_contents( $css_file );
304 $css = preg_replace('!/\*.*?\*/!s', '', $css, 1);
305
306 $snippets[] = wp_parse_args( $data, array(
307 'css' => str_replace( "\t", ' ', trim($css) ),
308 ) );
309 }
310 }
311
312 usort($snippets, array( $this, 'sort_snippet_callback' ) );
313 return $snippets;
314 }
315
316 /**
317 * Sort snippets by name.
318 *
319 * @param $a
320 * @param $b
321 *
322 * @return int
323 */
324 static function sort_snippet_callback( $a, $b ){
325 return $a['Name'] > $b['Name'] ? 1 : -1;
326 }
327
328 /**
329 * A very simple CSS sanitization function.
330 *
331 * @param $css
332 *
333 * @return string
334 */
335 static function sanitize_css( $css ){
336 return trim( strip_tags( $css ) );
337 }
338
339 /**
340 * Get all the available theme CSS
341 */
342 function get_theme_css(){
343 $css = '';
344 if( file_exists( get_template_directory() . '/style.css' ) ) {
345 $css .= file_get_contents( get_template_directory() . '/style.css' );
346 }
347
348 if( is_child_theme() ) {
349 $css .= file_get_contents( get_stylesheet_directory() . '/style.css' );
350 }
351
352 // Remove all CSS comments
353 $regex = array(
354 "`^([\t\s]+)`ism"=>'',
355 "`^\/\*(.+?)\*\/`ism"=>"",
356 "`([\n\A;]+)\/\*(.+?)\*\/`ism"=>"$1",
357 "`([\n\A;\s]+)//(.+?)[\n\r]`ism"=>"$1\n",
358 "`(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+`ism"=>"\n"
359 );
360 $css = preg_replace( array_keys($regex), $regex, $css );
361 $css = preg_replace('/\s+/', ' ', $css);
362
363 return $css;
364 }
365
366 /**
367 * Get the editor description
368 *
369 * @return string
370 */
371 static function editor_description(){
372 $theme = wp_get_theme();
373 return sprintf( __( 'Changes apply to %s and its child themes', 'so-css' ), $theme->get('Name') );
374 }
375
376 function enqueue_inspector_scripts(){
377 if( !current_user_can('edit_theme_options') ) return;
378
379 wp_enqueue_style( 'dashicons' );
380
381 wp_enqueue_script( 'siteorigin-css-parser-lib', plugin_dir_url(__FILE__) . 'js/css' . SOCSS_JS_SUFFIX . '.js', array( 'jquery' ), SOCSS_VERSION );
382
383 wp_enqueue_script('siteorigin-css-sizes', plugin_dir_url(__FILE__) . 'js/jquery.sizes' . SOCSS_JS_SUFFIX . '.js', array( 'jquery' ), '0.33' );
384 wp_enqueue_script('siteorigin-css-specificity', plugin_dir_url(__FILE__) . 'js/specificity' . SOCSS_JS_SUFFIX . '.js', array( ) );
385 wp_enqueue_script('siteorigin-css-inspector', plugin_dir_url(__FILE__) . 'js/inspector' . SOCSS_JS_SUFFIX . '.js', array( 'jquery', 'underscore', 'backbone' ), SOCSS_VERSION, true );
386 wp_enqueue_style('siteorigin-css-inspector', plugin_dir_url(__FILE__) . 'css/inspector.css', array( ), SOCSS_VERSION );
387
388 wp_localize_script('siteorigin-css-inspector', 'socssOptions', array(
389
390 ) );
391 }
392
393 function inspector_templates(){
394 if( !current_user_can('edit_theme_options') ) return;
395
396 include plugin_dir_path( __FILE__ ) . 'tpl/inspector-templates.php';
397 }
398
399 /**
400 * Change the stylesheets to all be inline
401 */
402 function inline_inspector_scripts(){
403 if( !current_user_can('edit_theme_options') ) return;
404
405 $regex = array(
406 "`^([\t\s]+)`ism"=>'',
407 "`^\/\*(.+?)\*\/`ism"=>"",
408 "`([\n\A;]+)\/\*(.+?)\*\/`ism"=>"$1",
409 "`([\n\A;\s]+)//(.+?)[\n\r]`ism"=>"$1\n",
410 "`(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+`ism"=>"\n"
411 );
412
413 global $wp_styles;
414 if( empty($wp_styles->queue) ) return;
415
416 // Make each of the scripts inline
417 foreach( $wp_styles->queue as $handle ) {
418 if( $handle === 'siteorigin-css-inspector' || $handle === 'dashicons' ) continue;
419 $style = $wp_styles->registered[$handle];
420 if( empty($style->src) || substr($style->src, 0, 4) !== 'http' ) continue;
421 $response = wp_remote_get( $style->src );
422 if( is_wp_error($response) || $response['response']['code'] !== 200 || empty($response['body']) ) continue;
423
424 $css = $response['body'];
425 $css = preg_replace( array_keys($regex), $regex, $css );
426
427 ?>
428 <script type="text/css" class="socss-theme-styles" id="socss-inlined-style-<?php echo sanitize_html_class( $handle ) ?>">
429 <?php echo strip_tags( $css ) ?>
430 </script>
431 <?php
432 }
433 }
434
435 function disable_ngg_resource_manager() {
436 if( !current_user_can('edit_theme_options') ) return;
437
438 //The NextGen Gallery plugin does some weird interfering with the output buffer.
439 define('NGG_DISABLE_RESOURCE_MANAGER', true);
440 }
441 }
442
443 // Initialize the single
444 SiteOrigin_CSS::single();
445