IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    给wordpress附件打个补丁,小议三则

    李惟发表于 2015-01-02 11:02:21
    love 0

    自补丁包0.2.6起,去除了新增的方法函数,而采取wordpress自带函数`get_attached_media`来获取文章附件,函数使用方法大家可以自行搜索,补丁说明见:http://levi.cg.am/wiki/wordpress-第三方补丁包/文章附件统计修复

    起初做这个研究之前是想了解“wordpress 设置默认特色图片”,这个问题我放后面说,先来看看之前我研究过的一个话题“wordpress统计附件不准确”的问题。

    修正wordpress附件统计不正确

    具体内容可以在这里查看:http://levi.cg.am/archives/3415,主要原因是因为wordpress为所有的post数据以parent_post方式进行统计的,而这个字段是数字型,如果有多篇文章使用同一个附件的时候怎么办呢?

    在之前就已给出了一个解决办法,这里我将其完善,先来看代码,如下:

    function save_post($post_id, $post)
    {
        global $wpdb;
        if (empty($_POST))
        {
            return ;
        }
    
        $data = array();
        $content = $post->post_content;
        if (stristr($content, '/wp-content/uploads/') &&
            preg_match_all('/(href|src)=[^>]+/wp-content/uploads/(sites/d+/)?([^"'>s]+)["'>s]/is', $content, $match))
        {
            $files = array_flip(array_flip($match[3]));
            $sql = "SELECT `post_id` FROM `%s` WHERE `meta_key`='_wp_attached_file' AND (`meta_value`='%s');";
            (FALSE != ($row = $wpdb->get_col(sprintf($sql, $wpdb->postmeta, implode("' OR `meta_value`='", $files))))) && $data = $row;
        }
    
        if (stristr($content, 'gallery') && preg_match_all('/[gallerys+ids=(["']?)([^"']]*)1s*]/is', $content, $gallery))
        {
            $where = array();
            $gallery = explode(',', implode(',', $gallery[2]));
            foreach ($gallery as $val)
            {
                $where[] = '`post_id`='.trim($val);
            }
    
            $sql = sprintf("SELECT `post_id` FROM `%s` WHERE `meta_key`='_wp_attached_file' AND (%s);", $wpdb->postmeta, implode(' OR ', $where));
            (FALSE != ($row = $wpdb->get_col($sql))) && $data = array_merge($data, $gallery);
        }
    
        if (FALSE != ($thumb_id = get_post_meta($post_id, '_thumbnail_id')))
        {
            $data[] = $thumb_id[0];
        }
    
        $data = apply_filters('wp_post_attach_total', $data, $post_id);
        if (!empty($data))
        {
            $data = array_flip(array_flip($data));
            update_post_meta($post_id, '_wp_post_attach_total_', implode(',', $data));
        }
        else
        {
            delete_post_meta($post_id, '_wp_post_attach_total_');
        }
    
        wp_cache_delete('attach_meda-'.$post_id, 'wp-plus');
    }
    
    function get_attached_from_post($post_id, $type = '', $must = false)
    {
        $key = sprintf('attach_meda-%d', $post_id);
        if (!$must && false != ($cache = wp_cache_get($key, 'wp-plus')))
        {
            return $cache;
        }
    
        if (false == ($meta = get_post_meta($post_id, '_wp_post_attach_total_', true)))
        {
            return array();
        }
    
        $arg = array(
            'include' => $meta,
            'post_type' => 'attachment',
            'post_mime_type' => $type,
            'posts_per_page' => -1,
            'orderby' => 'menu_order',
            'order' => 'ASC'
        );
    
        if (false == ($data = get_posts($arg)))
        {
            return array();
        }
    
        return wp_cache_set($key, $data, 'wp-plus', 900);
    }
    
    add_action('save_post', 'save_post', 100, 2);

    改进如下:

    1. 避免设置回收站时,重复操做文章,关于这个优化,详细可以看这里:http://levi.cg.am/archives/3842
    2. 图片和相册分别判断
    3. 增加一个查询数据的函数
    4. 增加缓存机制,缓存获取的数据,减少服务器压力

    这里说下查询函数,之前在文章中有提供一个查询附件统计的方法

    get_post_meta($post_id, '_wp_post_attach_total_');

    不过这个方法比较笨,获取到的是一个ID集合,例如:’342,345,44’;不便于实际操作。于是我增加了一个方法:get_attached_from_post,他接受3个参数:

    • $post_id:文章ID
    • $type:附件类型,默认为空(所有类型的附件),可以是:’image’, ‘audio’等
    • $must:是否强制获取数据,而不是从缓存获取,默认:false

    返回:获取的附件post对象数组集合

    顺带提下 get_posts 这个函数中的include, parent_post,在网站上搜索的资料中大多说包含的“ID”为文章ID,这是不正确的说法,源码中注释说明指的是 wp_posts 中的 ID字段

    关于wordpress缓存

    在这里在修正一个网上比较普遍的错误,wordpress中设置缓存函数包含有以下几个:wp_cache_add、wp_cache_set,这两个函数都包含一个参数:$expire,表示过期时间。

    在网上搜索下,基本千篇一律都是这么描述的:以秒为单位,默认为900秒。

    这是错的,不正确的,至少在现在的wordpress版本来看并非如此。wordpress缓存函数中$expire 默认为0,而并非900秒,这是其一;其二,wordpress默认的方法中参数 $expire 只是一个摆设,无任何实际用途,这是wordpress中的源码:

    public function set( $key, $data, $group = 'default', $expire = 0 ) {
        if ( empty( $group ) )
            $group = 'default';
    
        if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
            $key = $this->blog_prefix . $key;
    
        if ( is_object( $data ) )
            $data = clone $data;
    
        $this->cache[$group][$key] = $data;
        return true;
    }

    那为什么wordpress要增加一个“无意义的参数”?如果深入研究的话,你会发现其实也并非无用,在wordpress中有一类插件类型为“Drop-in”,通过wordpress提供的钩子机制代替默认的方法,比如我通过“Drop-in”使用 redis 作为我的缓存系统。具体方法就不多提了,这个以后有机会再详细说明,下面是相关代码:

    public function set( $key, $value, $group = 'default', $expiration = 0 ) {
        $derived_key = $this->build_key( $key, $group );
    
        // If group is a non-Redis group, save to internal cache, not Redis
        if ( in_array( $group, $this->no_redis_groups ) || ! $this->can_redis() ) {
            $this->add_to_internal_cache( $derived_key, $value );
    
            return true;
        }
    
        // Save to Redis
        $expiration = absint( $expiration );
        if ( $expiration ) {
            $result = $this->parse_predis_response( $this->redis->setex( $derived_key, $expiration, $this->prepare_value_for_redis( $value ) ) );
        } else {
            $result = $this->parse_predis_response( $this->redis->set( $derived_key, $this->prepare_value_for_redis( $value ) ) );
        }
    
        return $result;
    }

    设置文章默认的特色图片

    在网上搜索,也几乎千篇一律,代码如下:

    function autoset_featured()
    {
        global $post;
        $already_has_thumb = has_post_thumbnail($post->ID);
        if (!$already_has_thumb)
        {
            $attached_image = get_children( "post_parent=$post->ID&post;_type=attachment&post;_mime_type=image&numberposts;=1" );
            if ($attached_image)
            {
                foreach ($attached_image as $attachment_id => $attachment)
                {
                    set_post_thumbnail($post->ID, $attachment_id);
                }
            }
        }
    }  // end function
    
    add_action('the_post', 'autoset_featured');
    add_action('save_post', 'autoset_featured');
    add_action('draft_to_publish', 'autoset_featured');
    add_action('new_to_publish', 'autoset_featured');
    add_action('pending_to_publish', 'autoset_featured');
    add_action('future_to_publish', 'autoset_featured');

    那这个方法的确是可以行得通的。这里我补充下几个钩子说明:

    • the_post:当发表一篇新文章的时候会触发
    • save_post:当保存一篇文章的时候会触发

    后面的4个钩子都没有用,在当前的wordpress版本中找不到任何痕迹。在网上看到有人说“draft_to_publish”是在文章在草稿变为公布的时候触发的,也不知道那位开发者使用的是什么版本,还专门写了一篇“审核作者投稿通过后邮件通知”的函数。不过很遗憾,现在的wordpress中没有这个钩子了,上面代码中最后四个钩子都没有。

    那如何审核作者投稿呢,并邮件通知呢?我简单描述下,还是通过:transition_post_status,代码如下:

    function post_notify($new_status, $old_status, $post) {
        if (
                ($old_status == 'publish' && $new_status != 'publish' ) // post unpublished
                ||
                ($old_status != 'publish' && $new_status == 'publish') // post published
        )
        {
            // do it.....
        }
    }
    
    add_action('transition_post_status', 'post_notify', 10, 3);

    还是回到刚才那个话题,生成默认的特色图片,补充一点,上面有了6个钩子,当然4个是没用的;其实只要使用1个钩子:save_post,就足够了,没有必要占用资源。

    缩略图大小

    之前一朋友研究了好久,我这里将这个内容简单描述下,希望能够看得懂。

    wordpress缩略图有两种机制,分别为:

    • box-resize:盒子机制,等比缩放
    • hard-crop:裁剪机制

    这两个的区别靠最后一个参数来决定:

    set_post_thumbnail_size( 50, 50 );    // 盒子模式
    set_post_thumbnail_size( 50, 50, true );    // 裁剪模式

    不过这两个模式都存在一个问题,就是原图小于缩略图尺寸都不会被生成缩略图

    最后是添加缩略图尺寸,先来看代码:

    if (function_exists( 'add_image_size') && function_exists('add_image_size'))
    {
        add_theme_support('post-thumbnails');
        add_image_size('book-cover-big', 180, 236, true);
    }

    这段代码语义很简单,首先让wordpress支持缩略图,其次新增一个名叫:book-cover-big 的缩略图,方便之后调用;这个缩略图的尺寸为:180, 236,裁剪模式。

    那如何在首页调用这张缩略图呢?在前台,某一篇文章数据中放置下面代码即可

    the_post_thumbnail('book-cover-big');

    当然名字可以随意起,无所谓;你怎么起名,前台就这么调用。有一点很关键,缩略图的尺寸是严格按照设置的尺寸来的,居然有朋友在群里问了几个星期怎么获取缩略图尺寸。

    您可能也喜欢:
    wordpress第三方补丁包
    WordPress 修正:正确统计当前日志中所有的附件
    不得不说的9款WordPress SEO插件
    40个免费及收费的 WordPress 相册主题
    WordPress 简码插件 Shortcodes ultimate(终极简码)
    无觅


沪ICP备19023445号-2号
友情链接