wordpress创建metabox之image uploader

先添加metabox:

<?php 

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) exit;

// metabox creating main class
class Mx_Metaboxes_Class
{

	private $args = [];

	private $defauls = [];

	public function __construct( $args )
	{

		$this->defaults = [
			'id'			=> 'mx-extra-metabox-1',
			'post_types' 	=> 'page', // ['page', 'post']
			'name'			=> esc_html( 'Extra metabox 1', 'mx-domain' ),
			'metabox_type'	=> 'input-text'
		];

		$this->args = wp_parse_args( $args, $this->defaults );

		if( is_array( $this->args['post_types'] ) ) :

			$this->args['metabox_id'] = $this->args['id'] . '_' . implode( '_',  $this->args['post_types'] );

		else :

			$this->args['metabox_id'] = $this->args['id'] . '_' . $this->args['post_types'];

		endif;

		$this->args['post_meta_key'] = '_mx_' . $this->args['metabox_id'] . '_id';
		$this->args['nonce_action']  = $this->args['metabox_id'] . '_nonce_action';
		$this->args['nonce_name']    = $this->args['metabox_id'] . '_nonce_name';

		add_action( 'add_meta_boxes', [ $this, 'add_meta_box' ] );

		add_action( 'save_post', [ $this, 'save_meta_box' ] );

	}

	// add post meta
	public function add_meta_box() {
		add_meta_box(
			$this->args['metabox_id'],
			$this->args['name'],
			[ $this, 'meta_box_content' ],
			$this->args['post_types'],
			'normal'
			// 'low'
		);
	}

	// save post meta
	public function save_meta_box( $post_id ) {
		if ( ! isset( $_POST[ $this->args['nonce_name'] ] ) || ! wp_verify_nonce( wp_unslash( $_POST[ $this->args['nonce_name'] ] ), $this->args['nonce_action'] ) ) { // phpcs:ignore WordPress.Security
			return;
		}

		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			return;
		}

		$value = '';
		if ( isset( $_POST ) && isset( $_POST[ $this->args['post_meta_key'] ] ) ) :

			if( $this->args['metabox_type'] == 'input-email' ) :

				// email field
				$value = sanitize_email( wp_unslash( $_POST[ $this->args['post_meta_key'] ] ) );

			elseif( $this->args['metabox_type'] == 'input-url' ) :

				// url field
				$value = esc_url_raw( $_POST[ $this->args['post_meta_key'] ] );


			elseif( $this->args['metabox_type'] == 'textarea' ) :

				// textarea field
				$value = sanitize_textarea_field( $_POST[ $this->args['post_meta_key'] ] );

			elseif( $this->args['metabox_type'] == 'image' ) :

				// image id
				$value = sanitize_text_field( $_POST[ $this->args['post_meta_key'] ] );
				
			else :

				// input text
				$value = sanitize_text_field( wp_unslash( $_POST[ $this->args['post_meta_key'] ] ) );

			endif;


		endif;
		update_post_meta( $post_id, $this->args['post_meta_key'], $value );
	}

	// metabox content
	public function meta_box_content( $post, $meta )
	{

		$meta_value = get_post_meta(
			$post->ID,
			$this->args['post_meta_key'],
			true
		); ?>

		<p>
			<label for="<?php echo esc_attr( $this->args['post_meta_key'] ); ?>"></label>

			<?php if( $this->args['metabox_type'] == 'input-email' ) : ?>

				<!-- email field -->
				<input 
					type="email" id="<?php echo esc_attr( $this->args['post_meta_key'] ); ?>"
					name="<?php echo esc_attr( $this->args['post_meta_key'] ); ?>"
					value="<?php echo $meta_value; ?>"
				/>

			<?php elseif( $this->args['metabox_type'] == 'input-url' ) : ?>

				<!-- url field -->
				<input 
					type="url" id="<?php echo esc_attr( $this->args['post_meta_key'] ); ?>"
					name="<?php echo esc_attr( $this->args['post_meta_key'] ); ?>"
					value="<?php echo $meta_value; ?>"
				/>

			<?php elseif( $this->args['metabox_type'] == 'textarea' ) : ?>

				<!-- textarea field -->
				<textarea name="<?php echo esc_attr( $this->args['post_meta_key'] ); ?>" id="<?php echo esc_attr( $this->args['post_meta_key'] ); ?>" cols="30" rows="10"><?php echo $meta_value; ?></textarea>

			<?php elseif( $this->args['metabox_type'] == 'image' ) : ?>

				<?php

					$image_url = '';

					if( $meta_value !== '' ) {

						$image_url = wp_get_attachment_url( $meta_value );

					}

				?>

				<!-- image upload -->
				<div class="mx-image-uploader">

					<button
						class="mx_upload_image"
						<?php echo $image_url !== '' ? 'style="display: none;"' : ''; ?>
					>Choose image</button>				

					<!-- here we will save an id of image -->
					<input
						name="<?php echo esc_attr( $this->args['post_meta_key'] ); ?>"
						id="<?php echo esc_attr( $this->args['post_meta_key'] ); ?>"
						type="hidden"
						class="mx_upload_image_save"
					/>

					<!-- show an image -->
					<img
						src="<?php echo $image_url !== '' ? $image_url : ''; ?>"					
						style="width: 300px;"
						alt=""
						class="mx_upload_image_show"
						<?php echo $image_url == '' ? 'style="display: none;"' : ''; ?>						
					/>

					<!-- remove image -->
					<a
						href="#"
						class="mx_upload_image_remove"
						<?php echo $image_url == '' ? 'style="display: none;"' : ''; ?>
					>Remove Image</a>

				</div>
				
			<?php else : ?>

				<!-- input text -->
				<input 
					type="text" id="<?php echo esc_attr( $this->args['post_meta_key'] ); ?>"
					name="<?php echo esc_attr( $this->args['post_meta_key'] ); ?>"
					value="<?php echo $meta_value; ?>"
				/>

			<?php endif; ?>


		</p>

		<?php wp_nonce_field( $this->args['nonce_action'], $this->args['nonce_name'], true, true );

	}

}

