如何使用 Masonry 在 WordPress 中添加 Pinterest 风格的帖子网格


这是 Josh Pollock 的客座帖子

一段时间以来,类似 Pinterest 的帖子网格显示一直是 WordPress 博客索引页面的流行设计。它之所以受欢迎,不仅因为它模仿流行社交媒体网站的外观,还因为它充分利用了屏幕上的空间。在 WordPress 博客索引上,它允许每个帖子预览达到其自然需要的大小,而无需留下额外的空间。

在本教程中,我将向您展示如何使用流行的 Masonry JavaScript 库为您的博客索引创建级联网格布局,以及为您的主题创建存档页面。我将讨论移动优化时需要考虑的一些问题以及如何解决这些问题。

注意:这是一个高级教程,适合那些能够轻松编辑 WordPress 主题并具有足够 HTML/CSS 知识的人。

第 1 步:为您的主题添加必要的库

更新:WordPress 3.9 现在包含最新版本的 Masonry。

首先,您需要使用以下代码将 Masonry 加载到主题中:

if (! function_exists('slug_scripts_masonry') ) :
if ( ! is_admin() ) :
function slug_scripts_masonry() {
    wp_enqueue_script('masonry');
    wp_enqueue_style('masonry’, get_template_directory_uri().'/css/’);
}
add_action( 'wp_enqueue_scripts', 'slug_scripts_masonry' );
endif; //! is_admin()
endif; //! slug_scripts_masonry exists

此代码只是加载砌体并使其可用于主题的模板文件(请参阅我们有关如何在 WordPress 中正确添加 JavaScript 和样式的指南)。另请注意,我们没有添加 jQuery 作为其中任何一个的依赖项。 Masonry 3 的优点之一是它不需要 jQuery,但可以与它一起使用。根据我的经验,在没有 jQuery 的情况下初始化 Masonry 更可靠,并且提供了跳过加载 jQuery 的可能性,这有助于解决页面加载时间和兼容性问题。

第 2 步:初始化 Javascript

下一个函数设置 Masonry,定义将与其一起使用的容器,并确保一切都按正确的顺序发生。 Masonry 需要计算页面上每个项目的大小,以便动态布局其网格。我在许多浏览器中使用 Masonry 时遇到的一个问题是,Masonry 会错误计算加载图像缓慢的项目的高度,从而导致项目重叠。解决方案是使用 imagesLoaded 来阻止 Masonry 在加载所有图像之前计算布局。这确保了正确的尺寸。

这是将在页脚中输出初始化脚本的函数和操作:

if ( ! function_exists( 'slug_masonry_init' )) :
function slug_masonry_init() { ?>
<script>
    //set the container that Masonry will be inside of in a var
    var container = document.querySelector('#masonry-loop');
    //create empty var msnry
    var msnry;
    // initialize Masonry after all images have loaded
    imagesLoaded( container, function() {
        msnry = new Masonry( container, {
            itemSelector: '.masonry-entry'
        });
    });
</script>
<?php }
//add to wp_footer
add_action( 'wp_footer', 'slug_masonry_init' );
endif; // ! slug_masonry_init exists

该函数通过内联注释逐步解释。 Javascript 函数的作用是告诉 Masonry 在 id 为“masonry-loop”的容器内查找具有“masonry-entry”类的项目,并仅在加载图像后计算网格。我们使用 querySelector 设置外部容器,使用 itemSelector 设置内部容器。

第 2 步:创建砌体循环

我们将为其创建一个单独的模板部分,而不是将 Masonry 的 HTML 标记直接添加到模板中。创建一个名为“content-masonry.php”的新文件并将其添加到您的主题中。这将允许您将 Masonry 循环添加到任意数量的不同模板中。

在您的新文件中,您将添加如下所示的代码。标记与您通常在任何内容预览中看到的标记类似。您可以根据需要任意修改它,只需确保最外层元素具有我们在上一步中设置为 itemSelector 的“masonry-entry”类即可。

<article class="masonry-entry" id="post-<?php the_ID(); ?>" <?php post_class(); ?> >
<?php if ( has_post_thumbnail() ) : ?>
    <div class="masonry-thumbnail">
        <a href="<?php the_permalink(' ') ?>" title="<?php the_title(); ?>"><?php the_post_thumbnail('masonry-thumb'); ?></a>
    </div><!--.masonry-thumbnail-->
<?php endif; ?>
    <div class="masonry-details">
        <h5><a href="<?php the_permalink(' ') ?>" title="<?php the_title(); ?>"><span class="masonry-post-title"> <?php the_title(); ?></span></a></h5>
        <div class="masonry-post-excerpt">
            <?php the_excerpt(); ?>
        </div><!--.masonry-post-excerpt-->
    </div><!--/.masonry-entry-details -->  
</article><!--/.masonry-entry-->

