How to mount S3 Bucket on Ubuntu using S3FS

Today I will show you how I config to mount S3 Bucket as a local file system on Ubuntu 16.04.

What is an Amazon S3 bucket?

As a document, [Amazon S3 bucket] is storage for the Internet. It is designed to make web-scale computing easier for developers.

Create an Amazon S3 Bucket

First of all, you need register an AWS account to manage your buckets. Since you have the account, Amazon S3 provides APIs for you to create and manage buckets. By default, you can create 100 buckets limit. If you need additional buckets, you can increase your bucket limit by submitting a service limit increase. In each bucket, you can store any number of objects. See [create a bucket document]. Since you have a bucket, you can start mounting process.

Installation S3FS package

S3FS allows Linux and Mac OS X to mount an S3 bucket via FUSE.
Following S3FS guideline, we need to ensure all dependencies installed.

sudo apt-get install automake autotools-dev fuse g++ git libcurl4-gnutls-dev libfuse-dev libssl-dev libxml2-dev make pkg-config

Ensure libfuse2 and libfuse-dev packages are installed. Then compile from master via the following commands:

git clone https://github.com/s3fs-fuse/s3fs-fuse.git
cd s3fs-fuse
./autogen.sh
./configure
make && make install

Verify Fuse and F3FS installed
– Fuse

root@dac22c9e3125:/# pkg-config --modversion fuse
2.9.4

– F3FS

root@dac22c9e3125:/# s3fs --version
Amazon Simple Storage Service File System V1.82(commit:ab89b4c) with OpenSSL
Copyright (C) 2010 Randy Rizun <rrizun@gmail.com>
License GPL2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Then, enter your S3 identity and credential in a file /path/to/passwd and set owner-only permissions:

echo AccessKey:SecretKey > /path/to/passwd
chmod 600 /path/to/passwd

Mount an S3 bucket

Create a mount point directory for the S3 bucket and use the s3fs command to mount it.

1. Create a directory for mounting the S3 bucket

root@dac22c9e3125:/# mkdir /var/www/html/s3-bucket
root@dac22c9e3125:/# chmod -R 755 /var/www/html/s3-bucket

2. Create cache directory

root@dac22c9e3125:/# mkdir /tmp/cache 
root@dac22c9e3125:/# chmod -R 755 /tmp/cache

3. Mount the S3 bucket using the correct permissions and any other options

root@dac22c9e3125:/# s3fs -o allow_other -o use_cache=/tmp/cache mybucket /var/www/html/s3-bucket -o passwd_file=/.passwd-s3fs -o nonemprt

4. Verify the s3fs mounted file system

root@dac22c9e3125:/# df
s3fs on /var/www/html/s3-images type fuse.s3fs (rw,nosuid,nodev,relatime,user_id=0,group_id=0,allow_other)

5. You can also mount on boot

mybucket /path/to/mountpoint fuse.s3fs _netdev,allow_other 0 0

 

How to install PHP 7.0 or PHP 7.1 on Ubuntu

Most of the servers use PHP 5.5.9 or 5.6. Those PHP versions are not going to support soon. Since more and more applications use PHP 7.x to build, then we also need to upgrade it to our server.

Note: I am using Ubuntu 14.04. This way works for Ubuntu 16.04 as well.

Install PHP 7.0

First of all, you need to update modules

sudo apt-get update

Then, you can list all of the available PHP 7.0 packages for review

apt-cache pkgnames | grep php7.0
PHP 7.0 packages
PHP 7.0 packages

Select the packages that you want to install

sudo apt-get install php7.0 libapache2-mod-php7.0 php7.0-cli php7.0-common php7.0-mbstring php7.0-gd php7.0-intl php7.0-xml php7.0-mysql php7.0-mcrypt php7.0-zip

After the installation, check PHP version with command

php -v

The output should resemble

PHP 7.0.15-0ubuntu0.16.04.4 (cli) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
with Zend OPcache v7.0.15-0ubuntu0.16.04.4, Copyright (c) 1999-2017, by Zend Technologies

Install PHP 7.1

First of all, you also need to check wether PHP 7.1 is available or not

