Learning Wordpress Development

Usually I get my latest wordpress using this command below :

wget http://wordpress.org/latest.tar.gz
$tar -xf latest.tar.gz

Lets try something new, downloading each new wordpress core file wp cli.

# https://make.wordpress.org/cli/handbook/guides/installing/

curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp

Download latest New Wordpress

# Create new Folder
mkdir project
cd project

# Download Wordpress
wp core download

# Create config
wp config create --dbname=testing --dbuser=wp --dbpass=securepswd

# Create DB
wp db create

# Configure Site
wp core install --url=your_domain --title=Your_Blog_Title --admin_user=username --admin_password=password --admin_email=your_email.com

# Install Theme
wp theme install pop-rock

# Activate Theme
wp theme activate pop-rock

# Install Plugin 
wp plugin install classic-editor

# Activate Plugin
wp plugin activate classic-editor

Migrate Production to Local or Vice Versa

AIO WP Migration Download 6.77 , this version has no paid restriction for restoring backup and import using file sometimes has bugs.

Enable debug on development

in wp-config.php

define('WP_DEBUG',true);

Udemy - Complete WordPress Theme & Plugin Development Course [2020] - https://www.udemy.com/course/wordpress-theme-and-plugin-development-course/

Php Files in Wordpress

  1. Core Wordpress Files
  2. Theme Files
  3. Plugin Files

Loop

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<a href="<?php echo get_permalink(); ?>"><h1><?php the_title(); ?></h1></a>
        <?php the_content(); ?>
    <?php endwhile; else: ?>
        <?php _e("Sorry! No content found", "phpfowp"); ?>
    <?php endif; ?>

Template Tags

get_header() the_title() comment_author()
get_footer() get_the_title() the_post_thumbnail()
get_sidebar() the_content() the_permalink()
get_template_part() the_author() edit_post_link()
wp_login_form() the_category() site_url()
bloginfo() the_tags() wp_nav_menu()

get_header() - if you have a file header.php it will read that one and overwrite the header.php core wordpress.

wp_head() & wp_footer() - this will give wordpress a hook to add in head or footer. for wp_footer() this will enable navbar on top when you are loggedin as an admin in the template

body_class(); - this will give wordpress to know what page you are in.

<body class="<?php body_class(); ?>">

Listing posts

<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
<?php endwhile;
else : ?>
<h2><?php esc_html_e('404 Error', 'phpforwp'); ?></h2>
<p><?php esc_html_e('Sorry, content not found.', 'phpforwp'); ?></p>
<?php endif; ?>

post_class(): - inside the loop, this will give the div or wrapper a class for listing post

<article <?php post_class(); ?> >
</article>

Inside the loop

get_author_posts_url( $post->post_author ) : to get the url of the author
the_author() : to get the name of the author
the_time('M, j, Y') : get  the time of the post
the_category(',') : listing category with its delimiter
the_tags('', ',', '') : listing tags with its delimiter

<p class="byline">
    Author:
    <a href="<?php echo get_author_posts_url( $post->post_author ); ?>"> <?php the_author() ; ?></a>
    | Date : <?php the_time('M, j, Y'); ?>
    | Categories : <?php the_category( ',' ); ?>
    | Tags : <?php the_tags( '', ',', ''); ?>
</p>

Conditional Tags

<!-- Static Front Page -->
    <!-- if its front static page and its not home -->
    <?php if (is_front_page() && !is_home()) : ?>
        <h1>Static Front Page</h1>
    <?php endif; ?>

    <!-- Blog Home -->
    <?php if (is_home() && !is_404()) : ?>
        <h1>Blog</h1>
    <?php endif; ?>
    <!-- Page (Not Front Page) -->
    <?php if (is_page() && !is_front_page()) : ?>
        <h1>Page</h1>
    <?php endif; ?>
    <!-- Single Post -->
    <?php if (is_single() && !is_attachment()) : ?>
        <h1>Page</h1>
    <?php endif; ?>

    <!-- Single Attachment (Media) -->
    <?php if (is_attachment()) : ?>
        <h1>Attachment</h1>
    <?php endif; ?>

    <!-- Category Archive -->
    <!-- Single Attachment (Media) -->
    <?php if (is_category()) : ?>
        <h1><?php single_cat_title() ?></h1>
    <?php endif; ?>


    <!-- Tag Archive -->
    <?php if (is_tag()) : ?>
        <h1><?php single_tag_title() ?></h1>
    <?php endif; ?>

    <!-- Author Archive -->
    <?php if (is_author()) : ?>
        <h1><?php the_archive_title() ?></h1>
    <?php endif; ?>

    <!-- Date Archive -->
    <?php if (is_date()) : ?>
        <h1><?php the_archive_title() ?></h1>
    <?php endif; ?>

    <!-- 404 Page -->

    <?php if (is_404()) : ?>
        <h1>404</h1>
    <?php endif; ?>

