File: /var/www/ippmt.kauko.lt/wp-content/plugins/theme-editor/includes/classes/ms_theme_editor_admin.php
<?php
// Exit if accessed directly
if ( !defined( 'ABSPATH' ) ) exit;
class ms_theme_editor_admin {
var $genesis;
var $processdone;
var $childtype;
var $template;
var $is_ajax;
var $is_get;
var $is_post;
var $skip_form;
var $fs;
var $encoding;
var $fs_prompt;
var $fs_method;
var $uploadsubdir;
var $menuName;
var $cache_updates = TRUE;
var $debug;
var $is_debug;
var $is_new;
var $max_sel;
var $sel_limit;
var $mem_limit;
var $themes = array();
var $errors = array();
var $files = array();
var $updates = array();
var $css;
var $ui;
var $postarrays = array(
'ctc_img',
'ctc_file_parnt',
'ctc_file_child',
'ctc_additional_css',
);
var $configfields = array(
'theme_parnt',
'child_type',
'theme_child',
'child_template',
'configtype',
);
var $actionfields = array(
'load_styles',
);
var $imgmimes = array(
'jpg|jpeg|jpe' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
);
function __construct() {
$this->processdone = FALSE;
$this->genesis = FALSE;
$this->is_new = FALSE;
$this->encoding = WP_Http_Encoding::is_available();
$this->menuName = CHLD_THM_CFG_MENU;
$this->is_post = ( 'POST' == $_SERVER[ 'REQUEST_METHOD' ] );
$this->is_get = ( 'GET' == $_SERVER[ 'REQUEST_METHOD' ] );
$this->is_debug = get_option( MS_CHILD_THEME_EDITOR . '_debug' );
$this->debug = '';
$this->errors = array();
}
function ctc_page_init () {
$this->get_themes();
$this->childtype = count( $this->themes[ 'child' ] ) ? 'existing' : 'new';
$this->load_config();
do_action( 'chld_thm_cfg_preprocess' );
do_action( 'chld_thm_cfg_forms' );
$this->process_post();
$this->ui = new ms_theme_editor_ui();
}
function render() {
$this->ui->render();
}
function get( $property, $params = NULL ) {
return $this->css->get_prop( $property, $params );
}
function get_themes() {
$this->themes = array( 'child' => array(), 'parnt' => array() );
foreach ( wp_get_themes() as $theme ):
$group = $theme->parent() ? 'child' : 'parnt';
$slug = $theme->get_stylesheet();
$version = $theme->get( 'Version' );
if ( 'child' == $group ) $version = preg_replace("/\.\d{6}\d+$/", '', $version );
$this->themes[ $group ][ $slug ] = array(
'Template' => $theme->get( 'Template' ),
'Name' => $theme->get( 'Name' ),
'ThemeURI' => $theme->get( 'ThemeURI' ),
'Author' => $theme->get( 'Author' ),
'AuthorURI' => $theme->get( 'AuthorURI' ),
'Descr' => $theme->get( 'Description' ),
'Tags' => $theme->get( 'Tags' ),
'Version' => $version,
'screenshot' => $theme->get_screenshot(),
'allowed' => $theme->is_allowed(),
);
endforeach;
}
function validate_post( $action = 'ms_update', $noncefield = '_wpnonce', $cap = 'install_themes' ) {
return true;
}
function load_config() {
$this->css = new ms_theme_editor_css();
if ( FALSE !== $this->css->load_config() ):
$this->debug( 'config exists', __FUNCTION__, __CLASS__, __CLASS__ );
if ( ! $this->check_theme_exists( $this->get( 'child' ) )
|| ! $this->check_theme_exists( $this->get( 'parnt' ) ) ):
$this->debug( 'theme does not exist', __FUNCTION__, __CLASS__, __CLASS__ );
$this->css = new ms_theme_editor_css();
$this->css->enqueue = 'enqueue';
endif;
else:
$this->debug( 'config does not exist', __FUNCTION__, __CLASS__, __CLASS__ );
$this->css->enqueue = 'enqueue';
endif;
do_action( 'chld_thm_cfg_load' );
if ( $this->is_get ):
if ( $this->get( 'child' ) ):
$this->verify_creds();
$stylesheet = apply_filters(
'chld_thm_cfg_target',
$this->css->get_child_target( $this->get_child_stylesheet() ),
$this->css );
if ( !is_writable( $stylesheet ) && !$this->fs )
add_action( 'chld_thm_cfg_admin_notices', array( $this, 'writable_notice' ) );
if ( $fsize = $this->get( 'fsize' ) ):
$test = filesize( $stylesheet );
$this->debug( 'filesize saved: ' . $fsize . ' current: ' . $test, __FUNCTION__, __CLASS__, __CLASS__ );
endif;
if ( !$this->get( 'enqueue' ) ):
$this->debug( 'no enqueue:', __FUNCTION__, __CLASS__, __CLASS__ );
add_action( 'chld_thm_cfg_admin_notices', array( $this, 'enqueue_notice' ) );
endif;
endif;
if ( fileowner( $this->css->get_child_target( '' ) ) != fileowner( MS_THEME_EDITOR_DIR ) )
add_action( 'chld_thm_cfg_admin_notices', array( $this, 'owner_notice' ) );
endif;
}
function ajax_save_postdata( $action = 'ms_update' ) {
$this->is_ajax = TRUE;
$this->debug( 'ajax save ', __FUNCTION__, __CLASS__ );
if ( $this->validate_post( $action ) ):
if ( 'ctc_plugin' == $action ) do_action( 'chld_thm_cfg_pluginmode' );
$this->verify_creds();
add_action( 'chld_thm_cfg_cache_updates', array( $this, 'cache_debug' ) );
if ( FALSE !== $this->load_config() ):
if ( isset( $_POST[ 'ctc_is_debug' ] ) ):
$this->toggle_debug();
else:
$this->css->parse_post_data();
if ( $this->get( 'child' ) ):
do_action( 'chld_thm_cfg_addl_files' );
$this->css->write_css();
endif;
$this->save_config();
endif;
do_action( 'chld_thm_cfg_cache_updates' );
endif;
die( json_encode( $this->css->obj_to_utf8( $this->updates ) ) );
endif;
die();
}
function save_config() {
$this->css->save_config();
}
function ajax_query_css( $action = 'ms_update' ) {
$this->is_ajax = TRUE;
if ( $this->validate_post( $action ) ):
if ( 'ctc_plugin' == $action ) do_action( 'chld_thm_cfg_pluginmode' );
$this->load_config();
add_action( 'chld_thm_cfg_cache_updates', array( $this, 'cache_debug' ) );
$regex = "/^ctc_query_/";
foreach( preg_grep( $regex, array_keys( $_POST ) ) as $key ):
$name = preg_replace( $regex, '', $key );
$param[ $name ] = sanitize_text_field( $_POST[ $key ] );
endforeach;
$this->debug( 'ajax params: ' . print_r( $param, TRUE ), __FUNCTION__, __CLASS__, __CLASS__ );
if ( !empty( $param[ 'obj' ] ) ):
$this->updates[] = array(
'key' => isset( $param[ 'key' ] ) ? $param[ 'key' ] : '',
'obj' => $param[ 'obj' ],
'data' => $this->get( $param[ 'obj' ], $param ),
);
do_action( 'chld_thm_cfg_cache_updates' );
die( json_encode( $this->updates ) );
endif;
endif;
die( 0 );
}
function process_post() {
if ( $this->is_post ):
foreach ( $this->actionfields as $field ):
if ( in_array( 'ctc_' . $field, array_keys( $_POST ) ) ):
$actionfield = $field;
break;
endif;
endforeach;
if ( empty( $actionfield ) ) return FALSE;
if ( !$this->validate_post( apply_filters( 'chld_thm_cfg_action', 'ms_update' ) ) ):
$this->errors[] = 2;
else:
$args = preg_grep( "/nonce/", array_keys( $_POST ), PREG_GREP_INVERT );
$msg = FALSE;
$this->verify_creds( $args );
if ( $this->fs )
{
switch( $actionfield )
{
case 'load_styles':
$msg = $this->ms_create_child_theme();
break;
default:
$msg ='';
}
}
endif;
if ( $this->errors ):
$this->update_redirect( 0 );
elseif ( empty( $this->fs_prompt ) ):
$this->processdone = TRUE;
$this->update_redirect( $msg );
endif;
endif;
}
function ms_create_child_theme() {
$msg = 1;
$this->is_new = TRUE;
foreach ( $this->configfields as $configfield ):
$varparts = explode( '_', $configfield );
$varname = end( $varparts );
${$varname} = empty( $_POST[ 'ctc_' . $configfield ] ) ? '' :
preg_replace( "/\s+/s", ' ', sanitize_text_field( $_POST[ 'ctc_' . $configfield ] ) );
endforeach;
//Child Theme Parameter
$name = sanitize_text_field($_POST['child_name']);//child name
$themeuri = sanitize_text_field($_POST['child_theme_uri']);//child theme website
$author = sanitize_text_field($_POST['child_author']);//child theme website
$descr = sanitize_text_field($_POST['child_descr']);//child theme website
$authoruri = sanitize_text_field($_POST['child_author_uri']);//child theme website
$tags = sanitize_text_field($_POST['child_tags']);//child theme tags
$version = sanitize_text_field($_POST['child_version']);//child theme version
//child theme handler parameter
$repairheader = isset($_POST['repairheader']) ? sanitize_text_field($_POST['repairheader']) : '';
$ignoreparnt = isset($_POST['ignoreparnt']) ? sanitize_text_field($_POST['ignoreparnt']) : '';
$handling = isset($_POST['handling']) ? sanitize_text_field($_POST['handling']) : '';
$enqueue = isset($_POST['enqueue']) ? sanitize_text_field($_POST['enqueue']) : '';
if (isset( $type) )
{
$this->childtype = $type;
}
if ( !$this->is_theme( $configtype ) && $this->is_legacy() ):
$parnt = $this->get( 'parnt' );
$child = $this->get( 'child' );
$name = $this->get( 'child_name' );
endif;
if ( $parnt ):
if ( ! $this->check_theme_exists( $parnt ) ):
$this->errors[] = '3:' . $parnt;
endif;
else:
$this->errors[] = 5;
endif;
if ( 'new' != $type && empty( $child ) ):
$this->errors[] = 6;
elseif ( 'new' == $type || 'duplicate' == $type ):
if ( empty( $template ) && empty( $name ) ):
$this->errors[] = 7;
else:
$template_sanitized = preg_replace( "%[^\w\-]%", '', empty( $template ) ? $name : $template );
if ( $this->check_theme_exists( $template_sanitized ) ):
$this->errors[] = '8:' . $template_sanitized;
elseif ( 'duplicate' == $type ):
$this->clone_child_theme( $child, $template_sanitized );
if ( !empty( $this->errors ) ) return FALSE;
$this->copy_theme_mods( $child, $template_sanitized );
$msg = 3;
else:
$msg = 2;
endif;
$child = $template_sanitized;
endif;
endif;
if ( FALSE === $this->verify_child_dir( $child ) ):
$this->errors[] = 9;
return FALSE;
endif;
if ( 'reset' == $type ):
$this->reset_child_theme();
$this->enqueue_parent_css();
$msg = 4;
else:
if ( !empty( $this->errors ) ) return FALSE;
if ( empty( $name ) ):
$name = ucfirst( $child );
endif;
$oldhandling = $this->get( 'handling' );
$this->css = new ms_theme_editor_css();
if ( !$this->is_theme( $configtype ) )
$this->css->set_prop( 'enqueue', 'enqueue' );
else
$this->css->set_prop( 'enqueue', $enqueue );
$this->css->set_prop( 'handling', $handling );
$this->css->set_prop( 'ignoreparnt', $ignoreparnt );
$this->css->set_prop( 'parnt', $parnt );
$this->css->set_prop( 'child', $child );
$this->css->set_prop( 'child_name', $name );
$this->css->set_prop( 'child_author', $author );
$this->css->set_prop( 'child_themeuri', $themeuri );
$this->css->set_prop( 'child_authoruri', $authoruri );
$this->css->set_prop( 'child_descr', $descr );
$this->css->set_prop( 'child_tags', $tags );
$this->css->set_prop( 'child_version', strlen( $version ) ? $version : '1.0' );
if ( isset( $_POST[ 'ctc_action' ] ) && 'plugin' == $_POST[ 'ctc_action' ] ):
$this->css->addl_css = array();
if ( isset( $_POST[ 'ctc_additional_css' ] ) && is_array( $_POST[ 'ctc_additional_css' ] ) ):
foreach ( $_POST[ 'ctc_additional_css' ] as $file )
$this->css->addl_css[] = sanitize_text_field( $file );
endif;
add_action( 'chld_thm_cfg_parse_stylesheets', array( $this, 'parse_child_stylesheet_to_target' ) );
elseif ( isset( $_POST['ms_theme_child_analysis'] )):
$this->evaluate_signals();
endif;
$this->css->forcedep = array();
if ( isset( $_POST[ 'ctc_forcedep' ] ) && is_array( $_POST[ 'ctc_forcedep' ] ) ):
foreach ( $_POST[ 'ctc_forcedep' ] as $handle )
$this->css->forcedep[ sanitize_text_field( $handle ) ] = 1;
endif;
if ( $this->genesis ):
$handling = 'separate';
$enqueue = 'none';
$ignoreparnt = TRUE;
if ( $this->backup_or_restore_file( 'ms-separate-style.css', TRUE, 'style.css' ) &&
$this->backup_or_restore_file( 'style.css', TRUE, 'ctc-genesis.css' ) ):
$this->delete_child_file( 'ctc-genesis', 'css' );
else:
$this->errors[] = 10;
endif;
endif;
if ( !empty( $this->errors ) ) return FALSE;
if ( 'enqueue' == $enqueue && ( $this->get( 'parntloaded' ) || !$this->get( 'hasstyles' ) || $ignoreparnt ) ) $enqueue = 'none';
if ( $this->is_theme( $configtype ) || $this->is_legacy()):
if ( $this->get( 'hasstyles' ) && !$ignoreparnt ):
$this->debug( 'Adding action: parse_parent_stylesheet_to_source', __FUNCTION__, __CLASS__ );
add_action( 'chld_thm_cfg_parse_stylesheets', array( $this, 'parse_parent_stylesheet_to_source' ) );
endif;
if ( is_multisite())
add_action( 'chld_thm_cfg_addl_options', array( $this, 'network_enable' ) );
endif;
$this->debug( 'Adding action: parse_additional_stylesheets_to_source', __FUNCTION__, __CLASS__ );
add_action( 'chld_thm_cfg_parse_stylesheets', array( $this, 'parse_additional_stylesheets_to_source' ) );
if ( 'separate' == $handling ):
add_action( 'chld_thm_cfg_parse_stylesheets', array( $this, 'parse_child_stylesheet_to_source' ) );
$this->debug( 'Adding action: parse_custom_stylesheet_to_target', __FUNCTION__, __CLASS__ );
add_action( 'chld_thm_cfg_parse_stylesheets', array( $this, 'parse_custom_stylesheet_to_target' ) );
elseif ( 'primary' == $handling ):
add_action( 'chld_thm_cfg_parse_stylesheets', array( $this, 'parse_child_stylesheet_to_target' ) );
if ( $oldhandling != $handling ):
$this->debug( 'Adding action: parse_custom_stylesheet_to_target', __FUNCTION__, __CLASS__ );
add_action( 'chld_thm_cfg_parse_stylesheets', array( $this, 'parse_custom_stylesheet_to_target' ) );
endif;
endif;
if ( $this->is_theme( $configtype )):
add_action( 'chld_thm_cfg_addl_files', array( $this, 'add_base_files' ), 10, 2 );
add_action( 'chld_thm_cfg_addl_files', array( $this, 'copy_screenshot' ), 10, 2 );
add_action( 'chld_thm_cfg_addl_files', array( $this, 'enqueue_parent_css' ), 15, 2 );
if ( $repairheader && 'reset' != $type ):
add_action( 'chld_thm_cfg_addl_files', array( $this, 'repair_header' ) );
endif;
endif;
do_action( 'chld_thm_cfg_parse_stylesheets' );
if ( isset( $_POST[ 'ctc_parent_mods' ] ) && 'duplicate' != $type )
$this->copy_theme_mods( $parnt, $child );
$this->enqueue_parent_css( TRUE );
do_action( 'chld_thm_cfg_addl_files' );
if ( !empty ( $this->errors ) ) return FALSE;
if ( 'separate' == $handling ):
$this->debug( 'Writing new stylesheet header...', __FUNCTION__, __CLASS__ );
$this->rewrite_stylesheet_header();
endif;
$this->css->set_prop( 'converted', 1 );
$this->debug( 'Writing new CSS...', __FUNCTION__, __CLASS__ );
if ( FALSE === $this->css->write_css() ):
$this->errors[] = 11;
return FALSE;
endif;
$this->get_files( $parnt );
endif;
$this->save_config();
do_action( 'chld_thm_cfg_addl_options' );
return $msg;
}
function sanitize_options( $input ) {
return $input;
}
function sanitize_slug( $slug ) {
return preg_replace( "/[^\w\-]/", '', $slug );
}
function update_redirect( $msg = 1 ) {
$this->log_debug();
if ( empty( $this->is_ajax ) ):
$ctcpage = apply_filters( 'chld_thm_cfg_admin_page', CHLD_THM_CFG_MENU );
$screen = get_current_screen()->id;
wp_safe_redirect(
( strstr( $screen, '-network' ) ? network_admin_url( 'themes.php' ) : admin_url( 'admin.php' ) )
. '?page=' . $ctcpage . ( $msg ? '&updated=' . $msg : ( $this->errors ? '&error=' . implode( ',', $this->errors ) : '' ) ) );
die();
endif;
}
function verify_child_dir( $path ) {
$this->debug( 'Verifying child dir: ' . $path, __FUNCTION__, __CLASS__ );
if ( !$this->fs ):
$this->debug( 'No filesystem access.', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
global $wp_filesystem;
$themedir = $wp_filesystem->find_folder( get_theme_root() );
if ( ! $wp_filesystem->is_writable( $themedir ) ):
$this->debug( 'Directory not writable: ' . $themedir, __FUNCTION__, __CLASS__ );
return FALSE;
endif;
$childparts = explode( '/', $this->normalize_path( $path ) );
while ( count( $childparts ) ):
$subdir = array_shift( $childparts );
if ( empty( $subdir ) ) continue;
$themedir = trailingslashit( $themedir ) . $subdir;
if ( ! $wp_filesystem->is_dir( $themedir ) ):
if ( ! $wp_filesystem->mkdir( $themedir, FS_CHMOD_DIR ) ):
$this->debug( 'Could not make directory: ' . $themedir, __FUNCTION__, __CLASS__ );
return FALSE;
endif;
elseif ( ! $wp_filesystem->is_writable( $themedir ) ):
$this->debug( 'Directory not writable: ' . $themedir, __FUNCTION__, __CLASS__ );
return FALSE;
endif;
endwhile;
$this->debug( 'Child dir verified: ' . $themedir, __FUNCTION__, __CLASS__ );
return TRUE;
}
function add_base_files( $obj ){
$contents = "<?php
// Exit if accessed directly
if ( !defined( 'ABSPATH' ) ) exit;
";
$handling = $this->get( 'handling' );
$this->write_child_file( 'functions.php', $contents );
$this->backup_or_restore_file( 'style.css' );
$contents = $this->css->get_css_header_comment( $handling );
$this->debug( 'writing initial stylesheet header...' . LF . $contents, __FUNCTION__, __CLASS__ );
$this->write_child_file( 'style.css', $contents );
if ( 'separate' == $handling ):
$this->backup_or_restore_file( 'ms-separate-style.css' );
$this->write_child_file( 'ms-separate-style.css', $contents . LF );
endif;
}
function convert_import_to_enqueue( $import, $count, $execute = FALSE ) {
$relpath = $this->get( 'child' );
$import = preg_replace( "#^.*?url\(([^\)]+?)\).*#", "$1", $import );
$import = preg_replace( "#[\'\"]#", '', $import );
$path = $this->css->convert_rel_url( trim( $import ), $relpath , FALSE );
$abs = preg_match( '%(https?:)?//%', $path );
if ( $execute )
wp_enqueue_style( 'chld_thm_cfg_ext' . $count, $abs ? $path : trailingslashit( get_theme_root_uri() ) . $path );
else
return "wp_enqueue_style( 'chld_thm_cfg_ext" . $count . "', "
. ( $abs ? "'" . $path . "'" : "trailingslashit( get_theme_root_uri() ) . '" . $path . "'" ) . ' );';
}
function convert_enqueue_to_import( $path ) {
if ( preg_match( '%(https?:)?//%', $path ) ):
$this->css->imports[ 'child' ]['@import url(' . $path . ')'] = 1;
return;
endif;
$regex = '#^' . preg_quote( trailingslashit( $this->get( 'child' ) ) ) . '#';
$path = preg_replace( $regex, '', $path, -1, $count );
if ( $count ):
$this->css->imports[ 'child' ]['@import url(' . $path . ')'] = 1;
return;
endif;
$parent = trailingslashit( $this->get( 'parnt' ) );
$regex = '#^' . preg_quote( $parent ) . '#';
$path = preg_replace( $regex, '../' . $parent, $path, -1, $count );
if ( $count )
$this->css->imports[ 'child' ]['@import url(' . $path . ')'] = 1;
}
function enqueue_parent_code(){
$imports = $this->get( 'imports' );
$enqueues = array();
$code = "// AUTO GENERATED - Do not modify or remove comment markers above or below:" . LF;
$deps = $this->get( 'parnt_deps' );
$enq = $this->get( 'enqueue' );
$handling = $this->get( 'handling' );
$hasstyles = $this->get( 'hasstyles' );
$childloaded = $this->get( 'childloaded' );
$parntloaded = $this->get( 'parntloaded' );
$cssunreg = $this->get( 'cssunreg' );
$csswphead = $this->get( 'csswphead' );
$cssnotheme = $this->get( 'cssnotheme' );
$ignoreparnt = $this->get( 'ignoreparnt' );
$priority = $this->get( 'qpriority' );
$reorder = $this->get( 'reorder' );
$this->debug( 'forcedep: ' . print_r( $this->get( 'forcedep' ), TRUE ) . ' deps: ' . print_r( $deps, TRUE ) . ' enq: ' . $enq . ' handling: ' . $handling
. ' hasstyles: ' . $hasstyles . ' parntloaded: ' . $parntloaded . ' childloaded: ' . $childloaded . ' reorder: ' . $reorder
. ' ignoreparnt: ' . $ignoreparnt . ' priority: ' . $priority . ' childtype: ' . $this->childtype, __FUNCTION__, __CLASS__ );
if ( 'enqueue' == $enq && $hasstyles && !$parntloaded && !$ignoreparnt ):
$deps = array_diff( $deps, array( 'chld_thm_cfg_parent' ) );
$code .= "
if ( !function_exists( 'ms_theme_editor_parent_css' ) ):
function ms_theme_editor_parent_css() {
wp_enqueue_style( 'chld_thm_cfg_parent', trailingslashit( get_template_directory_uri() ) . 'style.css', array( " . implode( ',', $deps ) . " ) );
}
endif;
add_action( 'wp_enqueue_scripts', 'ms_theme_editor_parent_css', " . $priority . " );
";
$deps = array( "'chld_thm_cfg_parent'" );
endif;
if ( 'separate' != $handling && $childloaded && $reorder && ( $parntloaded || in_array( 'chld_thm_cfg_parent', $deps ) ) ):
$dephandle = $parntloaded ? $parntloaded : 'chld_thm_cfg_parent';
$code .= "
if ( !function_exists( 'ms_theme_editor_parent_dep') ):
function ms_theme_editor_parent_dep() {
global \$wp_styles;
array_unshift( \$wp_styles->registered[ '" . $childloaded . "' ]->deps, '" . $dephandle . "' );
}
endif;
add_action( 'wp_head', 'ms_theme_editor_parent_dep', 2 );
";
endif;
if ( !empty( $imports ) ):
$ext = 0;
foreach ( $imports as $import ):
if ( !empty( $import ) ):
$ext++;
$enqueues[] = ' ' . $this->convert_import_to_enqueue( $import, $ext );
endif;
endforeach;
endif;
if ( 'separate' != $handling && ( ( $csswphead || $cssunreg || $cssnotheme )
|| ( 'new' != $this->childtype && !$childloaded )
) ):
$deps = array_merge( $deps, $this->get( 'child_deps' ) );
$deps = array_diff( $deps, array( 'chld_thm_cfg_child' ) );
$enqueues[] = " wp_enqueue_style( 'chld_thm_cfg_child', trailingslashit( get_stylesheet_directory_uri() ) . 'style.css', array( " . implode( ',', $deps ) . " ) );";
$deps = array( "'chld_thm_cfg_child'" );
endif;
if ( 'separate' == $handling ):
$deps = array_merge( $deps, $this->get( 'child_deps' ) );
$deps = array_diff( $deps, array( 'ms_theme_editor_child_ms_separate' ) );
$enqueues[] = " wp_enqueue_style( 'ms_theme_editor_child_ms_separate', trailingslashit( get_stylesheet_directory_uri() ) . 'ms-separate-style.css', array( " . implode( ',', $deps ) . " ) );";
endif;
if ( count( $enqueues ) ):
$code .= "
if ( !function_exists( 'ms_theme_editor_child_css' ) ):
function ms_theme_editor_child_css() {" . LF;
$code .= implode( "\n", $enqueues );
$code .= "
}
endif;
add_action( 'wp_enqueue_scripts', 'ms_theme_editor_child_css', " . ( $priority + 10 ) . " );" . LF;
endif;
if ( $ignoreparnt )
$code .= "
defined( 'CHLD_THM_CFG_IGNORE_PARENT' ) or define( 'CHLD_THM_CFG_IGNORE_PARENT', TRUE );" . LF;
return explode( "\n", $code );
}
function enqueue_parent_css( $getexternals = FALSE ) {
$this->debug( 'enqueueing parent css: getexternals = ' . $getexternals, __FUNCTION__, __CLASS__ );
$marker = 'ENQUEUE PARENT ACTION';
$insertion = $this->enqueue_parent_code();
if ( $filename = $this->css->is_file_ok( $this->css->get_child_target( 'functions.php' ), 'write' ) ):
$this->insert_with_markers( $filename, $marker, $insertion, $getexternals );
if ( !$getexternals && 'reset' == $this->childtype ):
$marker = 'CTC ENQUEUE PLUGIN ACTION';
$this->insert_with_markers( $filename, $marker, array() );
endif;
endif;
}
function insert_with_markers( $filename, $marker, $insertion, $getexternals = FALSE ) {
if ( count( $this->errors ) ):
$this->debug( 'Errors detected, returning', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
if ( $this->is_ajax && is_readable( $filename ) && is_writable( $filename ) ):
$this->debug( 'Ajax update, bypassing wp filesystem.', __FUNCTION__, __CLASS__ );
$markerdata = explode( "\n", @file_get_contents( $filename ) );
elseif ( !$this->fs ):
$this->debug( 'No filesystem access.', __FUNCTION__, __CLASS__ );
return FALSE;
else:
global $wp_filesystem;
if( !$wp_filesystem->exists( $this->fspath( $filename ) ) ):
if ( $getexternals ):
$this->debug( 'Read only and no functions file yet, returning...', __FUNCTION__, __CLASS__ );
return FALSE;
else:
$this->debug( 'No functions file, creating...', __FUNCTION__, __CLASS__ );
$this->add_base_files( $this );
endif;
endif;
$markerdata = explode( "\n", $wp_filesystem->get_contents( $this->fspath( $filename ) ) );
endif;
$newfile = '';
$externals = array();
$phpopen = 0;
$in_comment = 0;
$foundit = FALSE;
if ( $markerdata ):
$state = TRUE;
foreach ( $markerdata as $n => $markerline ):
$str = preg_replace( "/\/\/.*$/", '', $markerline );
preg_match_all("/(<\?|\?>|\*\/|\/\*)/", $str, $matches );
if ( $matches ):
foreach ( $matches[1] as $token ):
if ( '/*' == $token ):
$in_comment = 1;
elseif ( '*/' == $token ):
$in_comment = 0;
elseif ( '<?' == $token && !$in_comment ):
$phpopen = 1;
elseif ( '?>' == $token && !$in_comment ):
$phpopen = 0;
endif;
endforeach;
endif;
if ( strpos( $markerline, '// BEGIN ' . $marker ) !== FALSE )
$state = FALSE;
if ( $state ):
if ( $n + 1 < count( $markerdata ) )
$newfile .= "{$markerline}\n";
else
$newfile .= "{$markerline}";
elseif ( $getexternals ):
if ( preg_match( "/wp_enqueue_style.+?'chld_thm_cfg_ext\d+'.+?'(.+?)'/", $markerline, $matches ) ):
$this->debug( 'external link found : ' . $matches[ 1 ] );
$this->convert_enqueue_to_import( $matches[ 1 ] );
endif;
endif;
if ( strpos( $markerline, '// END ' . $marker ) !== FALSE ):
if ( 'reset' != $this->childtype ):
$newfile .= "// BEGIN {$marker}\n";
if ( is_array( $insertion ) )
foreach ( $insertion as $insertline )
$newfile .= "{$insertline}\n";
$newfile .= "// END {$marker}\n";
endif;
$state = TRUE;
$foundit = TRUE;
endif;
endforeach;
else:
$this->debug( 'Could not parse functions file', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
if ( $foundit ):
$this->debug( 'Found marker, replaced inline', __FUNCTION__, __CLASS__ );
else:
if ( 'reset' != $this->childtype ):
if ( ! $phpopen ):
$this->debug( 'PHP not open', __FUNCTION__, __CLASS__ );
$newfile .= '<?php' . LF;
endif;
$newfile .= "\n// BEGIN {$marker}\n";
foreach ( $insertion as $insertline )
$newfile .= "{$insertline}\n";
$newfile .= "// END {$marker}\n";
endif;
endif;
if ( $getexternals ):
$this->debug( 'Read only, returning.', __FUNCTION__, __CLASS__ );
else:
$mode = 'direct' == $this->fs_method ? FALSE : 0666;
$this->debug( 'Writing new functions file...', __FUNCTION__, __CLASS__ );
if ( $this->is_ajax && is_writable( $filename ) ):
if ( FALSE === @file_put_contents( $filename, $newfile ) ):
$this->debug( 'Ajax write failed.', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
elseif ( FALSE === $wp_filesystem->put_contents(
$this->fspath( $filename ),
$newfile,
$mode
) ):
$this->debug( 'Filesystem write failed.', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
$this->css->set_prop( 'converted', 1 );
endif;
}
function write_child_file( $file, $contents ) {
if ( !$this->fs ):
$this->debug( 'No filesystem access, returning.', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
global $wp_filesystem;
if ( $file = $this->css->is_file_ok( $this->css->get_child_target( $file ), 'write' ) ):
$mode = 'direct' == $this->fs_method ? FALSE : 0666;
$file = $this->fspath( $file );
if ( $wp_filesystem->exists( $file ) ):
$this->debug( 'File exists, returning.', __FUNCTION__, __CLASS__ );
return FALSE;
else:
$this->debug( 'Writing to filesystem: ' . $file . LF . $contents, __FUNCTION__, __CLASS__ );
if ( FALSE === $wp_filesystem->put_contents(
$file,
$contents,
$mode
) ):
$this->debug( 'Filesystem write failed, returning.', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
endif;
else:
$this->debug( 'No directory, returning.', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
$this->debug( 'Filesystem write successful.', __FUNCTION__, __CLASS__ );
}
function copy_screenshot() {
$this->copy_parent_file( 'screenshot' );
}
function copy_parent_file( $file, $ext = 'php' ) {
if ( !$this->fs ):
$this->debug( 'No filesystem access.', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
global $wp_filesystem;
$parent_file = NULL;
if ( 'screenshot' == $file ):
foreach ( array_keys( $this->imgmimes ) as $extreg ):
foreach( explode( '|', $extreg ) as $ext )
if ( ( $parent_file = $this->css->is_file_ok( $this->css->get_parent_source( 'screenshot.' . $ext ) ) ) )
break;
if ( $parent_file ):
$parent_file = $this->fspath( $parent_file );
break;
endif;
endforeach;
if ( !$parent_file ):
$this->debug( 'No screenshot found.', __FUNCTION__, __CLASS__ );
return;
endif;
else:
$parent_file = $this->fspath( $this->css->is_file_ok( $this->css->get_parent_source( $file . '.' . $ext ) ) );
endif;
$child_file = $this->css->get_child_target( $file . '.' . $ext );
if ( $wp_filesystem->exists( $this->fspath( $child_file ) ) ) return TRUE;
$child_dir = dirname( $this->theme_basename( '', $child_file ) );
$this->debug( 'Verifying child dir... ', __FUNCTION__, __CLASS__ );
if ( $parent_file
&& $child_file
&& $this->verify_child_dir( $child_dir )
&& $wp_filesystem->copy( $parent_file, $this->fspath( $child_file ), FS_CHMOD_FILE ) ):
$this->debug( 'Filesystem copy successful', __FUNCTION__, __CLASS__ );
return TRUE;
endif;
$this->errors[] = '13:' . $parent_file;
}
function delete_child_file( $file, $ext = 'php' ) {
if ( !$this->fs ):
$this->debug( 'No filesystem access.', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
global $wp_filesystem;
$file = ( 'img' == $ext ? $file : $file . '.' . $ext );
if ( $child_file = $this->css->is_file_ok( $this->css->get_child_target( $file ), 'write' ) ):
if ( $wp_filesystem->exists( $this->fspath( $child_file ) ) ):
if ( $wp_filesystem->delete( $this->fspath( $child_file ) ) ):
return TRUE;
else:
$this->errors[] = '14:' . $ext;
$this->debug( 'Could not delete ' . $ext . ' file', __FUNCTION__, __CLASS__ );
endif;
endif;
endif;
}
function get_files( $theme, $type = 'template' ) {
$isparent = ( $theme === $this->get( 'parnt' ) );
if ( 'template' == $type && $isparent && ( $templates = $this->get( 'templates' ) ) ):
return $templates;
elseif ( !isset( $this->files[ $theme ] ) ):
$this->files[ $theme ] = array();
$imgext = '(' . implode( '|', array_keys( $this->imgmimes ) ) . ')';
foreach ( $this->css->recurse_directory(
trailingslashit( get_theme_root() ) . $theme, '', TRUE ) as $filepath ):
$file = $this->theme_basename( $theme, $filepath );
if ( preg_match( "/^style\-(\d+)\.css$/", $file, $matches ) ):
$date = date_i18n( 'D, j M Y g:i A', strtotime( $matches[ 1 ] ) );
$this->files[ $theme ][ 'backup' ][ $file ] = $date;
elseif ( strstr( $file, "msbackup" ) ):
$date = date_i18n( 'D, j M Y g:i A', filemtime( $filepath ) );
$this->files[ $theme ][ 'backup' ][ $file ] = $date;
elseif ( preg_match( "/\.php$/", $file ) ):
if ( $isparent ):
if ( ( $file_verified = $this->css->is_file_ok( $this->css->get_parent_source( $file, $theme ) , 'read' ) ) ):
$this->debug( 'scanning ' . $file_verified . '... ', __FUNCTION__, __CLASS__ );
$template = FALSE;
$size = 0;
if ( $handle = fopen( $file_verified, "rb") ):
while ( !feof( $handle ) ):
$size++;
if ( $size > 10 )
break;
$contents = fread($handle, 2048);
if ( preg_match( "/\w+\s*\(/", $contents ) ):
$template = TRUE;
$contents = preg_replace( "%<script>.+?</script>%s", '', $contents );
$contents = preg_replace( "%(^.+?</script>|<script>.+$)%s", '', $contents );
if ( preg_match( "/(function \w+?|require(_once)?)\s*\(/", $contents ) ):
$this->debug( 'disqualifying code found in chunk ' . $size, __FUNCTION__, __CLASS__ );
$template = FALSE;
break;
endif;
endif;
endwhile;
fclose( $handle );
endif;
if ( $template )
$this->files[ $theme ][ 'template' ][] = $file;
endif;
else:
$this->files[ $theme ][ 'template' ][] = $file;
endif;
elseif ( preg_match( "/\.css$/", $file )
&& ( !in_array( $file, array(
'style.css',
'ms-separate-style.css'
) ) ) ):
$this->files[ $theme ][ 'stylesheet' ][] = $file;
elseif ( preg_match( "/\.(js|txt)$/", $file ) ):
$this->files[ $theme ][ 'txt' ][] = $file;
elseif ( preg_match( "/^images\/.+?\." . $imgext . "$/", $file ) ):
$this->files[ $theme ][ 'img' ][] = $file;
else:
$this->files[ $theme ][ 'other' ][] = $file;
endif;
endforeach;
endif;
if ( $isparent ):
$this->css->templates = $this->files[ $theme ][ 'template' ];
endif;
$types = explode( ",", $type );
$files = array();
foreach ( $types as $type ):
if ( isset( $this->files[ $theme ][ $type ] ) )
$files = array_merge( $this->files[ $theme ][ $type ], $files );
endforeach;
return $files;
}
function theme_basename( $theme, $file ) {
$file = $this->normalize_path( $file );
$themedir = trailingslashit( $this->normalize_path( get_theme_root() ) ) . ( '' == $theme ? '' : trailingslashit( $theme ) );
return preg_replace( '%^' . preg_quote( $themedir ) . '%', '', $file );
}
function uploads_basename( $file ) {
$file = $this->normalize_path( $file );
$uplarr = wp_upload_dir();
$upldir = trailingslashit( $this->normalize_path( $uplarr[ 'basedir' ] ) );
return preg_replace( '%^' . preg_quote( $upldir ) . '%', '', $file );
}
function uploads_fullpath( $file ) {
$file = $this->normalize_path( $file );
$uplarr = wp_upload_dir();
$upldir = trailingslashit( $this->normalize_path( $uplarr[ 'basedir' ] ) );
return $upldir . $file;
}
function serialize_postarrays() {
foreach ( $this->postarrays as $field )
if ( isset( $_POST[ $field ] ) && is_array( $_POST[ $field ] ) )
$_POST[ $field ] = implode( "%%", $_POST[ $field ] );
}
function unserialize_postarrays() {
foreach ( $this->postarrays as $field )
if ( isset( $_POST[ $field ] ) && !is_array( $_POST[ $field ] ) )
$_POST[ $field ] = explode( "%%", $_POST[ $field ] );
}
function set_writable( $file = NULL ) {
if ( isset( $file ) ):
$file = $this->css->get_child_target( $file . '.php' );
else:
$file = apply_filters( 'chld_thm_cfg_target', $this->css->get_child_target( 'separate' == $this->get( 'handling' ) ? 'ms-separate-style.css' : 'style.css' ), $this->css );
endif;
if ( $this->fs ):
if ( is_writable( $file ) ) return;
global $wp_filesystem;
if ( $file && $wp_filesystem->chmod( $this->fspath( $file ), 0666 ) )
return;
endif;
$this->errors[] = 28;
return FALSE;
}
function clone_child_theme( $child, $clone ) {
if ( !$this->fs ) return FALSE;
global $wp_filesystem;
$this->css->set_prop( 'child', $child );
$dir = untrailingslashit( $this->css->get_child_target( '' ) );
$themedir = trailingslashit( get_theme_root() );
$fsthemedir = $this->fspath( $themedir );
$files = $this->css->recurse_directory( $dir, NULL, TRUE );
$errors = array();
foreach ( $files as $file ):
$childfile = $this->theme_basename( $child, $this->normalize_path( $file ) );
$newfile = trailingslashit( $clone ) . $childfile;
$childpath = $fsthemedir . trailingslashit( $child ) . $childfile;
$newpath = $fsthemedir . $newfile;
$this->debug( 'Verifying child dir... ', __FUNCTION__, __CLASS__ );
if ( $this->verify_child_dir( is_dir( $file ) ? $newfile : dirname( $newfile ) ) ):
if ( is_file( $file ) && !@$wp_filesystem->copy( $childpath, $newpath ) ):
$this->errors[] = '15:' . $newpath;
endif;
else:
$this->errors[] = '16:' . $newfile;
endif;
endforeach;
}
function unset_writable() {
if ( !$this->fs ) return FALSE;
global $wp_filesystem;
$dir = untrailingslashit( $this->css->get_child_target( '' ) );
$child = $this->theme_basename( '', $dir );
$newchild = untrailingslashit( $child ) . '-new';
$themedir = trailingslashit( get_theme_root() );
$fsthemedir = $this->fspath( $themedir );
if ( fileowner( $dir ) == fileowner( $themedir ) ):
$copy = FALSE;
$wp_filesystem->chmod( $dir );
else:
$copy = TRUE;
endif;
$files = $this->css->recurse_directory( $dir, NULL, TRUE );
$errors = array();
foreach ( $files as $file ):
$childfile = $this->theme_basename( $child, $this->normalize_path( $file ) );
$newfile = trailingslashit( $newchild ) . $childfile;
$childpath = $fsthemedir . trailingslashit( $child ) . $childfile;
$newpath = $fsthemedir . $newfile;
if ( $copy ):
$this->debug( 'Verifying child dir... ' . $file, __FUNCTION__, __CLASS__ );
if ( $this->verify_child_dir( is_dir( $file ) ? $newfile : dirname( $newfile ) ) ):
if ( is_file( $file ) && !$wp_filesystem->copy( $childpath, $newpath ) ):
$errors[] = '15:' . $newpath;
endif;
else:
$errors[] = '16:' . $newfile;
endif;
else:
$wp_filesystem->chmod( $this->fspath( $file ) );
endif;
endforeach;
if ( $copy ):
$newfiles = $this->css->recurse_directory( trailingslashit( $themedir ) . $newchild, NULL, TRUE );
$deleteddirs = $deletedfiles = 0;
if ( count( $newfiles ) == count( $files ) ):
if ( !$wp_filesystem->exists( trailingslashit( $fsthemedir ) . $child . '-old' ) )
$wp_filesystem->move( trailingslashit( $fsthemedir ) . $child, trailingslashit( $fsthemedir ) . $child . '-old' );
if ( !$wp_filesystem->exists( trailingslashit( $fsthemedir ) . $child ) )
$wp_filesystem->move( trailingslashit( $fsthemedir ) . $newchild, trailingslashit( $fsthemedir ) . $child );
$oldfiles = $this->css->recurse_directory( trailingslashit( $themedir ) . $child . '-old', NULL, TRUE );
array_unshift( $oldfiles, trailingslashit( $themedir ) . $child . '-old' );
foreach ( array_reverse( $oldfiles ) as $file ):
if ( $wp_filesystem->delete( $this->fspath( $file ) )
|| ( is_dir( $file ) && @rmdir( $file ) )
|| ( is_file( $file ) && @unlink( $file ) ) ):
$deletedfiles++;
endif;
endforeach;
if ( $deletedfiles != count( $oldfiles ) ):
$errors[] = '17:' . $deletedfiles . ':' . count( $oldfiles );
endif;
else:
$errors[] = 18;
endif;
endif;
if ( count( $errors ) ):
$this->errors[] = 19;
endif;
}
function verify_creds( $args = array() ) {
$this->fs_prompt = $this->fs = FALSE;
$this->serialize_postarrays();
$ctcpage = apply_filters( 'chld_thm_cfg_admin_page', CHLD_THM_CFG_MENU );
$url = is_multisite() ? network_admin_url( 'themes.php?page=' . $ctcpage ) :
admin_url( 'admin.php?page=' . $ctcpage );
$nonce_url = wp_nonce_url( $url, apply_filters( 'chld_thm_cfg_action', 'ms_update' ), '_wpnonce' );
ob_start();
if ( $creds = request_filesystem_credentials( $nonce_url, '', FALSE, FALSE, $args ) ):
if ( WP_Filesystem( $creds ))
$this->fs = TRUE;
else
$creds = request_filesystem_credentials( $nonce_url, '', TRUE, FALSE, $args );
else:
WP_Filesystem();
endif;
$this->fs_prompt = ob_get_clean();
$this->debug( 'FS: ' . $this->fs . ' PROMPT: ' . $this->fs_prompt, __FUNCTION__, __CLASS__ );
$this->unserialize_postarrays();
}
function fspath( $file ){
if ( ! $this->fs ) return FALSE; // return if no filesystem access
global $wp_filesystem;
if ( is_dir( $file ) ):
$dir = $file;
$base = '';
else:
$dir = dirname( $file );
$base = basename( $file );
endif;
$fsdir = $wp_filesystem->find_folder( $dir );
return trailingslashit( $fsdir ) . $base;
}
function normalize_path( $path ) {
$path = str_replace( '\\', '/', $path );
$path = substr( $path, 0, 1 ) . preg_replace( '|/+|','/', substr( $path, 1 ) );
if ( ':' === substr( $path, 1, 1 ) )
$path = ucfirst( $path );
return $path;
}
function check_theme_exists( $theme ) {
$search_array = array_map( 'strtolower', array_keys( wp_get_themes() ) );
return in_array( strtolower( $theme ), $search_array );
}
function is_legacy() {
return defined('CHLD_THM_CFG_PLUGINS_VERSION')
&& version_compare( CHLD_THM_CFG_PLUGINS_VERSION, '2.0.0', '<' );
}
function is_theme( $configtype = '' ) {
$pluginmode = apply_filters( 'chld_thm_cfg_action', NULL );
if ( $pluginmode || ( !empty( $configtype ) && 'theme' != $configtype ) ):
return FALSE;
endif;
if ( $this->is_legacy()
&& is_object( $this->css )
&& ( $configtype = $this->get( 'configtype' ) )
&& !empty( $configtype ) && 'theme' != $configtype ):
return FALSE;
endif;
return TRUE;
}
function get_current_parent() {
if ( $parent = $this->get( 'parnt' ) )
return $parent;
else return get_template();
}
function get_current_child() {
if ( $child = $this->get( 'child' ) )
return $child;
else return get_stylesheet();
}
function toggle_debug() {
$debug = '';
if ( $_POST[ 'ctc_is_debug' ] ):
$this->is_debug = 1;
else:
$this->is_debug = 0;
endif;
update_option( MS_CHILD_THEME_EDITOR . '_debug', $this->is_debug, FALSE );
delete_site_transient( MS_CHILD_THEME_EDITOR . '_debug' );
}
function debug( $msg = NULL, $fn = NULL, $cl = NULL ) {
if ( $this->is_debug )
$this->debug .= ( isset( $cl ) ? $cl . '::' : '' ) . ( isset( $fn ) ? $fn . ' -- ' : '' ) . ( isset( $msg ) ? $msg . LF : '' );
}
function log_debug() {
$this->debug( '*** END OF REQUEST ***', __FUNCTION__, __CLASS__ );
set_site_transient( MS_CHILD_THEME_EDITOR . '_debug', $this->debug, 3600 );
}
function get_debug() {
return get_site_transient( MS_CHILD_THEME_EDITOR . '_debug' ) . LF . $this->debug;
}
function cache_debug() {
$this->debug( '*** END OF REQUEST ***', __FUNCTION__, __CLASS__ );
$this->updates[] = array(
'obj' => 'debug',
'key' => '',
'data' => $this->debug,
);
}
function parse_parent_stylesheet_to_source() {
$this->css->parse_css_file( 'parnt' );
}
function parse_child_stylesheet_to_source() {
$this->css->parse_css_file( 'child', 'style.css', 'parnt' );
}
function parse_child_stylesheet_to_target() {
$this->css->parse_css_file( 'child', 'style.css' );
}
function parse_custom_stylesheet_to_target() {
$this->css->parse_css_file( 'child', 'ms-separate-style.css' );
}
function parse_genesis_stylesheet_to_source() {
$this->css->parse_css_file( 'child', 'ctc-genesis.css', 'parnt' );
}
function parse_additional_stylesheets_to_source() {
foreach ( $this->css->addl_css as $file ):
$this->css->parse_css_file( 'parnt', $file );
endforeach;
$this->debug( print_r( $this->css->addl_css, TRUE ), __FUNCTION__, __CLASS__ );
}
function reset_child_theme() {
$parnt = $this->get( 'parnt' );
$child = $this->get( 'child' );
$name = $this->get( 'child_name' );
$this->css = new ms_theme_editor_css();
$this->css->set_prop( 'parnt', $parnt );
$this->css->set_prop( 'child', $child );
$this->css->set_prop( 'child_name', $name );
$this->css->set_prop( 'enqueue', 'enqueue' );
$this->backup_or_restore_file( 'header.php', TRUE );
$this->delete_child_file( 'header.msbackup', 'php' );
$this->backup_or_restore_file( 'style.css', TRUE );
$this->delete_child_file( 'style.msbackup', 'css' );
$this->backup_or_restore_file( 'ms-style.css', TRUE );
$this->delete_child_file( 'ms-style.msbackup', 'css' );
}
function copy_theme_mods( $from, $to ) {
if ( strlen( $from ) && strlen( $to ) ):
$this->set_theme_mods( $to, $this->get_theme_mods( $from ) );
do_action( 'chld_thm_cfg_copy_theme_mods', $from, $to );
endif;
}
function get_theme_mods( $theme ){
$active_theme = get_stylesheet();
$mods = get_option( 'theme_mods_' . $theme );
if ( $active_theme == $theme ):
$this->debug( 'from is active, using active widgets', __FUNCTION__, __CLASS__ );
$mods[ 'sidebars_widgets' ][ 'data' ] = retrieve_widgets();
else:
$this->debug( 'from not active, using theme mods widgets', __FUNCTION__, __CLASS__ );
$mods[ 'sidebars_widgets' ][ 'data' ] = empty( $mods[ 'sidebars_widgets' ][ 'data' ] ) ?
array( 'wp_inactive_widgets' => array() ) : $mods[ 'sidebars_widgets' ][ 'data' ];
endif;
return $mods;
}
function set_theme_mods( $theme, $mods ){
$active_theme = get_stylesheet();
$widgets = $mods[ 'sidebars_widgets' ][ 'data' ];
if ( $active_theme == $theme ):
$this->debug( 'to active, setting active widgets', __FUNCTION__, __CLASS__ );
wp_set_sidebars_widgets( $mods[ 'sidebars_widgets' ][ 'data' ] );
unset( $mods[ 'sidebars_widgets' ] );
else:
$this->debug( 'child not active, saving widgets in theme mods', __FUNCTION__, __CLASS__ );
$mods[ 'sidebars_widgets' ][ 'time' ] = time();
endif;
update_option( 'theme_mods_' . $theme, $mods );
}
function network_enable() {
if ( $child = $this->get( 'child' ) ):
$allowed_themes = get_site_option( 'allowedthemes' );
$allowed_themes[ $child ] = true;
update_site_option( 'allowedthemes', $allowed_themes );
endif;
}
function backup_or_restore_file( $source, $restore = FALSE, $target = NULL ){
$action = $restore ? 'Restore' : 'Backup';
$this->debug( LF . LF . $action . ' main stylesheet...', __FUNCTION__, __CLASS__ );
if ( !$this->fs ):
$this->debug( 'No filesystem access, returning', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
list( $base, $suffix ) = explode( '.', $source );
if ( empty( $target ) )
$target = $base . '.msbackup.' . $suffix;
if ( $restore ):
$source = $target;
$target = $base . '.' . $suffix;
endif;
$fstarget = $this->fspath( $this->css->get_child_target( $target ) );
$fssource = $this->fspath( $this->css->get_child_target( $source ) );
global $wp_filesystem;
if ( ( !$wp_filesystem->exists( $fssource ) ) || ( !$restore && $wp_filesystem->exists( $fstarget ) ) ):
$this->debug( 'No stylesheet, returning', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
if ( $wp_filesystem->copy( $fssource, $fstarget, FS_CHMOD_FILE ) ):
$this->debug( 'Filesystem ' . $action . ' successful', __FUNCTION__, __CLASS__ );
return TRUE;
else:
$this->debug( 'Filesystem ' . $action . ' failed', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
}
function rewrite_stylesheet_header(){
$this->debug( LF . LF . 'Rewriting main stylesheet header...', __FUNCTION__, __CLASS__ );
if ( !$this->fs ):
$this->debug( 'No filesystem access, returning', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
$origcss = $this->css->get_child_target( 'style.css' );
$fspath = $this->fspath( $origcss );
global $wp_filesystem;
if( !$wp_filesystem->exists( $fspath ) ):
$this->debug( 'No stylesheet, returning', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
$contents = $wp_filesystem->get_contents( $fspath );
$child_headers = $this->css->get_css_header();
if ( is_array( $child_headers ) )
$regex = implode( '|', array_map( 'preg_quote', array_keys( $child_headers ) ) );
else $regex = 'NO HEADERS';
$regex = '/(' . $regex . '):.*$/';
$this->debug( 'regex: ' . $regex, __FUNCTION__, __CLASS__ );
$header = str_replace( "\r", LF, substr( $contents, 0, 8192 ) );
$contents = substr( $contents, 8192 );
$this->debug( 'original header: ' . LF . substr( $header, 0, 1024 ), __FUNCTION__, __CLASS__ );
$header = preg_replace( '#\@import\s+url\(.+?\);\s*#s', '', $header );
$headerdata = explode( "\n", $header );
$in_comment = 0;
$found_header = 0;
$headerdone = 0;
$newheader = '';
if ( $headerdata ):
$this->debug( 'parsing header...', __FUNCTION__, __CLASS__ );
foreach ( $headerdata as $n => $headerline ):
preg_match_all("/(\*\/|\/\*)/", $headerline, $matches );
if ( $matches ):
foreach ( $matches[1] as $token ):
if ( '/*' == $token ):
$in_comment = 1;
elseif ( '*/' == $token ):
$in_comment = 0;
endif;
endforeach;
endif;
if ( $in_comment ):
$this->debug( 'in comment', __FUNCTION__, __CLASS__ );
if ( preg_match( $regex, $headerline, $matches ) && !empty( $matches[ 1 ] ) ):
$found_header = 1;
$key = $matches[ 1 ];
$this->debug( 'found header: ' . $key, __FUNCTION__, __CLASS__ );
if ( array_key_exists( $key, $child_headers ) ):
$this->debug( 'child header value exists: ', __FUNCTION__, __CLASS__ );
$value = trim( $child_headers[ $key ] );
unset( $child_headers[ $key ] );
if ( $value ):
$this->debug( 'setting ' . $key . ' to ' . $value, __FUNCTION__, __CLASS__ );
$count = 0;
$headerline = preg_replace(
$regex,
( empty( $value ) ? '' : $key . ': ' . $value ),
$headerline
);
else:
$this->debug( 'removing ' . $key, __FUNCTION__, __CLASS__ );
continue;
endif;
endif;
endif;
$newheader .= $headerline . LF;
elseif ( $found_header && !$headerdone ):
foreach ( $child_headers as $key => $value ):
$this->debug( 'inserting ' . $key . ': ' . $value, __FUNCTION__, __CLASS__ );
if ( empty( $value ) ) continue;
$newheader .= $key . ': ' . trim( $value ) . "\n";
endforeach;
$newheader .= $headerline . "\n" . $this->css->get_css_imports();
$headerdone = 1;
else:
$newheader .= $headerline . LF;
endif;
endforeach;
$this->debug( 'new header: ' . LF . substr( $newheader, 0, 1024 ), __FUNCTION__, __CLASS__ );
if ( !$found_header ) return FALSE;
endif;
$contents = $newheader . $contents;
if ( FALSE === $wp_filesystem->put_contents( $fspath, $contents ) ):
else:
endif;
}
function get_child_stylesheet() {
$handling = $this->get( 'handling' );
if ( 'separate' == $handling )
return 'ms-separate-style.css';
elseif ( 'reset' == $this->childtype )
return FALSE;
else
return 'style.css';
}
function repair_header() {
if ( ! $this->get( 'cssunreg' ) && !$this->get( 'csswphead' ) ) return;
$this->debug( 'repairing parent header', __FUNCTION__, __CLASS__ );
$this->copy_parent_file( 'header' );
$this->backup_or_restore_file( 'header.php' );
global $wp_filesystem;
$cssstr = "get_template_directory_uri()";
$wphstr = '<?php // MODIFIED BY CTC' . LF . 'wp_head();' . LF . '?>' . LF . '</head>';
$filename = $this->css->get_child_target( 'header.php' );
$contents = $wp_filesystem->get_contents( $this->fspath( $filename ) );
if ( $this->get( 'cssunreg' ) || $this->get( 'csswphead' ) ):
$repairs = 0;
$contents = preg_replace( "#(get_bloginfo\(\s*['\"]stylesheet_url['\"]\s*\)|get_stylesheet_uri\(\s*\))#s", $cssstr . ' . "/style.css"', $contents, -1, $count );
$repairs += $count;
$contents = preg_replace( "#([^_])bloginfo\(\s*['\"]stylesheet_url['\"]\s*\)#s", "$1echo " . $cssstr . ' . "/style.css"', $contents, -1, $count );
$repairs += $count;
$contents = preg_replace( "#([^_])bloginfo\(\s*['\"]stylesheet_directory['\"]\s*\)#s", "$1echo " . $cssstr, $contents, -1, $count );
$repairs += $count;
$contents = preg_replace( "#(trailingslashit\()?(\s*)get_stylesheet_directory_uri\(\s*\)(\s*\))?\s*\.\s*['\"]\/?([\w\-\.\/]+?)\.css['\"]#s",
"$2echo $cssstr . '$3.css'", $contents, -1, $count );
$repairs += $count;
if ( $repairs )
$this->css->set_prop( 'parntloaded', TRUE );
endif;
if ( $this->get( 'csswphead' ) ):
$contents = preg_replace( "#wp_head\(\s*\)\s*;#s", '', $contents );
$contents = preg_replace( "#</head>#s", $wphstr, $contents );
$contents = preg_replace( "#\s*<\?php\s*\?>\s*#s", LF, $contents ); // clean up
endif;
$this->debug( 'Writing to filesystem: ' . $filename . LF . $contents, __FUNCTION__, __CLASS__ );
if ( FALSE === $wp_filesystem->put_contents( $this->fspath( $filename ), $contents ) ):
$this->debug( 'Filesystem write failed, returning.', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
}
function evaluate_signals() {
if ( !isset( $_POST[ 'ms_theme_child_analysis' ] ) ) return;
$analysis = json_decode( urldecode( $_POST[ 'ms_theme_child_analysis' ] ) );
$unregs = array( 'thm_past_wphead', 'thm_unregistered', 'dep_unregistered', 'css_past_wphead', 'dep_past_wphead' );
$baseline = $this->get( 'ignoreparnt' ) ? 'child' : 'parnt';
$this->debug( 'baseline: ' . $baseline, __FUNCTION__, __CLASS__ );
$this->css->parnt_deps = array();
$this->css->child_deps = array();
$this->css->addl_css = array();
if ( isset( $analysis->parnt->imports ) ):
foreach ( $analysis->parnt->imports as $import ):
if ( preg_match( '%(https?:)?//%', $import ) ) continue;
$this->css->addl_css[] = sanitize_text_field( $import );
endforeach;
endif;
if ( isset( $analysis->{ $baseline } ) ):
if ( isset( $analysis->{ $baseline }->deps ) ):
foreach ( $analysis->{ $baseline }->deps[ 0 ] as $deparray ):
if ( 'chld_thm_cfg_parent' == $deparray[ 0 ] )
continue;
if ( !in_array( $deparray[ 0 ], $unregs ) ):
$this->css->parnt_deps[] = $deparray[ 0 ];
endif;
if ( !preg_match( "/^style.*?\.css$/", $deparray[ 1 ] ) ):
$this->css->addl_css[] = sanitize_text_field( $deparray[ 1 ] );
endif;
endforeach;
foreach ( $analysis->{ $baseline }->deps[ 1 ] as $deparray ):
if ( 'chld_thm_cfg_child' == $deparray[ 0 ] )
continue;
if ( !in_array( $deparray[ 0 ], $unregs ) ):
$this->css->child_deps[] = $deparray[ 0 ];
endif;
if ( 'separate' == $this->get( 'handling' ) || !empty( $analysis->{ $baseline }->signals->ctc_child_loaded ) ):
if ( !preg_match( "/^style.*?\.css$/", $deparray[ 1 ] ) ):
$this->css->addl_css[] = sanitize_text_field( $deparray[ 1 ] );
endif;
endif;
endforeach;
endif;
endif;
if ( isset( $analysis->{ $baseline }->signals ) ):
$this->css->set_prop( 'hasstyles', isset( $analysis->{ $baseline }->signals->thm_no_styles ) ? 0 : 1 );
$this->css->set_prop( 'csswphead', isset( $analysis->{ $baseline }->signals->thm_past_wphead ) ? 1 : 0 );
$this->css->set_prop( 'cssunreg', isset( $analysis->{ $baseline }->signals->thm_unregistered ) ? 1 : 0 );
if ( isset( $analysis->{ $baseline }->signals->thm_parnt_loaded ) ):
$this->set_enqueue_priority( $analysis, $baseline );
endif;
endif;
if ( isset( $analysis->child->signals->thm_past_wphead ) )
$this->css->set_prop( 'csswphead', 1 );
if ( isset( $analysis->child->signals->thm_unregistered ) )
$this->css->set_prop( 'cssunreg', 1 );
if ( isset( $analysis->child->signals->thm_notheme ) )
$this->css->set_prop( 'cssnotheme', 1 );
if ( isset( $analysis->child->signals->thm_child_loaded ) ):
$this->css->set_prop( 'childloaded', $analysis->child->signals->thm_child_loaded );
$this->set_enqueue_priority( $analysis, 'child' );
else:
$this->css->set_prop( 'childloaded', 0 );
endif;
if ( isset( $analysis->child->signals->thm_parnt_loaded ) ):
$this->css->set_prop( 'parntloaded', $analysis->child->signals->thm_parnt_loaded );
if ( 'thm_unregistered' != $analysis->child->signals->thm_parnt_loaded ):
array_unshift( $this->css->child_deps, $analysis->child->signals->thm_parnt_loaded );
endif;
else:
$this->css->set_prop( 'parntloaded', 0 );
endif;
if ( isset( $analysis->child->signals->ctc_parnt_reorder ) )
$this->css->set_prop( 'reorder', 1 );
if ( isset( $analysis->child->signals->ctc_gen_loaded ) )
$this->genesis = TRUE;
}
function set_enqueue_priority( $analysis, $baseline ){
foreach ( $analysis->{ $baseline }->irreg as $irreg ):
$handles = explode( ',', $irreg );
$priority = array_shift( $handles );
$handle = $analysis->{ $baseline }->signals->{ 'thm_' . $baseline . '_loaded' };
if ( in_array( $handle, $handles ) ):
$this->debug( '(baseline: ' . $baseline . ') match: ' . $handle . ' setting priority: ' . $priority, __FUNCTION__, __CLASS__ );
$this->css->set_prop( 'qpriority', $priority );
break;
endif;
endforeach;
}
}