2

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:

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

2
  • It sounds like you need something for dummies. I would suggest using Visual composer: codecanyon.net/item/visual-composer-page-builder-for-wordpress/… Shortcode version: My experience shows that anyone can understand [two_thirds][/two_thirds][one_third_last][/one_third_last] - But you could just program them to be [content]Content here[/content] [sidebar]Sidebar content here[/sidebar] The shortcode names can be anything :)
    – Jeppe
    Commented Sep 8, 2015 at 11:22
  • I wrote a small plugin that lets the user add columns with TinyMce, but I would not recommend it. Editing layout in TinyMce is quite tricky. I think something like Visual Composer would work best for you, even if those editors are slow. Or you could the up something with reapeaters and flexible content in Advanced Custom Fields.
    – jannej
    Commented Sep 8, 2015 at 12:23

4 Answers 4

4
+50

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

5
  • it is not your answer, it is the too broad question.... On one site that I worked on the solution was to insert a "end of column" marker to create an almost identical height two column post. In retrospect I should probably just done it with JS especially now when responsive design is a must (that site I had done several years ago). The widget or second editor approach fails when you get the content from external source in a word document and you just want to C&P it and maybe do small edits. The answer depends on particular editorial flow and probably impossible to have a "canonical" one. Commented Sep 13, 2015 at 18:27
  • Did not say this is the only solution, as you say, it is a braod question. This is just an unconventional method that I came up with and felt pursueing Commented Sep 13, 2015 at 18:36
  • just had to use somewhere the answer I started to write and discarded, and your solution seemed a more appropriate place then the other answers :) Commented Sep 13, 2015 at 18:40
  • Some how this got flagged as low quality...don't ask me why. Commented Sep 14, 2015 at 13:33
  • @ialocin Hahahaha, someone has nothing better to do with his time, he is feeling bored, so he decided to be an asshole and flag real answers as low quality. Been childish is sometimes quite laughable and humoristic :-). Thanks for the comment. Commented Sep 14, 2015 at 13:51
3

EDIT- this answer is old, there are better options.

a few plugins - pods, magic fields, custom fields template.

or you can DIY with some meta boxes and tinymce editors, see this answer.

1
  • I had a look at your suggestions. I find "pods" to offer much more than what I need, "magic field" doesn't seem so bad and so is "custom fields template" but I was hoping for something a little more intuitive (that looks built-in as opposed to a separate metabox). I'll play around with the DIY option later today and see how that goes. Commented Jul 8, 2011 at 15:47
0

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

6
  • Please … do note recommend Advanced Custom Fields ! That is a pit and makes going backwards and removing it impossible!
    – kaiser
    Commented Sep 8, 2015 at 15:04
  • I just recommended that one because it was the first one I saw that was straight forward to use in this situation, would create a custom field that was WYSIWYG, was highly rated and was flagged as working with v4.3. Normally, I am a fan of writing ones own plug-ins except in certain cases (e.g. Limit Login Attempts)
    – Cedon
    Commented Sep 8, 2015 at 16:02
  • @kaiser why would it be impossible to remove? the data is in post meta, WordPress post meta functions can retrieve it, it's still there if you disable the plugin.
    – Milo
    Commented Sep 13, 2015 at 3:55
  • @Milo Have you ever tried to convert an "ACF enhanced"-site back to a normal one? There are intermediate post types etc added by the plugin and meta data that has hashed keys to reference other meta keys. So, yes, it's not completely impossible, but it's far from reasonable to use that plugin. When you realize that your DB contains hundreds of thousands of unneeded entries and grows exponentially (in relation to the actual content), then you also realize that you will have to get rid of it. Not funny.
    – kaiser
    Commented Sep 13, 2015 at 10:29
  • @kaiser I have. In the case of OP's question, a single field's content is easily retrievable with WP API functions. Sure, complex field types use lots of extra data, but explain how you could achieve those results without the code that originally enabled it?
    – Milo
    Commented Sep 13, 2015 at 14:53
-1

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.

3
  • Please, do not just add plugin recommendations. If the link is dead, the answer is worthless.
    – kaiser
    Commented Sep 13, 2015 at 10:30
  • (1) I would have added this as a comment, but I don't have the privileges. (2) Should I have just written "Surely there is a plugin somewhere that adds a WYSIWYG editor"? That's pretty lame. (3) Should I have have just pasted the code in the plugin I cited? Also pretty lame. (4) We can take this up in meta, but rather than stop perfect plugin recommendations which is the simplest fix for askers, why not flag answers whose links have died so that users work on editing them with updated links if and when that ever happens? (5) When has an official WP plugin link actually been 404 dead? Commented Sep 14, 2015 at 14:01
  • Ad (3) Yes, that's absolutely valid. Better would be if you extract some working code and show it here. Answers do not only answer the OPs specific problem, but should help later readers as well, hence we have voting on answers. Ad (4) Because working through flag lists is cumbersome and no one wants to do just clean up. Writing good answers is much more fun. Ad (5) Often enough. I have already taken down some of my own plugins, so this can absolutely happen. – Last: Again, link only answers will get deleted. Please do not force anyone to clean up after you :)
    – kaiser
    Commented Sep 14, 2015 at 15:03

Not the answer you're looking for? Browse other questions tagged or ask your own question.