Hooks

Hooks allows you to add custom code into existing software.
Action hooks let you run your own code when certain event take place in the wordpress run cycle.
Filter hooks let you modify how content is displayed on a page or saved to the database.
Hooks are generally used in plugins or function.php files in themes not in template files.

Themes

Child Theme allows you to override another theme (parent theme) without making direct changes that are lost during updates.

Starter Theme includes helpful files and functions for building themes from scratch. You usually edit starter theme from scratch. You usually edit starter theme directly, not using child themes.

  1. Underscore (WP Core Team)
  2. JointsWP (Foundation)
  3. Understrap (Bootstrap) (Paid)
  4. Sage (Roots Framework)

When to use Child Theme or Starter Theme

  • Use Child theme when customizing a theme
  • Use Starter theme when starting from scratch

Template Hierarchy

The template hierarchy is a list of possible files that can be used in a theme and their relationship to each other.

Fallback Architecture means that if a certain template is not found, Wordpress will look for through a series of backup templates to load instead.

  • if there's not page.php it will look to singular.php then to index.php
  • if there's not single.php it will look to singular.php then to index.php

All template eventually fall back to index.php.

Making Our Own Template

Get Dummy Assets

use http://wptest.io/ download then use importer wordpress, import wptest.xml, this will upload enough image, post and page so we can see build the template with the dummy assets.

Start Making Template

  • Make a folder in wp-content/themes
  • add index.php, functions.php, style.css
<?php // functions.php

// Add theme support
add_theme_support('title-tag');
add_theme_support('post-thumbnails');
add_theme_support('post-formats', ['aside', 'gallery', 'link', 'image', 'quote', 'status', 'video', 'audio', 'chat']);
add_theme_support('html5');
add_theme_support('automatic-feed-links');
add_theme_support('custom-background');
add_theme_support('custom-header');
add_theme_support('custom-logo');
add_theme_support('customize-selective-refresh-widgets');
add_theme_support('starter-content');

// Load in our css
function harukaeduone_enqueue_styles() {
    wp_enqueue_style('main-css', get_stylesheet_directory_uri() .'/style.css', [], time() , 'all');
}
add_action('wp_enqueue_scripts', 'harukaeduone_enqueue_styles');
?>


// setup widget areas
function harukaeduone_widgets_init() {
    register_sidebar([
        'name' => esc_html__('Main Sidebar', 'harukaeduone'),
        'id' => 'main-sidebar',
        'description' => esc_html__('Add widgets for main sidebar here', 'harukaeduone'),
        'before_widget' => '<section class="widget">',
        'after_widget' => '</section>',
        'before_title' => '<h2 class="widget-title">',
        'after_title' => '</h2>',
    ]);
}
add_action('widgets_init', 'harukaeduone_widgets_init');

in style.css add css comment that will show in templates description

/*
Theme Name: HarukaeduOne
Theme URI: Harukaedu.com
Author: mAdInDo
Author URI: fedrianto.com
Description: This is a template for the one
Version: 0.0.1
Requires at least: 5.1
Tested up to: 5.5
Requires PHP: 5.6
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Tags: one-column, two-columns, left-sidebar, right-sidebar, flexible-header, custom-background, custom-colors, custom-header, custom-menu, custom-logo, editor-style, featured-image-header, featured-images, footer-widgets, full-width-template, rtl-language-support, sticky-post, theme-options, threaded-comments, translation-ready, blog, holiday, portfolio
Text Domain: harukaedu-one

This theme, like WordPress, is licensed under the GPL.
Use it to make something cool, have fun, and share what you've learned with others.
*/

