devaloka / network-wp-query

:electric_plug: Network-wide WP Query for Multisite environment, which supports POSTS-PER-SITE query etc. [STAND-ALONE][Plugin]
GNU General Public License v2.0
16 stars 2 forks source link

Query not returning anything #11

Open vguenichon opened 7 years ago

vguenichon commented 7 years ago

I'm trying to get posts with this query:

$all_events = new WP_Query( array(
    'network'           => true,
    'post_type'         => 'events',
    'post_status'       => 'publish',
    'meta_key'          => 'date_debut',
    'orderby'           => 'meta_value',
    'order'             => $order,
    'posts_per_page'    => $posts_per_page,
    'meta_query'        => array(
    array(
        'key'       => 'date_debut',
        'value'     => date('Ymd'),
        'compare'   => $compare == '&lt;' ? '<' : $compare,
        'type'      => 'DATE',
        ),
    )));
$output = '';
if ( $all_events->have_posts() ) {
    $output .= '<div class="events-list '.$el_class.'">';
        while ( $all_events->have_posts() ) : $all_events->the_post();
            ob_start();
            get_template_part('components/modules/event');
            $output .= ob_get_clean();
        endwhile;
    $output .= '</div>';
}
return $output;
wp_reset_postdata();

Do you see anything wrong or a mistake using your plugin ?

// EDIT It seems that it doesn't accept variables as arguments. But I did not get anything from the sites except the main. However I have the same events CPT and some published posts.

whizark commented 7 years ago

@vguenichon Hi, doesn't the query work with simple parameters either?

wp_reset_postdata() should be placed inside if ( $all_events->have_posts() ) { ... } because you don't need to reset post data in the case that no posts found. In other words, you should reset post data if any posts found.

if ( $all_events->have_posts() ) {
    $output .= '<div class="events-list '.$el_class.'">';
        while ( $all_events->have_posts() ) : $all_events->the_post();
            ob_start();
            get_template_part('components/modules/event');
            $output .= ob_get_clean();
        endwhile;
    $output .= '</div>';
    wp_reset_postdata();    // HERE
}
return $output;

If that doesn't solve the issue, could you try to test with the following patterns?

A:

  1. remove 'network' => true,.
  2. check whether the query returns the correct post(s) from the current site.

B:

  1. simplify the query parameters (with 'network' => true,)
  2. check whether the query returns the correct post(s) from all your sites.

e.g.

$all_events = new WP_Query( array(
    'network'           => true,
    'post_type'         => 'events',
    'post_status'       => 'publish',
    ));
vguenichon commented 7 years ago

Thanks a lot for this very fast answer. A) works perfectly and it was my initial query B) returns only posts from current site (which is the main)

whizark commented 7 years ago

@vguenichon Hmmm, is the WP version the latest one (4.8.1)? How about the following code?

$output = '';
if ( $all_events->have_posts() ) {
    $output .= '<div class="events-list '.$el_class.'">';
        while ( $all_events->have_posts() ) : $all_events->the_post();
            ob_start();

            the_title();  // replace `get_template_part()` with a simple template function.

            // For debug.
            // var_dump($post->site_ID);  // should dump the site ID of the post. 

            $output .= ob_get_clean();
        endwhile;
    $output .= '</div>';
    wp_reset_postdata();
}
return $output;

Perhaps, some filters of Network WP Query, which modify SQL and tweak query, might conflict with other filters (including other plugins. In this case, you can test by disabling plugins).

I'll test your query later.

vguenichon commented 7 years ago

Yes it's the latest version of WP. I tried your code, without the template (I did it before), and nothing's out. Is there any dump or print I can do for you to check the nature of the queried objects or the query itself ?

vguenichon commented 7 years ago

Well... it's working very well. When I tried on another browser with which I had not previously visited the page, the results are fine. I just had to empty the cookies. Don't know why... and I'm sorry of that. Something's remaining : posts are sorted by site and not by date as the query should do it.

whizark commented 7 years ago

Well... it's working very well. When I tried on another browser with which I had not previously visited the page, the results are fine.

That's good to hear :smile: Simple order/orderby also should work but the query with meta query might not work (I can't remember whether it works so I'll test it later).

To debug the query, you can just dump $all_events after the query, $post in your loop or you might dump query by using pre_get_posts hook.