apt-cache pkgnames | grep php7.1

If it is still not yet, so you need to download it.
You add specified PPA to the system apt repository

sudo apt-get install -y python-software-properties
sudo add-apt-repository -y ppa:ondrej/php

Note: If you get this error add-apt-repository command not found, you need to install this module:

sudo apt-get install software-properties-common

After that run update command again

sudo apt-get update -y

Finally, you can install PHP 7.1 same PHP 7.0. Just change 7.0 to 7.1

sudo apt-get install php7.1 libapache2-mod-php7.1 php7.1-cli php7.1-common php7.1-mbstring php7.1-gd php7.1-intl php7.1-xml php7.1-mysql php7.1-mcrypt php7.1-zip

Ok, now you need to disable PHP 5 module

sudo a2dismod php5.6

and active PHP 7.x module

sudo a2enmod php7.x

Restart your server to apply the changes

service apache2 restart

That’s it. Hope this help.

How to Fix WordPress Posts Returning 404 Not Found

Sometimes you may look at this URL on your browser http://example.dev/index.php/hello-world/
When you try to remove index.php out of URL, you get 404 Not Found page. Or for some reasons your site gets 404 Not Found for all links. So below are what I did when I got this situation.

Save your permalink again

First of all, you need to check your permalink in admin settings and save it again.
Go to Settings » Permalinks and just click on Save Changes button

Save your permalink
Save your permalink

This action will rewrite .htaccess file and store permalink structure into the database. In most case, this solution the WordPress 404 Error. If not, you have to check the .htaccess file manually. Using FTP or SSH it up to you and then open the .htaccess file (you might change permission to 666 temporary to edit it). Then add this code to .htaccess file

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

If this bug still exists. So you need to use next solution to check.

Check Local Server Configuration

This bug causes your Apache does not active rewrite module. So you need to check this module activated or not yet.
Create a test PHP file and invoke phpinfo() function to look at our configuration.
If the module is activated, so it will be the list of Loaded Modules.

Check Local Server Configuration
Check Local Server Configuration

If not, you need to activate it. Open your terminal and type this command:

sudo a2enmod rewrite

And restart your server

sudo service apache2 restart

If still not working, so you need to check further a little bit.
Check your Apache config file. It located in /etc/apache2/apache2.conf
Open it in your editor. I like nano, so I use it to open this file

sudo nano /etc/apache2/apache2.conf

Find to this snippet config:

<Directory "path/to/your/document/root"> 
# ....

AllowOverride None

# ....

</Directory>

And change

AllowOverride None

to

AllowOverride All

After that restart your server again and check your site URL.
Hope this help!

Order product with no price in Woocommerce

Sometime you want to let your customers can order the product with no price. Woocommerce has a filter that allows you change purchasable ability. It is `woocommerce_is_purchasable`.

See the snippet below:

add_filter('woocommerce_is_purchasable', 'keepOrderNoPrice', 10, 2);

function keepOrderNoPrice($isPurchasable, $product)
{
	return $product->exists() && ('publish' === $product->get_status() || current_user_can( 'edit_post', $product->get_id()));
}

You can put the code in `functions.php` file.

How to remove custom post type slug from url

Today, I got a task call “Remove ‘product’ slug out single product url” in Woocommerce. The code below work ok but I properly make conflict with post, page which have same slug with product.

<?php
/**
 * [removeSlug description]
 * @param  [type] $postLink  [description]
 * @param  [type] $post      [description]
 * @param  [type] $leavename [description]
 * @return [type]            [description]
 */
function removeSlug($postLink, $post, $leavename)
{

    if ( 'product' != $post->post_type || 'publish' != $post->post_status ) {
        return $postLink;
    }

    $postLink = str_replace( '/' . $post->post_type . '/', '/', $postLink );

    return $postLink;
}

add_filter( 'post_type_link', 'removeSlug', 10, 3 );

/**
 * [na_parse_request description]
 * @param  [type] $query [description]
 * @return [type]        [description]
 */