dont forget to create screenshot.png

  • breakdown the index.php to header.php and footer.php
  • in header.php add <?php wp_head(); ?>
  • in footer.php add <?php wp_footer(); ?>
  • in index.php add <?php get_header(); ?> , <?php get_sidebar(); ?> in mid and <?php get_footer(); ?> bottom.
  • to make custom footer, make file called footer-ok.php then in index.php in <?php get_footer('ok);?> to call the custom footer this works with header and sidebar as well.
  • in body add <?php body_class(); ?>
  • copy index.php then make singular.php
// register menu locations
register_nav_menus([
    'main-menu' => esc_html__('Main menu', 'harukaeduone'),
    'footer-menu' => esc_html__('Footer menu', 'harukaeduone'),
    'sidebar-menu' => esc_html__('Sidebar menu', 'harukaeduone'),
]);

This will show in Customizing menus of template

index.php

<?php get_header(); ?>
<div id="primary" class="content-area">
    <main id="main" class="site-main" role="main">
        <?php if ( have_posts() ) : 
            while ( have_posts() ) : the_post(); ?>
                <?php get_template_part('template-parts/contents'); ?>
        <?php endwhile;
        else : ?>
            <?php get_template_part('template-parts/contents', 'none'); ?>
        <?php endif; ?>
        <p>Template : index.php</p>
    </main>
</div>
<?php get_sidebar(); ?>
<?php get_footer(); ?>

get_template_part reads the partial of the view, the second args is the name of the file after dash, for example 'template-parts/contents' , 'none' will ready the file contents-none.php

<!-- Example of 404 content -->
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    <header class="entry-header">
        <h1>
            <?php esc_html_e('404', 'harukaeduone'); ?>
        </h1>
    </header>
    <div class="entry-content">
        <p><?php esc_html_e('Sorry! No content found', 'harukaeduone'); ?></p>
    </div>
</article>
<!-- example of post / page -->
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    <header class="entry-header">
        <?php the_title('<h2><a href="'.esc_url(get_permalink()).'">', '</a></h2>'); ?>
    </header>
    <div class="entry-content">
        <?php the_content(); ?>
    </div>
</article>
  • singular.php => index.php
  • page.php (page-id.php || page-slug) || single.php || attachment.php => singular.php - so if you have page.php then it will show page.php if you don't have single.php then it will fallback to singular.php
  • video.php || photo.php || text.php => attachment.php , use get_post_mime_type()
  • single.php => singular.php => index.php
  • single.php this will show single blogpost template
  • home.php => index.php
  • date.php || author.php => archive.php => index.php
  • category-id.php (for id) || category-slug (for slug) => category.php => archive.php =>index.php

comments.php

<?php

if ( post_password_required() ) {
	return;
}
?>

<div id="comments" class="comments-area">

	<?php
	// You can start editing here -- including this comment!
	if ( have_comments() ) : ?>
		<h2 class="comments-title">
			<?php
				printf( // WPCS: XSS OK.
					esc_html( _nx( 'One thought on &ldquo;%2$s&rdquo;', '%1$s thoughts on &ldquo;%2$s&rdquo;', get_comments_number(), 'comments title', 'harukaeduone' ) ),
					esc_html( _nx( 'One thought on &ldquo;%2$s&rdquo;', '%1$s thoughts on &ldquo;%2$s&rdquo;', get_comments_number(), 'comments title', 'harukaeduone' ) ),
					number_format_i18n( get_comments_number() ),
					'<span>' . get_the_title() . '</span>'
				);
			?>
		</h2><!-- .comments-title -->

		<?php if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) : // Are there comments to navigate through? ?>
		<nav id="comment-nav-above" class="navigation comment-navigation" role="navigation">
			<h2 class="screen-reader-text"><?php esc_html_e( 'Comment navigation', 'harukaeduone' ); ?></h2>
			<h2 class="screen-reader-text"><?php esc_html_e( 'Comment navigation', 'harukaeduone' ); ?></h2>
			<div class="nav-links">

				<div class="nav-previous"><?php previous_comments_link( esc_html__( 'Older Comments', 'harukaeduone' ) ); ?></div>
				<div class="nav-previous"><?php previous_comments_link( esc_html__( 'Older Comments', 'harukaeduone' ) ); ?></div>
				<div class="nav-next"><?php next_comments_link( esc_html__( 'Newer Comments', 'harukaeduone' ) ); ?></div>
				<div class="nav-next"><?php next_comments_link( esc_html__( 'Newer Comments', 'harukaeduone' ) ); ?></div>

			</div><!-- .nav-links -->
		</nav><!-- #comment-nav-above -->
		<?php endif; // Check for comment navigation. ?>

		<ol class="comment-list">
			<?php
				wp_list_comments( array(
					'style'      => 'ol',
					'short_ping' => true,
				) );
			?>
		</ol><!-- .comment-list -->

		<?php if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) : // Are there comments to navigate through? ?>
		<nav id="comment-nav-below" class="navigation comment-navigation" role="navigation">
			<h2 class="screen-reader-text"><?php esc_html_e( 'Comment navigation', 'harukaeduone' ); ?></h2>
			<h2 class="screen-reader-text"><?php esc_html_e( 'Comment navigation', 'harukaeduone' ); ?></h2>
			<div class="nav-links">

				<div class="nav-previous"><?php previous_comments_link( esc_html__( 'Older Comments', 'harukaeduone' ) ); ?></div>
				<div class="nav-previous"><?php previous_comments_link( esc_html__( 'Older Comments', 'harukaeduone' ) ); ?></div>
				<div class="nav-next"><?php next_comments_link( esc_html__( 'Newer Comments', 'harukaeduone' ) ); ?></div>

			</div><!-- .nav-links -->
		</nav><!-- #comment-nav-below -->
		<?php
		endif; // Check for comment navigation.

	endif; // Check for have_comments().


	// If comments are closed and there are comments, let's leave a little note, shall we?
	if ( ! comments_open() && get_comments_number() && post_type_supports( get_post_type(), 'comments' ) ) : ?>

		<p class="no-comments"><?php esc_html_e( 'Comments are closed.', 'harukaeduone' ); ?></p>
	<?php
	endif;

	comment_form();
	?>

