Pages with 2 Columns

时间:2011-07-08 作者:indexdotphp

我看过许多可用的插件,但它们似乎都太难使用,或者没有提供足够的灵活性。

Plugins I\'ve already tried:

<我还研究了一种允许每页边栏的工具,该工具可以工作,但该栏的内容是独立的,因此很难管理,而缺少WYSIWYG编辑器则使那些不熟悉HTML的人很难管理。

What I\'m Trying Achieve:

我正在从事的项目要求负责输入内容的人员能够将内容添加到主内容的四分之三栏和与主内容相关的信息内容的四分之一栏中。1/4列的内容将根据页面的不同而变化。

对于大多数开发人员来说,在帖子的内容中编写HTML很简单,但是要添加/修改内容的人不知道HTML,所以我正在寻找替代方法。我更希望他们不必记住代码(或短代码)。

更复杂的是,我有3个模板:“1列”、“2列(1/4,3/4)”和“2列(3/4,1/4)”。

The Question:

有人想出了这个问题的简单解决方案吗?是否有一个我不知道的插件可以为一个页面添加多个内容(列)?或者是否有什么东西可以让我向小部件添加所见即所得编辑器?

我期待着您的想法和建议。

4 个回复
SO网友:Pieter Goosen

Here is an interesting approach:

THE PLAN AND LOGIC:

Custom fields are a build in functionality that will fit our needs perfectly. We can set a new custom field and then use that field to enter and store our custom data. We can then use a widget to display this custom content in the sidebar of our single pages

Example of custom field in post editor

enter image description here

Possible issues:

There are a few issues we need to take into account

  • Whether or not a widget has content or not, it counts as an active sidebar. The issue is, we do not want to display the widget on any other page that the single post page, also, we would want to hide the sidebar when we do not have any other widgets and when our custom widget is empty. There is no build in function to set the is_active_sidebar() conditional statement to false, or have any similar function to hide a sidebar when we have a sidebar with an empty widget only

  • Some themes do not have the ability to switch between full width mode and normal mode with sidebar when the status of a sidebar changes from active to inactive and vice versa

SOLUTIONS TO OUR MAIN ISSUE:

Our main issue is how to hide the widget when it is empty or if we are on a page that is not a single post page. Our plan here would be remove the custom widget from the array of sidebars widgets returned via the wp_get_sidebars_widgets() function. We specially make use of the build in filter sidebars_widgets.

It is really straight forward to determine the page we are on by simply using the is_single() conditional statement.

As to how to determine if our widget is empty or not, the logic is quite simple. We will need a helper function to get the post meta value from our custom filed on single post pages. This helper function will be used by our widget to display the content. Now, this logic can be used to determine if our widget will be empty or not, and according to this, we can hide/remove the widget from the wp_get_sidebars_widgets() which is used by functions like is_active_sidebar()

The issue regarding full width vs normal display according to the status of a sidebar is quite easy, and I\'m not going to go into this right here. In short though, if you look at the twentyfourteen theme, it uses body_classes to set a CSS class of full-width when the content sidebar (sidebar-2) is empty. This means that the content area is set to 100% width (if you want to call it that) to hide the blank space on the right of the content if there are no widgets in the sidebar.

Here is the section responsible for this

