PluginProbe ʕ •ᴥ•ʔ
SiteOrigin CSS / 1.0.8
SiteOrigin CSS v1.0.8
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 10 years ago inc 9 years ago js 9 years ago lib 10 years ago tpl 9 years ago LICENSE 11 years ago readme.txt 9 years ago so-css.php 9 years ago
so-css.php
438 lines
1 <?php
2 /*
3 Plugin Name: SiteOrigin CSS
4 Description: An advanced CSS editor from SiteOrigin.
5 Version: 1.0.8
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.0.8');
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__ ). '/languages/');
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 if( !wp_script_is( 'wp-color-picker' ) ) {
157 // Add in all the linting libs
158 wp_enqueue_script( 'codemirror-lint', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/lint/lint' . SOCSS_JS_SUFFIX . '.js', array( 'codemirror' ), '5.2.0' );
159 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' );
160 wp_enqueue_script( 'codemirror-lint-css-lib', plugin_dir_url(__FILE__) . 'js/csslint' . SOCSS_JS_SUFFIX . '.js', array(), '0.10.0' );
161 }
162
163 // The CodeMirror autocomplete library
164 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' );
165
166 // All the CodeMirror styles
167 wp_enqueue_style( 'codemirror', plugin_dir_url(__FILE__) . 'lib/codemirror/lib/codemirror.css', array(), '5.2.0' );
168 wp_enqueue_style( 'codemirror-theme-neat', plugin_dir_url(__FILE__) . 'lib/codemirror/theme/neat.css', array(), '5.2.0' );
169 wp_enqueue_style( 'codemirror-lint-css', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/lint/lint.css', array(), '5.2.0' );
170 wp_enqueue_style( 'codemirror-show-hint', plugin_dir_url(__FILE__) . 'lib/codemirror/addon/hint/show-hint.css', array( ), '5.2.0' );
171
172 // Enqueue the scripts for theme CSS processing
173 wp_enqueue_script( 'siteorigin-custom-css-parser', plugin_dir_url(__FILE__) . 'js/css' . SOCSS_JS_SUFFIX . '.js', array( 'jquery' ), SOCSS_VERSION );
174
175 // There are conflicts between CSS linting and the built in WordPress color picker, so use something else
176 wp_enqueue_style('siteorigin-custom-css-minicolors', plugin_dir_url(__FILE__) . 'lib/minicolors/jquery.minicolors.css', array(), '2.1.7' );
177 wp_enqueue_script('siteorigin-custom-css-minicolors', plugin_dir_url(__FILE__) . 'lib/minicolors/jquery.minicolors' . SOCSS_JS_SUFFIX . '.js', array('jquery'), '2.1.7' );
178
179 // We need Font Awesome
180 wp_enqueue_style( 'siteorigin-custom-css-font-awesome', plugin_dir_url(__FILE__) . 'lib/fontawesome/css/font-awesome.min.css', array( ), SOCSS_VERSION );
181
182 // All the custom SiteOrigin CSS stuff
183 wp_enqueue_script( 'siteorigin-custom-css', plugin_dir_url(__FILE__) . 'js/editor' . SOCSS_JS_SUFFIX . '.js', array( 'jquery', 'underscore', 'backbone', 'siteorigin-custom-css-parser', 'codemirror' ), SOCSS_VERSION, true );
184 wp_enqueue_style( 'siteorigin-custom-css', plugin_dir_url(__FILE__) . 'css/admin.css', array( ), SOCSS_VERSION );
185
186 wp_localize_script( 'siteorigin-custom-css', 'socssOptions', array(
187 'themeCSS' => SiteOrigin_CSS::single()->get_theme_css(),
188 'homeURL' => add_query_arg( 'so_css_preview', '1', site_url() ),
189 'snippets' => $this->get_snippets(),
190
191 'propertyControllers' => apply_filters( 'siteorigin_css_property_controllers', $this->get_property_controllers() ),
192
193 'loc' => array(
194 'unchanged' => __('Unchanged', 'so-css'),
195 'select' => __('Select', 'so-css'),
196 'select_image' => __('Select Image', 'so-css'),
197 'leave' => __('Are you sure you want to leave without saving?', 'so-css'),
198 )
199 ) );
200
201 // This is for the templates required by the CSS editor
202 add_action( 'admin_footer', array($this, 'action_admin_footer') );
203 }
204
205 /**
206 * @param $page
207 */
208 function dequeue_admin_scripts( $page ) {
209 if( $page != 'appearance_page_so_custom_css' ) return;
210
211 // Dequeue the core WordPress color picker on the custom CSS page.
212 // This script causes conflicts and other plugins seem to be enqueueing it on the SO CSS admin page.
213 wp_dequeue_script('wp-color-picker');
214 wp_dequeue_style('wp-color-picker');
215 }
216
217 /**
218 * Get all the available property controllers
219 */
220 function get_property_controllers() {
221 return include plugin_dir_path(__FILE__) . 'inc/controller-config.php';
222 }
223
224 /**
225 * Display the templates for the CSS Editor
226 */
227 function action_admin_footer(){
228 include plugin_dir_path( __FILE__ ) . 'tpl/js-templates.php';
229 }
230
231 function plugin_action_links( $links ){
232 if( isset($links['edit']) ) unset( $links['edit'] );
233 $links['css_editor'] = '<a href="' . admin_url('themes.php?page=so_custom_css') . '">'.__('CSS Editor', 'so-css').'</a>';
234 $links['support'] = '<a href="https://siteorigin.com/thread/" target="_blank">'.__('Support', 'so-css').'</a>';
235 return $links;
236 }
237
238 function display_admin_page(){
239 $theme = basename( get_template_directory() );
240
241 $custom_css = get_option( 'siteorigin_custom_css[' . $theme . ']', '' );
242 $custom_css_revisions = get_option('siteorigin_custom_css_revisions[' . $theme . ']');
243
244 if( !empty( $_GET['theme'] ) && $_GET['theme'] == $theme && !empty( $_GET['time'] ) && !empty( $custom_css_revisions[$_GET['time']] ) ) {
245 $custom_css = $custom_css_revisions[$_GET['time']];
246 $revision = true;
247 }
248
249 include plugin_dir_path(__FILE__).'/tpl/page.php';
250 }
251
252 /**
253 *
254 */
255 function admin_action_hide_getting_started(){
256 if( !isset($_GET['_wpnonce']) || !wp_verify_nonce( $_GET['_wpnonce'], 'hide' ) ) return;
257
258 $user = wp_get_current_user();
259 if( !empty( $user ) ) {
260 update_user_meta( $user->ID, 'socss_hide_gs', true );
261 }
262 }
263
264 /**
265 * Add one or more paths to the registered snippet paths
266 *
267 * @param string|array $path
268 */
269 function register_snippet_path( $path ){
270 $this->snippet_paths = array_merge( $this->snippet_paths, (array) $path );
271 }
272
273 /**
274 * Get all the available snippets
275 *
276 * @return array|bool
277 */
278 function get_snippets(){
279 // Get the snippet paths
280 $snippet_paths = apply_filters( 'siteorigin_css_snippet_paths', $this->snippet_paths );
281 if( empty($snippet_paths) ) return array();
282
283 static $snippets = array();
284 if( !empty($snippets) ) return $snippets;
285
286 if( !WP_Filesystem() ) return false;
287 global $wp_filesystem;
288 foreach( $snippet_paths as $path ) {
289 foreach( glob($path . '/*.css') as $css_file ) {
290 $data = get_file_data( $css_file, array(
291 'Name' => 'Name',
292 'Description' => 'Description',
293 ) );
294
295 // Get the CSS and strip out the first header
296 $css = $wp_filesystem->get_contents( $css_file );
297 $css = preg_replace('!/\*.*?\*/!s', '', $css, 1);
298
299 $snippets[] = wp_parse_args( $data, array(
300 'css' => str_replace( "\t", ' ', trim($css) ),
301 ) );
302 }
303 }
304
305 usort($snippets, array( $this, 'sort_snippet_callback' ) );
306 return $snippets;
307 }
308
309 /**
310 * Sort snippets by name.
311 *
312 * @param $a
313 * @param $b
314 *
315 * @return int
316 */
317 static function sort_snippet_callback( $a, $b ){
318 return $a['Name'] > $b['Name'] ? 1 : -1;
319 }
320
321 /**
322 * A very simple CSS sanitization function.
323 *
324 * @param $css
325 *
326 * @return string
327 */
328 static function sanitize_css( $css ){
329 return trim( strip_tags( $css ) );
330 }
331
332 /**
333 * Get all the available theme CSS
334 */
335 function get_theme_css(){
336 $css = '';
337 if( file_exists( get_template_directory() . '/style.css' ) ) {
338 $css .= file_get_contents( get_template_directory() . '/style.css' );
339 }
340
341 if( is_child_theme() ) {
342 $css .= file_get_contents( get_stylesheet_directory() . '/style.css' );
343 }
344
345 // Remove all CSS comments
346 $regex = array(
347 "`^([\t\s]+)`ism"=>'',
348 "`^\/\*(.+?)\*\/`ism"=>"",
349 "`([\n\A;]+)\/\*(.+?)\*\/`ism"=>"$1",
350 "`([\n\A;\s]+)//(.+?)[\n\r]`ism"=>"$1\n",
351 "`(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+`ism"=>"\n"
352 );
353 $css = preg_replace( array_keys($regex), $regex, $css );
354 $css = preg_replace('/\s+/', ' ', $css);
355
356 return $css;
357 }
358
359 /**
360 * Get the editor description
361 *
362 * @return string
363 */
364 static function editor_description(){
365 $theme = wp_get_theme();
366 return sprintf( __( 'Changes apply to %s and its child themes', 'so-css' ), $theme->get('Name') );
367 }
368
369 function enqueue_inspector_scripts(){
370 if( !current_user_can('edit_theme_options') ) return;
371
372 wp_enqueue_style( 'dashicons' );
373
374 wp_enqueue_script( 'siteorigin-custom-css-parser', plugin_dir_url(__FILE__) . 'js/css' . SOCSS_JS_SUFFIX . '.js', array( 'jquery' ), SOCSS_VERSION );
375
376 wp_enqueue_script('siteorigin-css-sizes', plugin_dir_url(__FILE__) . 'js/jquery.sizes' . SOCSS_JS_SUFFIX . '.js', array( 'jquery' ), '0.33' );
377 wp_enqueue_script('siteorigin-css-specificity', plugin_dir_url(__FILE__) . 'js/specificity' . SOCSS_JS_SUFFIX . '.js', array( ) );
378 wp_enqueue_script('siteorigin-css-inspector', plugin_dir_url(__FILE__) . 'js/inspector' . SOCSS_JS_SUFFIX . '.js', array( 'jquery', 'underscore', 'backbone' ), SOCSS_VERSION, true );
379 wp_enqueue_style('siteorigin-css-inspector', plugin_dir_url(__FILE__) . 'css/inspector.css', array( ), SOCSS_VERSION );
380
381 wp_localize_script('siteorigin-css-inspector', 'socssOptions', array(
382
383 ) );
384 }
385
386 function inspector_templates(){
387 if( !current_user_can('edit_theme_options') ) return;
388
389 include plugin_dir_path( __FILE__ ) . 'tpl/inspector-templates.php';
390 }
391
392 /**
393 * Change the stylesheets to all be inline
394 */
395 function inline_inspector_scripts(){
396 if( !current_user_can('edit_theme_options') ) return;
397
398 $regex = array(
399 "`^([\t\s]+)`ism"=>'',
400 "`^\/\*(.+?)\*\/`ism"=>"",
401 "`([\n\A;]+)\/\*(.+?)\*\/`ism"=>"$1",
402 "`([\n\A;\s]+)//(.+?)[\n\r]`ism"=>"$1\n",
403 "`(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+`ism"=>"\n"
404 );
405
406 global $wp_styles;
407 if( empty($wp_styles->queue) ) return;
408
409 // Make each of the scripts inline
410 foreach( $wp_styles->queue as $handle ) {
411 if( $handle === 'siteorigin-css-inspector' || $handle === 'dashicons' ) continue;
412 $style = $wp_styles->registered[$handle];
413 if( empty($style->src) || substr($style->src, 0, 4) !== 'http' ) continue;
414 $response = wp_remote_get( $style->src );
415 if( is_wp_error($response) || $response['response']['code'] !== 200 || empty($response['body']) ) continue;
416
417 $css = $response['body'];
418 $css = preg_replace( array_keys($regex), $regex, $css );
419
420 ?>
421 <script type="text/css" class="socss-theme-styles" id="socss-inlined-style-<?php echo sanitize_html_class( $handle ) ?>">
422 <?php echo strip_tags( $css ) ?>
423 </script>
424 <?php
425 }
426 }
427
428 function disable_ngg_resource_manager() {
429 if( !current_user_can('edit_theme_options') ) return;
430
431 //The NextGen Gallery plugin does some weird interfering with the output buffer.
432 define('NGG_DISABLE_RESOURCE_MANAGER', true);
433 }
434 }
435
436 // Initialize the single
437 SiteOrigin_CSS::single();
438