function parseRequest($query)
{

    if ( ! $query->is_main_query() || 2 != count( $query->query ) || ! isset( $query->query['page'] ) ) {
        return;
    }

    if ( ! empty( $query->query['name'] ) ) {
        $query->set( 'post_type', array( 'product' ) );
    }
}

add_action('pre_get_posts', 'parseRequest');

 

How to display full TinyMCE Editor In WordPress

When WordPress 3.9, the WordPress visual editor was given 14 buttons and 26 buttons when toggle the hidden toolbar.

To display the full TinyMCE text editor, you need a litter bit code. Add the following code to your `functions.php` file to enable hidden buttons:

<?php
/**
 * display full buttons of TinyMCE Editor
 * 
 * @param  array $buttons
 * @return array $buttons
 */
function enableButtonsTinyMCE($buttons)
{
	$buttons[] = 'fontselect';
	$buttons[] = 'fontsizeselect';
	$buttons[] = 'styleselect';
	$buttons[] = 'backcolor';
	$buttons[] = 'newdocument';
	$buttons[] = 'cut';
	$buttons[] = 'copy';
	$buttons[] = 'charmap';
	$buttons[] = 'hr';
	$buttons[] = 'visualaid';

	return $buttons;
}

add_filter('mce_buttons_3', 'enableButtonsTinyMCE');

To keep the toggle always on, you need also add below snippet to your `functions.php` file:

<?php
/**
 * keep kitchen always on
 * 
 * @param  array $open
 * @return array $open
 */
function keepTinyMceOn($open)
{

	$open['wordpress_adv_hidden'] = FALSE;

	return $open;
}

add_filter('tiny_mce_before_init', 'keepTinyMceOn');

Your editor now display full buttons:

If you would like to make this without node coding. There are some great plugins that allows you to do this: TinyMCE Advanced or WP Edit

 

CSS for individual web browser

Sometimes you need to add a custom CSS only for particular web browsers such as Chrome, Firefox or IE. This usually applies the fixes for web browsers. Below are CSS syntax for:

Safari 6.1-10.0 (Non-iOs)

@media screen and (min-color-index:0) and(-webkit-min-device-pixel-ratio:0) 
{ @media {
_:-webkit-full-screen, .safari_only { 
color: green; 
}
}}

Safari 6.1-7.0

@media screen and (-webkit-min-device-pixel-ratio:0) and (min-color-index:0)
{ 
.safari_only {(;
color: green;
);}
}

Safari 9.0-10.0 (non-iOS)

_:-webkit-full-screen:not(:root:root), .safari_only {
color: green;
}

Safari 9.0 (iOS Only)

@supports (-webkit-text-size-adjust:none) and (not (-ms-ime-align:auto))
and (not (-moz-appearance:none))
{
.safari_only {
color: green;
}
}

Safari 9

@supports (overflow:-webkit-marquee) and (justify-content:inherit) 
{
.safari_only {
color: green;
}
}

Safari 9.0-10.0 (not 10.1)

_::-webkit-:not(:root:root), .safari_only {
color: green; 
}

Safari 10.0 (not 10.1) but not on iOS

_::-webkit-:-webkit-full-screen:host:not(:root:root), .safari_only {
color: green;
}

Safari 10.0 (not 10.1)

_::-webkit-:host:not(:root:root), .safari_only {
color: green;
}

Safari 6.1-10.0 (not 10.1, which is the latest version of Safari at this time)

@media screen and (min-color-index:0) and(-webkit-min-device-pixel-ratio:0) 
{ @media {
.safari_only { 
color: green;
}
}}

Safari 10.1+ (alternate method)

@media not all and (min-resolution:.001dpcm)
{ @supports (-webkit-appearance:none) {
.safari_only { 
color: green;
}
}}

Safari 10.1+ (which is the latest version of Safari at this time)

@media not all and (min-resolution:.001dpcm) { @media {
.safari_only { 
color: green;
}
}}

Safari 7.1+

_::-webkit-full-page-media, _:future, :root .safari_only {
color: green;
}

For Chrome

Chrome 22-28

@media screen and(-webkit-min-device-pixel-ratio:0)
{
.chrome_only {-chrome-:only(;
color:#0000FF; 
);}
}

