migrate wordpress


select * from wp_options where option_name in ('siteurl', 'home');
update wp_options set option_value = 'http://xxx.xxx' where option_name in ('siteurl', 'home');


install Wordpress core

$ mkdir wp
$ cd wp
$ wp core download
$ wp core config --dbname=wpdemo --dbuser=wpdemo --dbpass=wpdemo
$ wp core install --url=http://wpdemo.local/ --title=wpdemo --admin_user=admin --admin_password=admin --admin_email=admin@example.com

install and activate plugins

wp plugin install plugin-name-here --activate

plugins to consider:






# WP Logo Showcase Responsive Slider

# Enable Media Replace

# encoding email addresses

# for customizing Woothemes child theme

you may need to add this to wp-config.php to install plugins automatically:

define('FS_METHOD', 'direct');

search and replace


wp search-replace --dry-run 'dev.example.com' 'www.example.com'

actually run:

wp search-replace 'dev.example.com' 'www.example.com'

It can even search and replace text in serialized PHP values, do the unserializing and serailizing automatically

wordpress multilanguage


one post per language

WPML (Premium)



alternative: Polylang, xili-language, Bogo

all languages in one post

qTranslate (free)



alternative: qTranslate-X, WPGlobus

automatic translation

multisite solution

Multilingual Press



alternative: Multisite Language Switcher, Zanto

Child theme

always create a child theme when you want to extend a existing theme

create a folder in the themes folder, create two files:

reference parent theme in style.css

Theme Name: child-thme-name
Template: parent-theme-name

parent theme's style.css will be overridden, see below to include

create custom functions in functions.php