</div><!-- #comments -->
  • add this to the contents post
    <?php if (comments_open()) : ?>
        <?php comments_template(); ?>
    <?php endif; ?>

Post Format

// enabled from function

add_theme_support('post-formats', ['aside', 'gallery', 'link', 'image', 'quote', 'status', 'video', 'audio', 'chat']);
  • aside – Typically styled without a title. Similar to a Facebook note update.
  • gallery – A gallery of images. Post will likely contain a gallery shortcode and will have image attachments.
  • link – A link to another site. Themes may wish to use the first <a href=””> tag in the post content as the external link for that post. An alternative approach could be if the post consists only of a URL, then that will be the URL and the title (post_title) will be the name attached to the anchor for it.
  • image – A single image. The first <img /> tag in the post could be considered the image. Alternatively, if the post consists only of a URL, that will be the image URL and the title of the post (post_title) will be the title attribute for the image.
  • quote – A quotation. Probably will contain a blockquote holding the quote content. Alternatively, the quote may be just the content, with the source/author being the title.
  • status – A short status update, similar to a Twitter status update.
  • video – A single video or video playlist. The first <video /> tag or object/embed in the post content could be considered the video. Alternatively, if the post consists only of a URL, that will be the video URL. May also contain the video as an attachment to the post, if video support is enabled on the blog (like via a plugin).
  • audio – An audio file or playlist. Could be used for Podcasting.
  • chat – A chat transcript, like so:

John: foo Mary: bar John: foo 2

Paginate

<?php echo paginate_links(); ?>

Dumping Variable

<pre><?php var_export($post); ?></pre>

Custom Shortcode

// https://code.tutsplus.com/tutorials/creating-a-custom-wordpress-registration-form-plugin--cms-20968