然后注册上传用的js框架,调用wp自带的Image上传的js框架:

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) exit;

// metabox creating main class
class Mx_Metaboxes_Image_Upload_Class
{

	// we will use jQuery
	// So we have to register scripts

	public static function register_scrips()
	{
		add_action( 'admin_enqueue_scripts', ['Mx_Metaboxes_Image_Upload_Class', 'upload_image_scrips'] );
	}

		public static function upload_image_scrips()
		{

			wp_enqueue_script( 'mx-image-upload', get_bloginfo( 'template_url' ) . '/mx-folder/js/image-upload.js', array( 'jquery' ), time(), true );

		}

}
image上传的js代码:
jQuery( document ).ready( function( $ ) {

	// upload image
	$( '.mx_upload_image' ).on( 'click', function( e ) {

		var mx_upload_button = $( this );

		e.preventDefault();

		var frame;

		if ( frame ) {
			frame.open();
			return;
		}

		frame = wp.media.frames.customBackground = wp.media({

			title: 'choose image',

			library: {
				type: 'image'
			},

			button: {

				text: 'Upload'
			},

			multyple: false
		});


		frame.on( 'select', function() {

			var attachment = frame.state().get('selection').first();

			// and show the image's data
			var image_id = attachment.id;

			var image_url = attachment.attributes.url;

			// pace an id
			mx_upload_button.parent().find( '.mx_upload_image_save' ).val( image_id );

			// show an image
			mx_upload_button.parent().find( '.mx_upload_image_show' ).attr( 'src', image_url );
				mx_upload_button.parent().find( '.mx_upload_image_show' ).show();

			// show "remove button"
			mx_upload_button.parent().find( '.mx_upload_image_remove' ).show();

			// hide "upload" button
			mx_upload_button.hide();

		} );

		frame.open();

	} );

	// remove image
	$( '.mx_upload_image_remove' ).on( 'click', function( e ) {

		var remove_button = $( this );

		e.preventDefault();

		// remove an id
		remove_button.parent().find( '.mx_upload_image_save' ).val( '' );

		// hide an image
		remove_button.parent().find( '.mx_upload_image_show' ).attr( 'src', '' );
			remove_button.parent().find( '.mx_upload_image_show' ).hide();

		// show "Upload button"
		remove_button.parent().find( '.mx_upload_image' ).show();

		// hide "remove" button
		remove_button.hide();

	} );

} )

functions里面的写法:

<?php 

require get_template_directory() . '/inc/metabox.php';

require get_template_directory() . '/inc/metabox-image-upload.php';

Mx_Metaboxes_Image_Upload_Class::register_scrips();


// image upload
new Mx_Metaboxes_Class(
	[
		'id'			=> 'featured-image-metabox',
		'post_types' 	=> 'post',
		'name'			=> esc_html( 'Featured image', 'mx-domain' ),
		'metabox_type'	=> 'image'
	]
);

// image upload 2
new Mx_Metaboxes_Class(
	[
		'id'			=> 'featured-image2-metabox',
		'post_types' 	=> 'post',
		'name'			=> esc_html( 'Featured image 2', 'mx-domain' ),
		'metabox_type'	=> 'image'
	]
);

// desc
new Mx_Metaboxes_Class(
	[
		'id'			=> 'desc-metabox',
		'post_types' 	=> 'post',
		'name'			=> esc_html( 'Some Description', 'mx-domain' ),
		'metabox_type'	=> 'textarea'
	]
);

wordpress添加theme option(step by step)

首先在主题文件夹创建inc,文件夹,创建两个文件,一个theme_functions,php(可选),一个wlk_theme_options.php.

第一步我们首先要注册admin page.首先注册的是一级的admin page,也就是menu page. 用到的函数是add_menu_page()。函数用法如下:

add_menu_page( string $page_title, string $menu_title, string $capability, string $menu_slug, callable $function = '', string $icon_url = '', int $position = null )

具体参数为:第一个是页面点进去显示在标题栏上的标题,第二个显示为在左侧管理菜单栏上显示的名称(较短,因为空间不够),第三个是权限或者生产力,wordpress专门有个学问叫做Roles and Capabilities,就是每个角色能做什么。具体链接在这里,这里我们用到的一般都是manage_options的capibility.第四个是页面的slug,也就是类似于页面的id,唯一识别码。在最后会以admin.php?page=wlk_admin_page这种显示。第五个是callback函数,也就是你在页面要呈现的内容,通常这个函数是由表格构成的,可以单独创建一个wp_custom_form.php之类的文件创建表格然后在这个管理页面进行require.下面一个是dashicon,可以直接粘贴wordpress的dashicon代码,也可以进行自定义的icon。最后一个函数的位置是position,就是你要在菜单栏哪个位置展示。数值越低越早展示。一般默认。

