标签: WordPress插件开发

  • WordPress系列之钩子hook的作用及基本用法

    WordPress系列之钩子hook的作用及基本用法

    WordPress 的插件机制实际上只的就是这个 Hook 了,它中文被翻译成钩子,允许你参与 WordPress 核心的运行,是一个非常棒的东西,下面我们来详细了解一下它。

    钩子分类

    钩子分为两种,一种叫做动作(action),还有一种叫做过滤器(filter)。这两种钩子实现原理基本一样,后边会讲到,使用上的区别在于过滤器有返回值,而动作没有。

    动作的理念是让你在一种情况或者一个特别的位置执行一些函数,比如发送一封邮件等;过滤器则是让你修改 WordPress 核心需要用到的一个值,然后 WordPress 再用这些值做一些事情,比如函数的返回值等。

    动作钩子

    wp_head 是一个很常用的动作钩子,在开发主题过程中,开发者都会在 head 标签里加上 wp_head() 函数,事实上,正是这个函数调用了 wp_head 钩子。

    如果插件开发者想要在 head 标签里添加一句话,就可以使用 wp_head 钩子,下边是个简单的例子。

    //在 head 标签添加一些内容
    function Bing_add_head_tag(){
      echo '添加内容';
    }
    add_action( 'wp_head', 'Bing_add_head_tag' );

    添加代码后,查看前台的网页源代码,就能在 head 标签里看到我们添加的内容了。

    上边是一个简单的例子,只是打印了一句话。利用这个钩子,我们还可以做一个遇到 404 页面给管理员发送一封邮件的插件,下边简单的写了一个。

    //遇到 404 页面给管理员发送邮件
    function Bing_404_page_mail(){
      if( !is_404() ) return;//如果不是 404 页面就退出函数
      $to = get_option( 'admin_email' );//获取管理员地址
      $subject = '遇到 404 页面啦!';//邮件标题
      $message = '404 页面的地址:http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];//邮件内容
      wp_mail( $to, $subject, $message );//发送邮件
    }
    add_action( 'wp_head', 'Bing_404_page_mail' );

    过滤器钩子

    过滤器钩子可以让你改一些东西的值,过滤器回调函数会接受一个参数,这就是当前的值。还记得那个用来调用文章内容的 the_content() 函数吧,这个函数就提供了一个 the_content 过滤器。

    给 the_content 钩子添加一个函数,这个函数需要接收一个参数,这个参数就是当前的值。

    //文章内容全部链接新窗口打开
    function Bing_autoblank( $content ){//$content 变量就是文章内容,因为其它过滤器也要过滤,所以这个内容可能是经过其它函数过滤的
      $content = str_replace( '<a', '<a target="_blank"', $content );//添加 target="_blank"
      return $content;//必须要把过滤后的内容返回回去,否则值就丢了
    }
    add_filter( 'the_content', 'Bing_autoblank' );

    钩子原理

    事实上,在调用 add_action() 和 add_filter() 的时候,只是向 $wp_filter 全局变量添加了一个数组元素,还要说的就是动作和过滤器是公用的一个全局变量,也就是说,过滤器和动作是不能重名的。

    当调用 do_action() 的时候,会查找 $wp_filter 全局变量中都有哪些添加到此动作的函数,循环执行即可。

    apply_filters() 比 do_action() 多了一个步奏,就是每次调用函数时还要接收这个函数的返回值,最后把经过多次过滤的值返回出去,供使用。

    获取当前钩子列表
    WordPress 的动作和过滤器是插件机制的核心部分,允许你在特定的地方主动添加自己需要执行的动作,一般使用 add_action() 和 add_filter() 函数挂载函数。

    这些钩子被储存在 $wp_filter 全局变量里,所以,要获取钩子列表,可以直接获取 $wp_filter 全局变量。

    <?php var_dump( $GLOBALS['wp_filter'] ); ?>

    上边的代码会打印出钩子列表数组。

  • WordPress 如何获取文章发表用户ID

    WordPress 如何获取文章发表用户ID

    WordPress插件/主题开发中,如何获取文章发表用户的ID ?

    LOOP循环中

    官方文档:

    get_the_author_meta( string $field = '', int|false $user_id = false )

    Retrieves the requested data of the author of the current post.

    Description 

    Valid values for the $field parameter include:

    • admin_color
    • aim
    • comment_shortcuts
    • description
    • display_name
    • first_name
    • ID
    • jabber
    • last_name
    • nickname
    • plugins_last_view
    • plugins_per_page
    • rich_editing
    • syntax_highlighting
    • user_activation_key
    • user_description
    • user_email
    • user_firstname
    • user_lastname
    • user_level
    • user_login
    • user_nicename
    • user_pass
    • user_registered
    • user_status
    • user_url
    • yim

    Parameters

    $field

    (string) (Optional) The user field to retrieve.

    Default value: ”$user_id

    (int|false) (Optional) User ID.

    Default value: false

    Return

    (string) The author’s field from the current author’s DB object, otherwise an empty string.

    在循环外面通过以下方法获取用户ID

    $author_id = get_post_field ('post_author', get_the_ID() );
  • WordPress 插件开发 激活插件时添加通知 代码实例

    WordPress 插件开发 激活插件时添加通知 代码实例

    最近我们在重构WordPress采集插件WP-JPost,这里记录一下当我们激活插件时在面板中添加通知的方法。

    使用场景

    我们插件使用register_post_type方法来构建了自定义文章(wordpress使用register_post_type 函数创建自定义文章类型)后出现了404的错误。这里我们使用添加通知的方法来告知用户必须设置一下【固定链接】(WordPress 固定链接设置)才能正常使用。下面我们记录一下具体的实现方法。

    添加通知方法

    可以通过admin_notices的add_action来实现。

    		add_action( 'admin_notices', array( $this, 'jpost_notice' ) );

    实现方法函数

    做好输出工作即可。

    	public function jpost_notice(){
    		if( get_post_type() == $this->post_type )
    			printf('<div class="jads"></div>');
    		/* Check transient, if available display notice */
    		if (! get_option('permalink_structure') ){
    			printf('<div class="updated notice notice-warning is-dismissible">');
    			printf('<p>%s</p>', __( 'WP-JPost need Navigate to [ <strong>Dashboard</strong> ] -> [ <strong>Settings</strong> ] -> [ <strong>Permalink</strong> ] page -> click [ <strong>Save</strong> ] button to flush rewrite rules. [ <a href="https://www.jiloc.com/44235.html">?</a> ]') );
    			printf('</div>');
    			/* Delete transient, only display this notice once. */
    			// delete_transient( 'jpost-notice' );
    		}
    	}

    激活插件事件

    当没有设置固定链接的时候输出 jpost-notice 的通知。

    	static function active() {
    		if (! get_option('permalink_structure') )
    			set_transient( 'jpost-notice', true );
    		flush_rewrite_rules();
    	}

    全部代码

    //register activation function
    register_activation_hook( __FILE__, array( 'WP_JPost', 'active') );
    //register deactivation function
    register_deactivation_hook( __FILE__ , array( 'WP_JPost', 'deactive') );
    class WP_JPost {
    	protected $jpost_readme = 'https://www.jiloc.com/wp-jpost';
    	protected $post_type = 'wp-jpost';
    	protected $rewrite_slug = 'jpost';
    	/**
    	 * Constructor.
    	 */
    	public function __construct() {
                    add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
    		add_action( 'init', array( $this, 'register_post_type' ) );
    		// add_filter( 'post_type_link', array($this , 'custom_link' ), 1, 3);
    		add_filter( 'query_vars', array( $this, 'jpost_query_vars') );
    		add_filter( 'post_updated_messages', array( $this, 'updated_message' ) );
    		// add_action( 'admin_init',array($this,'register_setting_page'));
    		add_action( 'admin_menu', array( $this, 'add_meta_box' ) );
    		add_action( 'save_post', array( $this, 'meta_box_save' ), 1, 2 );
    		add_action( 'manage_wp-jpost_posts_custom_column', array( $this, 'columns_data' ) );
    		add_filter( 'manage_wp-jpost_posts_columns', array( $this, 'columns_filter' ) );
    		add_action( 'template_redirect', array( $this, 'jpost_grab' ) );
    		add_action( 'admin_notices', array( $this, 'jpost_notice' ) );
    	}
    	
    	public function custom_link( $permalink, $post ){
    		if ( $post->post_type == $this->post_type ){
    			return $permalink . ( strpos( $permalink ,'?' ) !== false ? '&' : '?') . 'jpage='.get_post_meta( get_the_ID(), '_jpost_task_list_max_page', true ) . '&debug=1';
    		} else {
    			return $permalink;
    		}
    	}
    	public function jpost_notice(){
    		if( get_post_type() == $this->post_type )
    			printf('<div class="jads"></div>');
    		/* Check transient, if available display notice */
    		if (! get_option('permalink_structure') ){
    			printf('<div class="updated notice notice-warning is-dismissible">');
    			printf('<p>%s</p>', __( 'WP-JPost need Navigate to [ <strong>Dashboard</strong> ] -> [ <strong>Settings</strong> ] -> [ <strong>Permalink</strong> ] page -> click [ <strong>Save</strong> ] button to flush rewrite rules. [ <a href="https://www.jiloc.com/44235.html">?</a> ]') );
    			printf('</div>');
    			/* Delete transient, only display this notice once. */
    			// delete_transient( 'jpost-notice' );
    		}
    	}
    	static function active() {
    		if (! get_option('permalink_structure') )
    			set_transient( 'jpost-notice', true );
    		flush_rewrite_rules();
    	}
    }
  • WordPress插件开发 register_post_type 设定菜单 位置 结合 add_submenu_page 添加自定义设置页面

    WordPress插件开发 register_post_type 设定菜单 位置 结合 add_submenu_page 添加自定义设置页面

    前面我们讲述了利用 register_post_type 进行注册了自定义的文章(wordpress使用register_post_type 函数创建自定义文章类型), 然后我们为这个自定义的文章添加了自定义的设置页面。要把菜单放在一个栏目中。如下图所示:

    下面我们直接给出示例代码。

    plugin.php 设置前后台使用不同的类

    require_once JPOST_DIR . '/includes/class-wp-jpost.php';
    new WP_JPost();
    if ( is_admin() ) {
    	require_once JPOST_DIR . '/includes/class-wp-jpost-settings.php';
    	new JPostSettings();
    }

    WP_JPost 类

    在 admin_menu 钩子中添加add_meta_box

     add_action( 'admin_menu', array( $this, 'add_meta_box' ) ); 

    add_meta_box 里添加菜单

    	public function add_meta_box() {
    		add_menu_page( 'wp_jpost', 'wp-jpost', 'administrator', 'wp-jpost', '', '', 100);
    		add_submenu_page('wp-jpost', __('Add New','wp-jpost'), __('Add New','wp-jpost'), 'administrator', 'post-new.php?post_type=wp-jpost', '' );
                    // do something
    	}

    注册自定义文章

    		register_post_type(
    			$slug,
    			array(
    				'labels'              => $labels,
    				'public'              => true,
    				'exclude_from_search' => apply_filters( 'jposts_exclude_from_search', true ),
    				'show_ui'             => true,
    				'query_var'           => true,
    				'menu_position'       => 999,
    				'supports'            => $supports_array,
    				'rewrite'             => array(
    					'slug'       => $rewrite_slug,
    					'with_front' => false,
    				),
    				'show_in_menu'	=>	'wp-jpost',
    				'show_in_rest'        => true,
    			)
    		);

    注意参数 show_in_menu 。这里设置显示的位置。

    JPostSettings 类中创建设置菜单

        public function __construct(){
            add_action( 'admin_menu', array( $this, 'settings' ) );
        }

    添加子菜单

        // Add Menu 
        public function settings(){
            add_submenu_page('wp-jpost', __('Settings','wp-jpost'), __('Settings','wp-jpost'), 'administrator', 'wp-jpost', array($this, 'create_admin_page'));
        }
    
        /**
         * Options page callback
         */
        public function create_admin_page(){
            // Set class property
            $this->options = get_option( '_jpost_setting' );
            settings_errors();//show settings messages.
            printf( '<div class="wrap"><h1>%s</h1><form method="post" action="options.php">',__('WP-JPost Settings','wp-jpost') );
            settings_fields( '_jpost_option_group' );
            do_settings_sections( '_jpost_settings' );
            submit_button();
            printf( '</form></div>' );
        }

    到这里我们的菜单就建立完成了。

  • WordPress函数:load_theme_textdomain()(载入本地化语言文件)

    WordPress函数:load_theme_textdomain()(载入本地化语言文件)

    WordPress 做一个多语言网站,或者让我们的主题支持多种语言,那么就可以使用load_theme_textdomain()函数来定义主题的语言路径,只要将语言放到该目录下面且命名正确,就可以生效。

    描述

    加载翻译后的主题文件语言包文件

    用法

    <?php load_theme_textdomain( $domain, $path ) ?>

    参数

    $domain
    (字符串)(必需)用以检索被翻译字符串的唯一标识符
    默认值: None
    $path
    (未知)(可选)语言包 .mo 文件所在的目录(没有结尾的斜线)
    默认值:false

    返回值

    (布尔)
    如果 textdomain 可以正常加载,返回 TRUE ;反之返回 FALSE

    实例

    load_theme_textdomain() 必须在?after_setup_theme?动作钩子后调用。
    在主题的functions.php中加入以下代码:

    add_action('after_setup_theme', 'wpdocs_theme_setup');
    /**
    * Load translations for wpdocs_theme
    */
    function wpdocs_theme_setup(){
        load_theme_textdomain('wpdocs_theme', get_template_directory() . '/languages');
    }

    以上例子,指明主题的语言目录位于该主题的 languages 文件夹。
    需要注意的是,WordPress主题语言包不像插件语言包,如果你将主题语言包命名为my_theme-zh_CN.mo ,它是没办法使用的。正确的命名方式是根据本地语言设置命名来命名,比如 zh_CN.mo
    如果主题页面中提供语言切换的功能,可通过http://youdomain/?lan=zh-CN的形式切换语言,则需要在functions.php中加入:

    // 必须在 load_theme_textdomain() 的前面调用
    add_filter( 'locale', 'my_theme_localized' );
    function my_theme_localized($locale) {
        if (isset($_GET['lan'])) {
            return $_GET['lan'];    
        }    
        return $locale;
    }
    load_theme_textdomain( 'my_theme', get_template_directory(). '/languages' );

    由于加载语言包会让你的网页加载速度变慢,如果你不想加载语言包,在functions.php中加入以下代码即可:

    add_filter( 'locale', 'wpjam_locale' );
    function wpjam_locale($locale) {
        $locale = ( is_admin() ) ? $locale : 'en_US';
    }

    让插件调用语言包需在插件的主文件中加入以下代码:

    add_action('plugins_loaded', 'plugin_languages_init');
    function plugin_languages_init(){
        load_plugin_textdomain( 'plugin', false,dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
    }

    需要注意的是,和主题语言包不同,插件语言包的一般命名包含两大部分:插件主文件名+语言及国别简码。如index-zh_CN.po和zh_CN.mo

    源文件

    load_theme_textdomain() 位于 wp-includes/l10n.php

    官方文档:http://codex.wordpress.org/Function_Reference/load_theme_textdomain

WeChat
↑