wordpress指定自定义字段的相邻文章调用方法

这个博客,先从日贴变成月经贴,再到现在几个月不更新,已经算是严重”失调”了。 “失调”是种病,无论对男人亦或女人都是很不好的。

今天就分享一个项目中碰到的一个很特别的需求,以及我的解决方法。

客户的需求是这样的:
1.首页中显示的内容,要是精选的内容。
2.然后在内容页的时候,会有一个下一篇的链接,点击链接就要显示相同分类下的下一篇内容。

这样的需求没有什么太大的难度 。第一点需求很容易处理的,需求中要精选是吧,那可以使用post meta来记录哪些内容是精选的,比如这里,我使用featured来做这个post_meta的key(关于要怎么给文章添加post_meta, 并不在这篇文章的讨论范围)。

然后再使用pre_get_posts这个常用的filter来处理:

add_filter('pre_get_posts', 'mk_pre_get_posts');
function mk_pre_get_posts($query){
	if( $query->is_main_query() && is_home() ){
		$wp_query->set('meta_key','featured');
		$wp_query->set('meta_value','1');
	}
	return $query;
}

就这样,首页就只显示精选的文章了。

再来看第二条,这里客户的需求就有点变态了,首页点进去的文章,那么在内容页的时候,要做一个显示下一篇的链接。这个下一篇的链接就是要看用户是从哪里点进去了,分类页的那好办,直接使用使用 get_previous_post()函数我们可以得到和当前文章相邻的文章。 但是变态的地方在首页点进去,首页点进去的内容页,那显示的下一篇要精选中的内容。这个精选的内容有可能来自不同的分类 的。所以再使用默认的get_previous_post()函数很明显就不能实现了。

get_previous_post()的代码,找到了一些有用的filter, 既然要记录用户是从首页点进来 的,那只能使用cookie了, 所以我在index.php文件开着的时候,先定义一个cookie

setcookie('source','homepage');

然后再看我修改的filter的代码:

add_filter("get_previous_post_join", "mk_get_previous_post_join", 10, 3);
function mk_get_previous_post_join($sql, $in_same_term, $excluded_terms){
	global $source, $wpdb;
	if($source == 'homepage'){
		$sql = $sql . ' INNER JOIN wp_postmeta AS mt ON p.ID = mt.post_id ';
		
	}
	return $sql;
}



add_filter("get_previous_post_where", "mk_get_previous_post_where", 10, 3);
function mk_get_previous_post_where($sql, $in_same_term, $excluded_terms){
	global $source;
	if($source == 'homepage'){
		$sql = $sql . ' AND mt.meta_key = "featured" ';
	}
	return $sql;
}

明白点SQL的人一看就明白,我是先判断是不是首页进来的,如果是,那就在sql中把post_meta数表也加入来,然后再筛选出所有设置meta_key为 featured的文章ID.

到这里,客户的变态需求已经解决了。 而且这种解决方法,依然使用了wp官方的缓存,并没有破坏wordpress的缓存机制。

ubuntu下为wordpress安装memcache

memcache对wordpress速度的提升我想这里我已经不用再解释了。 想要安装一个memcache,但是会有一大堆的教程跟你解释什么叫memcache或memcached. 这里没有太多的解释,只教你如何安装上memcache. 作为 一个wordpress程序员,我只想让memcache实现网站秒开。

我这里的服务器系统ubuntu. 其它系统的也基本雷同。

sudo apt-get install memcached && sudo apt-get install php5-memcache && sudo apt-get install php5-memcached

安装成功之后 ,memcache的配置文件在memcached.conf
memcached这里有几个常用命令:

sudo service memcached restart
sudo service memcached start
sudo service memcached stop

 

在内容页中的body_class中添加入当前内容分类的class

如果标题,wordress开发开发的时候,也许为了做一些模板上的多样性,经常会要在内容页中添加一些当前内容专有的东西,比如这篇帖子要说到的以body_class中添加入当前的分类的class。

如果是默认的分类类型(category),那就可以使用下面的方法。