注册一级admin page的样例如下:

function wlk_register_admin_pages() {

  // $page_title, $menu_title, $capability, $menu_slug, '', null
  add_menu_page( 'wlk Theme Options','Options','manage_options','wlk_admin_page','wlk_create_admin_page','dashicons-admin-network' );

  add_action('admin_init','wlk_register_admin_fields');  
}
add_action('admin_menu','wlk_register_admin_pages');

function wlk_create_admin_page() {
  require_once get_template_directory() . '/inc/templates/wlk_admin_form.php';
}

function wlk_register_admin_fields() {

}

这样会在左侧创建一个菜单名字为Options的按钮,点进去就是你可以进行下一步操作的主题或者插件选项设置。创建好页面之后我们要进行的是注册选项的字段。通过add_action(‘admin_init’,’wlk_register_admin_fields’);钩子来进行注册,通过函数wlk_register_admin_fields来添加注册内容。

下面我们添加二级的管理页面。这个函数是:

add_submenu_page( string $parent_slug, string $page_title, string $menu_title, string $capability, string $menu_slug, callable $function = '', int $position = null )

属性是一样的操作。只不过第一个参数变成了父级管理页面的slug,也就是我们上文提到的wlk_admin_page。然后子级的管理页面不需要icon。

当创建子级管理页面的时候,你会发现上面多了一个和父级管理页面一样的子级页面,这个是wordpress默认创建的。所以我们要repeat 一样的settings,所以第一个子级的页面title跟父级的要设置一样,menu的name可以不变,slug也要变成和父级页面一样,因为我们要一样的页面来作为子级页面,所以callback函数也是一样。

简而言之就是设置第一个子级页面跟父级页面一样的选项,点击父级选项按钮的时候就直接跳转到子级选项。

theme option以下几项缺一不可:

先注册admin page,然后注册field section, 然后resgister fields,然后add settings field.

Settings Api

Setting api 允许半自动管理包含设置表格的管理页。它允许您定义设置页、这些页中的节以及节中的字段。新的setting page可以添加setting section和setting fields,存在的setting page也可以添加新的setting section和setting fields进去。

settings api的优势:

  • Handling Form Submissions – Let WordPress handle retrieving and storing your $_POST submissions.
  • Include Security Measures – You get extra security measures such as nonces, etc. for free.
  • Sanitizing Data – You get access to the same methods that the rest of WordPress uses for ensuring strings are safe to use.

我们先在注册管理页面的函数里添加钩子,add_action(‘admin_init’,’wlk_register_admin_fields’);,然后创建对应函数,

function wlk_register_admin_fields() {
register_setting( ‘wlk-setting-group’,’first_name’ ); //创建setting group, 第二个参数是Input里面的name值。
}并首先添加setting,用到register_setting() 函数。

register_setting函数用法是:register_setting( string $option_group, string $option_name, array $args = array() );

第一个参数option group名字:

$option_group

(string) (Required) A settings group name. Should correspond to an allowed option key name. Default allowed option key names include ‘general’, ‘discussion’, ‘media’, ‘reading’, ‘writing’, ‘misc’, ‘options’, and ‘privacy’. 与允许的option值名必须对应。是唯一的名字我们希望保存这些集合

第二个是

$option_name

(string) (Required) The name of an option to sanitize and save.是option的名字,用来过滤和保存。是pacific single option name.

第三个是数组,来描述和进行函数的callback. 用法是:

$args

(array) (Optional) Data used to describe the setting when registered.

  • ‘type’
    (string) The type of data associated with this setting. Valid values are ‘string’, ‘boolean’, ‘integer’, ‘number’, ‘array’, and ‘object’.
  • ‘description’
    (string) A description of the data attached to this setting.
  • ‘sanitize_callback’
    (callable) A callback function that sanitizes the option’s value.
  • ‘show_in_rest’
    (bool|array) Whether data associated with this setting should be included in the REST API. When registering complex settings, this argument may optionally be an array with a ‘schema’ key.
  • ‘default’
    (mixed) Default value when calling get_option().

Default value: array().使用的时候基本保存默认

theme options 注册fields由register setting和add_settings_field组成。register注册option_group并添加option到表。add_settings_field添加新的字段区域到设置页的setion里,同时通过callback函数input里面的name值和注册的option相对应,来进行数据的写入。

Theme form 的代码:

<h1><?php __('设置主题选项'); ?></h1>

<?php settings_errors(); ?>

<form action="options.php" method="post">
	<?php settings_fields( 'dom-fields-group' ); ?>
	<?php do_settings_sections( 'dom_admin_page' ); ?>
	<?php submit_button(); ?>
</form>

WP_query参数详解

<?php
/**
* WordPress Query Comprehensive Reference
* Compiled by luetkemj - luetkemj.github.io
*
* CODEX: http://codex.wordpress.org/Class_Reference/WP_Query#Parameters
* Source: https://core.trac.wordpress.org/browser/tags/4.9.4/src/wp-includes/query.php
*/