该标记的每个部分都有类,因此您可以添加标记以匹配您的主题。我喜欢为 .masonry-entry 添加一个漂亮的、略圆的边框。另一个不错的选择是 .masonry-entry 没有边框,但给它一个轻微的阴影。当帖子缩略图一直延伸到容器的边界时,这看起来特别好,这可以通过在所有方向上将 .masonry-thumbnail 边距和填充设置为 0 来实现。您需要将所有这些样式添加到主题 css 目录中名为 masonry.css 的文件中。

第 3 步:将砌体循环添加到模板

现在我们有了模板部分,您可以在您喜欢的主题中的任何模板中使用它。如果您不希望将其用于类别档案,您可以将其添加到index.php,但不要添加到category.php。如果您只想在主题的主页上使用它,当它设置为显示博客文章时,您可以在 home.php 中使用它。无论您选择何处,您需要做的就是将循环包装在 ID 为“masonry-loop”的容器中,并使用 get_template_part() 将模板部分添加到循环中。确保在 while (have_posts() ) 之前启动砌体循环容器。

例如,以下是二十三的 index.php 的主循环:

<?php if ( have_posts() ) : ?>

    <?php /* The loop */ ?>
    <?php while ( have_posts() ) : the_post(); ?>
        <?php get_template_part( 'content', get_post_format() ); ?>
    <?php endwhile; ?>

    <?php twentythirteen_paging_nav(); ?>

<?php else : ?>
    <?php get_template_part( 'content', 'none' ); ?>
<?php endif; ?>

这里对其进行了修改以使用我们的 Masonry 循环:

