Pages with 2 Columns

I’ve had a look at many of the available plugins but they all seem to be too difficult to use or do not provide enough flexibility.

Plugins I’ve already tried:

Read More
  • WP Post Columns
  • Magazine Columns
  • WP Columns
  • WP Easy Columns

I’ve also look at one that allowed for per-page sidebars which could work but the column is separate for the content making it difficult to manage, and the lack of a WYSIWYG editor makes it difficult for those not familiar with HTML.

What I’m Trying Achieve:

The project I’m working on requires that the people responsible for entering the content be able to add content to a 3/4 column that is the main content and a 1/4 column that is informational content relating to the main content. The content of the 1/4 column will change depending on the page.

To most developers, it’s simple to write HTML to do that in the post’s content but the people that will be adding/modifying the content don’t know HTML so I’m looking for alternatives. I would prefer if they didn’t have to remember codes (or short codes).

To complicate things, I have 3 templates: “1 column”, “2 columns (1/4, 3/4)” and “2 columns (3/4, 1/4)”.

The Question:

Has anyone come up with a simple solution to this problem? Is there a plugin that I’m not aware of that would add the ability to have multiple content (column) for a single page? Or is there something that would allow me to add a WYSIWYG editor to widgets?

I look forward to your thoughts and recommendations.

Related posts

Leave a Reply

4 comments

  1. 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

  2. This is something I would handle at the theme template level. You mention that the person entering in the content needs to do both so I presume the writer is entering both on the same post.

    On the back-end, I would install the plugin Advanced Custom Fields. This is just to save you the headache of trying to add a WYSIWYG custom field option for the sidebar. It is relatively straight forward process to create this and even allows some rules that make it highly customized.

    In the content.php template file for this post type you would use the following code:

    <?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; ?>
    

    What this code will do within the article tag, since you state its content is directly related to the main content, is create an aside within the article, go into the _postmeta table with the current post’s ID and lookup the key ‘sidebar_content’ (This is a name that you will give the field in ACF).

  3. The requirement is unclear: Must content editors create new columns ONLY within the post content? Or is it OK to use the post content as their 3/4 column and then they can edit a sidebar widget which will create the 1/4 column?

    If it is the latter — which you asked at the end with “Is there something that would allow me to add a WYSIWYG editor to widgets?” — then the answer is simple: just install WYSIWYG editor widget(s) in your sidebar and have your people edit content there. WP Editor Widget looks like a well-supported plugin that does just that.