$args = array(

// Author Parameters - Show posts associated with certain author.
// http://codex.wordpress.org/Class_Reference/WP_Query#Author_Parameters
  'author' => '1,2,3,', // (int | string) -  use author id or comma-separated list of IDs [use minus (-) to exclude authors by ID ex. 'author' => '-1,-2,-3,']
  'author_name' => 'luetkemj', // (string) - use 'user_nicename' (NOT name)
  'author__in' => array( 2, 6 ), // (array) - use author id (available with Version 3.7).
  'author__not_in' => array( 2, 6 ), // (array)' - use author id (available with Version 3.7).

// Category Parameters - Show posts associated with certain categories.
// http://codex.wordpress.org/Class_Reference/WP_Query#Category_Parameters
  'cat' => 5, // (int) - Display posts that have this category (and any children of that category), using category id.
  'cat' => '-12,-34,-56' // Display all posts except those from a category by prefixing its id with a '-' (minus) sign.
  'category_name' => 'staff, news', // (string) - Display posts that have these categories (and any children of that category), using category slug.
  'category_name' => 'staff+news', // (string) - Display posts that have "all" of these categories, using category slug.
  'category__and' => array( 2, 6 ), // (array) - Display posts that are in multiple categories. This shows posts that are in both categories 2 and 6.
  'category__in' => array( 2, 6 ), // (array) - Display posts that have this category (not children of that category), using category id.
  'category__not_in' => array( 2, 6 ), // (array) - Display posts that DO NOT HAVE these categories (not children of that category), using category id.

// Tag Parameters - Show posts associated with certain tags.
// http://codex.wordpress.org/Class_Reference/WP_Query#Tag_Parameters
  'tag' => 'cooking', // (string) - use tag slug.
  'tag_id' => 5, // (int) - use tag id.
  'tag__and' => array( 2, 6), // (array) - use tag ids.
  'tag__in' => array( 2, 6), // (array) - use tag ids.
  'tag__not_in' => array( 2, 6), // (array) - use tag ids.
  'tag_slug__and' => array( 'red', 'blue'), // (array) - use tag slugs.
  'tag_slug__in' => array( 'red', 'blue'), // (array) - use tag slugs.

// Taxonomy Parameters - Show posts associated with certain taxonomy.
// http://codex.wordpress.org/Class_Reference/WP_Query#Taxonomy_Parameters
// Important Note: tax_query takes an array of tax query arguments arrays (it takes an array of arrays)
// This construct allows you to query multiple taxonomies by using the relation parameter in the first (outer) array to describe the boolean relationship between the taxonomy queries.
  'tax_query' => array( // (array) - use taxonomy parameters (available with Version 3.1).
    'relation' => 'AND', // (string) - The logical relationship between each inner taxonomy array when there is more than one. Possible values are 'AND', 'OR'. Do not use with a single inner taxonomy array. Default value is 'AND'.
    array(
      'taxonomy' => 'color', // (string) - Taxonomy.
      'field' => 'slug', // (string) - Select taxonomy term by Possible values are 'term_id', 'name', 'slug' or 'term_taxonomy_id'. Default value is 'term_id'.
      'terms' => array( 'red', 'blue' ), // (int/string/array) - Taxonomy term(s).
      'include_children' => true, // (bool) - Whether or not to include children for hierarchical taxonomies. Defaults to true.
      'operator' => 'IN' // (string) - Operator to test. Possible values are 'IN', 'NOT IN', 'AND', 'EXISTS' and 'NOT EXISTS'. Default value is 'IN'.
    ),
    array(
      'taxonomy' => 'actor',
      'field' => 'id',
      'terms' => array( 103, 115, 206 ),
      'include_children' => false,
      'operator' => 'NOT IN'
    )
  ),

// Post & Page Parameters - Display content based on post and page parameters.
// http://codex.wordpress.org/Class_Reference/WP_Query#Post_.26_Page_Parameters
  'p' => 1, // (int) - use post id.
  'name' => 'hello-world', // (string) - use post slug.
  'title' => 'Hello World' // (string) - use post title (available with Version 4.4)
  'page_id' => 1, // (int) - use page id.
  'pagename' => 'sample-page', // (string) - use page slug.
  'pagename' => 'contact_us/canada', // (string) - Display child page using the slug of the parent and the child page, separated ba slash
  'post_name__in' => 'sample-post' (array) // - use post slugs. Specify posts to retrieve. (available since Version 4.4)
  'post_parent' => 1, // (int) - use page id. Return just the child Pages. (Only works with heirachical post types.)
  'post_parent__in' => array(1,2,3) // (array) - use post ids. Specify posts whose parent is in an array. NOTE: Introduced in 3.6
  'post_parent__not_in' => array(1,2,3), // (array) - use post ids. Specify posts whose parent is not in an array.
  'post__in' => array(1,2,3), // (array) - use post ids. Specify posts to retrieve. ATTENTION If you use sticky posts, they will be included (prepended!) in the posts you retrieve whether you want it or not. To suppress this behaviour use ignore_sticky_posts
  'post__not_in' => array(1,2,3), // (array) - use post ids. Specify post NOT to retrieve.
  // NOTE: you cannot combine 'post__in' and 'post__not_in' in the same query

// Password Parameters - Show content based on post and page parameters. Remember that default post_type is only set to display posts but not pages.
// http://codex.wordpress.org/Class_Reference/WP_Query#Password_Parameters
  'has_password' => true, // (bool) - available with Version 3.9
                          // true for posts with passwords;
                          // false for posts without passwords;
                          // null for all posts with and without passwords
  'post_password' => 'multi-pass', // (string) - show posts with a particular password (available with Version 3.9)

// Post Type Parameters - Show posts associated with certain type or status.
// http://codex.wordpress.org/Class_Reference/WP_Query#Type_Parameters
  'post_type' => array( // (string / array) - use post types. Retrieves posts by Post Types, default value is 'post';
    'post', // - a post.
    'page', // - a page.
    'revision', // - a revision.
    'attachment', // - an attachment. The default WP_Query sets 'post_status'=>'published', but atchments default to 'post_status'=>'inherit' so you'll need to set the status to 'inherit' or 'any'.
    'nav_menu_item' // - a navigation menu item
    'my-custom-post-type', // - Custom Post Types (e.g. movies)
  ),
  // NOTE: The 'any' keyword available to both post_type and post_status queries cannot be used within an array.
  'post_type' => 'any', // - retrieves any type except revisions and types with 'exclude_from_search' set to true.

// Post Status Parameters - Show posts associated with certain type or status.
// http://codex.wordpress.org/Class_Reference/WP_Query#Status_Parameters
    'post_status' => array( // (string | array) - use post status. Retrieves posts by Post Status, default value i'publish'.
      'publish', // - a published post or page.
      'pending', // - post is pending review.
      'draft',  // - a post in draft status.
      'auto-draft', // - a newly created post, with no content.
      'future', // - a post to publish in the future.
      'private', // - not visible to users who are not logged in.
      'inherit', // - a revision. see get_children.
      'trash', // - post is in trashbin (available with Version 2.9).
    ),
    // NOTE: The 'any' keyword available to both post_type and post_status queries cannot be used within an array.
    'post_status' => 'any', // - retrieves any status except those from post types with 'exclude_from_search' set to true.


// Comment Paremters - @since Version 4.9 Introduced the `$comment_count` parameter.
// https://codex.wordpress.org/Class_Reference/WP_Query#Comment_Parameters
    'comment_count' => 10 // (int | array) The amount of comments your CPT has to have ( Search operator will do a '=' operation )
    'comment_count' => array(
      'value' => 10 // (int) - The amount of comments your CPT has to have when comparing
      'compare' => '=' // (string) - The search operator. Possible values are '=', '!=', '>', '>=', '<', '<='. Default value is '='.
    )

// Pagination Parameters
    //http://codex.wordpress.org/Class_Reference/WP_Query#Pagination_Parameters
    'posts_per_page' => 10, // (int) - number of post to show per page (available with Version 2.1). Use 'posts_per_page' => -1 to show all posts.
                            // Note: if the query is in a feed, wordpress overwrites this parameter with the stored 'posts_per_rss' option. Treimpose the limit, try using the 'post_limits' filter, or filter 'pre_option_posts_per_rss' and return -1
    'nopaging' => false, // (bool) - show all posts or use pagination. Default value is 'false', use paging.
    'paged' => get_query_var('paged'), // (int) - number of page. Show the posts that would normally show up just on page X when usinthe "Older Entries" link.
                                       // NOTE: Use get_query_var('page'); if you want your query to work in a Page template that you've set as your static front page. The query variable 'page' holds the pagenumber for a single paginated Post or Page that includes the <!--nextpage--> Quicktag in the post content.
    'nopaging' => false, // (boolean) - show all posts or use pagination. Default value is 'false', use paging.
    'posts_per_archive_page' => 10, // (int) - number of posts to show per page - on archive pages only. Over-rides posts_per_page and showposts on pages where is_archive() or is_search() would be true.
    'offset' => 3, // (int) - number of post to displace or pass over.
                   // Warning: Setting the offset parameter overrides/ignores the paged parameter and breaks pagination. for a workaround see: http://codex.wordpress.org/Making_Custom_Queries_using_Offset_and_Pagination
                   // The 'offset' parameter is ignored when 'posts_per_page'=>-1 (show all posts) is used.
    'paged' => get_query_var('paged'), // (int) - number of page. Show the posts that would normally show up just on page X when usinthe "Older Entries" link.
                                       // NOTE: This whole paging thing gets tricky. Some links to help you out:
                                       // http://codex.wordpress.org/Function_Reference/next_posts_link#Usage_when_querying_the_loop_with_WP_Query
                                       // http://codex.wordpress.org/Pagination#Troubleshooting_Broken_Pagination
    'page' => get_query_var('page'), // (int) - number of page for a static front page. Show the posts that would normally show up just on page X of a Static Front Page.
                                     // NOTE: The query variable 'page' holds the pagenumber for a single paginated Post or Page that includes the <!--nextpage--> Quicktag in the post content.
    'ignore_sticky_posts' => false, // (boolean) - ignore sticky posts or not (available with Version 3.1, replaced caller_get_posts parameter). Default value is 0 - don't ignore sticky posts. Note: ignore/exclude sticky posts being included at the beginning of posts returned, but the sticky post will still be returned in the natural order of that list of posts returned.

// Order & Orderby Parameters - Sort retrieved posts.
// http://codex.wordpress.org/Class_Reference/WP_Query#Order_.26_Orderby_Parameters
    'order' => 'DESC', // (string) - Designates the ascending or descending order of the 'orderby' parameter. Default to 'DESC'.
                       //Possible Values:
                       //'ASC' - ascending order from lowest to highest values (1, 2, 3; a, b, c).
                       //'DESC' - descending order from highest to lowest values (3, 2, 1; c, b, a).
    'orderby' => 'date', // (string) - Sort retrieved posts by parameter. Defaults to 'date'. One or more options can be passed. EX: 'orderby' => 'menu_order title'
                         //Possible Values:
                         // 'none' - No order (available since Version 2.8).
                         // 'ID' - Order by post id. Note the capitalization.
                         // 'author' - Order by author. ('post_author' is also accepted.)
                         // 'title' - Order by title. ('post_title' is also accepted.)
                         // 'name' - Order by post name (post slug). ('post_name' is also accepted.)
                         // 'type' - Order by post type (available since Version 4.0). ('post_type' is also accepted.)
                         // 'date' - Order by date. ('post_date' is also accepted.)
                         // 'modified' - Order by last modified date. ('post_modified' is also accepted.)
                         // 'parent' - Order by post/page parent id. ('post_parent' is also accepted.)
                         // 'rand' - Random order. You can also use 'RAND(x)' where 'x' is an integer seed value.
                         // 'comment_count' - Order by number of comments (available since Version 2.9).
                         // 'relevance' - Order by search terms in the following order: First, whether the entire sentence is matched. Second, if all the search terms are within the titles. Third, if any of the search terms appear in the titles. And, fourth, if the full sentence appears in the contents.
                         // 'menu_order' - Order by Page Order. Used most often for Pages (Order field in the Edit Page Attributes box) and for Attachments (the integer fields in the Insert / Upload Media Gallery dialog), but could be used for any post type with distinct 'menu_order' values (they all default to 0).
                         // 'meta_value' - Note that a 'meta_key=keyname' must also be present in the query. Note also that the sorting will be alphabetical which is fine for strings (i.e. words), but can be unexpected for numbers (e.g. 1, 3, 34, 4, 56, 6, etc, rather than 1, 3, 4, 6, 34, 56 as you might naturally expect). Use 'meta_value_num' instead for numeric values.
                         // 'meta_type' if you want to cast the meta value as a specific type. Possible values are 'NUMERIC', 'BINARY',  'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED', same as in '$meta_query'. When using 'meta_type' you can also use 'meta_value_*' accordingly. For example, when using DATETIME as 'meta_type' you can use 'meta_value_datetime' to define order structure.
                         // 'meta_value_num' - Order by numeric meta value (available since Version 2.8). Also note that a 'meta_key=keyname' must also be present in the query. This value allows for numerical sorting as noted above in 'meta_value'.
                         // 'post__in' - Preserve post ID order given in the 'post__in' array (available since Version 3.5). Note - the value of the order parameter does not change the resulting sort order.
                         // 'post_name__in' - Preserve post slug order given in the 'post_name__in' array (available since Version 4.6). Note - the value of the order parameter does not change the resulting sort order.
                         // 'post_parent__in' - Preserve post parent order given in the 'post_parent__in' array (available since Version 4.6). Note - the value of the order parameter does not change the resulting sort order.

// Date Parameters - Show posts associated with a certain time and date period.
// http://codex.wordpress.org/Class_Reference/WP_Query#Date_Parameters
    'year' => 2014, // (int) - 4 digit year (e.g. 2011).
    'monthnum' => 4, // (int) - Month number (from 1 to 12).
    'w' =>  25, // (int) - Week of the year (from 0 to 53). Uses the MySQL WEEK command. The mode is dependenon the "start_of_week" option.
    'day' => 17, // (int) - Day of the month (from 1 to 31).
    'hour' => 13, // (int) - Hour (from 0 to 23).
    'minute' => 19, // (int) - Minute (from 0 to 60).
    'second' => 30, // (int) - Second (0 to 60).
    'm' => 201404, // (int) - YearMonth (For e.g.: 201307).
    'date_query' => array( // (array) - Date parameters (available with Version 3.7).
                           // these are super powerful. check out the codex for more comprehensive code examples http://codex.wordpress.org/Class_Reference/WP_Query#Date_Parameters
      array(
        'year' => 2014, // (int) - 4 digit year (e.g. 2011).
        'month' => 4, // (int) - Month number (from 1 to 12).
        'week' => 31, // (int) - Week of the year (from 0 to 53).
        'day' => 5, // (int) - Day of the month (from 1 to 31).
        'hour' => 2, // (int) - Hour (from 0 to 23).
        'minute' => 3, // (int) - Minute (from 0 to 59).
        'second' => 36, // (int) - Second (0 to 59).
        'after' => 'January 1st, 2013', // (string/array) - Date to retrieve posts after. Accepts strtotime()-compatible string, or array of 'year', 'month', 'day'
        'before' => array( // (string/array) - Date to retrieve posts after. Accepts strtotime()-compatible string, or array of 'year', 'month', 'day'
          'year' => 2013, // (string) Accepts any four-digit year. Default is empty.
          'month' => 2, // (string) The month of the year. Accepts numbers 1-12. Default: 12.
          'day' => 28, // (string) The day of the month. Accepts numbers 1-31. Default: last day of month.
        ),
        'inclusive' => true, // (boolean) - For after/before, whether exact value should be matched or not'.
        'compare' =>  '=', // (string) - Possible values are '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'EXISTS' (only in WP >= 3.5), and 'NOT EXISTS' (also only in WP >= 3.5). Default value is '='
        'column' => 'post_date', // (string) - Column to query against. Default: 'post_date'.
        'relation' => 'AND', // (string) - OR or AND, how the sub-arrays should be compared. Default: AND.
      ),
    ),

// Custom Field Parameters - Show posts associated with a certain custom field.
// http://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters
    'meta_key' => 'key', // (string) - Custom field key.
    'meta_value' => 'value', // (string) - Custom field value.
    'meta_value_num' => 10, // (number) - Custom field value.
    'meta_compare' => '=', // (string) - Operator to test the 'meta_value'. Possible values are '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'NOT EXISTS', 'REGEXP', 'NOT REGEXP' or 'RLIKE'. Default value is '='.
    'meta_query' => array( // (array) - Custom field parameters (available with Version 3.1).
      'relation' => 'AND', // (string) - Possible values are 'AND', 'OR'. The logical relationship between each inner meta_query array when there is more than one. Do not use with a single inner meta_query array.
       array(
         'key' => 'color', // (string) - Custom field key.
         'value' => 'blue', // (string/array) - Custom field value (Note: Array support is limited to a compare value of 'IN', 'NOT IN', 'BETWEEN', or 'NOT BETWEEN') Using WP < 3.9? Check out this page for details: http://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters
         'type' => 'CHAR', // (string) - Custom field type. Possible values are 'NUMERIC', 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED'. Default value is 'CHAR'. The 'type' DATE works with the 'compare' value BETWEEN only if the date is stored at the format YYYYMMDD and tested with this format.
                           //NOTE: The 'type' DATE works with the 'compare' value BETWEEN only if the date is stored at the format YYYYMMDD and tested with this format.
         'compare' => '=', // (string) - Operator to test. Possible values are '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'EXISTS' (only in WP >= 3.5), and 'NOT EXISTS' (also only in WP >= 3.5). Default value is '='.
       ),
       array(
         'key' => 'price',
         'value' => array( 1,200 ),
         'compare' => 'NOT LIKE',
       )
    ),

// Permission Parameters - Display published posts, as well as private posts, if the user has the appropriate capability:
// http://codex.wordpress.org/Class_Reference/WP_Query#Permission_Parameters
    'perm' => 'readable', // (string) Possible values are 'readable', 'editable'

// Mime Type Parameters - Used with the attachments post type.
// https://codex.wordpress.org/Class_Reference/WP_Query#Mime_Type_Parameters
    'post_mime_type' => 'image/gif', // (string/array) - Allowed mime types.


// Caching Parameters
// http://codex.wordpress.org/Class_Reference/WP_Query#Caching_Parameters
// NOTE Caching is a good thing. Setting these to false is generally not advised.
    'cache_results' => true, // (bool) Default is true - Post information cache.
    'update_post_term_cache' => true, // (bool) Default is true - Post meta information cache.
    'update_post_meta_cache' => true, // (bool) Default is true - Post term information cache.
    'no_found_rows' => false, // (bool) Default is false. WordPress uses SQL_CALC_FOUND_ROWS in most queries in order to implement pagination. Even when you don’t need pagination at all. By Setting this parameter to true you are telling wordPress not to count the total rows and reducing load on the DB. Pagination will NOT WORK when this parameter is set to true. For more information see: http://flavio.tordini.org/speed-up-wordpress-get_posts-and-query_posts-functions


// Search Parameter
// http://codex.wordpress.org/Class_Reference/WP_Query#Search_Parameter
    's' => $s, // (string) - Passes along the query string variable from a search. For example usage see: http://www.wprecipes.com/how-to-display-the-number-of-results-in-wordpress-search
    'exact' => true, // (bool) - flag to make it only match whole titles/posts - Default value is false. For more information see: https://gist.github.com/2023628#gistcomment-285118
    'sentence' => true, // (bool) - flag to make it do a phrase search - Default value is false. For more information see: https://gist.github.com/2023628#gistcomment-285118

// Post Field Parameters
// For more info see: http://codex.wordpress.org/Class_Reference/WP_Query#Return_Fields_Parameter
// also https://gist.github.com/luetkemj/2023628/#comment-1003542
    'fields' => 'ids', // (string) - Which fields to return. All fields are returned by default.
                       // Possible values:
                       // 'ids'        - Return an array of post IDs.
                       // 'id=>parent' - Return an associative array [ parent => ID, … ].
                       // Passing anything else will return all fields (default) - an array of post objects.

// Filters
// For more information on available Filters see: http://codex.wordpress.org/Class_Reference/WP_Query#Filters

);