add_filter('body_class','add_category_to_single');
function add_category_to_single($classes, $class) {
        if (is_single() ) {
                global $post;
                foreach((get_the_category($post->ID)) as $category) {
                        $classes[] = 'sgl-cat-'.$category->category_nicename;
                }
        }
        return $classes;
}

但是如果不是系统默认的分类,那就可以变通 一下:

add_filter('body_class','add_category_to_single');
function add_category_to_single($classes, $class) {
        if (is_single() ) {
                global $post;
                foreach((get_the_terms($post->ID, '分类名称')) as $category) {
                        $classes[] = 'sgl-cat-'.$category->category_nicename;
                }
        }
        return $classes;
}

注意,使用的时候,要把代码中折分类名称替换成你要使用的分类名称。

参考资料:
http://wpsnipp.com/index.php/cat/add-post-category-body_class-single-posts/

WordPress最好的缓存函数

wp一直被人说速度不行。其实我看很多wp网站都是因为没有做好优化。我总觉得这主要是因为wp门槛太低了,所以只要知道一点点编程知识的人都可以做出很好看的主题 ,但是能用并代表用好,大部分wp网站速度跟不上,是因为没有做好优化。 比如应该缓存的数据没有做缓存,造成非常大的服务器压力。

以下是我根据公司项目中优化过的缓存函数,

if(!function_exists('wpjam_query_cache')){
	function wpjam_query_cache($args=array(), $key = '',$cache_time='600'){
		$cache_key = empty($key) ? 'wpjam_query'.md5(serialize($args)): $key;
		$wpjam_query = get_transient($cache_key);
		if($wpjam_query === false){
			$wpjam_query = new WP_Query($args);
			set_transient($cache_key, $wpjam_query, $cache_time);
		}
		return $wpjam_query;
	}
}

if(!function_exists('wpjam_comment_query_cache')){
	function wpjam_comment_query_cache($args=array(), $key = '',$cache_time='600'){
		$cache_key = empty($key) ? 'wpjam_query'.md5(serialize($args)): $key;
		$wpjam_query = get_transient($cache_key);
		if($wpjam_query === false){
			$comments_query = new WP_Comment_Query;
			$wpjam_query = $comments_query->query( $args );
			set_transient($cache_key, $wpjam_query, $cache_time);
		}
		return $wpjam_query;
	}
}

排除worpdress目录分类中的指定分类

worpdress默认边栏中会有一个叫目录分类的小工具(widget), 启用这个widget就会默认地显示出所有内容不为空的目录分类。可以说官方已经做得非常的人性化了。 但是实际项目的需求总是多变的。 比如用户会要指定显示某几个目录分类,或是不显示其中某几个目录分类。 这里有几行代码可以让你轻松实现。

老样子,直接把下面的几行代码粘贴到当前主题 的functions.php文件中即可:

add_filter( 'widget_categories_args', 'mk_exclude_widget_category', 10, 1 );
function mk_exclude_widget_category( $cat_args ) {
	$cat_args['exclude'] = array(18,19,20,21,22);	
	return $cat_args;
}

注意代码中的数组中的数值为要排除的目录分类的ID。
参考资料:http://wpsites.net/wordpress-tips/exclude-specific-categories-from-native-wordpress-category-widget/

wordpress 3.5 多媒体上传工具

wordpress 3.5之后 ,多媒体上传工具已经有了新的改变。但是同样的如果想要在自定义meta box中调用已经有了一些新的改变,

这里我写了一个相对比较简洁的js代码了:

jQuery(function($){
    $('body').on('click', '.mu_mediauploader', function(e) {
    	var custom_uploader;
    	var obj = $(this);
 		var ids = new Array();
        e.preventDefault();
        if (custom_uploader) {
            custom_uploader.open();
            return;
        }
        custom_uploader = wp.media.frames.file_frame = wp.media({
            title: 'Choose Image',
            button: {
                text: 'Choose Image'
            },
            multiple: true
        }).on('select', function() {
            var selection = custom_uploader.state().get('selection');
		    selection.map( function( data ) {
		      data = data.toJSON();
		      ids.push(data.id);
		    });
		    response = ids.join(",");
		    obj.prev().val(response);
        }).open();

    });	
});

自定义页面模板添加自定义的class

自定义页面模板添加自定义的class

