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