PluginProbe ʕ •ᴥ•ʔ
Post Views Counter / trunk
Post Views Counter vtrunk
1.7.13 1.7.12 1.7.11 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.2 1.3.2.1 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.7.10 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9
post-views-counter / includes / class-integration-gutenberg.php
post-views-counter / includes Last commit date
class-admin.php 3 months ago class-columns-modal.php 1 month ago class-columns.php 2 weeks ago class-counter.php 2 months ago class-crawler-detect.php 7 months ago class-cron.php 1 month ago class-dashboard.php 1 month ago class-emails-mailer.php 1 month ago class-emails-period.php 1 month ago class-emails-query.php 1 month ago class-emails-scheduler.php 1 month ago class-emails-template.php 1 month ago class-emails.php 1 month ago class-frontend.php 2 weeks ago class-functions.php 1 year ago class-import.php 2 months ago class-integration-gutenberg.php 6 months ago class-integrations.php 2 months ago class-query.php 2 months ago class-settings-api.php 1 month ago class-settings-display.php 4 months ago class-settings-emails.php 1 month ago class-settings-general.php 1 month ago class-settings-integrations.php 5 months ago class-settings-other.php 1 month ago class-settings-reports.php 1 month ago class-settings.php 1 month ago class-toolbar.php 3 months ago class-traffic-signals.php 2 months ago class-update.php 1 month ago class-widgets.php 1 month ago functions.php 1 month ago
class-integration-gutenberg.php
278 lines
1 <?php
2 // exit if accessed directly
3 if ( ! defined( 'ABSPATH' ) )
4 exit;
5
6 /**
7 * Post_Views_Counter_Integration_Gutenberg class.
8 *
9 * Handles Gutenberg block editor integration for ordering posts by views.
10 *
11 * @class Post_Views_Counter_Integration_Gutenberg
12 */
13 class Post_Views_Counter_Integration_Gutenberg {
14 /**
15 * Stack of active Latest Posts blocks using post_views ordering.
16 *
17 * @var array
18 */
19 private $latest_posts_stack = [];
20
21 /**
22 * Class constructor.
23 *
24 * @return void
25 */
26 public function __construct() {
27 add_action( 'init', [ $this, 'init' ] );
28 }
29
30 /**
31 * Initialize integration hooks.
32 *
33 * @return void
34 */
35 public function init() {
36 // bail if integration is disabled
37 if ( ! Post_Views_Counter_Integrations::is_integration_enabled( 'gutenberg' ) )
38 return;
39
40 // frontend query filters
41 add_filter( 'query_loop_block_query_vars', [ $this, 'query_loop_block_query_vars' ], 10, 3 );
42 add_filter( 'render_block_data', [ $this, 'render_block_data_latest_posts' ], 10, 2 );
43 add_filter( 'render_block', [ $this, 'render_block_latest_posts_cleanup' ], 10, 2 );
44 add_action( 'pre_get_posts', [ $this, 'modify_latest_posts_query' ], 10, 1 );
45
46 // REST API support for editor preview
47 add_action( 'rest_api_init', [ $this, 'register_rest_orderby' ] );
48
49 // enqueue block editor assets
50 add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_editor_assets' ] );
51 }
52
53 /**
54 * Filter Query Loop block query vars to add post views ordering.
55 *
56 * @param array $query
57 * @param WP_Block $block
58 * @param int $page
59 *
60 * @return array
61 */
62 public function query_loop_block_query_vars( $query, $block, $page ) {
63 // check if orderBy is set to post_views in the Query block
64 if ( empty( $block->context['query']['orderBy'] ) || $block->context['query']['orderBy'] !== 'post_views' )
65 return $query;
66
67 // set orderby to post_views
68 $query['orderby'] = 'post_views';
69
70 // handle include zero views setting (default: true)
71 // check for custom attribute first, fallback to true
72 $include_zero_views = true;
73
74 if ( isset( $block->context['query']['pvcIncludeZeroViews'] ) )
75 $include_zero_views = (bool) $block->context['query']['pvcIncludeZeroViews'];
76
77 if ( ! isset( $query['views_query'] ) )
78 $query['views_query'] = [];
79
80 $query['views_query']['hide_empty'] = ! $include_zero_views;
81
82 return $query;
83 }
84
85 /**
86 * Track Latest Posts blocks before rendering to adjust query parameters.
87 *
88 * @param array $parsed_block
89 * @param array $source_block
90 *
91 * @return array
92 */
93 public function render_block_data_latest_posts( $parsed_block, $source_block ) {
94 // only process Latest Posts block
95 if ( empty( $parsed_block['blockName'] ) || $parsed_block['blockName'] !== 'core/latest-posts' )
96 return $parsed_block;
97
98 // check if orderBy is set to post_views
99 if ( empty( $parsed_block['attrs']['orderBy'] ) || $parsed_block['attrs']['orderBy'] !== 'post_views' )
100 return $parsed_block;
101
102 // handle include zero views setting (default: true)
103 $include_zero_views = true;
104
105 if ( isset( $parsed_block['attrs']['pvcIncludeZeroViews'] ) )
106 $include_zero_views = (bool) $parsed_block['attrs']['pvcIncludeZeroViews'];
107
108 $this->latest_posts_stack[] = [
109 'include_zero_views' => $include_zero_views
110 ];
111
112 return $parsed_block;
113 }
114
115 /**
116 * Clear Latest Posts block context after rendering.
117 *
118 * @param string $block_content
119 * @param array $block
120 *
121 * @return string
122 */
123 public function render_block_latest_posts_cleanup( $block_content, $block ) {
124 if ( empty( $block['blockName'] ) || $block['blockName'] !== 'core/latest-posts' )
125 return $block_content;
126
127 if ( empty( $block['attrs']['orderBy'] ) || $block['attrs']['orderBy'] !== 'post_views' )
128 return $block_content;
129
130 array_pop( $this->latest_posts_stack );
131
132 return $block_content;
133 }
134
135 /**
136 * Modify WP_Query for Latest Posts block to add post views ordering.
137 *
138 * @param WP_Query $query
139 *
140 * @return void
141 */
142 public function modify_latest_posts_query( $query ) {
143 if ( empty( $this->latest_posts_stack ) )
144 return;
145
146 // only modify if orderby is already set to post_views
147 if ( empty( $query->query_vars['orderby'] ) || $query->query_vars['orderby'] !== 'post_views' )
148 return;
149
150 // mark query for Post_Views_Counter_Query to handle
151 $query->pvc_orderby = true;
152
153 // handle include zero views setting (default: true)
154 $context = end( $this->latest_posts_stack );
155 $include_zero_views = isset( $context['include_zero_views'] ) ? (bool) $context['include_zero_views'] : true;
156
157 if ( ! isset( $query->query_vars['views_query'] ) )
158 $query->query_vars['views_query'] = [];
159
160 $query->query_vars['views_query']['hide_empty'] = ! $include_zero_views;
161 $query->query['views_query'] = $query->query_vars['views_query'];
162 }
163
164 /**
165 * Register REST API support for post_views orderby.
166 *
167 * @return void
168 */
169 public function register_rest_orderby() {
170 // get main instance
171 $pvc = Post_Views_Counter();
172
173 // get countable post types
174 $post_types = $pvc->options['general']['post_types_count'];
175
176 if ( empty( $post_types ) )
177 return;
178
179 foreach ( $post_types as $post_type ) {
180 // register post_views as valid orderby parameter
181 add_filter( "rest_{$post_type}_collection_params", [ $this, 'rest_collection_params' ], 10, 1 );
182
183 // modify query when orderby=post_views
184 add_filter( "rest_{$post_type}_query", [ $this, 'rest_query' ], 10, 2 );
185 }
186 }
187
188 /**
189 * Add post_views to REST API collection parameters.
190 *
191 * @param array $params
192 *
193 * @return array
194 */
195 public function rest_collection_params( $params ) {
196 if ( isset( $params['orderby']['enum'] ) && is_array( $params['orderby']['enum'] ) ) {
197 $params['orderby']['enum'][] = 'post_views';
198 }
199
200 return $params;
201 }
202
203 /**
204 * Modify REST API query for post_views orderby.
205 *
206 * @param array $args
207 * @param WP_REST_Request $request
208 *
209 * @return array
210 */
211 public function rest_query( $args, $request ) {
212 if ( $request->get_param( 'orderby' ) !== 'post_views' )
213 return $args;
214
215 // set orderby
216 $args['orderby'] = 'post_views';
217
218 // handle include zero views (default: true for consistency)
219 if ( ! isset( $args['views_query'] ) )
220 $args['views_query'] = [];
221
222 // check for custom parameter (camelCase used by Query Loop restQueryArgs)
223 $include_zero_views = $request->get_param( 'pvc_include_zero_views' );
224
225 if ( $include_zero_views === null )
226 $include_zero_views = $request->get_param( 'pvcIncludeZeroViews' );
227
228 if ( $include_zero_views !== null )
229 $args['views_query']['hide_empty'] = ! rest_sanitize_boolean( $include_zero_views );
230 else
231 $args['views_query']['hide_empty'] = false; // default: include zero views
232
233 return $args;
234 }
235
236 /**
237 * Enqueue block editor assets.
238 *
239 * @return void
240 */
241 public function enqueue_editor_assets() {
242 // check if JS file exists
243 $js_file = POST_VIEWS_COUNTER_PATH . 'js/integration-gutenberg.js';
244
245 if ( ! file_exists( $js_file ) )
246 return;
247
248 // get main instance
249 $pvc = Post_Views_Counter();
250 $version = $pvc->defaults['version'];
251
252 $file_version = @filemtime( $js_file );
253 if ( $file_version )
254 $version = $file_version;
255
256 // enqueue script
257 wp_enqueue_script(
258 'pvc-integration-gutenberg',
259 POST_VIEWS_COUNTER_URL . '/js/integration-gutenberg.js',
260 [ 'wp-element', 'wp-components', 'wp-block-editor', 'wp-hooks', 'wp-compose', 'wp-data', 'wp-i18n' ],
261 $version,
262 true
263 );
264
265 // add inline script with configuration
266 wp_add_inline_script(
267 'pvc-integration-gutenberg',
268 'var pvcGutenbergIntegration = ' . wp_json_encode( [
269 'enabled' => true,
270 'defaultIncludeZeroViews' => true
271 ] ) . ';',
272 'before'
273 );
274 }
275 }
276
277 new Post_Views_Counter_Integration_Gutenberg();
278