wordpress开发的时候,经常会在某个自定义页面模板添加自定义的class到页面中,以达到自定义css的效果,这时候下面的这一个函数就会起到很大作用, 比如我主题中有一个news.php模板文件,我想为这个文件生成 的页面添加一个叫news的class, 这时可以使用下面的代码了:

add_filter('body_class', 'add_archive_classes_to_page_templates');
function add_archive_classes_to_page_templates($classes) {
	if (is_page_template('news.php')) {
		$classes[] = 'news';
	}
	return $classes;
}

参考资料:http://wpsnipp.com/index.php/functions-php/add-body_class-page-templates-wordpress/

主题激活时创建自定义数据表

上一篇帖子中写到了如何在插件激活的时候,自动触发自定义数据表函数。但是很多时候我们并不需要安装一个插件,这时候那要就考虑主题激活的过程中触发 自定义数据表函数了。

wordpress中还有一个钩子 after_switch_theme. 可以在主题安装过程是实现这个功能。 代码如下:

add_action('after_switch_theme', 'create_custom_db' );
function create_custom_db(){
	global $wpdb;
	$table_name = $wpdb->prefix.'test'
	$sql = "CREATE TABLE  $table_name (
			`ID` INT NOT NULL ,
			`name` VARCHAR( 64 ) NOT NULL
			) ENGINE = MYISAM ;";

	require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
	dbDelta( $sql );
}

wordpress为插件创建自定义数据表

wordpress开发的时候,经常需要创建一些默认之外的数据表,在wordpress中其实可以使用register_activation_hook函数在插件激活的时候就自动创建好数据表,并写入一定的数据。

代码如下:

global $custom_table_example_db_version;
$custom_table_example_db_version = '1.1'; //从1.0版本更新到1.1版本

/**
 * register_activation_hook 实现
 *
 * 第一次激活插件的时候将会执行
 * 创建必需的数据表
 */
function custom_table_example_install()
{
    global $wpdb;
    global $custom_table_example_db_version;

    $table_name = $wpdb->prefix . 'cte'; // do not forget about tables prefix

    // 创建数据表的sql
    // 注意:
    // 1. 每个字段必须分行
    // 2. 主键和主键名之间必须要有两个空格距离
    //    比如这样: PRIMARY KEY[空隔][空隔](id)
    // otherwise dbDelta will not work
    $sql = "CREATE TABLE " . $table_name . " (
      id int(11) NOT NULL AUTO_INCREMENT,
      name tinytext NOT NULL,
      email VARCHAR(100) NOT NULL,
      age int(11) NULL,
      PRIMARY KEY  (id)
    );";

    // 我们不直接执行sql语法
    // we are calling dbDelta which cant migrate database
    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql);

    // 保存当前数据表的版本号,方便日后升级更新
    add_option('custom_table_example_db_version', $custom_table_example_db_version);

}

register_activation_hook(__FILE__, 'custom_table_example_install');

获取wordpress meta的ID

wordpress开发中要根据post id取回meta的值是很方便的,可以使用wordpress的内置的函数, get_post_meta, get_postmeta等等, 但是要根据wordpress的post id 和meta的key取回这个meta的id,那就可以使用下面的函数实现:

function get_mid_by_key( $post_id, $meta_key ) {
  global $wpdb;
  $mid = $wpdb->get_var( $wpdb->prepare("SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s", $post_id, $meta_key) );
  if( $mid != '' )
    return (int)$mid;

  return false;
}

上面 的函数只是返回了单一的meta的id, 但是如果有很多个meta具有相同的key的时候,那就要对函数进行一些修改了,我把函数修改成下面的样子,就可以可以返回一个meta id的数组了。

function get_mids_by_key( $post_id, $meta_key ) {
    global $wpdb;
    $mids_obj = $wpdb->get_results( $wpdb->prepare(
        "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s", $post_id, $meta_key));
    $mids = array();
    foreach ($mids_obj as $mid) {
        $mids[] = $mid->meta_id;
    }
    if(empty($mids)){
        return false;
    }else{
        return $mids;
    }
}

参考资料:http://wpseek.com/blog/2010/how-to-get-the-meta-id-by-meta-key/80/