// functions.php in your theme.
// The raw query.
add_action('pre_get_posts', function ($query) { var_dump($query); }, ~PHP_INT_MAX);

// The modified query by Network WP Query.
// This action should be added after Network WP Query is booted since the plugin adds an action with `PHP_INT_MAX`.
add_action('pre_get_posts', function ($query) { var_dump($query); }, PHP_INT_MAX);

https://github.com/devaloka/network-wp-query/blob/master/src/Subscriber.php#L45

For SQL:

$all_events = new WP_Query( /* ... */ );
var_dump( $all_events->request );
vguenichon commented 7 years ago

False joy (as we say in french). I'm sorry but I have some problems with a cache plugin yet deactivated on a website (not the main where the query is played). So, now, everytime I change my code I see a correct result, not cached. And when I add the variables of your plugin, posts disappeared. If I simplify the query, only the posts from the main website are returned.

Here's the SQL request: string(867) "SELECT SQL_CALC_FOUND_ROWS tables.* FROM ( ( SELECT adwp_posts.*, '1' AS site_ID FROM adwp_posts LEFT JOIN adwp_term_relationships ON (adwp_posts.ID = adwp_term_relationships.object_id) WHERE 1=1 AND ( adwp_term_relationships.term_taxonomy_id IN (1780) ) AND adwp_posts.post_type = 'events' AND ((adwp_posts.post_status = 'publish')) GROUP BY adwp_posts.ID ORDER BY adwp_posts.post_date DESC LIMIT 0, 10 ) UNION ( SELECT adwp_3_posts.*, '3' AS site_ID FROM adwp_3_posts LEFT JOIN adwp_3_term_relationships ON (adwp_3_posts.ID = adwp_3_term_relationships.object_id) WHERE 1=1 AND ( adwp_3_term_relationships.term_taxonomy_id IN (1780) ) AND adwp_3_posts.post_type = 'events' AND ((adwp_3_posts.post_status = 'publish')) GROUP BY adwp_3_posts.ID ORDER BY adwp_3_posts.post_date DESC LIMIT 0, 10 ) ) tables ORDER BY tables.post_date DESC LIMIT 0, 10"

whizark commented 7 years ago

I'm sorry but I have some problems with a cache plugin yet deactivated on a website (not the main where the query is played).

Ah, a cache plugin could cause problems...

Workarounds that come to my mind:

And when I add the variables of your plugin, posts disappeared.

What're the variables? $order, $posts_per_page and $compare ?

vguenichon commented 7 years ago

These variables will be filled via a shortcode. This code takes place in a shortcode.

whizark commented 7 years ago

These variables will be filled via a shortcode. This code takes place in a shortcode.

Are the variables actually filled? The attribute values are filled in $atts ($atts['order'] etc.) until you explicitly extract them with extract($atts).

In addition, if CPT events is not registered in each main/sub site you need register CPT events in each site, or you need register CPT before your query with 'network' => true and unregister it after the query. To confirm it, try to query against normal post please.

vguenichon commented 7 years ago

I didn't mention that the attributes are extracted before. Here's the complete function:

function events_vc( $atts, $content = null ) {
    extract( shortcode_atts( array (
        'compare' => '>=',
        'posts_per_page' => '-1',
        'order' => 'ASC',
        'el_class' => '',
    ), $atts ));

    $all_events = new WP_Query([
        // 'network'            => true,
        // 'sites__in'          => [1,3],
        'post_type'         => 'events',
        'post_status'       => 'publish',
        'meta_key'          => 'date_debut',
        'orderby'           => 'meta_value',
        'order'             => $order,
        'posts_per_page'    => $posts_per_page,
        'meta_query'        => [[
            'key'           => 'date_debut',
            'value'         => date('Ymd'),
            'compare'       => $compare == '&lt;' ? '<' : $compare,
            'type'          => 'DATE',
            ],
        ]
    ]);

    $output = '';
    if ( $all_events->have_posts() ) {
        $output .= '<div class="events-list '.$el_class.'">';
            while ( $all_events->have_posts() ) : $all_events->the_post();
                ob_start();
                get_template_part('components/modules/event');
                $output .= ob_get_clean();
            endwhile;
        $output .= '</div>';
        wp_reset_postdata();
    }
    return $output;
}
add_shortcode( 'events_vc_output', 'events_vc');

It's a shortcode that create an element for Visual Composer. So, the page is saved with the values filled in the element.