$the_query = new WP_Query( $args );

// The Loop
if ( $the_query->have_posts() ) :
while ( $the_query->have_posts() ) : $the_query->the_post();
  // Do Stuff
endwhile;
endif;

// Reset Post Data
wp_reset_postdata();

今日错误记录

今天这段wp代码,最后我要echo出来后面通过过滤的变量名字,

function slb_save_slb_subscriber_meta($post_id,$post) {

    //verify nonce
    if (!isset($_POST['slb_subscriber_nonce']) OR !wp_verify_nonce( $_POST['slb_subscriber_nonce'],basename( __FILE__ ) ) ) {
      return $post_id;
    }

    //get the post type object
    
    $post_type = get_post_type_object( $post->post_type );

    //check if the current user has permition to edit
    
    if (!current_user_can( $post_type->cap->edit_post , $post_id )) {
      return $post_id;
    }

    //get the posted data and sanitize it
    
    $first_name = ( isset($_POST['slb_first_name'])) ? sanitize_text_field( $_POST['slb_first_name'] ) : '';
    $last_name = ( isset($_POST['slb_last_name'])) ? sanitize_text_field( $_POST['slb_last_name'] ) : '';
    $email = ( isset($_POST['slb_email'])) ? sanitize_text_field( $_POST['slb_email'] ) : '';
    $lists = ( isset($_POST['slb_list']) && is_array($_POST['slb_list'])) ? (array) $_POST['slb_list'] : [];

    echo $first_name;
    exit;
  }

  add_action('save_post','slb_save_slb_subscriber_meta',10,2);