Chrome 28+, Now Also Safari 9+, Firefox, and Microsoft Edge

@supports (-webkit-appearance:none) 
{
.chrome_and_safari {
color:#0000FF; 
}
}

Chrome 29+

@supports (-webkit-appearance:none) and (not (overflow:-webkit-marquee))
and (not (-ms-ime-align:auto)) and (not (-moz-appearance:none))
{
.chrome_only {
color:#0000FF; 
}
}

Chrome 29+

@media screen and (-webkit-min-device-pixel-ratio:0) and (min-resolution:.001dpcm)
{
.chrome_only {
color:#0000FF; 
}
}

 

For Firefox

@-moz-document url-prefix() {
h1 {
color: red;
}
}

 

How to add category with comma in WordPress

Hi, everyone! Today, I have a task about creating a category with the commas in WordPress. By default, we could not create a category with the commas in category box in the single post.

If you do that, WordPress will split your category title to many individual categories.

We only do this in the category manager page. But your clients doesn’t know this. They go to single post. And suddenly they want to add a new category for their post. They see the category box. They may type some text like this “12 Tran Hung Dao St, Hoan Kiem District, Ha Noi”. And they hit enter. The problem is WordPress does not create a single category name “12 Tran Hung Dao St, Hoan Kiem District, Ha Noi”. It creates to 3 sub-categories are “12 Tran Hung Dao St”, “Hoan Kiem District” and “Ha Noi”. This is not good for users who has no experiences about content management. We can also notice this to the user say that they should not create the category with the commas. But this makes your website is fewer user experiences (UX).

So my approach is injection into the progress that after the user hit enters and before the category created actually. Unfortunately, WordPress does not produce an action or filter to do this. Luckily, WordPress calls an ajax request to handle exploding the category title. This progress will detect the category title. If it contains any commas, it will split to sub-titles. And we can change this ajax request via filter named:
`wp_ajax_add-{category or taxonomy-slug}`

Take a look at the code below how I handle this.

Remove default WordPress filter AJAX

remove_filter('wp_ajax_add-category' , '_wp_ajax_add_hierarchical_term');

With taxonomy you use `taxonomy-slug` instead of `category`. For example: the taxonomy has slug is book_author. So the filter above rewrite like this:

`remove_filter(‘wp_ajax_add-book_author’ , ‘_wp_ajax_add_hierarchical_term’);`

Add your new filter

add_filter('wp_ajax_add-category', 'callbackFunction');

Write function callback