function theme_enqueue_styles() {
    wp_enqueue_style('parent-style', get_template_directory_uri() . '/style.css');

    // add styles and scripts here
    wp_register_style('bootstrap', get_stylesheet_directory_uri() . '/css/bootstrap.min.css', '', '0.3.2');

    wp_register_script('bootstrap', get_stylesheet_directory_uri() . '/js/bootstrap.min.js', '', '0.3.2' );

add_action('wp_enqueue_scripts', 'theme_enqueue_styles');

register_nav_menus( array(
    'footer_nav' => __( 'Footer Nav', 'twentysixteen' ),
) );



quick sql

menu items

SELECT * FROM wp_posts WHERE post_type='nav_menu_item';
SELECT * FROM  `wp_postmeta` WHERE meta_key LIKE  '%_menu_item_%';

check and update links (check any absolute links before go live/moving domain)

check links do not go to devleopment site before put the site alive:

SELECT * FROM `wp_options` where option_value like '%isindevelopment%';
    FROM  `wp_posts` 
    WHERE post_status =  'publish'
    AND post_content LIKE  '%isindevelopment%'
    LIMIT 0 , 30;
SELECT * FROM `wp_postmeta` where meta_value like '%isindevelopment%';

UPDATE `wp_posts` SET post_content = REPLACE(post_content,  'http://example.com/',  '/' ) WHERE post_status =  'publish';
UPDATE `wp_postmeta` set meta_value = REPLACE(meta_value, 'XXX', 'YYY') WHERE meta_key = '_menu_item_url' AND meta_value LIKE '%isindevelopment%';



you can enable debug mode in wp-config.php by setting WP_DEBUG to TRUE, using WP_DEBUG_DISPLAY and WP_DEBUG_LOG to make sure that your error messages aren`t shown to all the visitors but rather saved to a log file.

recommended settings for debug:

// Enable WP_DEBUG mode
define( 'WP_DEBUG', true );

// Enable Debug logging to the /wp-content/debug.log file
define( 'WP_DEBUG_LOG', true );

// Disable display of errors and warnings 
define( 'WP_DEBUG_DISPLAY', true );
@ini_set( 'display_errors', 1 );

// Use dev versions of core JS and CSS files (only needed if you are modifying these core files)
define( 'SCRIPT_DEBUG', true );

WP loading process

index.php -> wp-blog-header.php 
                         |-> wp-load.php -> wp-config.php -> wp-settings.php
                         |-> wp()
                         |-> template-loader.php

important hooks in wp-settings.php

export / import

if you want to import media library from another wp install, do this

  1. download the upload folder and merge to the new site;
  2. export the attachment post type from the old site's posts and postmeta tables and import to new site

refer: Importing WordPress attachments into Media Library


export data for the following two sqls

SELECT * FROM wp_posts WHERE post_type = 'attachment' AND post_parent != '0';
SELECT * FROM wp_postmeta WHERE post_id IN ( SELECT ID FROM wp_posts WHERE post_type = 'attachment' AND post_parent != '0' );

In the wp_posts.sql file I did the following:

First I change all the INSERT INTO sentences to INSERT IGNORE INTO in case duplicate keys exists It don`t break them
I modified all image urls to match new domain (not always needed, depending where you are importing from)
I removed all unnecessary SQL code such as ALTER TABLE and INSERT TABLE and just left the INSERT INTO SENTENCES
Zipped the file and imported into new site db with phpmyadmin

In the wp_postmeta.sql file I did the following:

I removed all the unnecessary SQL code such as ALTER TABLE and INSERT TABLE and just left the INSERT INTO SENTENCES
I changed all the INSERT INTO `wp_postmeta` ( `meta_id`, `post_id`, `meta_key`, `meta_value`) VALUES to INSERT INTO `wp_postmeta` ( `post_id`, `meta_key`, `meta_value`) VALUES . Basically Im removing meta_id because I want to insert all the postmeta at the end of the table and use the auto increment
I did a regex search and replace to remove all ID from values. I used \( ([0-9]+), and replaced with just (
Zipped file and imported to new site

Theme tips

display content of multiple pages on one page:



Smashing magazine Wordpress Ajax process

query object


build and use a custom query object:

wp_reset_postdata(); // reset the post meta

$query = new WP_Query(array(
        'post_type' => 'page',
        'page_category' => 'apple',
        'posts_per_page' => -1,

if ( $query->have_posts() ) while ( $query->have_posts() ) : $query->the_post();



Wordpress Customizer

include a customizer.php in your theme's functions.php

a basic example (add a phone number in the header):

function gary_customize_register( $wp_customize ) {
    // the class should be included inside the hook, WP_Customize_Control only loads in Customizer interface
    class gary_Customize_Textarea_Control extends WP_Customize_Control {
        public $type = 'textarea';

        public function render_content() {
            echo '<label>';
            echo '<span class="customize-control-title">' . esc_html( $this-> label ) . '</span>';
            echo '<textarea rows="2" style ="width: 100%;"';
            echo '>' . esc_textarea( $this->value() ) . '</textarea>';
            echo '</label>';

    $wp_customize->add_section( 'gary_contact' , array(
            'title' => __( 'Contact Details', 'gary')
    ) );

    $wp_customize->add_setting( 'gary_telephone_setting', array (
            'default' => __( 'Your telephone number', 'gary' )
    ) );
    $wp_customize->add_control( new gary_Customize_Textarea_Control(
                    'label' => __( 'Telephone Number', 'gary' ),
                    'section' => 'gary_contact',
                    'settings' => 'gary_telephone_setting'

add_action( 'customize_register', 'gary_customize_register' );

// add a hook to display the info
function gary_display_contact_details_in_header() { ?>
    <div class="phone-number">
        <?php echo get_theme_mod( 'gary_telephone_setting', '0800 GARY' ); ?>
<?php }
add_action( 'gary_header', 'gary_display_contact_details_in_header' );

a quick alternative to add some theme specific settings:

`set_theme_mod()`, `get_theme_mod()`

image sizes

Post Thumbnails
Responsive Images in WordPress 4.4
Using Responsive Images (Now)

by default, Wordpress got thumbnail, medium, large and full image sizes, a medium_large size is added in Wordpress 4.4 (which is 768px wide by default)

When a theme adds post-thumbnail support, a special post-thumbnail image size is registered, which differs from the default thumbnail image size, the Feature Image meta box will only be available after this is added

//customize thumbnail size
add_theme_support( 'post-thumbnails' );
set_post_thumbnail_size( 720, 400, true );  // default Post Thumbnail dimensions (cropped)

// add another custom image size
add_image_size('gary_custom', 780, 600, true);

// add the custom image size to the image size dropdown on the popup
function gary_custom_imagesizes ( $sizes ) {
    $sizes['gary_custom'] = __( 'Gary Custom', 'gary_custom' );
    return $sizes;

add_filter('image_size_names_choose', 'gary_custom_imagesizes', 11, 1);

template hierarchy

The WordPress Template Hierarchy

wordpress template hirerarchy map

Queries and Loops

pretty good article on wpmudev: WordPress Development for Intermediate Users: Queries and Loops Codex - Query Overview

get_posts example

/* arguments */
$args = array(
    'sort_order' => 'desc',
    'sort_column' => 'date',
    'number' => '5',

// now run get_posts and check that any are returned
$myposts = get_posts( $args );
if  ( $myposts ) { ?>

    <h2>Latest Posts</h2>

    <?php // output the posts
    foreach( $myposts as $mypost ) {

        $postID = $mypost->ID; ?>

        <article class="post recent <?php echo $postID; ?>">

            <h3><a href="<?php echo get_page_link( $postID ); ?>"><?php echo get_the_title( $postID ); ?></a></h3>
            <section class="entry">
                <?php echo get_the_excerpt( $postID ); ?>
                <a href="<?php echo get_page_link( $postID ); ?>">Read More</a>

<?php }

WP_Query example

Note: always use wp_reset_postdata() after using WP_Query, so Wordpress can reset back to the main query

use rewind_posts() to rewind a custom loop to use it again

// arguments for query
$args = array(
    'post_type' => 'project',
    'posts_per_page' => 1

// run the query
$query = new WP_query ( $args );

// check the query returns posts
if ( $query->have_posts() ) { ?>

    <section class="projects">

        <?php while ( $query->have_posts() ) : $query->the_post(); ?>

        <?php //contents of loop ?>
        <h3>Latest Project - <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
        <a href="<?php the_permalink(); ?>"><?php the_post_thumbnail( 'medium' ); ?></a>
        <?php the_excerpt(); ?>

        <?php endwhile; ?>

    <?php wp_reset_postdata(); ?>


<?php } ?>

code snippets

limit 'prev', 'next' to posts in same category


default JS files and libraries in Wordpress, see tables in following pages:



internationalization and localization

.pot, .po, .mo

refer: Wiki gettext



enable shortcode in text widget

// Enable shortcodes in text widgets

hidden all settings page

this page http://xx.xx/wp-admin/options.php will display all setting options

Archive page

get the term object in an archive page:

    $term_slug = get_query_var('term');

    $term = get_term_by('slug', $term_slug, 'custom_category');
    $page_title = $term->name;

get post content by ID

echo apply_filters('the_content', get_post_field('post_content', $post_id));


  1. By default, WP's Object Cache is non-persistent, it only keeps data during one HTTP request, persistent caching can be enabled by install some plugin (Memcached, Redis, etc), which will create a new wp-content/object-cache.php file to overwrite default functions;

  2. All MySQL queries use the Object Cache, to reduce DB queries;

  3. The Transient API will use Object Cache if persistent cache is enabled, otherwise it will save data in the wp-options table;

  4. The Options API always use the options table, since all MySQL queries use Object Cache, so it uses Object Cache as well.


Wordpress Caching Wordpress Customizer