function registration_form($username, $password, $email, $website, $first_name, $last_name, $nickname, $bio)
{
echo '
<style>
    div {
        margin-bottom: 2px;
    }

    input {
        margin-bottom: 4px;
    }
</style>
';

echo '
<form action="' . $_SERVER['REQUEST_URI'] . '" method="post">
    <div>
        <label for="username">Username <strong>*</strong></label>
        <input type="text" name="username" value="' . (isset($_POST['username']) ? $username : null) . '">
    </div>

    <div>
        <label for="password">Password <strong>*</strong></label>
        <input type="password" name="password" value="' . (isset($_POST['password']) ? $password : null) . '">
    </div>

    <div>
        <label for="email">Email <strong>*</strong></label>
        <input type="text" name="email" value="' . (isset($_POST['email']) ? $email : null) . '">
    </div>

    <div>
        <label for="website">Website</label>
        <input type="text" name="website" value="' . (isset($_POST['website']) ? $website : null) . '">
    </div>

    <div>
        <label for="firstname">First Name</label>
        <input type="text" name="fname" value="' . (isset($_POST['fname']) ? $first_name : null) . '">
    </div>

    <div>
        <label for="website">Last Name</label>
        <input type="text" name="lname" value="' . (isset($_POST['lname']) ? $last_name : null) . '">
    </div>

    <div>
        <label for="nickname">Nickname</label>
        <input type="text" name="nickname" value="' . (isset($_POST['nickname']) ? $nickname : null) . '">
    </div>

    <div>
        <label for="bio">About / Bio</label>
        <textarea name="bio">' . (isset($_POST['bio']) ? $bio : null) . '</textarea>
    </div>
    <input type="submit" name="submit" value="Register" />
</form>
';
}

function complete_registration()
{
global $reg_errors, $username, $password, $email, $website, $first_name, $last_name, $nickname, $bio;
if (1 > count($reg_errors->get_error_messages())) {
$userdata = array(
'user_login' => $username,
'user_email' => $email,
'user_pass' => $password,
'user_url' => $website,
'first_name' => $first_name,
'last_name' => $last_name,
'nickname' => $nickname,
'description' => $bio,
);
$user = wp_insert_user($userdata);
echo 'Registration complete. Goto <a href="' . get_site_url() . '/wp-login.php">login page</a>.';
}
}

function custom_registration_function()
{
if (isset($_POST['submit'])) {
registration_validation(
$_POST['username'],
$_POST['password'],
$_POST['email'],
$_POST['website'],
$_POST['fname'],
$_POST['lname'],
$_POST['nickname'],
$_POST['bio']
);

// sanitize user form input
global $username, $password, $email, $website, $first_name, $last_name, $nickname, $bio;
$username = sanitize_user($_POST['username']);
$password = esc_attr($_POST['password']);
$email = sanitize_email($_POST['email']);
$website = esc_url($_POST['website']);
$first_name = sanitize_text_field($_POST['fname']);
$last_name = sanitize_text_field($_POST['lname']);
$nickname = sanitize_text_field($_POST['nickname']);
$bio = esc_textarea($_POST['bio']);

// call @function complete_registration to create the user
// only when no WP_error is found
complete_registration(
$username,
$password,
$email,
$website,
$first_name,
$last_name,
$nickname,
$bio
);
}

registration_form(
$username,
$password,
$email,
$website,
$first_name,
$last_name,
$nickname,
$bio
);
}

function registration_validation($username, $password, $email, $website, $first_name, $last_name, $nickname, $bio)
{
global $reg_errors;
$reg_errors = new WP_Error;

if (empty($username) || empty($password) || empty($email)) {
$reg_errors->add('field', 'Required form field is missing');
}
if (4 > strlen($username)) {
$reg_errors->add('username_length', 'Username too short. At least 4 characters is required');
}
if (username_exists($username))
$reg_errors->add('user_name', 'Sorry, that username already exists!');

if (!validate_username($username)) {
$reg_errors->add('username_invalid', 'Sorry, the username you entered is not valid');
}

if (5 > strlen($password)) {
$reg_errors->add('password', 'Password length must be greater than 5');
}
if (!is_email($email)) {
$reg_errors->add('email_invalid', 'Email is not valid');
}
if (email_exists($email)) {
$reg_errors->add('email', 'Email Already in use');
}
if (!empty($website)) {
if (!filter_var($website, FILTER_VALIDATE_URL)) {
$reg_errors->add('website', 'Website is not a valid URL');
}
}

if (is_wp_error($reg_errors)) {

foreach ($reg_errors->get_error_messages() as $error) {

echo '<div>';
    echo '<strong>ERROR</strong>:';
    echo $error . '<br />';
    echo '</div>';
}
}
}
// Register a new shortcode: [cr_custom_registration]
add_shortcode('cr_custom_registration', 'custom_registration_shortcode');

// The callback function that will replace [book]
function custom_registration_shortcode()
{
ob_start();
custom_registration_function();
return ob_get_clean();
}

Now you can add [cr_custom_registration] shortcode to any of your post

Subscribe to You Live What You Learn

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
[email protected]
Subscribe