function callbackFunction() {
    $action = $_POST['action'];

    $taxonomy = get_taxonomy(substr($action, 4));

    check_ajax_referer( $action, '_ajax_nonce-add-' . $taxonomy->name );

    if ( !current_user_can( $taxonomy->cap->edit_terms ) )
        wp_die( -1 );

    $parent = isset($_POST['new'.$taxonomy->name.'_parent']) ? (int) $_POST['new'.$taxonomy->name.'_parent'] : 0;

    if ( 0 > $parent )
        $parent = 0;
        
    if ( $taxonomy->name == 'category' )
        $post_category = isset($_POST['post_category']) ? (array) $_POST['post_category'] : array();
    else
        $post_category = ( isset($_POST['tax_input']) && isset($_POST['tax_input'][$taxonomy->name]) ) ? (array) $_POST['tax_input'][$taxonomy->name] : array();
        
    $checked_categories = array_map( 'absint', (array) $post_category );
    $popular_ids = wp_popular_terms_checklist($taxonomy->name, 0, 10, false);

    $cat_name = trim($_POST['new'.$taxonomy->name]);
    $category_nicename = sanitize_title($cat_name);

    if ($category_nicename !== '') {
        if (!$cat_id = term_exists( $cat_name, $taxonomy->name, $parent)) {
            $cat_id = wp_insert_term(
                $cat_name, 
                $taxonomy->name, 
                array('parent' => $parent)
            );
        }
            
            
        if (is_array($cat_id)) {
            $cat_id = $cat_id['term_id'];
        }
        
        $checked_categories[] = $cat_id;
        
        if (!$parent) {
            ob_start();
    
            wp_terms_checklist( 0, array(
                'taxonomy' => $taxonomy->name, 
                'descendants_and_self' => $cat_id, 
                'selected_cats' => $checked_categories, 
                'popular_cats' => $popular_ids )
            );
    
            $data = ob_get_clean();
    
            $add = array(
                'what' => $taxonomy->name,
                'id' => $cat_id,
                'data' => str_replace( array("\n", "\t"), '', $data),
                'position' => -1
            );
        }
        
    }

    if ( $parent ) { // Foncy - replace the parent and all its children
        $parent = get_term( $parent, $taxonomy->name );
        $term_id = $parent->term_id;

        while ( $parent->parent ) { // get the top parent
            $parent = get_term( $parent->parent, $taxonomy->name );
            if ( is_wp_error( $parent ) )
                break;
            $term_id = $parent->term_id;
        }

        ob_start();

        wp_terms_checklist( 0, array(
            'taxonomy' => $taxonomy->name, 
            'descendants_and_self' => $term_id, 
            'selected_cats' => $checked_categories, 
            'popular_cats' => $popular_ids)
        );

        $data = ob_get_clean();

        $add = array(
            'what' => $taxonomy->name,
            'id' => $term_id,
            'data' => str_replace( array("\n", "\t"), '', $data),
            'position' => -1
        );
    }

    ob_start();

    wp_dropdown_categories( array(
        'taxonomy' => $taxonomy->name, 'hide_empty' => 0, 'name' => 'new'.$taxonomy->name.'_parent', 'orderby' => 'name',
        'hierarchical' => 1, 'show_option_none' => '&mdash; '.$taxonomy->labels->parent_item.' &mdash;'
    ) );

    $sup = ob_get_clean();

    $add['supplemental'] = array( 'newcat_parent' => $sup );

    $x = new \WP_Ajax_Response( $add );
    $x->send();
}

Now, we can create the category that contains the commas

Hope this tutorial is helpful for you.

How to create a Custom WordPress Widget

Widgets are helpful elements of WordPress. It makes user can simply drag and drop elements into their site. There are many themes uses their custom widgets to make their themes more flexible and allows users to create their own layouts. By the side, there are even plugins that allow you manage your widgets. Today, I will show you how to create your own custom widget in WordPress.

So what is a WordPress Widget?

As codex.wordpress.org defines, a WordPress widget adds content and features to your sidebar. Widgets were originally designed to provide a simple and easy-to-use way of giving design and structure control in WordPress theme to the user. You can add, remove, rearrange the widgets on Theme Customizer or  Appearance > Widgets. This allows great flexibility to plugin and theme developers. They can add functionality into their products and lets user decides when and where to use functionality without code.

Create a widget in WordPress

You can put your code in `functions.php` file or you can create a plugin and place widget code there.
In this tutorial, I will create a backbone class for my custom widget. Why do I do this? The reason for this is I would like to create many widgets with its specific options. Take a look at this code and add this into your plugin

<?php
class MyWidget extends \WP_Widget {
    /**
     * @var   array
     * @since 1.0.0
     */
    public $fields;
    
    /**
     * @var   array
     * @since 1.0.0
     */
    protected $widget;
    
	/**
	 * constructor
	 * 
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function __construct($widget, $fields, $template) {
		if (!is_array($widget) || !is_array($fields)) {
		    wp_die(__('It must be an array.'));
		}
		
		if (empty($widget) || empty($fields)) {
		    wp_die(__('It is not empty.'));    
		}
		
		$this->widget   = $widget;
		$this->fields   = $fields;
	    
		parent::__construct(
			$this->widget['id'],
			__($this->widget['label'], ''),
			['description' => __($this->widget['description'], '')]
		);
		
		add_action('widgets_init', [$this, 'widgetInit']);
		
	}
	
	/**
	 * register widget
	 * 
	 * @since 1.1.0
	 * @return void
	 */
	public function widgetInit()
	{
		register_widget($this);
	}
	
