'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png', ); function __construct() { $this->processdone = FALSE; $this->genesis = FALSE; //$this->reorder = FALSE; $this->is_new = FALSE; $this->encoding = WP_Http_Encoding::is_available(); $this->menuName = CHLD_THM_CFG_MENU; // backward compatability for plugins extension $this->is_post = ( 'POST' == $_SERVER[ 'REQUEST_METHOD' ] ); $this->is_get = ( 'GET' == $_SERVER[ 'REQUEST_METHOD' ] ); $this->is_debug = get_option( CHLD_THM_CFG_OPTIONS . '_debug' ); $this->debug = ''; $this->errors = array(); } /** * initialize configurator */ function ctc_page_init () { // get all available themes $this->get_themes(); $this->childtype = count( $this->themes[ 'child' ] ) ? 'existing' : 'new'; // load config data and validate $this->load_config(); // perform any checks prior to processing config data do_action( 'chld_thm_cfg_preprocess' ); // process any additional forms do_action( 'chld_thm_cfg_forms' ); // hook for custom forms // process main post data $this->process_post(); // initialize UI $this->ui = new ChildThemeConfiguratorUI(); // initialize help $this->ui->render_help_content(); } function render() { $this->ui->render(); } /* helper function to retreive css object properties */ function get( $property, $params = NULL ) { return $this->css->get_prop( $property, $params ); } function get_themes() { // create cache of theme info $this->themes = array( 'child' => array(), 'parnt' => array() ); foreach ( wp_get_themes() as $theme ): // organize into parent and child themes $group = $theme->parent() ? 'child' : 'parnt'; // get the theme slug $slug = $theme->get_stylesheet(); // get the theme slug $version = $theme->get( 'Version' ); // strip auto-generated timestamp from CTC child theme version if ( 'child' == $group ) $version = preg_replace("/\.\d{6}\d+$/", '', $version ); // add theme to themes array $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 = 'ctc_update', $noncefield = '_wpnonce', $cap = 'install_themes' ) { // security: request must be post, user must have permission, referrer must be local and nonce must match return ( $this->is_post && current_user_can( $cap ) // ( 'edit_themes' ) && ( $this->is_ajax ? check_ajax_referer( $action, $noncefield, FALSE ) : check_admin_referer( $action, $noncefield, FALSE ) ) ); } function load_config() { $this->css = new ChildThemeConfiguratorCSS(); if ( FALSE !== $this->css->load_config() ): $this->debug( 'config exists', __FUNCTION__, __CLASS__, __CLASS__ ); // if themes do not exist reinitialize if ( ! $this->check_theme_exists( $this->get( 'child' ) ) || ! $this->check_theme_exists( $this->get( 'parnt' ) ) ): $this->debug( 'theme does not exist', __FUNCTION__, __CLASS__, __CLASS__ ); add_action( 'chld_thm_cfg_admin_notices', array( $this, 'config_notice' ) ); $this->css = new ChildThemeConfiguratorCSS(); $this->css->enqueue = 'enqueue'; endif; else: $this->debug( 'config does not exist', __FUNCTION__, __CLASS__, __CLASS__ ); // this is a fresh install $this->css->enqueue = 'enqueue'; endif; do_action( 'chld_thm_cfg_load' ); if ( $this->is_get ): /** * using 'updated' get var to indicate theme mods should be copied and the to/from themes * otherwise set msg id */ if ( isset( $_GET[ 'updated' ] ) ): $msgparts = explode( ',', $_GET[ 'updated' ] ); $this->msg = array_shift( $msgparts ); if ( count( $msgparts ) ) $this->copy_mods = $msgparts; endif; if ( $this->get( 'child' ) ): // get filesystem credentials if available $this->verify_creds(); $stylesheet = apply_filters( 'chld_thm_cfg_target', $this->css->get_child_target( $this->get_child_stylesheet() ), $this->css ); // check file permissions 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__ ); if ( $test != $fsize ) add_action( 'chld_thm_cfg_admin_notices', array( $this, 'changed_notice' ) ); endif; // enqueue flag will be null for existing install < 1.6.0 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 ( !$this->seen_upgrade_notice() ): add_action( 'chld_thm_cfg_admin_notices', array( $this, 'upgrade_notice' ) ); endif; /** * Future use: check if max selectors reached * if ( $this->get( 'max_sel' ) ): $this->debug( 'Max selectors exceeded.', __FUNCTION__, __CLASS__, __CLASS__ ); //$this->errors[] = 26; //__( 'Maximum number of styles exceeded.', 'child-theme-configurator' ); add_action( 'chld_thm_cfg_admin_notices', array( $this, 'max_styles_notice' ) ); endif; */ // check if file ownership is messed up from old version or other plugin // by comparing owner of plugin to owner of child theme: if ( fileowner( $this->css->get_child_target( '' ) ) != fileowner( CHLD_THM_CFG_DIR ) ) add_action( 'chld_thm_cfg_admin_notices', array( $this, 'owner_notice' ) ); endif; } /** * ajax callback for saving form data */ function ajax_save_postdata( $action = 'ctc_update' ) { $this->is_ajax = TRUE; $this->debug( 'ajax save ', __FUNCTION__, __CLASS__ ); // security check if ( $this->validate_post( $action ) ): if ( 'ctc_plugin' == $action ) do_action( 'chld_thm_cfg_pluginmode' ); $this->verify_creds(); // initialize filesystem access add_action( 'chld_thm_cfg_cache_updates', array( $this, 'cache_debug' ) ); // get configuration data from options API if ( FALSE !== $this->load_config() ): // sanity check: only update if config data exists if ( isset( $_POST[ 'ctc_is_debug' ] ) ): // toggle debug $this->toggle_debug(); else: if( isset( $_POST[ 'ctc_copy_mods' ] ) ): // copy menus, widgets and other customizer options from parent to child if selected if ( isset( $_POST[ 'ctc_copy_from' ] ) && isset( $_POST[ 'ctc_copy_to' ] ) ): $this->debug( 'Copy Theme Mods on resubmit', __FUNCTION__, __CLASS__ ); $from = sanitize_text_field( $_POST[ 'ctc_copy_from' ] ); $to = sanitize_text_field( $_POST[ 'ctc_copy_to' ] ); $this->copy_theme_mods( $from, $to ); else: $this->debug( 'Copy Theme Mods passed but missing to and from values', __FUNCTION__, __CLASS__ ); endif; endif; if ( isset( $_POST[ 'ctc_analysis' ] ) ): // process ANALYZER SIGNAL inputs if ( $this->cache_updates ): $this->updates[] = array( 'obj' => 'analysis', 'data' => array(), ); endif; $this->evaluate_signals(); endif; $this->css->parse_post_data(); // parse any passed values // if child theme config has been set up, save new data // return recent edits and selected stylesheets as cache updates if ( $this->get( 'child' ) ): // hook for add'l plugin files and subdirectories do_action( 'chld_thm_cfg_addl_files' ); if ( !$this->css->write_css() ) die( 0 ); /* $this->updates[] = array( 'obj' => 'addl_css', 'key' => '', 'data' => $this->get( 'addl_css' ), ); */ endif; // update config data in options API $this->save_config(); endif; // add any additional updates to pass back to browser do_action( 'chld_thm_cfg_cache_updates' ); endif; if ( count( $this->errors ) ) $this->updates[] = array( 'obj' => 'errors', 'key' => '', 'data' => $this->errors, ); // send all updates back to browser to update cache die( json_encode( $this->css->obj_to_utf8( $this->updates ) ) ); endif; die(); } function save_config() { // update config data in options API $this->css->save_config(); } /** * ajax callback to query config data */ function ajax_query_css( $action = 'ctc_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' ] ) ): // add any additional updates to pass back to browser $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 ); } /** * check if user has been notified about upgrade */ function seen_upgrade_notice() { $seen_upgrade_version = get_user_meta( get_current_user_id(), 'chld_thm_cfg_upgrade_notice', TRUE ); return version_compare( $seen_upgrade_version, CHLD_THM_CFG_PREV_VERSION, '>=' ); } /** * ajax callback to dismiss upgrade notice */ function ajax_dismiss_notice( $action = 'ctc_update' ) { $this->is_ajax = TRUE; if ( $this->validate_post( $action ) ): update_user_meta( get_current_user_id(), 'chld_thm_cfg_upgrade_notice' , CHLD_THM_CFG_VERSION ); $this->updates[] = array( 'key' => '', 'obj' => 'dismiss', 'data' => CHLD_THM_CFG_VERSION, ); die( json_encode( $this->updates ) ); endif; die( 0 ); } function ajax_analyze() { $this->is_ajax = TRUE; do_action( 'chld_thm_cfg_pluginmode' ); if ( $this->validate_post( apply_filters( 'chld_thm_cfg_action', 'ctc_update' ) ) ): $analysis = new ChildThemeConfiguratorAnalysis(); $analysis->fetch_page(); die( json_encode( $analysis->get_analysis() ) ); endif; die( 0 ); } function get_pathinfo( $path ){ $pathinfo = pathinfo( $path ); $path = ( preg_match( "/^[\.\/]/", $pathinfo[ 'dirname' ] ) ? '' : $pathinfo[ 'dirname' ] . '/' ) . $pathinfo[ 'filename' ]; return array( $path, $pathinfo[ 'extension' ] ); } /** * Handles processing for all form submissions. * Moved conditions to switch statement with the main setup logic in a separate function. */ function process_post() { // make sure this is a post if ( $this->is_post ): // see if a valid action was passed foreach ( $this->actionfields as $field ): if ( in_array( 'ctc_' . $field, array_keys( $_POST ) ) ): $actionfield = $field; break; endif; endforeach; if ( empty( $actionfield ) ) return FALSE; // make sure post passes security checkpoint if ( !$this->validate_post( apply_filters( 'chld_thm_cfg_action', 'ctc_update' ) ) ): // if you end up here you are persona non grata $this->errors[] = 2; //__( 'You do not have permission to configure child themes.', 'child-theme-configurator' ); else: // reset debug log delete_site_transient( CHLD_THM_CFG_OPTIONS . '_debug' ); // handle uploaded file before checking filesystem if ( 'theme_image_submit' == $actionfield && isset( $_FILES[ 'ctc_theme_image' ] ) ): $this->handle_file_upload( 'ctc_theme_image', $this->imgmimes ); elseif ( 'theme_screenshot_submit' == $actionfield && isset( $_FILES[ 'ctc_theme_screenshot' ] ) ): $this->handle_file_upload( 'ctc_theme_screenshot', $this->imgmimes ); endif; // now we need to check filesystem access $args = preg_grep( "/nonce/", array_keys( $_POST ), PREG_GREP_INVERT ); $this->verify_creds( $args ); if ( $this->fs ): // we have filesystem access so proceed with specific actions switch( $actionfield ): case 'export_child_zip': case 'export_theme': $this->export_theme(); // if we get here the zip failed $this->errors[] = 1; //__( 'Zip file creation failed.', 'child-theme-configurator' ); break; case 'load_styles': // main child theme setup function $this->setup_child_theme(); break; case 'parnt_templates_submit': // copy parent templates to child if ( isset( $_POST[ 'ctc_file_parnt' ] ) ): foreach ( $_POST[ 'ctc_file_parnt' ] as $file ): list( $path, $ext ) = $this->get_pathinfo( sanitize_text_field( $file ) ); $this->copy_parent_file( $path, $ext ); endforeach; $this->msg = '8&tab=file_options'; endif; break; case 'child_templates_submit': // delete child theme files if ( isset( $_POST[ 'ctc_file_child' ] ) ): foreach ( $_POST[ 'ctc_file_child' ] as $file ): list( $path, $ext ) = $this->get_pathinfo( sanitize_text_field( $file ) ); if ( 'functions' == $path ): $this->errors[] = 4; // __( 'The Functions file is required and cannot be deleted.', 'child-theme-configurator' ); continue; else: $this->delete_child_file( $path, $ext ); endif; endforeach; $this->msg = '8&tab=file_options'; endif; break; case 'image_submit': // delete child theme images if ( isset( $_POST[ 'ctc_img' ] ) ): foreach ( $_POST[ 'ctc_img' ] as $file ) $this->delete_child_file( 'images/' . sanitize_text_field( $file ), 'img' ); $this->msg = '8&tab=file_options'; endif; break; case 'templates_writable_submit': // make specific files writable ( systems not running suExec ) if ( isset( $_POST[ 'ctc_file_child' ] ) ): foreach ( $_POST[ 'ctc_file_child' ] as $file ): list( $path, $ext ) = $this->get_pathinfo( sanitize_text_field( $file ) ); $this->set_writable( $path, $ext ); endforeach; $this->msg = '8&tab=file_options'; endif; break; case 'set_writable': // make child theme style.css and functions.php writable ( systems not running suExec ) $this->set_writable(); // no argument defaults to style.css $this->set_writable( 'functions' ); $this->msg = '8&tab=file_options'; break; case 'reset_permission': // make child theme read-only ( systems not running suExec ) $this->unset_writable(); $this->msg = '8&tab=file_options'; break; case 'theme_image_submit': // move uploaded child theme images (now we have filesystem access) if ( isset( $_POST[ 'movefile' ] ) ): $this->move_file_upload( 'images' ); $this->msg = '8&tab=file_options'; endif; break; case 'theme_screenshot_submit': // move uploaded child theme screenshot (now we have filesystem access) if ( isset( $_POST[ 'movefile' ] ) ): // remove old screenshot foreach( array_keys( $this->imgmimes ) as $extreg ): foreach ( explode( '|', $extreg ) as $ext ) $this->delete_child_file( 'screenshot', $ext ); endforeach; $this->move_file_upload( '' ); $this->msg = '8&tab=file_options'; endif; break; default: // assume we are on the files tab so just redirect there $msg = '8&tab=file_options'; endswitch; endif; // end filesystem condition endif; // end post validation condition // if we have errors, redirect failure if ( $this->errors ): $this->update_redirect( 0 ); // if we have filesystem access, redirect successful elseif ( empty( $this->fs_prompt ) ): $this->processdone = TRUE; //die( '
' . print_r( $_POST, TRUE ) . '
' );
// no errors so we redirect with confirmation message
$this->update_redirect();
endif;
endif; // end request method condition
// if we are here, then this is either a get request or we need filesystem access
}
/**
* Handle the creation or update of a child theme
*/
function setup_child_theme() {
$this->msg = 1;
$this->is_new = TRUE;
// sanitize and extract config fields into local vars
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 ] ) );
$this->debug( 'Extracting var ' . $varname . ' from ctc_' . $configfield . ' value: ' . ${$varname} , __FUNCTION__, __CLASS__ );
endforeach;
if ( isset( $type ) ) $this->childtype = $type;
// legacy plugin extension needs parent/new values but this version disables the inputs
// so get we them from current css object
if ( !$this->is_theme( $configtype ) && $this->is_legacy() ):
$parnt = $this->get( 'parnt' );
$child = $this->get( 'child' );
$name = $this->get( 'child_name' );
endif;
// validate parent and child theme inputs
if ( $parnt ):
if ( ! $this->check_theme_exists( $parnt ) ):
$this->errors[] = '3:' . $parnt; //sprintf( __( '%s does not exist. Please select a valid Parent Theme.', 'child-theme-configurator' ), $parnt );
endif;
else:
$this->errors[] = 5; // __( 'Please select a valid Parent Theme.', 'child-theme-configurator' );
endif;
// if this is reset, duplicate or existing, we must have a child theme
if ( 'new' != $type && empty( $child ) ):
$this->errors[] = 6; //__( 'Please select a valid Child Theme.', 'child-theme-configurator' );
// if this is a new or duplicate child theme we must validate child theme directory
elseif ( 'new' == $type || 'duplicate' == $type ):
if ( empty( $template ) && empty( $name ) ):
$this->errors[] = 7; // __( 'Please enter a valid Child Theme directory name.', 'child-theme-configurator' );
else:
$template_sanitized = preg_replace( "%[^\w\-]%", '', empty( $template ) ? $name : $template );
if ( $this->check_theme_exists( $template_sanitized ) ):
$this->errors[] = '8:' . $template_sanitized; //sprintf( __( '%s exists. Please enter a different Child Theme template name.', 'child-theme-configurator' ), $template_sanitized );
elseif ( 'duplicate' == $type ):
// clone existing child theme
$this->clone_child_theme( $child, $template_sanitized );
if ( !empty( $this->errors ) ) return FALSE;
/**
* using 'updated' get var to indicate theme mods should be copied and the to/from themes
*/
$this->msg = '3,' . $child . ',' . $template_sanitized;
else:
$this->msg = 2;
endif;
$child = $template_sanitized;
endif;
endif;
// verify_child_dir creates child theme directory if it doesn't exist.
if ( FALSE === $this->verify_child_dir( $child ) ):
// if it returns false then it could not create directory.
$this->errors[] = 9; //__( 'Your theme directories are not writable.', 'child-theme-configurator' );
return FALSE;
endif;
// load or reset config
if ( 'reset' == $type ):
$this->debug( 'resetting child theme', __FUNCTION__, __CLASS__ );
$this->reset_child_theme();
$this->enqueue_parent_css();
$this->msg = 4;
else:
// if any errors, bail before we create css object
if ( !empty( $this->errors ) ) return FALSE;
// if no name is passed, create one from the child theme directory
if ( empty( $name ) ):
$name = ucfirst( $child );
endif;
/**
* before we configure the child theme we need to check if this is a rebuild
* and compare some of the original settings to the new settings.
*/
//$oldchild = $this->get( 'child' );
//$oldimports = $this->get( 'imports' );
//$oldenqueue = $this->get( 'enqueue' );
$oldhandling = $this->get( 'handling' );
// reset everything else
$this->css = new ChildThemeConfiguratorCSS();
// restore imports if this is a rebuild
//$this->css->imports[ 'child' ] = $oldimports;
// update with new parameters
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 is for PRO plugins
$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[ 'ctc_analysis' ] ) ):
// this is for themes
$this->evaluate_signals();
endif;
// v2.1.3 - remove dependency for specific stylesheets
$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;
$this->debug( 'Removing dependency: ' . $handle, __FUNCTION__, __CLASS__ );
endforeach;
endif;
// roll back CTC Pro Genesis handling option
if ( $this->genesis ):
$handling = 'separate';
$enqueue = 'none';
$ignoreparnt = TRUE;
if ( $this->backup_or_restore_file( 'ctc-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; //__( 'Could not upgrade child theme', 'child-theme-configurator' );
endif;
endif;
// if any errors, bail before we set action hooks or write to filesystem
if ( !empty( $this->errors ) ) return FALSE;
// override enqueue action for parent theme if it is already being loaded
if ( 'enqueue' == $enqueue && ( $this->get( 'parntloaded' ) || !$this->get( 'hasstyles' ) || $ignoreparnt ) ) $enqueue = 'none';
// parse parent stylesheet if theme or legacy plugin extension
if ( $this->is_theme( $configtype ) || $this->is_legacy() ):
// do we parse parent stylesheet?
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;
// automatically network enable new theme // FIXME: shouldn't this be an option?
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 ):
// parse child theme style.css into source config
$this->debug( 'Adding action: parse_child_stylesheet_to_source', __FUNCTION__, __CLASS__ );
add_action( 'chld_thm_cfg_parse_stylesheets', array( $this, 'parse_child_stylesheet_to_source' ) );
// parse child theme ctc-style.css into target config
$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 ):
// parse child theme style.css into target config
$this->debug( 'Adding action: parse_child_stylesheet_to_target', __FUNCTION__, __CLASS__ );
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;
// function to support wp_filesystem requirements
if ( $this->is_theme( $configtype ) ):
// is theme means this is not a plugin stylesheet config
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;
// plugin hooks for additional stylesheet handling options
// do_action( 'chld_thm_cfg_stylesheet_handling' );
// do_action( 'chld_thm_cfg_existing_theme' );
// plugin hook to parse additional or non-standard files
do_action( 'chld_thm_cfg_parse_stylesheets' );
if ( isset( $_POST[ 'ctc_parent_mods' ] ) && 'duplicate' != $type )
/**
* using 'updated' get var to indicate theme mods should be copied and the to/from themes
*/
$this->msg .= ',' . $parnt . ',' . $child;
// run code generation function in read-only mode to add existing external stylesheet links to config data
$this->enqueue_parent_css( TRUE );
// hook for add'l plugin files and subdirectories. Must run after stylesheets are parsed to apply latest options
do_action( 'chld_thm_cfg_addl_files' );
// do not continue if errors
if ( !empty ( $this->errors ) ) return FALSE;
//echo ' no errors! saving...' . LF;
if ( 'separate' == $handling ):
$this->debug( 'Writing new stylesheet header...', __FUNCTION__, __CLASS__ );
$this->rewrite_stylesheet_header();
endif;
// set flag to skip import link conversion on ajax save
$this->css->set_prop( 'converted', 1 );
// try to write new stylsheet. If it fails send alert.
$this->debug( 'Writing new CSS...', __FUNCTION__, __CLASS__ );
if ( FALSE === $this->css->write_css() ):
//$this->debug( print_r( debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ), TRUE ), __FUNCTION__, __CLASS__ );
$this->errors[] = 11; //__( 'Your stylesheet is not writable.', 'child-theme-configurator' );
return FALSE;
endif;
// get files to reload templates in new css object
$this->get_files( $parnt );
endif;
$this->debug( 'Saving new config...', __FUNCTION__, __CLASS__ );
// save new object to WP options table
$this->save_config();
$this->debug( 'Firing additional options action...', __FUNCTION__, __CLASS__ );
// plugin hook for additional child theme setup functions
do_action( 'chld_thm_cfg_addl_options' );
//$this->dump_configs();
// return message id 1, which says new child theme created successfully;
}
/*
* TODO: this is a stub for future use
*/
function sanitize_options( $input ) {
return $input;
}
/**
* remove slashes and non-alphas from stylesheet name
*/
function sanitize_slug( $slug ) {
return preg_replace( "/[^\w\-]/", '', $slug );
}
function update_redirect() {
$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( 'tools.php' ) )
. '?page=' . $ctcpage . ( $this->errors ? '&error=' . implode( ',', $this->errors ) : ( $this->msg ? '&updated=' . $this->msg : '' ) ) );
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; // return if no filesystem access
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 ){
//$this->debug( LF . LF, __FUNCTION__, __CLASS__ );
// add functions.php file
$contents = "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( 'ctc-style.css' );
$this->write_child_file( 'ctc-style.css', $contents . LF );
endif;
}
// parses @import syntax and converts to wp_enqueue_style statement
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 . "'" ) . ' );';
}
// converts enqueued path into @import statement for config settings
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;
}
/**
* Generates wp_enqueue_script code block for child theme functions file
* Enqueues parent and/or child stylesheet depending on value of 'enqueue' setting.
* If external imports are present, it enqueues them as well.
*/
function enqueue_parent_code(){
//$this->debug( print_r( debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ), TRUE ), __FUNCTION__, __CLASS__ );
$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' );
$maxpriority = $this->get( 'mpriority' );
$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__ );
// add RTL handler
$code .= "
if ( !function_exists( 'chld_thm_cfg_locale_css' ) ):
function chld_thm_cfg_locale_css( \$uri ){
if ( empty( \$uri ) && is_rtl() && file_exists( get_template_directory() . '/rtl.css' ) )
\$uri = get_template_directory_uri() . '/rtl.css';
return \$uri;
}
endif;
add_filter( 'locale_stylesheet_uri', 'chld_thm_cfg_locale_css' );
";
// enqueue parent stylesheet
if ( 'enqueue' == $enq && $hasstyles && !$parntloaded && !$ignoreparnt ):
// Sanity check: remove dependency to parent css handle to avoid loop v2.3.0
$deps = array_diff( $deps, array( 'chld_thm_cfg_parent' ) );
$code .= "
if ( !function_exists( 'chld_thm_cfg_parent_css' ) ):
function chld_thm_cfg_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', 'chld_thm_cfg_parent_css', " . $priority . " );
";
// if loading parent theme, reset deps and add parent stylesheet
$deps = array( "'chld_thm_cfg_parent'" );
endif;
// force a stylesheet dependency if parent is loading out of sequence
if ( 'separate' != $handling && $childloaded && $reorder && ( $parntloaded || in_array( 'chld_thm_cfg_parent', $deps ) ) ):
$dephandle = $parntloaded ? $parntloaded : 'chld_thm_cfg_parent';
$code .= "
if ( !function_exists( 'chld_thm_cfg_add_parent_dep' ) ):
function chld_thm_cfg_add_parent_dep() {
global \$wp_styles;
array_unshift( \$wp_styles->registered[ '" . $childloaded . "' ]->deps, '" . $dephandle . "' );
}
endif;
add_action( 'wp_head', 'chld_thm_cfg_add_parent_dep', 2 );
";
endif;
// enqueue external stylesheets (previously used @import in the stylesheet)
if ( !empty( $imports ) ):
$ext = 0;
foreach ( $imports as $import ):
if ( !empty( $import ) ):
$ext++;
$enqueues[] = ' ' . $this->convert_import_to_enqueue( $import, $ext );
endif;
endforeach;
endif;
// deregister and re-register swaps
foreach ( $this->get( 'swappath' ) as $sphandle => $sppath ):
if ( file_exists( trailingslashit( get_template_directory() ) . $sppath ) ):
$enqueues[] = " if ( !file_exists( trailingslashit( get_stylesheet_directory() ) . '" . $sppath . "' ) ):";
$enqueues[] = " wp_deregister_style( '" . $sphandle . "' );";
$enqueues[] = " wp_register_style( '" . $sphandle . "', trailingslashit( get_template_directory_uri() ) . '" . $sppath . "' );";
$enqueues[] = " endif;";
endif;
endforeach;
//die( print_r( $enqueues, TRUE ) );
// if child not loaded, enqueue it and add it to dependencies
if ( 'separate' != $handling && ( ( $csswphead || $cssunreg || $cssnotheme )
|| ( 'new' != $this->childtype && !$childloaded )
) ):
$deps = array_merge( $deps, $this->get( 'child_deps' ) );
// Sanity check: remove dependency to child css handle to avoid loop v2.3.0
$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 ) . " ) );";
// if loading child theme stylesheet, reset deps and add child stylesheet
$deps = array( "'chld_thm_cfg_child'" );
endif;
if ( 'separate' == $handling ):
$deps = array_merge( $deps, $this->get( 'child_deps' ) );
// Sanity check: remove dependency to separate css handle to avoid loop v2.3.0
$deps = array_diff( $deps, array( 'chld_thm_cfg_separate' ) );
$enqueues[] = " wp_enqueue_style( 'chld_thm_cfg_separate', trailingslashit( get_stylesheet_directory_uri() ) . 'ctc-style.css', array( " . implode( ',', $deps ) . " ) );";
endif;
if ( count( $enqueues ) ):
$code .= "
if ( !function_exists( 'child_theme_configurator_css' ) ):
function child_theme_configurator_css() {" . LF;
$code .= implode( "\n", $enqueues );
$code .= "
}
endif;
add_action( 'wp_enqueue_scripts', 'child_theme_configurator_css', " . $maxpriority . " );" . LF;
endif;
if ( $ignoreparnt )
$code .= "
defined( 'CHLD_THM_CFG_IGNORE_PARENT' ) or define( 'CHLD_THM_CFG_IGNORE_PARENT', TRUE );" . LF;
//$this->debug( $code, __FUNCTION__, __CLASS__ );
return explode( "\n", $code ); // apply_filters( 'chld_thm_cfg_enqueue_code_filter', $code ) ); // FIXME?
}
// updates function file with wp_enqueue_script code block. If getexternals flag is passed function is run in read-only mode
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 );
/// FIXME - reset for Pro version
if ( !$getexternals && 'reset' == $this->childtype ):
$marker = 'CTC ENQUEUE PLUGIN ACTION';
$this->insert_with_markers( $filename, $marker, array() );
endif;
endif;
}
/**
* Update functions file with wp_enqueue_style code block. Runs in read-only mode if getexternals is passed.
* This function uses the same method as the WP core function that updates .htaccess
* we would have used WP's insert_with_markers function,
* but it does not use wp_filesystem API.
*/
function insert_with_markers( $filename, $marker, $insertion, $getexternals = FALSE ) {
if ( count( $this->errors ) ):
$this->debug( 'Errors detected, returning', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
// first check if this is an ajax update
if ( $this->is_ajax && is_readable( $filename ) && is_writable( $filename ) ):
// ok to proceed
$this->debug( 'Ajax update, bypassing wp filesystem.', __FUNCTION__, __CLASS__ );
$markerdata = @file_get_contents( $filename );
elseif ( !$this->fs ):
$this->debug( 'No filesystem access.', __FUNCTION__, __CLASS__ );
return FALSE; // return if no filesystem access
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:
// make sure file exists with php header
$this->debug( 'No functions file, creating...', __FUNCTION__, __CLASS__ );
$this->add_base_files( $this );
endif;
endif;
// get_contents_array returns extra linefeeds so just split it ourself
$markerdata = $wp_filesystem->get_contents( $this->fspath( $filename ) );
endif;
// remove closing php tag
$markerdata = preg_replace( "/\?>\s*\$/s", '', $markerdata );
// divide into lines
$markerdata = explode( "\n", $markerdata );
$newfile = '';
$externals = array();
$phpopen = 0;
$in_comment = 0;
$foundit = FALSE;
if ( $getexternals ):
$this->debug( 'Read only, returning.', __FUNCTION__, __CLASS__ );
endif;
if ( $markerdata ):
$state = TRUE;
foreach ( $markerdata as $n => $markerline ):
// remove double slash comment to end of line
$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 ):
// look for existing external stylesheets and add to imports config data
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 ] );
// look for deregister/register link paths for swapping parent/child
elseif ( preg_match( "/wp_register_style[^']+'(.+?)'[^']+'(.+?)'/", $markerline, $matches ) ):
$this->debug( 'link swap found : ' . $matches[ 1 ] . ' => ' . $matches[ 2 ] );
$handle = sanitize_text_field( $matches[ 1 ] );
$path = sanitize_text_field( $matches[ 2 ] );
$this->css->swappath[ $handle ] = $path;
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 ):
// verify there is no PHP close tag at end of file
if ( ! $phpopen ):
$this->debug( 'PHP not open', __FUNCTION__, __CLASS__ );
$this->errors[] = 12; //__( 'A closing PHP tag was detected in Child theme functions file so "Parent Stylesheet Handling" option was not configured. Closing PHP at the end of the file is discouraged as it can cause premature HTTP headers. Please edit functions.php
to remove the final ?>
tag and click "Generate/Rebuild Child Theme Files" again.', 'child-theme-configurator' );
return FALSE;
//$newfile .= '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 ) ):
// with ajax we have to bypass wp filesystem so file must already be writable
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
) ): // chmod will fail unless we have fs access. user can secure files after configuring
$this->debug( 'Filesystem write failed.', __FUNCTION__, __CLASS__ );
return FALSE;
endif;
$this->css->set_prop( 'converted', 1 );
endif;
}
// creates/updates file via filesystem API
function write_child_file( $file, $contents ) {
//$this->debug( LF . LF, __FUNCTION__, __CLASS__ );
if ( !$this->fs ):
$this->debug( 'No filesystem access, returning.', __FUNCTION__, __CLASS__ );
return FALSE; // return if no filesystem access
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() {
// always 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; // return if no filesystem access
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;
// get child theme + file + ext ( passing empty string and full child path to theme_basename )
$child_file = $this->css->get_child_target( $file . '.' . $ext );
// return true if file already exists
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 // sanity check
&& $child_file // sanity check
&& $this->verify_child_dir( $child_dir ) //create child subdir if necessary
&& $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; //__( 'Could not copy file:' . $parent_file, 'child-theme-configurator' );
}
function delete_child_file( $file, $ext = 'php' ) {
if ( !$this->fs ):
$this->debug( 'No filesystem access.', __FUNCTION__, __CLASS__ );
return FALSE; // return if no filesystem access
endif;
global $wp_filesystem;
// verify file is in child theme and exists before removing.
$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; //__( 'Could not delete ' . $ext . ' file.', 'child-theme-configurator' );
$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;
//$this->debug( 'This is a backup file', __FUNCTION__, __CLASS__ );
elseif ( strstr( $file, "ctcbackup" ) ):
$date = date_i18n( 'D, j M Y g:i A', filemtime( $filepath ) );
$this->files[ $theme ][ 'backup' ][ $file ] = $date;
elseif ( preg_match( "/^ctc\-plugins\-(\d+)\.css$/", $file, $matches ) ):
$date = date_i18n( 'D, j M Y g:i A', strtotime( $matches[ 1 ] ) );
$this->files[ $theme ][ 'pluginbackup' ][ $file ] = $date;
//$this->debug( 'This is a plugin backup file', __FUNCTION__, __CLASS__ );
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__ );
// read 2k at a time and bail if code detected
$template = FALSE;
$size = 0;
if ( $handle = fopen( $file_verified, "rb") ):
while ( !feof( $handle ) ):
$size++;
if ( $size > 10 ) // if larger than 20k this ain't a template
break;
$contents = fread($handle, 2048);
if ( preg_match( "/\w+\s*\(/", $contents ) ):
$template = TRUE;
// remove scripts so they don't cause false positives - v.2.3.0.4
$contents = preg_replace( "%%s", '', $contents );
$contents = preg_replace( "%(^.+?|