一开始没加exit, 导致保存的时候怎样都不会提示出来这个first name的变量, 加了exit 结束后面的代码运行,终于提示出来了。

wp_nonce_field函数详解

wp_nonce_field( int|string $action = -1, string $name = ‘_wpnonce’, bool $referer = true, bool $echo = true )

Retrieve or display nonce hidden field for forms.检索或显示表格的临时隐藏字段。是wp表格的自带验证,可以有效防止注册、提交等动作。

The nonce field is used to validate that the contents of the form came from the location on the current site and not somewhere else. The nonce does not offer absolute protection, but should protect against most cases. It is very important to use nonce field in forms.

The $action and $name are optional, but if you want to have better security, it is strongly suggested to set those two parameters. It is easier to just call the function without any parameters, because validation of the nonce doesn’t require any parameters, but since crackers know what the default is it won’t be difficult for them to find a way around your nonce and cause damage.

The input name will be whatever $name value you gave. The input value will be the nonce creation value.

nonce字段用于验证表单的内容是否来自当前站点上的位置,而不是其他位置。nonce不能提供绝对的保护,但应该可以防止大多数情况。在表单中使用nonce字段非常重要。

$action和$name是可选的,但是如果您想要更好的安全性,强烈建议您设置这两个参数。只调用不带任何参数的函数更容易,因为验证nonce不需要任何参数,但是由于破解者知道默认值是什么,所以他们很容易找到绕过nonce的方法并造成损害。

输入名称将是您给定的$name值。输入值将是nonce创建值。

参数解释:

$action

(int|string) (Optional) Action name.

Default value: -1$name

(string) (Optional) Nonce name.

Default value: ‘_wpnonce’$referer

(bool) (Optional) Whether to set the referer field for validation.

Default value: true$echo

(bool) (Optional) Whether to display or return hidden form field.

Default value: true

Anytime you submit form data and you add it todatabase it’s a good idea to use wp’s nonce field generate a unique ID it’s for the functions so that you know the not being posted you are not geting data posted from a malicious script.(恶意脚本)

用表格的话用wp_nonce_field增加安全。

add_meta_box函数详解

Adds a meta box to one or more screens.

add_meta_box( string $id, string $title, callable $callback, string|array|WP_Screen $screen = null, string $context = ‘advanced’, string $priority = ‘default’, array $callback_args = null )

在各个屏幕当中添加自定义字段集合。 meta_box是所有字段的container.

参数详解:

$id

(string) (Required) Meta box ID (used in the ‘id’ attribute for the meta box).

$title

(string) (Required) Title of the meta box.

$callback

(callable) (Required) Function that fills the box with the desired content. The function should echo its output.

$screen

(string|array|WP_Screen) (Optional) The screen or screens on which to show the box (such as a post type, ‘link’, or ‘comment’). Accepts a single screen ID, WP_Screen object, or array of screen IDs. Default is the current screen. If you have used add_menu_page() or add_submenu_page() to create a new screen (and hence screen_id), make sure your menu slug conforms to the limits of sanitize_key() otherwise the ‘screen’ menu may not correctly render on your page.

Default value: null

$context

(string) (Optional) The context within the screen where the box should display. Available contexts vary from screen to screen. Post edit screen contexts include ‘normal’, ‘side’, and ‘advanced’. Comments screen contexts include ‘normal’ and ‘side’. Menus meta boxes (accordion sections) all use the ‘side’ context. Global

Default value: ‘advanced’

$priority

(string) (Optional) The priority within the context where the box should show. Accepts ‘high’, ‘core’, ‘default’, or ‘low’.

Default value: ‘default’

$callback_args

(array) (Optional) Data that should be set as the $args property of the box array (which is the second parameter passed to your callback).

Default value: null

wp怎样找到自定义类型的名字,也就是post_type?

点击相应的自定义类型,在Url栏里最后一个就是post_type的名字。

怎样找到分类等的id?你可以hover那个分类,会跳出来分类的id。

sublime的snippets只要点击tools:snippets就可以看到snippets的列表,右边是怎样唤出这个snippet的快捷键。