function twentyfourteen_body_classes( $classes ) {
    /* ...................*/

    if ( ( ! is_active_sidebar( \'sidebar-2\' ) )
        || is_page_template( \'page-templates/full-width.php\' )
        || is_page_template( \'page-templates/contributors.php\' )
        || is_attachment() ) {
        $classes[] = \'full-width\';
    }

    /* ...................*/

    return $classes;
}
add_filter( \'body_class\', \'twentyfourteen_body_classes\' );

You can, in your own time, have a look at the CSS that is used to switch between full width and normal view with a sidebar, and be sure to play around with the possibilities

THE CODE:

HELPER FUNCTION get_custom_field_content

We will first write our helper function to return the custom content from the custom field from the post in single view. I have commented the code, so it will be easy to follow

function get_custom_field_content( $key = \'\' )
{
    // Make sure this is a singel page, if not, return false
    if ( !is_single() )
        return false;

    // Make sure we have a custom field key value, if not, return false
    if ( !$key )
        return false;

    // We have made it this far, so let sanitize the $key input
    $key = filter_var( $key, FILTER_SANITIZE_STRING );

    // OK, we\'ve come this far, all our conditions checked out, lets get the current post ID
    $current_post_ID = get_queried_object_id();

    // Lets us now get and return our custom post meta value
    $custom_content = get_post_meta( 
        $current_post_ID, // Current post ID to get post meta from
        $key, // Custom field to get value from
        true // Return single value
    );
    return $custom_content;
}

This function will be used in our widget to get the custom content and then display it. The $key parameter in the function will be the custom field name, in our example, that will be custom_content. This function will also be used by our filter function to determine if our widget is empty and to remove our widget from our sidebars on a conditional statement

THE WIDGET:

This our widget, which will have a field where you should enter the custom field name in the specified field. Again, the code is commented to make it easy to follow

/**
 * RelatedContentWidget widget class
 *
 * Displays posts from a selected category
 *
 * @since 1.0.0
*/
class RelatedContentWidget extends WP_Widget 
{

    public function __construct() 
    {
        parent::__construct(
            \'widget_related_content\', 
            _x( \'Related Content Widget\', \'Related Content Widget\' ), 
            [ \'description\' => __( \'Display a list of related content.\' ) ] 
        );
        $this->alt_option_name = \'widget_related_content\';

        add_action( \'save_post\', [$this, \'flush_widget_cache\'] );
        add_action( \'deleted_post\', [$this, \'flush_widget_cache\'] );
        add_action( \'switch_theme\', [$this, \'flush_widget_cache\'] );
    }

    public function widget( $args, $instance ) 
    {
        $cache = [];
        if ( ! $this->is_preview() ) {
            $cache = wp_cache_get( \'widget_rel_content\', \'widget\' );
        }

        if ( ! is_array( $cache ) ) {
            $cache = [];
        }

        if ( ! isset( $args[\'widget_id\'] ) ) {
            $args[\'widget_id\'] = $this->id;
        }

        if ( isset( $cache[ $args[\'widget_id\'] ] ) ) {
            echo $cache[ $args[\'widget_id\'] ];
            return;
        }

        ob_start();

        $title            = ( ! empty( $instance[\'title\'] ) ) ? $instance[\'title\'] : __( \'Related Content\' );
        /** This filter is documented in wp-includes/default-widgets.php */
        $title            = apply_filters( \'widget_title\', $title, $instance, $this->id_base );
        // This holds the custom field key that holds the custom content
        $custom_field_key = ( ! empty( $instance[\'custom_field_key\'] ) ) ? $instance[\'custom_field_key\'] : \'\';

        /**
         * Make sure we only run this on a singular page/single post. 
         * Also make sure that we have a value inside $custom_field_key
         */
        if (  $custom_field_key  
             && is_single() 
        ) { 

            /**
             * Get the custom field having our custom content
             * First make sure that the custom function get_custom_field_content() exists to avoid fatal errors
             */
            if ( function_exists( \'get_custom_field_content\' ) ) {
                $custom_content = get_custom_field_content( 
                    $custom_field_key // The custom field we need to retrieve content from
                );

                // Make sure we actually have a value before we display anything
                if ( $custom_content ) {

                    echo $args[\'before_widget\'];
                    if ( $title ) { 
                        echo $args[\'before_title\'] . $title . $args[\'after_title\'];
                    }               

                    // Display our current content
                    echo $custom_content;

                    echo $args[\'after_widget\']; 

                }
            }
        }

        if ( ! $this->is_preview() ) {
            $cache[ $args[\'widget_id\'] ] = ob_get_flush();
            wp_cache_set( \'widget_rel_content\', $cache, \'widget\' );
        } else {
            ob_end_flush();
        }
    }

    public function update( $new_instance, $old_instance ) 
    {
        $instance                      = $old_instance;
        $instance[\'title\']             = filter_var( $new_instance[\'title\'],            FILTER_SANITIZE_STRING );
        $instance[\'custom_field_key\']  = filter_var( $new_instance[\'custom_field_key\'], FILTER_SANITIZE_STRING );
        $this->flush_widget_cache();

        $alloptions = wp_cache_get( \'alloptions\', \'options\' );
        if ( isset($alloptions[\'widget_related_content\']) )
            delete_option(\'widget_related_content\');

        return $instance;
    }

    public function flush_widget_cache() 
    {
        wp_cache_delete(\'widget_rel_content\', \'widget\');
    }

    public function form( $instance ) 
    {

        $title            = isset( $instance[\'title\'] )            ? esc_attr( $instance[\'title\'] )            : \'\';
        $custom_field_key = isset( $instance[\'custom_field_key\'] ) ? esc_attr( $instance[\'custom_field_key\'] ) : \'\';
        ?>

        <p>
            <label for="<?php echo $this->get_field_id( \'title\' ); ?>"><?php _e( \'Title:\' ); ?></label>
            <input class="widefat" id="<?php echo $this->get_field_id( \'title\' ); ?>" name="<?php echo $this->get_field_name( \'title\' ); ?>" type="text" value="<?php echo $title; ?>" />
        </p>

        <p>
            <label for="<?php echo $this->get_field_id( \'custom_field_key\' ); ?>"><?php _e( \'Custom field key:\' ); ?></label>
            <input class="widefat" id="<?php echo $this->get_field_id( \'custom_field_key\' ); ?>" name="<?php echo $this->get_field_name( \'custom_field_key\' ); ?>" type="text" value="<?php echo $custom_field_key; ?>" />
        </p>

    <?php
    }

}

add_action( \'widgets_init\', function () 
{
    register_widget( \'RelatedContentWidget\' );
});

This is how our widget will look like in back end

enter image description here

FILTER FUNCTION:

Lastly is our helper function to remove the widget on all pages except single post pages and whenever the widget is empty. Again, the code is commented to make it easy to follow

add_filter( \'sidebars_widgets\', function ( $sidebars_widgets )
{
    // Return our filter when we are on admin screen
    if ( is_admin() )
        return $sidebars_widgets;

    // Widget we need to target. This should be the name/id we used to register it, in this case widget_related_content
    $custom_widget = \'widget_related_content\';
    // Set our custom field key to get our custom content
    $custom_field_key = \'custom_content\'; // Be sure to change this to your exact name

    /**
     * Only run the next block for all templates/pages except the single page. You can
     * adjust this as needed. 
     *
     * We also want to run this on a single page if our custom widget is empty
     */

    // Set a variable to test for single pages
    $single_post = false;
    // Set variable to hold the custom content
    $custom_content = \'\';

    /**
     * Check for a single page and if it is, check if we have custom content
     * We will use the custom function we have created, get_custom_field_content()
     * to run this conditions
     */
    if ( is_single() ) {
        if ( function_exists( \'get_custom_field_content\' ) )
            $custom_content = get_custom_field_content( $custom_field_key );
        $single_post    = true;
    }

    // Stop and return $sidebars_widgets if we are on a single page and have custom content
    if ( $single_post && $custom_content )
        return $sidebars_widgets;

    // We have come this far, let us wrap this up
    // See if our custom content widget exists is any sidebar, if so, get the array index
    foreach ( $sidebars_widgets as $sidebars_key=>$sidebars_widget ) {
        // Skip the wp_inactive_widgets set, we do not need them
        if ( $sidebars_key == \'wp_inactive_widgets\' )
        continue;

        // Only continue our operation if $sidebars_widget are not an empty array
        if ( $sidebars_widget ) {
            foreach ( $sidebars_widget as $k=>$v ) {
                /**
                 * Look for our custom widget, if found, unset it from the $sidebars_widgets array
                 * @see stripos()
                 */
                if ( stripos( $v, $custom_widget ) !== false )
                unset( $sidebars_widgets[$sidebars_key][$k] );
            } // endforeach $sidebars_widget
        } // endif $sidebars_widget
    } // endforeach $sidebars_widgets

    return $sidebars_widgets;
});

And that is all we need. Using the twentyfourteen theme, this is what you will see if we have custom content

enter image description here

and here is a post without custom content

enter image description here

SO网友:Milo

编辑-此答案很旧,有更好的选项。

一些插件-pods, magic fields, custom fields template.

或者您可以使用一些元框和tinymce编辑器进行DIY,请参见this answer.

SO网友:Cedon

这是我将在主题模板级别处理的事情。您提到,输入内容的人需要同时输入这两个内容,因此我认为作者是在同一篇文章中输入这两个内容的。

在后端,我会安装插件Advanced Custom Fields. 这只是为了省去您在侧边栏中添加所见即所得自定义字段选项的麻烦。创建这个过程相对简单,甚至允许一些规则使其高度定制。

在内容中。此帖子类型的php模板文件将使用以下代码:

<?php if (have_posts()) : ?>
    <?php while (have_posts()) : ?>
        <article>
            // Your Post Code Here
            <aside>
               <?php echo get_post_meta(get_the_ID(), \'sidebar_content\', true); ?>
            </aside>
        </article>
    <?php endwhile; ?>
<?php endif; ?>
由于您声明其内容与主要内容直接相关,因此此代码将在文章标记中执行的操作是在文章中创建一个旁白,使用当前帖子的ID进入\\u postmeta表,并查找键“sidebar\\u content”(这是您将在ACF中为字段指定的名称)。

SO网友:Adam Friedman

要求不明确:内容编辑器必须仅在帖子内容中创建新列吗?或者可以使用帖子内容作为他们的3/4列,然后他们可以编辑一个边栏小部件来创建1/4列?

如果是后者——你在最后问“是否有什么东西可以让我向小部件添加所见即所得编辑器?”—答案很简单:只需在侧边栏中安装所见即所得编辑器小部件,并让您的人员在那里编辑内容。WP Editor Widget 看起来是一个支持良好的插件,可以做到这一点。

结束