├── screenshot.png ├── .editorconfig ├── style.css ├── README.md ├── functions.php └── index.php /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidegreenwald/Bare-Minimum/HEAD/screenshot.png -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | end_of_line = lf 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | /* 2 | Theme Name: Bare Minimum 3 | Author: David Greenwald 4 | Author URI: https://www.davidgreenwald.com 5 | Description: A minimum viable product WordPress starter theme with no styles and strictly basic functionality. 6 | Version: 1.0 7 | License: GNU General Public License v2 or later 8 | License URI: http://www.gnu.org/licenses/gpl-2.0.html 9 | 10 | The goal of this theme is to serve as an educational project to see what it 11 | takes to get started on WordPress theme building. 12 | */ 13 | 14 | /** 15 | * For the absolute bare minimum, WordPress can install a theme with a single 16 | * "Theme Name" comment header. A header must be provided before CSS begins. 17 | * 18 | * Above, this stylesheet has the practical minimum for non-Theme Directory use. 19 | * 20 | * I suggest getting started on your CSS with my reset/normalization stylesheet, 21 | * Setup. 22 | * https://github.com/davidegreenwald/css-setup 23 | */ 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bare Minimum 2 | ## A minimum viable product WordPress theme that's as simple as possible 3 | 4 | This is pretty close to the absolute bare minimum of what you would need to install a theme to publish WordPress content. I created it as a learning exercise to show how basic WordPress theme development can be. 5 | 6 | This theme can display single posts and pages, a homepage with posts, search results, a 404 page, and a sidebar and footer from a single index.php file. 7 | 8 | It does not have internationalization, custom post types, or other common features. Just the minimum code to get a theme off the ground. 9 | 10 | It needs some clean-up to match WordPress standards, so I'll be doing that next. It also needs page-to-page navigation and a couple of other actual features (but again, bare minimum). 11 | 12 | It has no CSS styles at all. Add some! 13 | 14 | Explore the files for documentation about why each part is necessary. You can use this as a from-scratch (seriously, from scratch) starter theme, add your own CSS, add more template files, whatever you want. Hope it helps. I'll be publishing a full walkthrough tutorial in the coming weeks. -------------------------------------------------------------------------------- /functions.php: -------------------------------------------------------------------------------- 1 | 's tag for SEO 30 | add_theme_support( 'title-tag' ); 31 | 32 | // Add RSS feed links to the document <head> 33 | add_theme_support( 'automatic-feed-links' ); 34 | 35 | /** 36 | * Enable featured images (post thumbnails), commonly displayed on index, 37 | * archive, and blog pages and also used as the thumbnail image when sharing 38 | * to social media 39 | */ 40 | add_theme_support( 'post-thumbnails' ); 41 | 42 | /** 43 | * Update default WordPress core markup tags to modern HTML5 code for this 44 | * array of items - comments, search form, gallery images, photo captions 45 | */ 46 | add_theme_support( 'html5', array( 47 | 'comment-list', 48 | 'comment-form', 49 | 'search-form', 50 | 'gallery', 51 | 'caption' ) 52 | ); 53 | 54 | /** 55 | * Add theme support for selective refresh for widgets to allow 56 | * Customizer editing without a full page reload. 57 | * 58 | * Not strictly "bare minimum" but basic and nice to have 59 | */ 60 | add_theme_support( 'customize-selective-refresh-widgets' ); 61 | 62 | /** 63 | * Other common functions you might add here: 64 | * Post formats (a la Tumblr style) 65 | * Content width 66 | * Custom Theme background (color or image) 67 | * Custom Header 68 | * Custom Logo 69 | * Additional image sizes 70 | */ 71 | } 72 | add_action( 'after_setup_theme', 'bareminimum_setup' ); 73 | } // don't forget to close the pluggable if statement 74 | 75 | /* ============================================================================= 76 | #SCRIPTS - Enqueue styles and scripts 77 | */ 78 | 79 | if ( ! function_exists( 'bareminimum_enqueue_scripts' ) ) { 80 | function bareminimum_enqueue_scripts() { 81 | // Load main stylesheet 82 | wp_enqueue_style( 'style', get_stylesheet_uri() ); 83 | 84 | // naturally we can load jQuery and any other scripts from here 85 | } 86 | add_action( 'wp_enqueue_scripts', 'bareminimum_enqueue_scripts' ); 87 | } 88 | 89 | /* ============================================================================= 90 | #MENUS - Register menus 91 | */ 92 | 93 | // Register main menu 94 | function bareminimum_register_menus() { 95 | register_nav_menu( 'main_menu', 'Main Menu' ); 96 | } 97 | add_action( 'after_setup_theme', 'bareminimum_register_menus' ); 98 | 99 | /* Print this menu in the theme template by copying this code: 100 | 101 | <?php if (has_nav_menu( 'main_menu') : 102 | wp_nav_menu(array('theme_location' => 'main_menu')); 103 | endif; ?> 104 | 105 | */ 106 | 107 | /* ============================================================================= 108 | #WIDGETS - Enqueue widget areas (sidebars and footers) 109 | */ 110 | 111 | function bareminimum_register_widget_areas() { 112 | 113 | // Add whatever wrappers and classes you need for styling 114 | // The before/after keys have WordPress defaults and can be skipped 115 | 116 | $footer = array( 117 | 'name' => 'Footer widgets', // Displays in the WP dashboard 118 | 'id' => 'footer_widgets', // must be lowercase 119 | 'description' => '', 120 | 'before_widget' => '<div>', 121 | 'after_widget' => '</div>', 122 | 'before_title' => '<h2>', 123 | 'after_title' => '</h2>', 124 | ); 125 | register_sidebar( $footer ); 126 | 127 | /* Print this widget space in a theme template page by copying this code: 128 | 129 | <?php if ( is_active_sidebar( 'footer_widgets' ) ) : 130 | dynamic_sidebar( 'footer_widgets' ); 131 | endif; ?> 132 | 133 | */ 134 | 135 | $sidebar = array( 136 | 'name' => 'Sidebar', 137 | 'id' => 'sidebar_widgets', // must be lowercase 138 | 'description' => '', 139 | 'before_widget' => '<div>', 140 | 'after_widget' => '</div>', 141 | 'before_title' => '<h2>', 142 | 'after_title' => '</h2>', 143 | ); 144 | register_sidebar( $sidebar ); 145 | 146 | } 147 | add_action( 'widgets_init', 'bareminimum_register_widget_areas' ); 148 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * This single template includes a home (blog) page, a single page, search 4 | * results, and a 404 page. 5 | */ 6 | ?> 7 | 8 | <? // This section would usually go in a header.php file 9 | // And you would call it here with get_header(); 10 | ?> 11 | <!DOCTYPE html> 12 | <html <?php language_attributes(); ?>> 13 | <head> 14 | <?php 15 | // https://developer.wordpress.org/reference/functions/bloginfo/ 16 | // Encoding for pages and feeds” set in Settings > Reading 17 | // Defaults to UTF-8 18 | ?> 19 | <meta charset="<?php bloginfo( 'charset' ); ?>"> 20 | 21 | <?php // for Internet Explorer 8-10, remove if unnecessary ?> 22 | <meta http-equiv="x-ua-compatible" content="ie=edge"> 23 | 24 | <?php // Allow proper zooming and resizing ?> 25 | <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 26 | 27 | <?php 28 | /** 29 | * WordPress action hook to load <head> scripts and headers. Must include 30 | * for proper WP functionality. Same deal with wp_footer() below. 31 | */ 32 | ?> 33 | <?php wp_head(); ?> 34 | </head> 35 | 36 | <?php // The WP body_class() adds helpful bonus classes to the body tag ?> 37 | <body <?php body_class(); ?>> 38 | <?php // a skiplink should go here for accessibility, btw ?> 39 | <header> 40 | 41 | <?php 42 | /** 43 | * Wrap the Site Title in H1 tags for SEO only on the home or main page 44 | * bloginfo( 'name' ) echoes the Site Title from Settings > General 45 | * https://developer.wordpress.org/reference/functions/bloginfo/ 46 | */ 47 | ?> 48 | <?php 49 | if ( ! ( is_front_page() || is_home() ) ): 50 | bloginfo( 'name' ); 51 | else: ?> 52 | <h1><?php bloginfo( 'name' ); ?></h1> 53 | <?php endif; ?> 54 | 55 | <?php 56 | /** 57 | * Echo Tagline from Settings > General in the WP dashboard 58 | * https://developer.wordpress.org/reference/functions/bloginfo/ 59 | */ 60 | ?> 61 | <p><?php bloginfo('description'); ?></p> 62 | 63 | <?php // Display our main menu registered in functions.php if it has content ?> 64 | <?php if (has_nav_menu( 'main_menu')) : ?> 65 | <nav><?php wp_nav_menu(array('theme_location' => 'main_menu')); ?></nav> 66 | <?php endif; ?> 67 | 68 | </header> 69 | <main id="main"> 70 | <?php // end of what could go into header.php ?> 71 | 72 | <?php 73 | // Check if there are posts or pages to display 74 | if ( have_posts() ) : 75 | ?> 76 | <section> 77 | 78 | <?php 79 | // Begin the loop to show all matching posts or pages 80 | while ( have_posts() ) : 81 | // The post function starts and moves the loop ahead one post at a time 82 | the_post(); ?> 83 | 84 | <?php 85 | // single page or post view: 86 | if ( is_single() || is_page() ) : 87 | ?> 88 | <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> 89 | <header> 90 | <?php the_category(); ?> 91 | <h1><?php the_title(); ?></h1> 92 | <p><?php the_author(); ?></p> 93 | <p><?php the_date(); ?></p> 94 | </header> 95 | <div> 96 | <?php the_content(); ?> 97 | </div> 98 | <footer> 99 | <?php the_tags(); ?> 100 | </footer> 101 | </article> 102 | 103 | <?php 104 | // Feed, archive, blog view 105 | else : ?> 106 | 107 | <?php 108 | // Set up a page title for search results only 109 | if (is_search()) : ?> 110 | <h1>Search results for <?php the_search_query(); ?>:</h1> 111 | <? endif; ?> 112 | 113 | <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> 114 | <header> 115 | <figure><?php the_post_thumbnail(); ?></figure> 116 | <a href="<?php the_permalink(); ?>"> 117 | <h2><?php the_title(); ?></h2> 118 | </a> 119 | <p><?php the_author(); ?></p> 120 | <p><?php the_date(); ?></p> 121 | </header> 122 | <div> 123 | <?php the_excerpt(); ?> 124 | </div> 125 | </article> 126 | <?php endif; // end content 127 | endwhile; // close the loop ?> 128 | </section> 129 | <?php else: ?> 130 | <?php 131 | // 404 page if no page content or search refults 132 | if( is_404()) : ?> 133 | <p>Sorry, we couldn't find your page.</p> 134 | <?php endif; ?> 135 | <?php endif; // end have_posts() conditional ?> 136 | 137 | <aside> 138 | <?php if ( is_active_sidebar( 'sidebar_widgets' ) ) : ?> 139 | <?php dynamic_sidebar( 'sidebar_widgets' ); ?> 140 | <?php endif; ?> 141 | </aside> 142 | 143 | <?php 144 | // This end section would normally go in footer.php 145 | // and you would call it with get_footer(); 146 | ?> 147 | 148 | <?php // close the main tag and content and begin the footer ?> 149 | </main> 150 | <footer> 151 | 152 | <?php 153 | /** 154 | * Call our registered sidebar from functions.php 155 | * but only if it has live widgets, testing with is_active_sidebar() 156 | */ 157 | ?> 158 | <?php if ( is_active_sidebar( 'footer_widgets' ) ) : ?> 159 | <?php dynamic_sidebar( 'footer_widgets' ); ?> 160 | <?php endif; ?> 161 | 162 | </footer> 163 | 164 | <?php 165 | /** 166 | * Close with another action hook for plugin and core script files 167 | * The Twenty Seventeen theme places wp_footer() below </footer> 168 | * so we will follow their lead and put it here at the very bottom. 169 | */ 170 | ?> 171 | <?php wp_footer(); ?> 172 | </body> 173 | </html> 174 | --------------------------------------------------------------------------------