	/**
	 * Front-end display of widget.
	 *
	 * @see WP_Widget::widget()
	 *
	 * @param  array $args     Widget arguments.
	 * @param  array $instance Saved values from database.
	 * @return void
	 */
	public function widget($args, $instance) {
		echo $args['before_widget'];
		
		$title = apply_filters( 'widget_title', $instance['title'] );
        
		if (!empty($title)) {
            echo $args['before_title'] . $title . $args['after_title'];
        }
		
		$this->handle($instance);
        
		echo $args['after_widget'];
	}
	
	/**
	 * handle data
	 * 
	 * @param  array $instance
	 * @since  1.2.1
	 * @return void
	 */
	public function handle($instance) {
		// echo
	}
	
	/**
	 * Back-end widget form.
	 *
	 * @see WP_Widget::form()
	 *
	 * @param  array $instance Previously saved values from database.
	 * @return void
	 */
	public function form($instance) {
		foreach ($this->fields as $field) {
			
			if (@$instance[$field['name']] == null) $instance[$field['name']] = '';
			
			$this->checkTypeOfField($field, $instance[$field['name']]);
		}
	}
	
	/**
	 * check type of the field and navigate it to correct rendering method
	 * 
	 * @param array $field
	 * @param array $instance
	 * 
	 * @since 1.0.0
	 * @return void
	 */
	public function checkTypeOfField($field, $instance) {
        switch ($field['type']) {
            case 'text':
                $this->renderTextField($field, $instance);
                break;
            case 'select':
                $this->renderSelectField($field, $instance);
                break;
            case 'checkbox':
                $this->renderCheckboxField($field, $instance);
                break;
            
        }
	}
	
	/**
	 * render input text field
	 * 
	 * @since 1.0.0
	 * 
	 * @param  array $field
	 * @param  array $instance
	 * @return void
	 */
	public function renderTextField($field, $instance) {
		?>
		<p>
		
		<label for="<?php echo esc_attr($this->get_field_id($field['name'])); ?>">
			<?php esc_attr_e($field['label'] . ':', 'text_domain'); ?>
		</label>
		
		<input class="widefat" 
				id="<?php echo esc_attr( $this->get_field_id($field['name']) ); ?>" 
				name="<?php echo esc_attr( $this->get_field_name($field['name']) ); ?>" 
				type="text" 
				value="<?php echo esc_attr($instance); ?>">
		
		</p>
		<?php
	}
	
	/**
	 * render input number field
	 * 
	 * @since 1.2.2
	 * 
	 * @param  array $field
	 * @param  array $instance
	 * @return void
	 */
	public function renderNumberField($field, $instance) {
		?>
		<p>
		
		<label for="<?php echo esc_attr($this->get_field_id($field['name'])); ?>">
			<?php esc_attr_e($field['label'] . ':', 'text_domain'); ?>
		</label>
		
		<input class="widefat" 
				id="<?php echo esc_attr( $this->get_field_id($field['name']) ); ?>" 
				name="<?php echo esc_attr( $this->get_field_name($field['name']) ); ?>" 
				type="number" 
				value="<?php echo esc_attr($instance); ?>">
		
		</p>
		<?php
	}
	
	/**
	 * render a checkbox field
	 * 
	 * @since 1.0.0
	 * 
	 * @param array $field
	 * @param array $instance
	 * @return void
	 */
	public function renderCheckboxField($field, $instance) {
	    ?>
	    <p>
	    	
        <label for="<?php echo esc_attr($this->get_field_id($field['name'])); ?>">
        	<?php esc_attr_e($field['label'] . ':', 'text_domain'); ?>
        </label>
        
        <input class="widefat" 
        		id="<?php echo esc_attr( $this->get_field_id($field['name']) ); ?>" 
        		name="<?php echo esc_attr( $this->get_field_name($field['name']) ); ?>" 
        		type="checkbox" value="<?php echo $field['name']; ?>" 
        		<?php checked($instance, $field['name']); ?>>
	    
	    </p>
	    <?php
	}
	
