cabrerahector / wordpress-popular-posts

WordPress Popular Posts - A highly customizable WordPress widget that displays your most popular posts.
https://wordpress.org/plugins/wordpress-popular-posts/
GNU General Public License v2.0
280 stars 82 forks source link

Fixes an undefined variable warning in wpp_get_views() #387

Closed robwkirby closed 1 week ago

robwkirby commented 1 week ago

What?

Warning: Undefined variable $query in /plugins/wordpress-popular-posts/src/template-tags.php on line 157

Why?

$query seems to be undefined when cache arg is used

How?

Check if query exists before using it

Testing Instructions

Use wpp_get_views on a page with with the following args:

if ( function_exists('wpp_get_views') ) {
    $wpp = wpp_get_views(
        $post->ID,
        "last24hours",
    false,
    true
    );
}
cabrerahector commented 1 week ago

Hi @robwkirby,

Nice catch! Can't believe I didn't notice that at all...

With that being said, while I appreciate the PR it doesn't fix the problem. It just removes the PHP warning and the function will still return 0 when the post/page might actually have views.

I'm thinking that it would be best to move this line to the end of the if ( ! $results ) { ... } block, like so for example:

if ( ! $results ) {
    // Get all-time views count
    if ( 'all' == $args['range'] ) {
        //phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $table_name is safe to use
        $query = $wpdb->prepare( "SELECT pageviews FROM {$table_name}data WHERE postid = %d;",
            $args['_postID']
        );
        //phpcs:enable
    } // Get views count within time range
    else {
        $start_date = new \DateTime(
            \WordPressPopularPosts\Helper::now(),
            wp_timezone()
        );

        // Determine time range
        switch( $args['range'] ){
            case 'last24hours':
            case 'daily':
                $start_date = $start_date->sub(new \DateInterval('P1D'));
                $start_datetime = $start_date->format('Y-m-d H:i:s');
                $views_time_range = "view_datetime >= '{$start_datetime}'";
                break;
            case 'last7days':
            case 'weekly':
                $start_date = $start_date->sub(new \DateInterval('P6D'));
                $start_datetime = $start_date->format('Y-m-d');
                $views_time_range = "view_date >= '{$start_datetime}'";
                break;
            case 'last30days':
            case 'monthly':
                $start_date = $start_date->sub(new \DateInterval('P29D'));
                $start_datetime = $start_date->format('Y-m-d');
                $views_time_range = "view_date >= '{$start_datetime}'";
                break;
            case 'custom':
                $time_units = ['MINUTE', 'HOUR', 'DAY', 'WEEK', 'MONTH'];

                // Valid time unit
                if (
                    isset($args['time_unit'])
                    && in_array(strtoupper($args['time_unit']), $time_units)
                    && isset($args['time_quantity'])
                    && filter_var($args['time_quantity'], FILTER_VALIDATE_INT)
                    && $args['time_quantity'] > 0
                ) {
                    $time_quantity = $args['time_quantity'];
                    $time_unit = strtoupper($args['time_unit']);

                    if ( 'MINUTE' == $time_unit ) {
                        $start_date = $start_date->sub(new \DateInterval('PT' . (60 * $time_quantity) . 'S'));
                        $start_datetime = $start_date->format('Y-m-d H:i:s');
                        $views_time_range = "view_datetime >= '{$start_datetime}'";
                    } elseif ( 'HOUR' == $time_unit ) {
                        $start_date = $start_date->sub(new \DateInterval('PT' . ((60 * $time_quantity) - 1) . 'M59S'));
                        $start_datetime = $start_date->format('Y-m-d H:i:s');
                        $views_time_range = "view_datetime >= '{$start_datetime}'";
                    } elseif ( 'DAY' == $time_unit ) {
                        $start_date = $start_date->sub(new \DateInterval('P' . ($time_quantity - 1) . 'D'));
                        $start_datetime = $start_date->format('Y-m-d');
                        $views_time_range = "view_date >= '{$start_datetime}'";
                    } elseif ( 'WEEK' == $time_unit ) {
                        $start_date = $start_date->sub(new \DateInterval('P' . ((7 * $time_quantity) - 1) . 'D'));
                        $start_datetime = $start_date->format('Y-m-d');
                        $views_time_range = "view_date >= '{$start_datetime}'";
                    } else {
                        $start_date = $start_date->sub(new \DateInterval('P' . ((30 * $time_quantity) - 1) . 'D'));
                        $start_datetime = $start_date->format('Y-m-d');
                        $views_time_range = "view_date >= '{$start_datetime}'";
                    }
                } // Invalid time unit, default to last 24 hours
                else {
                    $start_date = $start_date->sub(new \DateInterval('P1D'));
                    $start_datetime = $start_date->format('Y-m-d H:i:s');
                    $views_time_range = "view_datetime >= '{$start_datetime}'";
                }

                break;
            default:
                $start_date = $start_date->sub(new \DateInterval('P1D'));
                $start_datetime = $start_date->format('Y-m-d H:i:s');
                $views_time_range = "view_datetime >= '{$start_datetime}'";
                break;
        }

        //phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- $views_time_range is safe to use
        $query = $wpdb->prepare(
            "SELECT SUM(pageviews) AS pageviews FROM `{$wpdb->prefix}popularpostssummary` WHERE {$views_time_range} AND postid = %d;",
            $args['_postID']
        );
        //phpcs:enable
    }

    $results = $wpdb->get_var($query); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- We already prepared $query above
}

If you can, please update your PR with that adjustment and check that the function stills works as intended. If you don't have the time it's fine too, I can make that change myself.

Thanks nonetheless for bringing this up to my attention.

robwkirby commented 1 week ago

@cabrerahector

Great, thanks for the pointer, that makes sense. PR updated.

This works as expected in the website I'm working on.