<?php if ( have_posts() ) : ?>
<div id="masonry-loop">
    <?php /* The loop */ ?>
    <?php while ( have_posts() ) : the_post(); ?>
        <?php get_template_part( 'content', 'masonry' ?>
    <?php endwhile; ?>
</div><!--/#masonry-loop-->
    <?php twentythirteen_paging_nav(); ?>

<?php else : ?>
    <?php get_template_part( 'content', 'none' ); ?>
<?php endif; ?>

步骤 4:设置砌体项目的响应宽度

有多种方法可以设置每个 Masonry 项目的宽度。初始化 Masonry 时,您可以使用多个像素设置宽度。我不喜欢这样做,因为我使用响应式主题,并且它需要一些复杂的媒体查询才能在小屏幕上得到正确的结果。对于响应式设计,我发现最好的做法是根据您想要连续显示的项目数量,为 .masonry-entry 设置一个百分比宽度值,然后让 Masonry 为您完成其余的数学计算。

所有这一切都需要将 100 除以您想要在主题的 style.css 的简单条目中设置百分比的项目数量。例如,如果您希望每行有四个项目,您可以在 masonry.css 文件中执行此操作:

.masonry-entry{width:25%}

第五步:移动优化

我们可以到此为止,但我认为最终结果在小手机屏幕上效果不佳。一旦您对桌面上新的 Masonry 网格的主题外观感到满意,请在手机上查看。如果您对手机上的外观不满意,那么您需要做一些工作。

我认为手机屏幕上没有足够的空间来容纳我们添加到内容砌体模板部分的所有内容。您可以使用两种好的解决方案:缩短手机的摘录或完全跳过它。这是一个额外的函数,您可以将其添加到主题的functions.php中来执行此操作。因为我认为这些问题在平板电脑上不是问题,所以我在本节的所有示例中使用了一个很棒的插件 Mobble,只在手机上进行更改,而不是在平板电脑上进行更改。在使用 Mobble 之前,我还会检查 Mobble 是否处于活动状态,如有必要,我会回退到 WordPress 内置的更通用的移动检测功能 wp_is_mobile。

if (! function_exists('slug_custom_excerpt_length') ) :
function slug_custom_excerpt_length( $length ) {
    //set the shorter length once
    $short = 10;
    //set long length once
    $long = 55;
    //if we can only set short excerpt for phones, else short for all mobile devices
    if (function_exists( 'is_phone') {
        if ( is_phone() ) {
            return $short;
        }
        else {
            return $long;
        }        
    }
    else {
        if ( wp_is_mobile() ) {
            return $short;
        }
        else {
            return $long;
        }
    }
}
add_filter( 'excerpt_length', 'slug_custom_excerpt_length', 999 );
endif; // ! slug_custom_excerpt_length exists

正如您所看到的,我们首先将长摘录长度和短摘录长度存储在变量中,因为我们将使用这些值两次,并且我们希望能够在以后需要时从一个地方更改它们。从那里我们测试是否可以使用 Mobble 的 is_phone()。如果是这样,我们为手机设置简短摘录,如果不是,则设置长摘录。之后我们做同样的基本事情,但是使用 wp_is_mobile,如果 is_phone() 不能使用,这将影响所有移动设备。希望这个函数的 else 部分永远不会被使用,但最好有一个备份以防万一。设置摘录长度逻辑后,只需将函数挂钩到 excerpt_length 过滤器即可。

缩短摘录是一种选择,但我们也可以通过一个简单的过程完全取消它。这是内容砌体的新版本,在手机上省略了整个摘录部分:

<article class="masonry-entry" id="post-<?php the_ID(); ?>" <?php post_class(); ?> >
<?php if ( has_post_thumbnail() ) : ?>
    <div class="masonry-thumbnail">
        <a href="<?php the_permalink(' ') ?>" title="<?php the_title(); ?>"><?php the_post_thumbnail('masonry-thumb'); ?></a>
    </div><!--.masonry-thumbnail-->
<?php endif; ?>
    <div class="masonry-details">
        <h5><a href="<?php the_permalink(' ') ?>" title="<?php the_title(); ?>"><span class="masonry-post-title"> <?php the_title(); ?></span></a></h5>
        <?php 
            //put the excerpt markup in variable so we don't have to repeat it multiple times.
            $excerpt = '<div class="masonry-post-excerpt">';
            $excerpt .= the_excerpt();
            $excerpt .= '</div><!--.masonry-post-excerpt-->';
//if we can only skip for phones, else skip for all mobile devices
            if (function_exists( 'is_phone') {
                if ( ! is_phone() ) {
                    echo $excerpt;
                }
            }
            else {
                if ( ! wp_is_mobile() ) {
                    echo $excerpt;
                }
            }
        ?>
    </div><!--/.masonry-entry-details -->  
</article><!--/.masonry-entry-->

这次我们正在测试我们是否不在电话/移动设备上,如果是,我们返回循环的摘录部分。如果我们使用电话/移动设备,我们什么也不做。

您可能想做的另一件事是增加 Masonry 项目的宽度,这会减少移动设备上的连续数量。为此,我们将根据设备检测向标头添加不同的内联样式。由于此函数使用 wp_add_inline_styles ,因此它将依赖于特定的样式表。在本例中,我使用您可能需要的 masonry.css 来保持砌体样式独立。如果您最终没有使用它,您可以使用另一个已注册样式表的句柄。

if ( ! function_exists ( 'slug_masonry_styles' ) ) :
function slug_masonry_styles() {
    //set the wide width
    $wide = '25%';
    //set narrow width
    $narrow = '50%';
    /**Determine value for $width**/
    //if we can only set narrow for phones, else narrow for all mobile devices
    if (function_exists( 'is_phone') {
        if ( is_phone() ) {
            $width = $narrow;
        }
        else {
            $width = $wide;
        }        
    }
    else {
        if ( wp_is_mobile() ) {
            $width = $narrow;
        }
        else {
            $width = $wide;
        }
    }
    /**Output CSS for .masonry-entry with proper width**/
    $custom_css = ".masonry-entry{width: {$width};}";
    //You must use the handle of an already enqueued stylesheet here.
    wp_add_inline_style( 'masonry', $custom_css );
}
add_action( 'wp_enqueue_scripts', 'slug_masonry_styles' );
endif; // ! slug_masonry_styles exists

该函数枚举自定义样式表,然后使用现在应该非常熟悉的逻辑设置宽度值。之后,我们通过使用 {$width} 将宽度值传递到 CSS 的其他常规位中来创建 $custom_css 变量。之后,我们使用 wp_add_inline_style 告诉 WordPress 在使用 Masonry 样式表时在标头中打印内联样式,然后将整个函数挂接到 wp_enqueue_scripts 上,我们就完成了。

如果您选择将 Masonry 样式合并到现有样式表中,请确保将该样式表的句柄与 wp_add_inline_style 一起使用,否则您的内联样式将不会被包含在内。我喜欢使用 wp_add_inline_style 因为我通常将用于将 Masonry 入队的操作钩子包装在条件中,因此仅在需要时才添加它。例如,如果我仅在博客索引和存档页面上使用 Masonry,我会这样做:

if ( is_home() || is_archive() ) {
    add_action( 'wp_enqueue_scripts', 'slug_scripts_masonry' );
}

最后几个例子应该会在你的大脑中打开一些其他的想法。例如,您可以使用类似的逻辑在移动设备上完全跳过 Masonry。此外,wp_add_inline_style() 是一个较少使用但非常有用的函数,因为它允许您根据任何类型的条件以编程方式设置不同的样式。它可以让您不仅基于设备检测来从根本上更改任何元素的样式,而且更改还可以基于正在使用的模板,或者即使用户是否登录。

我希望您将我所做的这些不同的改变视为发挥创造力的机会。砌体和类似的级联网格系统已经流行了一段时间,所以现在是时候对这个流行的想法进行一些新的改变了。在评论中向我们展示您在 WordPress 主题中使用 Masonry 的酷炫方法。

Josh Pollock 是一位多用途 WordPress 人士,撰写有关 WordPress 的文章、进行主题开发、担任 Pods 框架的社区经理并倡导可持续设计的开源解决方案。