	/**
	 * render select field
	 * 
	 * @since 1.0.0
	 * 
	 * @param array $field
	 * @param array $instance
	 * @return void
	 */
	public function renderSelectField($field, $instance) {
		?>
		<?php if (!empty($field['options'])) : ?>
		<p>
			
		<label for="<?php echo esc_attr($this->get_field_id($field['name'])); ?>">
			<?php esc_attr_e($field['label'] . ':', 'text_domain'); ?>
		</label>
		
		<select class="widefat" 
				id="<?php echo esc_attr( $this->get_field_id($field['name']) ); ?>" 
				name="<?php echo esc_attr( $this->get_field_name($field['name']) ); ?>">
			
			<?php foreach ($field['options'] as $key => $option) : ?>
				<option value="<?php echo $key; ?>" <?php selected($instance, (int) $key); ?>>
					<?php echo $option; ?>
				</option>
			
			<?php endforeach; ?>
		</select>
		
		</p>
		<?php endif; ?>
		<?php
	}
	
	/**
	 * Sanitize widget form values as they are saved.
	 *
	 * @see WP_Widget::update()
	 *
	 * @param array $new_instance Values just sent to be saved.
	 * @param array $old_instance Previously saved values from database.
	 *
	 * @return array Updated safe values to be saved.
	 */
	public function update($new_instance, $old_instance) {
		$instance = array();
		
		foreach ($this->fields as $field) {
			/**
			 * @TODO validate url value with HTTP Protocol
			 */
            $instance[$field['name']] = (!empty( $new_instance[$field['name']])) ? strip_tags($new_instance[$field['name']]) : '';
		}
		
		return $instance;
	}
}

Let me explain a few useful methods in above code.

The `checkTypeOfField()` method
This method will check the type of field you pass to it. And then switch to corresponding creation field method.

Rendering Field method
Let’s use `renderTextField()` for example. This method will be invoked when `checkTypeOfField()` return `text` value. It renders an input text field in admin form of the widget. You can add a more similar method to render other field types you want.

The `handle()` method
Write what you want the widget to do into this method. It will render out front-end.

Create an instance of MyWidget class

Now, you can create as much as instances of class MyWidget. Each instance will create an individual widget.

<?php
class RelatedPosts extends MyWidget {
    /**
     * Initialize
     * 
     * @since 1.0.0
     * @return void
     */
    public function __construct() {
        
        $fields = array(
            [
                'label' => 'Title',
                'name' => 'title',
                'type' => 'text',            
            ],
            [
                'label' => 'Number Items',
                'name' => 'number_items',
                'type' => 'text',
            ],
        );
        
        $widget = [
            'id'          => 'related_posts',
            'label'       => __('Related Posts Widget', 'text-domain'),
            'description' => __('This widget shows related posts', 'text-domain')
        ];
        
        parent::__construct($widget, $fields);
    }
    
    /**
     * [inherit]
     * 
     * 
     */
    public function handle($instance) {
        $args = [
            'post_type'      => 'post',
            'posts_per_page' => $instance['number_items'],
            'cat'            => '1'
        ];
        
        $posts = get_posts($args);

        if (!empty($posts)) {
            foreach ($posts as $post) {
                echo $post->post_title . '<br />';
            }    
        }
    }
}

Then, you create WordPress widget instance.

$relatedPostsWidget = new RelatedPosts;

Hope this tutorial helps you.

Resolve block IP using another server IP

Sometimes, you forget your account password. And you attempt login many times. So you get an message from website such as `401 unauthorized`. Depending on which website you are on, they might block your IP from 5 mins to 1 hour. If you are hurry to fix something. You can not wait for 1 hour.

If you have a hosting. So my this solution may help you. Let’s begin.

Create private port to connect your local with server

`ssh root@server_IP -p port_number -D 9999`

-D: This option will create a private port on your server with number 9999. You feel free to set this number as 1234, 3432 etc…

Then, change your network proxy

If you are on Chrome

Go to Chrome → Settings → Network → Change proxy settings…

Type these line into the settings panel fields

Host: 127.0.0.1

Port: 9999

Type: SOCKS

Using ignitor browser to access the website

To open ignitor browser tab on Chrome, you can hit `Command+Shitf+N`. Open the website again.

Hope this help.