Skip to content

Instantly share code, notes, and snippets.

@bryanwillis
Created February 14, 2016 06:08
Show Gist options
  • Select an option

  • Save bryanwillis/1b67321fbdc9043ecfcf to your computer and use it in GitHub Desktop.

Select an option

Save bryanwillis/1b67321fbdc9043ecfcf to your computer and use it in GitHub Desktop.
<?php
/**
* Plugin Name: Underscores.me Generator
* Description: Generates themes based on the _s theme.
*/
class Underscores_Generator_Plugin {
protected $theme;
function __construct() {
add_action( 'init', array( $this, 'init' ) );
add_filter( 'underscoresme_generator_file_contents', array( $this, 'do_replacements' ), 10, 2 );
add_action( 'underscoresme_print_form', array( $this, 'underscoresme_print_form' ) );
}
function underscoresme_print_form() {
?>
<div id="generator-form" class="generator-form-skinny">
<form method="POST">
<input type="hidden" name="underscoresme_generate" value="1" />
<?php if ( isset( $_REQUEST['can_i_haz_wpcom'] ) ) : ?>
<input type="hidden" name="can_i_haz_wpcom" value="1" />
<?php endif; ?>
<div class="generator-form-inputs">
<div class="generator-form-primary form-group">
<label class="sr-only" for="underscoresme-name">What would you like to name your theme?</label>
<input type="text" id="underscoresme-name" name="underscoresme_name" class="form-control" placeholder="Theme Name" />
</div><!-- .generator-form-primary -->
<div class="generator-form-secondary">
<div class="form-group">
<label class="sr-only" for="underscoresme-slug">Theme Slug</label>
<input type="text" id="underscoresme-slug" name="underscoresme_slug" class="form-control" placeholder="Theme Slug" />
</div>
<div class="form-group">
<label class="sr-only" for="underscoresme-author">Author</label>
<input type="text" id="underscoresme-author" name="underscoresme_author" class="form-control" placeholder="Author" />
</div>
<div class="form-group">
<label class="sr-only" for="underscoresme-author-uri">Author URI</label>
<input type="text" id="underscoresme-author-uri" name="underscoresme_author_uri" class="form-control" placeholder="Author URI" />
</div>
<div class="form-group">
<label class="sr-only" for="underscoresme-description">Description</label>
<input type="text" id="underscoresme-description" name="underscoresme_description" class="form-control" placeholder="Description" />
</div>
<div class="checkbox">
<label>
<input type="checkbox" id="underscoresme-sass" name="underscoresme_sass" value="1"> SASS ME!
</label>
</div>
</div><!-- .generator-form-secondary -->
</div><!-- .generator-form-inputs -->
<div class="generator-form-submit">
<input type="submit" name="underscoresme_generate_submit" class="btn btn-primary" value="Generate" style="padding: 8px 10px;" />
</div><!-- .generator-form-submit -->
</form>
</div><!-- .generator-form -->
<?php
}
/**
* Creates zip files and does a bunch of other stuff.
*/
function init() {
if ( ! isset( $_REQUEST['underscoresme_generate'], $_REQUEST['underscoresme_name'] ) )
return;
if ( empty( $_REQUEST['underscoresme_name'] ) )
wp_die( 'Please enter a theme name. Please go back and try again.' );
$this->theme = array(
'name' => 'Theme Name',
'slug' => 'theme-name',
'uri' => 'http://bootstraptheme.me/',
'author' => 'Bryan Willis',
'author_uri' => 'http://github.com/bryanwillis/',
'description' => 'Theme Description',
'sass' => false,
'wpcom' => false,
);
$this->theme['name'] = trim( $_REQUEST['underscoresme_name'] );
$this->theme['slug'] = sanitize_title_with_dashes( $this->theme['name'] );
$this->theme['sass'] = (bool) isset( $_REQUEST['underscoresme_sass'] );
$this->theme['wpcom'] = (bool) isset( $_REQUEST['can_i_haz_wpcom'] );
if ( ! empty( $_REQUEST['underscoresme_slug'] ) ) {
$this->theme['slug'] = sanitize_title_with_dashes( $_REQUEST['underscoresme_slug'] );
}
// Let's check if the slug can be a valid function name.
if ( ! preg_match( '/^[a-z_]\w+$/i', str_replace( '-', '_', $this->theme['slug'] ) ) ) {
wp_die( 'Theme slug could not be used to generate valid function names. Please go back and try again.' );
}
if ( ! empty( $_REQUEST['underscoresme_description'] ) ) {
$this->theme['description'] = trim( $_REQUEST['underscoresme_description'] );
}
if ( ! empty( $_REQUEST['underscoresme_author'] ) ) {
$this->theme['author'] = trim( $_REQUEST['underscoresme_author'] );
}
if ( ! empty( $_REQUEST['underscoresme_author_uri'] ) ) {
$this->theme['author_uri'] = trim( $_REQUEST['underscoresme_author_uri'] );
}
$zip = new ZipArchive;
$zip_filename = sprintf( '/tmp/underscoresme-%s.zip', md5( print_r( $this->theme, true ) ) );
$res = $zip->open( $zip_filename, ZipArchive::CREATE && ZipArchive::OVERWRITE );
$prototype_dir = dirname( __FILE__ ) . '/prototype/';
$exclude_files = array( '.travis.yml', 'codesniffer.ruleset.xml', 'CONTRIBUTING.md', '.git', '.svn', '.DS_Store', '.gitignore', '.', '..' );
$exclude_directories = array( '.git', '.svn', '.', '..' );
if ( ! $this->theme['sass'] ) {
$exclude_directories[] = 'sass';
}
if ( ! $this->theme['wpcom'] )
$exclude_files[] = 'wpcom.php';
$iterator = new RecursiveDirectoryIterator( $prototype_dir );
foreach ( new RecursiveIteratorIterator( $iterator ) as $filename ) {
if ( in_array( basename( $filename ), $exclude_files ) )
continue;
foreach ( $exclude_directories as $directory )
if ( strstr( $filename, "/{$directory}/" ) )
continue 2; // continue the parent foreach loop
$local_filename = str_replace( trailingslashit( $prototype_dir ), '', $filename );
if ( 'languages/_s.pot' == $local_filename )
$local_filename = sprintf( 'languages/%s.pot', $this->theme['slug'] );
$contents = file_get_contents( $filename );
$contents = apply_filters( 'underscoresme_generator_file_contents', $contents, $local_filename );
$zip->addFromString( trailingslashit( $this->theme['slug'] ) . $local_filename, $contents );
}
$zip->close();
$this->do_tracking();
header( 'Content-type: application/zip' );
header( sprintf( 'Content-Disposition: attachment; filename="%s.zip"', $this->theme['slug'] ) );
readfile( $zip_filename );
unlink( $zip_filename );/**/
die();
}
/**
* Runs when looping through files contents, does the replacements fun stuff.
*/
function do_replacements( $contents, $filename ) {
// Replace only text files, skip png's and other stuff.
$valid_extensions = array( 'php', 'css', 'scss', 'js', 'txt' );
$valid_extensions_regex = implode( '|', $valid_extensions );
if ( ! preg_match( "/\.({$valid_extensions_regex})$/", $filename ) )
return $contents;
// Special treatment for style.css
if ( in_array( $filename, array( 'style.css', 'sass/style.scss' ), true ) ) {
$theme_headers = array(
'Theme Name' => $this->theme['name'],
'Theme URI' => esc_url_raw( $this->theme['uri'] ),
'Author' => $this->theme['author'],
'Author URI' => esc_url_raw( $this->theme['author_uri'] ),
'Description' => $this->theme['description'],
'Text Domain' => $this->theme['slug'],
);
foreach ( $theme_headers as $key => $value ) {
$contents = preg_replace( '/(' . preg_quote( $key ) . ':)\s?(.+)/', '\\1 ' . $value, $contents );
}
$contents = preg_replace( '/\b_s\b/', $this->theme['name'], $contents );
return $contents;
}
// Special treatment for functions.php
if ( 'functions.php' == $filename ) {
if ( ! $this->theme['wpcom'] ) {
// The following hack will remove the WordPress.com comment and include in functions.php.
$find = 'WordPress.com-specific functions';
$contents = preg_replace( '#/\*\*\n\s+\*\s+' . preg_quote( $find ) . '#i', '@wpcom_start', $contents );
$contents = preg_replace( '#/inc/wpcom\.php\';#i', '@wpcom_end', $contents );
$contents = preg_replace( '#@wpcom_start(.+)@wpcom_end\n?(\n\s)?#ims', '', $contents );
}
}
// Special treatment for footer.php
if ( 'footer.php' == $filename ) {
// <?php printf( __( 'Theme: %1$s by %2$s.', '_s' ), '_s', '<a href="http://automattic.com/" rel="designer">Automattic</a>' );
$contents = str_replace( 'http://automattic.com/', esc_url( $this->theme['author_uri'] ), $contents );
$contents = str_replace( 'Automattic', $this->theme['author'], $contents );
$contents = preg_replace( "#printf\\((\\s?__\\(\\s?'Theme:[^,]+,[^,]+,)([^,]+),#", sprintf( "printf(\\1 '%s',", esc_attr( $this->theme['name'] ) ), $contents );
}
// Function names can not contain hyphens.
$slug = str_replace( '-', '_', $this->theme['slug'] );
// Regular treatment for all other files.
$contents = str_replace( "@package _s", sprintf( "@package %s", str_replace( ' ', '_', $this->theme['name'] ) ), $contents ); // Package declaration.
$contents = str_replace( "_s-", sprintf( "%s-", $this->theme['slug'] ), $contents ); // Script/style handles.
$contents = str_replace( "'_s'", sprintf( "'%s'", $this->theme['slug'] ), $contents ); // Textdomains.
$contents = str_replace( "_s_", $slug . '_', $contents ); // Function names.
$contents = preg_replace( '/\b_s\b/', $this->theme['name'], $contents );
return $contents;
}
function do_tracking() {
// Track downloads.
$user_agent = 'regular';
if ( '_sh' == $_SERVER['HTTP_USER_AGENT'] ) {
$user_agent = '_sh';
}
// Track features.
$features = array();
if ( $this->theme['sass'] ) {
$features[] = 'sass';
}
if ( $this->theme['wpcom'] ) {
$features[] = 'wpcom';
}
if ( empty( $features ) ) {
$features[] = 'none';
}
wp_remote_get( add_query_arg( array(
'v' => 'wpcom-no-pv',
'x_underscoresme-downloads' => $user_agent,
'x_underscoresme-features' => implode( ',', $features ),
), 'http://stats.wordpress.com/g.gif' ), array( 'blocking' => false ) );
}
}
new Underscores_Generator_Plugin;
add_action('underscoresme_print_form', 'add_hide_show_styles_generator', -1);
function add_hide_show_styles_generator() {
add_action('wp_footer', 'add_scripts_to_footer_generator', 999);
?>
<style type="text/css">
.generator-form-skinny .generator-form-secondary {
display: none;
}
.generator-form-primary a.generator-form-optionstoggle {
display: none;
}
.generator-form-skinny .generator-form-primary a.generator-form-optionstoggle {
display: block;
}
.generator-form-secondary {
display: block;
}
</style>
<?php
}
function add_scripts_to_footer_generator() {
?>
<script>/*
jQuery( function( $ ) {
var advanced, simple,
form = $('#generator-form');
advanced = $('<a href="#" class="generator-form-optionstoggle">Advanced Options <i class="fa fa-angle-down"></i></a>').appendTo('.generator-form-primary');
simple = $('<a href="#" class="generator-form-optionstoggle">Simple Options <i class="fa fa-angle-up"></a>').appendTo('.generator-form-secondary');
advanced.click( function( event ) {
form.removeClass('generator-form-skinny');
event.preventDefault();
});
simple.click( function( event ) {
form.addClass('generator-form-skinny');
event.preventDefault();
});
});*/
jQuery( function( $ ) {
$( "#generator-form" ).removeClass( "generator-form-skinny" );
/*$( ".generator-form-primary" ).click(function() {
$( "#generator-form" ).removeClass( "generator-form-skinny" );
event.preventDefault();
});*/
});
</script>
<?php
}
add_action( 'widgets_init', function(){
register_widget( 'Underscores_Generator_Widget' );
});
class Underscores_Generator_Widget extends WP_Widget {
function __construct() {
$widget_options = array( 'classname' => 'underscores-generator-widget' ,
'description' => __( 'Add a theme generator widget.' , 'underscores-generator-widget' ) ,
);
$control_ops = array('width' => 250);
parent::__construct('underscores_generator_widget','Underscores Generator Widget',$widget_options,$control_ops);
}
public function form( $instance ) {
if ( isset( $instance[ 'title' ] ) ) {
$title = $instance[ 'title' ];
}
else {
$title = __( 'Theme Generator Title' );
}
?>
<p>
<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
</p>
<?php
}
public function widget( $args , $instance ) {
echo $args['before_widget'];
if ( ! empty( $instance['title'] ) ) {
echo $args['before_title'] . apply_filters( 'widget_title', $instance['title'] ). $args['after_title'];
}
do_action( 'underscoresme_print_form' );
echo $args[ 'after_widget' ];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment