1 of 81

WordPress Plugin #3

Mar. 2nd, 2017

changwoo

2 of 81

Recap

Hooks in Nutshell

  • Hook is an event
  • Plugin is hook-driven
  • Task separation
    • Changing core's workflow: action
    • Modifying contents: filter
    • In fact, action and filter are the same

3 of 81

Recap

Hooks in Nutshell

  • Callback function utility
  • You can define your own hooks
  • There are many predefined hooks

4 of 81

Recap

Database Nutshell

  • Parent-meta strategy
    • Flexibility
    • Extendibility
    • But can experience some defects�
  • Meta key, meta-value
    • Hash-like storage

5 of 81

Recap

Database Nutshell

  • Term, taxonomy
    • Term: a word
    • Taxonomy: a classification of words�
  • There are some pre-defined terms, and taxonomies
    • category (hierarchical), post_tag (flat)

6 of 81

Recap

7 of 81

Note: Slides Repository

8 of 81

Today's Topics

  1. Entry Points in Plugin
    1. Menu
    2. Shortcodes
    3. Admin Post
    4. Ajax
    5. Redirect
    6. activation, deactivation, un-install�
  2. Managing Your Own Contents
    • All About Custom Posts

9 of 81

Entry Points in Plugin

10 of 81

Entry Points

Plugins run on the server side.

Server only responds when it is requested.

Requested moment → entry point

11 of 81

Entry Points

Q. When the server is requested?

A. It is when clients access via a URL.

Q. Why a URL is used?

A. To define a resource: output to clients

A. To receive data: input from clients

12 of 81

Entry Points

Q. Output form?

A. Whatever.

Images, audio, video, html documents, ...

Q. Input form?

A. Generally submitting forms

via GET/POST method.

13 of 81

Entry Points

There are some special entry points for plugins�

  • Menu items
  • Shortcodes
  • Admin post
  • AJAX
  • Redirecting
  • Activation, deactivation, un-install

14 of 81

Menu Items

Callback from admin menu clicking

add_menu_page()

add_submenu_page()

remove_menu_page()

remove_submenu_page()

15 of 81

Where is default menu?

wp-admin/menu-header.php

<ul id="adminmenu">

<?php

_wp_menu_output( $menu, $submenu );

function _wp_menu_output( $menu, $submenu, $submenu_as_parent = true )

here menus are printed in html

16 of 81

Where is default menu?

wp-admin/menu.php (admin.php includes it)

wp-admin/includes/menu.php

builds administrative menus

global $menu, $submenu stores menu information

17 of 81

Our custom menus

wp-admin/includes/menu.php

do_action( 'admin_menu', '' );

Menu API are defined in wp-admin/includes/plugin.php

18 of 81

add_menu_page

function add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '', $position = null ) {

...

$new_menu = array( $menu_title, $capability, $menu_slug, $page_title, 'menu-top ' . $icon_class . $hookname, $hookname, $icon_url );

if ( null === $position )

$menu[] = $new_menu;

else

$menu[$position] = $new_menu;

19 of 81

add_submenu_page

function add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {

...

$submenu[$parent_slug][] = array (

$menu_title, $capability, $menu_slug, $page_title );

...

}

20 of 81

derivatives

21 of 81

Shortcodes

What is shortcode?

A "magic word" in post content that is replaced by some process defined in plugin or themes in runtime.

Good for displaying complex, dynamic contents

22 of 81

Shortcodes

Sample:

[gallery id="123" size="medium"]

[gallery]

or

[caption]My Caption[/caption] *enclosed form

23 of 81

Shortcodes

add_shortcode()

$shortcode_tags = array();

function add_shortcode($tag, $func) {

global $shortcode_tags;

if ( is_callable($func) )

$shortcode_tags[$tag] = $func;

}

24 of 81

Shortcodes

function do_shortcode($content) {

global $shortcode_tags;

if ( false === strpos( $content, '[' ) ) {

return $content;

}

if (empty($shortcode_tags) || !is_array($shortcode_tags))

return $content;

$pattern = get_shortcode_regex();

return preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $content );

}

25 of 81

Shortcodes

function do_shortcode_tag( $m ) {

...

$content = isset( $m[5] ) ? $m[5] : null;

$output = $m[1] . call_user_func( $shortcode_tags[ $tag ], $attr, $content, $tag ) . $m[6];

...

}

26 of 81

Shortcodes

callback params

  • $attrs: attributes
  • $content: text of enclosed tag
  • $tag: shortcode tag itself

27 of 81

Admin-post

Data from clients.

Processing requests.

You can just process requests in your own page because $_REQUEST, $_GET, $_POST is global.

28 of 81

Admin-post

But in your own handler,

You cannot use WP core functions.

You cannot authenticate.

Do not reinvent the wheel!

So there is admin-post.php

29 of 81

Admin-post

wp-admin/admin-post.php

define & include minimal settings,

and do_action

$action = empty( $_REQUEST['action'] ) ? '' : $_REQUEST['action'];

admin_post_nopriv, admin_post_nopriv_{$action}

admin_post, admin_post_{$action}

finish using die() in callback function!

30 of 81

AJAX

Very similar to admin-post, but 'DOING_AJAX' is defined:

define( 'DOING_AJAX', true );

also use die() in callback function

if ( is_user_logged_in() ) {

do_action( 'wp_ajax_' . $_REQUEST['action'] );

} else {

do_action( 'wp_ajax_nopriv_' . $_REQUEST['action'] );

}

// Default status

die( '0' );

31 of 81

Redirect

You can generate custom page in plugin, by using 'template_redirect' action.

function my_page_template_redirect() {

if( is_page( 'goodies' ) && ! is_user_logged_in() ) {

wp_redirect( home_url( '/signup/' ) );

exit();

}

}

add_action( 'template_redirect', 'my_page_template_redirect' );

32 of 81

Redirect

You can generate web pages on-the-fly by utilizing these 3 hooks.

  • rewrite rule
  • query parsing
  • redirect

Detailed instructions, later

33 of 81

(de)activation, uninstall

register_activation_hook($file, $cb)

register_deactivation_hook($file, $cb)

register_uninstall_hook($file, $cb)

$file: full path of plugin file

$cb: callback function

  • callbacks should be "SILENT". No echo please.

34 of 81

Summary

  • menu items, shortcodes, admin post, ajax, template redirects, and (de)activation- uninstall hooks are good initial entry points.
    • It is a good strategy to find these hooks in plugins first and dissect their codes from those points.

35 of 81

I know you want to do something!

You understand hook concept.

You know database detail.

Now you know entry points

Definitely, you wanna make something.

36 of 81

Visit http://[ip]/03-entry-point/ and download entry-points.php

37 of 81

Source code explained

소스코드:

  1. 어드민 화면에 메뉴 추가
  2. 쇼트코드 추가
  3. 메뉴에서 admin post 전송
  4. 메뉴에서 ajax 전송
  5. redirect 테스트

<author> 부분은 자신의 이름으로 일괄변경하고,

적절히 콜백 함수를 정의해 주세요.

38 of 81

10 minutes break

39 of 81

Managing Your Own Contents

40 of 81

Wow, there are too many things about posts!

41 of 81

For today, just focus on

"custom post type"

42 of 81

Arguments are too complex!

Just use Types, or Pods plugin.

That's all, problem solved!

Yeah!

43 of 81

... of course, you might not want this.

44 of 81

Custom Post

You want to manage your own contents.

That's why custom post type is.

  • Music collections
  • Online store
  • Event calendar
  • Book data
  • Photo portfolio

45 of 81

Custom Post: Motivation

Well, with just one type "post", and you may define many categories and use them to organize all contents.

JUST ONE TYPE: POST

MANY CATEGORIES:

portfolio, calendar, music db, ...

46 of 81

Custom Post: Motivation

But you might feel that some post types:

  • should be hidden from some users
  • even might be excluded from search
  • may be only for private use
  • may have very complex taxonomies�so that it should have its own territory.
  • can be accessible from their own URL rules

47 of 81

Custom Post: Motivation

Moreover, "category" is just for classification of your posts. It is only related to its contents.

Not for ACL or administrative management facilities: categories must be de-coupled from those "heavy" burdens

48 of 81

Custom Post: Motivation

Why re-invent wheel again?

By extending built-in post type system,

you can REUSE whole facilities related to posts easily!

UI, and all thing about managing

49 of 81

Built-in Custom Post Types

wp-includes/post.php (included in wp-settings.php)

function create_initial_post_types() {

register_post_type( 'post', array( ...

register_post_type( 'page', array( ...

register_post_type( 'attachment', array( ...

register_post_type( 'revision', array( ...

register_post_type( 'nav_menu_item', array( ...

register_post_status( 'publish', array( ...

...

50 of 81

register_post_type

<?php register_post_type( $post_type, $args ); ?>

$arg is very complex.

But I think it should be explained in detail. Actually, you cannot avoid it, because eventually all post type plugins will use that function, too.

Those plugins also have difficult UIs, too.

51 of 81

register_post_type

Let's take a look how Types, and Pods create their custom posts...

They have easy (really?) UI and provide better functionality, but you can see horribly many options there.

52 of 81

register_post_type $post_type

  • Up to 20 characters
  • Only lowercase and numbers

53 of 81

$args:everything is optional

  • label
  • labels (array)
  • description
  • public
  • exclude_from_search
  • publicly_queryable
  • show_ui
  • show_in_nav_menus
  • show_in_menu
  • show_in_admin_bar
  • menu_postion
  • menu_icon
  • capability_type
  • capabilites (array)
  • map_meta_cap
  • hierarchical
  • supports (array)
  • register_meta_box_cb
  • taxonomies (array)
  • has_archive
  • permalink_epmask
  • rewrite (array)
  • query_var
  • can_export

Total 24+

54 of 81

$args: categorize'em

  • Exposure
  • Visual Cue
  • Resource Location Management
  • Access Control
  • Content Characteristics
  • Etc

55 of 81

$args: categorize'em

  • Exposure
    • interface exposure
  • Visual Cue
    • if visible, then how?
  • Resource Location Management
    • accessing
  • Access Control
    • permission
  • Content Characteristics
  • Etc

56 of 81

$args: categorize'em

Exposure: interface exposure

public: TRUE

  • exclude from search: FALSE
  • publicly_queryable: TRUE
  • show_in_nav_menus: TRUE
  • show_ui: TRUE
    • show_in_menu: TRUE (show_ui must be true)
      • show_in_admin_bar: TRUE

57 of 81

$args: categorize'em

Exposure: interface exposure

public: FALSE

  • exclude from search: TRUE
  • publicly_queryable: FALSE
  • show_in_nav_menus: FALSE
  • show_ui: FALSE
    • show_in_menu: FALSE
      • show_in_admin_bar: FALSE

58 of 81

$args: categorize'em

Visual Queue: if visible, then how?

  • label
  • labels (array)
  • menu_postion
  • menu_icon

59 of 81

$args: categorize'em

Resource Location: accessing

  • permalink_epmask
  • rewrite (array)
  • query_var

60 of 81

$args: categorize'em

Access Control: permission

  • capability_type
  • capabilities (array)
  • map_meta_cap

61 of 81

$args: categorize'em

Content Characteristics:

  • hierarchical
  • supports (array)
  • register_meta_box_cb
  • taxonomies (array)
  • has_archive

62 of 81

$args: categorize'em

ETC:

  • description
  • can_export

63 of 81

register_post_type $args

public:

visible to authors�

true implies

exclude_from_search: false,

publicly_queryable, show_in_nav_manues, show_ui�

false implies

exclude_from_search: true, publicly_queryable: false,

show_in_nav_manues: false, show_ui: false

64 of 81

register_post_type $args

exclude_from_search:

do not search this post type

try '/s=beatles'

65 of 81

register_post_type $args

publicly_queryable:

can use query

e.g) /?post_type=music_collection

66 of 81

register_post_type $args

show_ui:

display default UI

67 of 81

register_post_type $args

show_in_nav_menus:

show in navigation menus

be careful! 'publicly_queryable'

must be true

68 of 81

register_post_type $args

show_in_menu:

show admin_menu. show_ui must be true.

Just showing menu.

true, false, else some strings

(tools.php / edit.php)

although it is false,

you can access URLS like:

/wp-admin/edit.php?post_type=music_collection

(show_ui must be true!)

69 of 81

register_post_type $args

show_in_admin_bar:

available in admin bar

70 of 81

register_post_type $args

label:

plural descriptive name

e.g: __(Music Collections, textdomain)

menu_postion:

default: below comments

menu_icon

see dashicons

71 of 81

register_post_type $args

permalink_epmask:

rewrite endpoint bitmask

query_var:

to query posts /?{query_var}={slug}

rewrite:

to use pretty permalinks.

72 of 81

register_post_type $args

labels: more specific text labels

name

sigular_name

menu_name

name_admin_bar

all_items

add_new

add_new_item

edit_item

view_item

search_items

search_items

not_found

not_found in trash

parent_item_colon

73 of 81

register_post_type $args

capability_type:

string or array to build capabilities

in our example,

edit_music_collections

edit_others_music_collections

publish_music_collections

read_private_music_collections

74 of 81

register_post_type $args

capabilities:

to give specific names to each capability

map_meta_cap:

if true, default meta capability will be added

and then, your role or account need capabilities

75 of 81

register_post_type $args

hierarchical:

post type can be hierarchical.

this is for page-styles.

supports:

editable components

76 of 81

register_post_type $args

register_meta_box_cb: meta box

taxonomies:

has_archive:

Enables post type archive

77 of 81

register_post_type $args

description:

summary of this post type

can_export:

true makes the post can be exported

78 of 81

Too exhaustive... but worth it.

79 of 81

Practice Custom Post

Create custom-post-<author>.php

Create a simple custom post.

Display admin menu,

Hide admin_bar,

Write your post:

  • Any content is OK.
  • Include at least one meta field.

80 of 81

Next Week.

Customizing Visual Components

  • List Table Screen
  • Widgets
  • ...

Underneath WordPress System

  • Constants and Globals
  • WPDB

81 of 81

Appendix