And obviously I thought about the CPT but it exists and existed before I wanted to merge events from the sites of this network. If I use switch_to_blog and perform a query, I get the posts from the other sites. But the posts are not merged.

whizark commented 7 years ago

Thank you for posting the complete function :+1: Although I'm not very familiar with Visual Composer, the problem might be related to Visual Composer or something else. I'll also test the function.

vguenichon commented 7 years ago

Goog to know : this is a shortcode declaration, not much related to Visual Composer. I can do anything in this function as I can in a Wordpress shortcode function. The only difference is the filter after to pass the function to another function of Visual Composer (the one which will do the UI). A big thanx for your help and the time you're going to take. Sure it will help.

whizark commented 7 years ago

The only difference is the filter after to pass the function to another function of Visual Composer (the one which will do the UI).

I confirmed that the shortcode with Network WP Query itself works although I haven't tested with Visual Composer (VC) yet.

It seems to be related to the process, filter or parameter handling etc. of VC as you said. If so, <?php echo do_shortcode('[events_vc_output]'); ?> (in wp-content/your-theme/index.php, page.php etc.) should output the correct result.

This is a just a quick note as I haven't tested with VC. I think there are possible cases when we should do additional works. For example, with nested filters, nested shortcodes, nested WP queries (including nested post loops), nested switch_to_blog(), internal cache (wp_cache_*), incorrect nested output buffering, the context/scope that we cannot use WP_Query etc.

In these cases, we might use an ugly but quick workaround:

  1. create a function which fetches VC parameters and outputs the Network WP Query result.
  2. invoke the function outside VC and cache (wp_cache_*, Transient etc) them.
  3. create a shortcode for VC which just outputs the cached result.
  4. use the shortcode (3) for VC.
vguenichon commented 7 years ago

I completely understand what you mean. But I don't output the shortcode like that. It's visually integrated by their function which is basically a filter to overload a function or a class. A bit time ago, I asked VC team to help me getting their shortcode to output another shortcode. And they came back to me with this function:

add_filter( 'vc_grid_item_shortcodes', 'my_module_add_grid_shortcodes' );
function my_module_add_grid_shortcodes( $shortcodes ) {
    $shortcodes['vc_post_content'] = array(
        'name' => __( 'Post content', 'fluidtopics' ),
        'base' => 'vc_post_content',
        'category' => __( 'Content', 'fluidtopics' ),
        'description' => __( 'Show current post content', 'fluidtopics' ),
        'post_type' => Vc_Grid_Item_Editor::postType(),
    );

    return $shortcodes;
}

add_shortcode( 'vc_post_content', 'vc_post_content_render' );
function vc_post_content_render() {
    return '{{ do_shortcode_post_content }}';
}

add_filter( 'vc_gitem_template_attribute_do_shortcode_post_content', 'vc_gitem_template_attribute_do_shortcode_post_content', 10, 2 );

function vc_gitem_template_attribute_do_shortcode_post_content( $value, $data ) {
    /**
     * @var null|Wp_Post $post ;
     * @var string $data ;
     */
    extract( array_merge( array(
        'post' => null,
        'data' => '',
    ), $data ) );
    $atts_extended = array();
    parse_str( $data, $atts_extended );

    WPBMap::addAllMappedShortcodes();

    $output = do_shortcode( $post->post_content );
    ob_start();
//  do_action( 'wp_enqueue_scripts' );
//  wp_print_styles();
//  wp_print_scripts();
//  wp_print_footer_scripts();
    $output .= ob_get_clean();

    return $output;
}
whizark commented 7 years ago

It is the best way to integrate Network WP Query with VC's API, I agree. The problem probably comes from running WP_Query or its filters inside VC so doing a shortcode from another shortcode also might not help your case. Could you try to read the VC's source code around the process for shortcode? If I would have time, I would also test with VC. Sorry I cannot do it soon... :pensive:

vguenichon commented 7 years ago

Unfortunately, I'm not a developer. I can guess some things but reading code to understand it is not easy for me. Anyway, thanks a lot for taking time to this issue and I hope Wordpress will integrate something easy to use to request any post through a network. In this way, the VC team would probably take care of it to enhance its plugin.

jasmines commented 4 years ago

if I use 'orderby' => 'meta_value' in $arg, I get no results. mysql error: Unknown column 'KNV5fu_postmeta.meta_value' in 'order clause