Category Posts Widget - Version 4.9.5

Version Description

  • May 12th 2020 =
  • Fixed Widget_Title filter missing parameters
Download this release

Release Info

Developer Kometschuh
Plugin Icon 128x128 Category Posts Widget
Version 4.9.5
Comparing to
See all releases

Code changes from version 4.9.4 to 4.9.5

Files changed (3) hide show
  1. cat-posts.php +2 -2
  2. class-widget.php +1689 -1687
  3. readme.txt +4 -1
cat-posts.php CHANGED
@@ -12,7 +12,7 @@ Plugin Name: Category Posts Widget
12
  Plugin URI: https://wordpress.org/plugins/category-posts/
13
  Description: Adds a widget that shows the most recent posts from a single category.
14
  Author: TipTopPress
15
- Version: 4.9.4
16
  Author URI: http://tiptoppress.com
17
  Text Domain: category-posts
18
  Domain Path: /languages
@@ -25,7 +25,7 @@ if ( ! defined( 'ABSPATH' ) ) {
25
  exit;
26
  }
27
 
28
- const VERSION = '4.9.4';
29
  const DOC_URL = 'http://tiptoppress.com/category-posts-widget/documentation-4-9/';
30
  const PRO_URL = 'http://tiptoppress.com/term-and-category-based-posts-widget/';
31
  const SUPPORT_URL = 'https://wordpress.org/support/plugin/category-posts/';
12
  Plugin URI: https://wordpress.org/plugins/category-posts/
13
  Description: Adds a widget that shows the most recent posts from a single category.
14
  Author: TipTopPress
15
+ Version: 4.9.5
16
  Author URI: http://tiptoppress.com
17
  Text Domain: category-posts
18
  Domain Path: /languages
25
  exit;
26
  }
27
 
28
+ const VERSION = '4.9.5';
29
  const DOC_URL = 'http://tiptoppress.com/category-posts-widget/documentation-4-9/';
30
  const PRO_URL = 'http://tiptoppress.com/term-and-category-based-posts-widget/';
31
  const SUPPORT_URL = 'https://wordpress.org/support/plugin/category-posts/';
class-widget.php CHANGED
@@ -1,1687 +1,1689 @@
1
- <?php
2
- /**
3
- * Implementation of the widget class.
4
- *
5
- * @package categoryposts.
6
- *
7
- * @since 4.7
8
- */
9
-
10
- namespace categoryPosts;
11
-
12
- // Don't call the file directly.
13
- if ( ! defined( 'ABSPATH' ) ) {
14
- exit;
15
- }
16
-
17
- /**
18
- * Category Posts Widget Class
19
- *
20
- * Shows the single category posts with some configurable options
21
- */
22
- class Widget extends \WP_Widget {
23
-
24
- /**
25
- * Widget constructor.
26
- */
27
- public function __construct() {
28
- $widget_ops = array(
29
- 'classname' => 'cat-post-widget',
30
- 'description' => __( 'List single category posts', 'category-posts' ),
31
- );
32
- parent::__construct( WIDGET_BASE_ID, __( 'Category Posts', 'category-posts' ), $widget_ops );
33
- }
34
-
35
- /**
36
- * Calculate the HTML for showing the thumb of a post item.
37
- *
38
- * Used as a filter for the thumb wordpress API to add css based stretching and cropping
39
- * when the image is not at the requested dimensions
40
- *
41
- * @param string $html The original HTML generated by the core APIS.
42
- * @param int $post_id the ID of the post of which the thumb is a featured image.
43
- * @param int $post_thumbnail_id The id of the featured image attachment.
44
- * @param string|array $size The requested size identified by name or (width, height) array.
45
- * @param mixed $attr ignored in this context.
46
- * @return string The HTML for the thumb related to the post
47
- *
48
- * @since 4.1
49
- */
50
- public function post_thumbnail_html( $html, $post_id, $post_thumbnail_id, $size, $attr ) {
51
-
52
- $use_css_cropping = isset( $this->instance['use_css_cropping'] ) && $this->instance['use_css_cropping'];
53
- $thumb = isset( $this->instance['template'] ) && preg_match( '/%thumb%/', $this->instance['template'] );
54
-
55
- if ( ! ( $use_css_cropping && $thumb ) ) {
56
- return $html;
57
- }
58
- $meta = image_get_intermediate_size( $post_thumbnail_id, $size );
59
-
60
- if ( empty( $meta ) ) {
61
- $post_img = wp_get_attachment_metadata( $post_thumbnail_id, $size );
62
- $meta['file'] = basename( $post_img['file'] );
63
- }
64
-
65
- $origfile = get_attached_file( $post_thumbnail_id, true ); // the location of the full file.
66
- $file = dirname( $origfile ) . '/' . $meta['file']; // the location of the file displayed as thumb.
67
- if ( file_exists( $file ) ) {
68
- list( $width, $height ) = getimagesize( $file ); // get actual size of the thumb file.
69
-
70
- if ( isset( $this->instance['use_css_cropping'] ) && $this->instance['use_css_cropping'] ) {
71
- $show_post_format = isset( $this->instance['show_post_format'] ) && ( 'none' !== $this->instance['show_post_format'] );
72
- if ( $show_post_format || $this->instance['thumb_hover'] ) {
73
- $format = get_post_format() ? : 'standard';
74
- $post_format_class = 'cat-post-format cat-post-format-' . $format;
75
- }
76
- $html = '<span class="cat-post-crop ' . $post_format_class . '">' . $html . '</span>';
77
- } else {
78
- // use_css_cropping is not used.
79
- // wrap span.
80
- $html = '<span>' . $html . '</span>';
81
- }
82
- }
83
- return $html;
84
- }
85
-
86
- /*
87
- * wrapper to execute the the_post_thumbnail with filters.
88
- */
89
- /**
90
- * Calculate the HTML for showing the thumb of a post item.
91
- *
92
- * It is a wrapper to execute the the_post_thumbnail with filters
93
- *
94
- * @param string|array $size The requested size identified by name or (width, height) array.
95
- *
96
- * @return string The HTML for the thumb related to the post and empty string if it can not be calculated
97
- *
98
- * @since 4.1
99
- */
100
- public function the_post_thumbnail( $size = 'post-thumbnail' ) {
101
- if ( empty( $size ) ) { // if junk value, make it a normal thumb.
102
- $size = 'post-thumbnail';
103
- } elseif ( is_array( $size ) && ( 2 === count( $size ) ) ) { // good format at least.
104
- // normalize to ints first.
105
- $size[0] = (int) $size[0];
106
- $size[1] = (int) $size[1];
107
- if ( ( 0 === $size[0] ) && ( 0 === $size[1] ) ) { // Both values zero then revert to thumbnail.
108
- $size = array( get_option( 'thumbnail_size_w', 150 ), get_option( 'thumbnail_size_h', 150 ) );
109
- } elseif ( ( 0 === $size[0] ) && ( 0 !== $size[1] ) ) {
110
- // if thumb width 0 set to max/full widths for wp rendering
111
- $post_thumb = get_the_post_thumbnail( get_the_ID(), 'full' );
112
- preg_match( '/(?<=width=")[\d]*/', $post_thumb, $thumb_full_w );
113
- $size[0] = $thumb_full_w[0];
114
- } elseif ( ( 0 !== $size[0] ) && ( 0 === $size[1] ) ) {
115
- // if thumb height 0 get full thumb for ratio and calc height with ratio
116
- $post_thumb = get_the_post_thumbnail( get_the_ID(), 'full' );
117
- preg_match( '/(?<=width=")[\d]*/', $post_thumb, $thumb_full_w );
118
- preg_match( '/(?<=height=")[\d]*/', $post_thumb, $thumb_full_h );
119
- $ratio = $thumb_full_w[0] / $thumb_full_h[0];
120
- $size[1] = intval( $size[0] / $ratio );
121
- }
122
- } else {
123
- $size = array( get_option( 'thumbnail_size_w', 150 ), get_option( 'thumbnail_size_h', 150 ) ); // yet another form of junk.
124
- }
125
-
126
- $post_thumbnail_id = get_post_thumbnail_id( get_the_ID() );
127
- if ( ! $post_thumbnail_id && $this->instance['default_thunmbnail'] ) {
128
- $post_thumbnail_id = $this->instance['default_thunmbnail'];
129
- }
130
-
131
- do_action( 'begin_fetch_post_thumbnail_html', get_the_ID(), $post_thumbnail_id, $size );
132
- $html = wp_get_attachment_image( $post_thumbnail_id, $size, false, '' );
133
- if ( ! $html ) {
134
- $ret = '';
135
- } else {
136
- $ret = $this->post_thumbnail_html( $html, get_the_ID(), $post_thumbnail_id, $size, '' );
137
- }
138
- do_action( 'end_fetch_post_thumbnail_html', get_the_ID(), $post_thumbnail_id, $size );
139
-
140
- return $ret;
141
- }
142
-
143
- /**
144
- * Excerpt more link filter
145
- *
146
- * @param string $more The "more" text passed by the filter.
147
- *
148
- * @return string The link to the post with the "more" text configured in the widget.
149
- */
150
- public function excerpt_more_filter( $more ) {
151
- return ' <a class="cat-post-excerpt-more more-link" href="' . get_permalink() . '">' . esc_html( $this->instance['excerpt_more_text'] ) . '</a>';
152
- }
153
-
154
- /**
155
- * Apply the_content filter for excerpt
156
- * This should show sharing buttons which comes with other widgets in the widget output in the same way as on the main content
157
- *
158
- * @param string $text The HTML with other applied excerpt filters.
159
- *
160
- * @return string If option hide_social_buttons is unchecked applay the_content filter.
161
- *
162
- * @since 4.6
163
- */
164
- public function apply_the_excerpt( $text ) {
165
- $ret = apply_filters( 'the_content', $text );
166
-
167
- return $ret;
168
- }
169
-
170
- /**
171
- * Calculate the wp-query arguments matching the filter settings of the widget
172
- *
173
- * @param array $instance Array which contains the various settings.
174
- * @return array The array that can be fed to wp_Query to get the relevant posts
175
- *
176
- * @since 4.6
177
- */
178
- public function queryArgs( $instance ) {
179
-
180
- $valid_sort_orders = array( 'date', 'title', 'comment_count', 'rand' );
181
- if ( isset( $instance['sort_by'] ) && in_array( $instance['sort_by'], $valid_sort_orders, true ) ) {
182
- $sort_by = $instance['sort_by'];
183
- } else {
184
- $sort_by = 'date';
185
- }
186
- $sort_order = ( isset( $instance['asc_sort_order'] ) && $instance['asc_sort_order'] ) ? 'ASC' : 'DESC';
187
-
188
- // Get array of post info.
189
- $args = array(
190
- 'orderby' => $sort_by,
191
- 'order' => $sort_order,
192
- 'ignore_sticky_posts' => 1, // Make sure we do not get stickies out of order.
193
- 'no_found_rows' => true, // Do not count the total numbers of rows by default.
194
- );
195
-
196
- $non_default_valid_status = array(
197
- 'publish',
198
- 'future',
199
- 'publish,future',
200
- 'private',
201
- 'private,publish',
202
- 'private,publish,future',
203
- );
204
- if ( isset( $instance['status'] ) && in_array( $instance['status'], $non_default_valid_status, true ) ) {
205
- $args['post_status'] = $instance['status'];
206
- }
207
-
208
- if ( isset( $instance['num'] ) ) {
209
- $args['showposts'] = (int) $instance['num'];
210
- }
211
-
212
- if ( isset( $instance['offset'] ) && ( (int) $instance['offset'] > 1 ) ) {
213
- $args['offset'] = (int) $instance['offset'] - 1;
214
- }
215
- if ( isset( $instance['cat'] ) ) {
216
- if ( isset( $instance['no_cat_childs'] ) && $instance['no_cat_childs'] ) {
217
- $args['category__in'] = (int) $instance['cat'];
218
- } else {
219
- $args['cat'] = (int) $instance['cat'];
220
- }
221
- }
222
-
223
- if ( is_singular() && isset( $instance['exclude_current_post'] ) && $instance['exclude_current_post'] ) {
224
- $args['post__not_in'] = array( get_the_ID() );
225
- }
226
-
227
- if ( isset( $instance['hideNoThumb'] ) && $instance['hideNoThumb'] ) {
228
- $args = array_merge( $args, array(
229
- 'meta_query' => array(
230
- array(
231
- 'key' => '_thumbnail_id',
232
- 'compare' => 'EXISTS',
233
- ),
234
- ),
235
- ) );
236
- }
237
-
238
- switch ( $instance['date_range'] ) {
239
- case 'days_ago':
240
- $ago = (int) $instance['days_ago'];
241
-
242
- // If there is no valid integer value given, bail.
243
- if ( 0 === $ago ) {
244
- break;
245
- }
246
-
247
- $date = date( 'Y-m-d', strtotime( '-' . $ago . ' days' ) );
248
- $args['date_query'] = array(
249
- 'after' => $date,
250
- 'inclusive' => true,
251
- );
252
- break;
253
- case 'between_dates':
254
- // Validation note - not doing any, assuming the query will
255
- // fail gracefully enough for now as it is not clear what Should
256
- // the validation be right now.
257
- $start_date = $instance['start_date'];
258
- $end_date = $instance['end_date'];
259
- $args['date_query'] = array(
260
- 'after' => $start_date,
261
- 'before' => $end_date,
262
- 'inclusive' => true,
263
- );
264
- break;
265
- }
266
-
267
- return $args;
268
- }
269
-
270
- /**
271
- * Calculate the HTML of the title based on the widget settings
272
- *
273
- * @param string $before_title The sidebar configured HTML that should come
274
- * before the title itself.
275
- * @param string $after_title The sidebar configured HTML that should come
276
- * after the title itself.
277
- * @param array $instance Array which contains the various settings.
278
- * @return string The HTML for the title area
279
- *
280
- * @since 4.6
281
- */
282
- public function titleHTML( $before_title, $after_title, $instance ) {
283
- $ret = '';
284
-
285
- // If no title, use the name of the category.
286
- if ( ! isset( $instance['title'] ) || ! $instance['title'] ) {
287
- $instance['title'] = '';
288
- if ( 0 !== (int) $instance['cat'] ) {
289
- $category_info = get_category( $instance['cat'] );
290
- if ( $category_info && ! is_wp_error( $category_info ) ) {
291
- $instance['title'] = $category_info->name;
292
- } else {
293
- $instance['cat'] = 0; // For further processing treat it like "all categories".
294
- $instance['title'] = __( 'Recent Posts', 'category-posts' );
295
- }
296
- } else {
297
- $instance['title'] = __( 'Recent Posts', 'category-posts' );
298
- }
299
- }
300
-
301
- if ( ! ( isset( $instance['hide_title'] ) && $instance['hide_title'] ) ) {
302
- $ret = $before_title;
303
- if ( isset( $instance['is_shortcode'] ) ) {
304
- $title = esc_html( $instance['title'] );
305
- } else {
306
- $title = apply_filters( 'widget_title', $instance['title'] );
307
- }
308
-
309
- if ( isset( $instance['title_link'] ) && $instance['title_link'] ) {
310
- if ( 0 !== $instance['cat'] ) {
311
- $ret .= '<a href="' . get_category_link( $instance['cat'] ) . '">' . $title . '</a>';
312
- } elseif ( isset( $instance['title_link_url'] ) && $instance['title_link_url'] ) {
313
- $ret .= '<a href="' . esc_url( $instance['title_link_url'] ) . '">' . $title . '</a>';
314
- } else {
315
- $ret .= '<a href="' . esc_url( $this->blog_page_url() ) . '">' . $title . '</a>';
316
- }
317
- } else {
318
- $ret .= $title;
319
- }
320
-
321
- $ret .= $after_title;
322
- }
323
-
324
- return $ret;
325
- }
326
-
327
- /**
328
- * Get the URL of the blog page or home page if no explicit blog page is defined.
329
- *
330
- * @return string The URL of the blog page
331
- *
332
- * @since 4.8
333
- */
334
- private function blog_page_url() {
335
-
336
- $blog_page = get_option( 'page_for_posts' );
337
- if ( $blog_page ) {
338
- $url = get_permalink( $blog_page );
339
- } else {
340
- $url = home_url();
341
- }
342
-
343
- return $url;
344
- }
345
-
346
- /**
347
- * Calculate the HTML of the load more button based on the widget settings
348
- *
349
- * @param array $instance Array which contains the various settings.
350
- *
351
- * @return string The HTML for the load more area
352
- *
353
- * @since 4.9
354
- */
355
- public function loadMoreHTML( $instance ) {
356
-
357
- if ( ! $instance['enable_loadmore'] ) {
358
- return '';
359
- }
360
-
361
- $ret = '<div class="' . __NAMESPACE__ . '-loadmore">';
362
- $context = 0;
363
- if ( is_singular() ) {
364
- $context = get_the_ID();
365
- }
366
-
367
- add_action( 'wp_footer', __NAMESPACE__ . '\embed_loadmore_scripts' );
368
-
369
- // We rely on the widget number to be properly set.
370
- // but need a slight different handling for proper widgets.
371
- if ( is_int( $this->number ) ) {
372
- // it is a proper widget, add the prefix.
373
- $id = 'widget-' . $this->number;
374
- } else {
375
- $id = str_replace( WIDGET_BASE_ID . '-', '', $this->number );
376
- }
377
-
378
- $number = $instance['num'];
379
- $start = $instance['offset'] + $number;
380
- $loading = $instance['loading_text'];
381
-
382
- $ret .= '<button type="button" data-loading="' . esc_attr( $loading ) . '" data-id="' . esc_attr( $id ) . '" data-start="' . esc_attr( $start ) . '" data-context="' . esc_attr( $context ) . '" data-number="' . esc_attr( $number ) . '">' . esc_html( $instance['loadmore_text'] ) . '</button>';
383
- $ret .= '</div>';
384
- return $ret;
385
- }
386
-
387
- /**
388
- * Calculate the HTML of the footer based on the widget settings
389
- *
390
- * @param array $instance Array which contains the various settings.
391
- * @return string The HTML for the footer area
392
- *
393
- * @since 4.6
394
- */
395
- public function footerHTML( $instance ) {
396
-
397
- $ret = '';
398
- $url = '';
399
- $text = '';
400
-
401
- if ( isset( $instance['footer_link'] ) ) {
402
- $url = $instance['footer_link'];
403
- }
404
-
405
- if ( isset( $instance['footer_link_text'] ) ) {
406
- $text = $instance['footer_link_text'];
407
- }
408
-
409
- // if url is set, but no text, just use the url as text.
410
- if ( empty( $text ) && ! empty( $url ) ) {
411
- $text = $url;
412
- }
413
-
414
- // if no url is set but just text, assume the url should be to the relevant archive page
415
- // category archive for categories filter and home page or blog page when "all categories"
416
- // is used.
417
- if ( ! empty( $text ) && empty( $url ) ) {
418
- if ( isset( $instance['cat'] ) && ( 0 !== $instance['cat'] ) && ( null !== get_category( $instance['cat'] ) ) ) {
419
- $url = get_category_link( $instance['cat'] );
420
- } else {
421
- $url = $this->blog_page_url();
422
- }
423
- }
424
-
425
- if ( ! empty( $url ) ) {
426
- $ret .= '<a class="cat-post-footer-link" href="' . esc_url( $url ) . '">' . esc_html( $text ) . '</a>';
427
- }
428
-
429
- return $ret;
430
- }
431
-
432
- /**
433
- * Current post item date string based on the format requested in the settings
434
- *
435
- * @param array $instance Array which contains the various settings.
436
- * @param bool $everything_is_link Indicates whether the return string should avoid links.
437
- *
438
- * @since 4.8
439
- */
440
- public function itemDate( $instance, $everything_is_link ) {
441
- $ret = '';
442
-
443
- if ( ! isset( $instance['preset_date_format'] ) ) {
444
- $preset_date_format = 'other';
445
- } else {
446
- $preset_date_format = $instance['preset_date_format'];
447
- }
448
-
449
- $attr = '';
450
- switch ( $preset_date_format ) {
451
- case 'sitedateandtime':
452
- $date = get_the_time( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) );
453
- break;
454
- case 'localsitedateandtime':
455
- $date = get_the_time( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ) . ' GMT';
456
- $time = get_post_time( 'U', true );
457
- $attr = ' data-publishtime="' . $time . '" data-format="time"';
458
- add_action( 'wp_footer', __NAMESPACE__ . '\embed_date_scripts' );
459
- break;
460
- case 'sitedate':
461
- $date = get_the_time( get_option( 'date_format' ) );
462
- break;
463
- case 'localsitedate':
464
- $date = get_the_time( get_option( 'date_format' ) ) . ' GMT';
465
- $time = get_post_time( 'U', true );
466
- $attr = ' data-publishtime="' . $time . '" data-format="date"';
467
- add_action( 'wp_footer', __NAMESPACE__ . '\embed_date_scripts' );
468
- break;
469
- case 'sincepublished':
470
- $date = human_time_diff( get_the_time( 'U' ), current_time( 'timestamp' ) );
471
- break;
472
- default:
473
- if ( isset( $instance['date_format'] ) && strlen( trim( $instance['date_format'] ) ) > 0 ) {
474
- $date_format = $instance['date_format'];
475
- } else {
476
- $date_format = 'j M Y';
477
- }
478
- $date = get_the_time( $date_format );
479
- break;
480
- }
481
- $ret .= '<span class="cat-post-date"' . $attr . '>';
482
- if ( isset( $instance['date_link'] ) && $instance['date_link'] && ! $everything_is_link ) {
483
- $ret .= '<a href="' . \get_the_permalink() . '">';
484
- }
485
- $ret .= $date;
486
-
487
- if ( isset( $instance['date_link'] ) && $instance['date_link'] && ! $everything_is_link ) {
488
- $ret .= '</a>';
489
- }
490
- $ret .= '</span>';
491
- return $ret;
492
- }
493
-
494
-
495
- /**
496
- * Calculate the HTML for showing the thumb of a post item.
497
- * Expected to be called from a loop with globals properly set.
498
- *
499
- * @param array $instance Array which contains the various settings.
500
- * @param bool $no_link indicates whether the thumb should be wrapped in a link or a span.
501
- * @return string The HTML for the thumb related to the post
502
- *
503
- * @since 4.6
504
- */
505
- public function itemThumb( $instance, $no_link ) {
506
- $ret = '';
507
-
508
- if ( ( isset( $instance['default_thunmbnail'] ) && ( $instance['default_thunmbnail'] ) ) || has_post_thumbnail() ) {
509
- $class = '';
510
- $disable_css = isset( $instance['disable_css'] ) && $instance['disable_css'];
511
-
512
- if ( isset( $this->instance['thumb_hover'] ) && ! $disable_css ) {
513
- $class = 'class="cat-post-thumbnail cat-post-' . $instance['thumb_hover'] . '"';
514
- } else {
515
- $class = 'class="cat-post-thumbnail"';
516
- }
517
-
518
- $title_args = array( 'echo' => false );
519
-
520
- if ( $no_link ) {
521
- $ret .= '<span ' . $class . '>';
522
- } else {
523
- $ret .= '<a ' . $class . ' href="' . get_the_permalink() . '" title="' . the_title_attribute( $title_args ) . '">';
524
- }
525
-
526
- $ret .= $this->the_post_thumbnail( array( $this->instance['thumb_w'], $this->instance['thumb_h'] ) );
527
-
528
- if ( $no_link ) {
529
- $ret .= '</span>';
530
- } else {
531
- $ret .= '</a>';
532
- }
533
- }
534
-
535
- return $ret;
536
- }
537
-
538
- /**
539
- * Current post item categories string
540
- *
541
- * @param array $instance Array which contains the various settings.
542
- * @param bool $everything_is_link Indicates whether the return string should avoid links.
543
- *
544
- * @since 4.8
545
- */
546
- public function itemCategories( $instance, $everything_is_link ) {
547
-
548
- $ret = '<span class="cat-post-tax-category">';
549
- $cat_ids = wp_get_post_categories( get_the_ID(), array( 'number' => 0 ) );
550
- foreach ( $cat_ids as $cat_id ) {
551
- if ( $everything_is_link ) {
552
- $ret .= ' ' . get_cat_name( $cat_id );
553
- } else {
554
- $ret .= " <a href='" . get_category_link( $cat_id ) . "'>" . get_cat_name( $cat_id ) . '</a>';
555
- }
556
- }
557
- $ret .= '</span>';
558
- return $ret;
559
- }
560
-
561
- /**
562
- * Current post item tags string
563
- *
564
- * @param array $instance Array which contains the various settings.
565
- * @param bool $everything_is_link Indicates whether the return string should avoid links.
566
- *
567
- * @since 4.8
568
- */
569
- public function itemTags( $instance, $everything_is_link ) {
570
-
571
- $ret = '<span class="cat-post-tax-tag">';
572
- $tag_ids = wp_get_post_tags( get_the_ID(), array( 'number' => 0 ) );
573
- foreach ( $tag_ids as $tag_id ) {
574
- if ( $everything_is_link ) {
575
- $ret .= ' ' . $tag_id->name;
576
- } else {
577
- $ret .= " <a href='" . get_tag_link( $tag_id->term_id ) . "'>" . $tag_id->name . '</a>';
578
- }
579
- }
580
- $ret .= '</span>';
581
- return $ret;
582
- }
583
-
584
- /**
585
- * Current post item comment number string
586
- *
587
- * @param array $instance Array which contains the various settings.
588
- * @param bool $everything_is_link Indicates whether the return string should avoid links.
589
- *
590
- * @since 4.8
591
- */
592
- public function itemCommentNum( $instance, $everything_is_link ) {
593
- global $post;
594
-
595
- $ret = '<span class="cat-post-comment-num">';
596
-
597
- if ( $everything_is_link ) {
598
- $ret .= '(' . \get_comments_number() . ')';
599
- } else {
600
- $link = sprintf(
601
- '<a href="%1$s" title="%2$s">(%3$d)</a>',
602
- esc_url( get_comments_link( $post->ID ) ),
603
- esc_attr( sprintf( __( '(%d) comments to this post' ), get_comments_number() ) ),
604
- get_comments_number()
605
- );
606
- $ret .= $link;
607
- }
608
-
609
- $ret .= '</span>';
610
- return $ret;
611
- }
612
-
613
- /**
614
- * Current post item author string
615
- *
616
- * @param array $instance Array which contains the various settings.
617
- * @param bool $everything_is_link Indicates whether the return string should avoid links.
618
- *
619
- * @since 4.8
620
- */
621
- public function itemAuthor( $instance, $everything_is_link ) {
622
-
623
- $ret = '<span class="cat-post-author">';
624
-
625
- if ( $everything_is_link ) {
626
- $ret .= get_the_author();
627
- } else {
628
- $link = get_the_author_posts_link();
629
- $ret .= $link;
630
- }
631
- $ret .= '</span>';
632
- return $ret;
633
- }
634
-
635
- /**
636
- * Current post item excerpt string
637
- *
638
- * @param array $instance Array which contains the various settings.
639
- * @param bool $everything_is_link Indicates whether the return string should avoid links.
640
- *
641
- * @since 4.8
642
- */
643
- public function itemExcerpt( $instance, $everything_is_link ) {
644
- global $post;
645
-
646
- // use the_excerpt filter to get the "normal" excerpt of the post
647
- // then apply our filter to let users customize excerpts in their own way.
648
- if ( isset( $instance['excerpt_length'] ) && ( $instance['excerpt_length'] > 0 ) ) {
649
- $length = (int) $instance['excerpt_length'];
650
- } else {
651
- $length = 999; // Use the wordpress default.
652
- }
653
-
654
- if ( ! isset( $instance['excerpt_filters'] ) || $instance['excerpt_filters'] ) { // pre 4.7 widgets has filters on.
655
- $excerpt = apply_filters( 'the_excerpt', \get_the_excerpt() );
656
- } else { // if filters off replicate functionality of core generating excerpt.
657
- $more_text = '[&hellip;]';
658
- if ( isset( $instance['excerpt_more_text'] ) && $instance['excerpt_more_text'] ) {
659
- $more_text = ltrim( $instance['excerpt_more_text'] );
660
- }
661
-
662
- if ( $everything_is_link ) {
663
- $excerpt_more_text = ' <span class="cat-post-excerpt-more">' . $more_text . '</span>';
664
- } else {
665
- $excerpt_more_text = ' <a class="cat-post-excerpt-more" href="' . get_permalink() . '" title="' . sprintf( __( 'Continue reading %s' ), get_the_title() ) . '">' . $more_text . '</a>';
666
- }
667
- if ( '' === $post->post_excerpt ) {
668
- $text = get_the_content( '' );
669
- $text = strip_shortcodes( $text );
670
- $excerpt = \wp_trim_words( $text, $length, $excerpt_more_text );
671
- // adjust html output same way as for the normal excerpt,
672
- // just force all functions depending on the_excerpt hook.
673
- $excerpt = shortcode_unautop( wpautop( convert_chars( convert_smilies( wptexturize( $excerpt ) ) ) ) );
674
- } else {
675
- $text = $post->post_excerpt;
676
- $excerpt = \wp_trim_words( $text, $length, $excerpt_more_text );
677
- $excerpt = shortcode_unautop( wpautop( convert_chars( convert_smilies( wptexturize( $excerpt ) ) ) ) );
678
- }
679
- }
680
- $ret = apply_filters( 'cpw_excerpt', $excerpt, $this );
681
- return $ret;
682
- }
683
-
684
- /**
685
- * Current post item title string
686
- *
687
- * @param array $instance Array which contains the various settings.
688
- * @param bool $everything_is_link Indicates whether the return string should avoid links.
689
- *
690
- * @since 4.8
691
- */
692
- public function itemTitle( $instance, $everything_is_link ) {
693
-
694
- $ret = '';
695
-
696
- if ( $everything_is_link ) {
697
- $ret .= '<span class="cat-post-title">' . get_the_title() . '</span>';
698
- } else {
699
- $ret .= '<a class="cat-post-title"';
700
- $ret .= ' href="' . get_the_permalink() . '" rel="bookmark">' . get_the_title();
701
- $ret .= '</a>';
702
- }
703
- return $ret;
704
- }
705
-
706
- /**
707
- * Calculate the HTML for a post item based on the widget settings and post.
708
- * Expected to be called in an active loop with all the globals set.
709
- *
710
- * @param array $instance Array which contains the various settings.
711
- * @param null|integer $current_post_id If on singular page specifies the id of
712
- * the post, otherwise null.
713
- * @return string The HTML for item related to the post
714
- *
715
- * @since 4.6
716
- */
717
- public function itemHTML( $instance, $current_post_id ) {
718
- global $post;
719
-
720
- $everything_is_link = isset( $instance['everything_is_link'] ) && $instance['everything_is_link'];
721
- $wrap = isset( $instance['text_do_not_wrap_thumb'] ) && $instance['text_do_not_wrap_thumb'];
722
-
723
- $template = '';
724
- if ( isset( $instance['template'] ) ) {
725
- $template = $instance['template'];
726
- } else {
727
- $template = convert_settings_to_template( $instance );
728
- }
729
- $ret = '<li ';
730
-
731
- // Current post.
732
- if ( $current_post_id === $post->ID ) {
733
- $ret .= "class='cat-post-item cat-post-current'";
734
- } else {
735
- $ret .= "class='cat-post-item'";
736
- }
737
- $ret .= '>'; // close the li opening tag.
738
-
739
- if ( $everything_is_link ) {
740
- $ret .= '<a class="cat-post-everything-is-link" href="' . get_the_permalink() . '" title="">';
741
- }
742
-
743
- // Try to do smart formatting for floating thumb based on its location.
744
- if ( $wrap ) {
745
- if ( preg_match( '#(\%thumb\%)#', $template ) && ! preg_match( '#(\%thumb\%$)#', $template ) ) {
746
- $thumb_flex = explode( '%thumb%', $template );
747
- if ( 1 === count( $thumb_flex ) ) {
748
- $template = '<div class="cat-post-do-not-wrap-thumbnail">%thumb%<div>' . $thumb_flex[0] . '</div></div>';
749
- }
750
- if ( 2 === count( $thumb_flex ) ) {
751
- $template = $thumb_flex[0] . '<div class="cat-post-do-not-wrap-thumbnail">%thumb%<div>' . $thumb_flex[1] . '</div></div>';
752
- }
753
- }
754
- }
755
-
756
- // Post details (Template).
757
- $widget = $this;
758
- $template_res = preg_replace_callback( get_template_regex(), function ( $matches ) use ( $widget, $instance, $everything_is_link ) {
759
- switch ( $matches[0] ) {
760
- case '%title%':
761
- return $widget->itemTitle( $instance, $everything_is_link );
762
- case '%author%':
763
- return $widget->itemAuthor( $instance, $everything_is_link );
764
- case '%commentnum%':
765
- return $widget->itemCommentNum( $instance, $everything_is_link );
766
- case '%date%':
767
- return $widget->itemDate( $instance, $everything_is_link );
768
- case '%thumb%':
769
- return $widget->itemThumb( $instance, $everything_is_link );
770
- case '%post_tag%':
771
- return $widget->itemTags( $instance, $everything_is_link );
772
- case '%category%':
773
- return $widget->itemCategories( $instance, $everything_is_link );
774
- case '%excerpt%':
775
- return $widget->itemExcerpt( $instance, $everything_is_link );
776
- default:
777
- return $matches[0];
778
- }
779
- }, $template );
780
-
781
- // Replace empty line with closing and opening DIV.
782
- $template_res = trim( $template_res );
783
- $template_res = str_replace( "\n\r", '</div><div>', $template_res ); // in widget areas.
784
- $template_res = str_replace( "\n\n", '</div><div>', $template_res ); // as shortcode.
785
- $template_res = '<div>' . $template_res . '</div>';
786
-
787
- // replace new lines with spaces.
788
- $template_res = str_replace( "\n\r", ' ', $template_res ); // in widget areas.
789
- $template_res = str_replace( "\n\n", ' ', $template_res ); // as shortcode.
790
-
791
- $ret .= $template_res;
792
-
793
- if ( $everything_is_link ) {
794
- $ret .= '</a>';
795
- }
796
-
797
- $ret .= '</li>';
798
- return $ret;
799
- }
800
-
801
- /**
802
- * Filter to set the number of words in an excerpt
803
- *
804
- * @param int $length The number of words as configured by wordpress core or set by previous filters.
805
- * @return int The number of words configured for the widget,
806
- * or the $length parameter if it is not configured or garbage value.
807
- *
808
- * @since 4.6
809
- */
810
- public function excerpt_length_filter( $length ) {
811
- if ( isset( $this->instance['excerpt_length'] ) && $this->instance['excerpt_length'] > 0 ) {
812
- $length = $this->instance['excerpt_length'];
813
- }
814
- return $length;
815
- }
816
-
817
- /**
818
- * Set the proper excerpt filters based on the settings
819
- *
820
- * @param array $instance widget settings.
821
- * @return void
822
- *
823
- * @since 4.6
824
- */
825
- public function setExcerpFilters( $instance ) {
826
-
827
- if ( isset( $instance['excerpt'] ) && $instance['excerpt'] ) {
828
-
829
- // Excerpt length filter.
830
- if ( isset( $instance['excerpt_length'] ) && ( (int) $instance['excerpt_length'] ) > 0 ) {
831
- add_filter( 'excerpt_length', array( $this, 'excerpt_length_filter' ) );
832
- }
833
-
834
- if ( isset( $instance['excerpt_more_text'] ) && ( '' !== ltrim( $instance['excerpt_more_text'] ) ) ) {
835
- add_filter( 'excerpt_more', array( $this, 'excerpt_more_filter' ) );
836
- }
837
-
838
- add_filter( 'the_excerpt', array( $this, 'apply_the_excerpt' ) );
839
- }
840
- }
841
-
842
- /**
843
- * Remove the excerpt filter
844
- *
845
- * @param array $instance widget settings.
846
- * @return void
847
- *
848
- * @since 4.6
849
- */
850
- public function removeExcerpFilters( $instance ) {
851
- remove_filter( 'excerpt_length', array( $this, 'excerpt_length_filter' ) );
852
- remove_filter( 'excerpt_more', array( $this, 'excerpt_more_filter' ) );
853
- add_filter( 'get_the_excerpt', 'wp_trim_excerpt' );
854
- remove_filter( 'the_excerpt', array( $this, 'apply_the_excerpt' ) );
855
- }
856
-
857
- /**
858
- * The main widget display controller
859
- *
860
- * Called by the sidebar processing core logic to display the widget.
861
- *
862
- * @param array $args An array containing the "environment" setting for the widget,
863
- * namely, the enclosing tags for the widget and its title.
864
- * @param array $instance The settings associate with the widget.
865
- *
866
- * @since 4.1
867
- */
868
- public function widget( $args, $instance ) {
869
-
870
- $instance = upgrade_settings( $instance );
871
-
872
- extract( $args );
873
-
874
- $this->instance = $instance;
875
-
876
- $current_post_id = '';
877
- if ( is_singular() ) {
878
- $current_post_id = get_the_ID();
879
- }
880
-
881
- $items = $this->get_elements_HTML( $instance, $current_post_id, 0, 0 );
882
-
883
- if ( ( 'nothing' === $instance['no_match_handling'] ) || ! empty( $items ) ) {
884
- echo $before_widget; // Xss ok. This is how widget actually expected to behave.
885
- echo $this->titleHTML( $before_title, $after_title, $instance );
886
-
887
- $thumb = isset( $this->instance['template'] ) && preg_match( '/%thumb%/', $this->instance['template'] );
888
-
889
- if ( ! ( isset( $instance['is_shortcode'] ) && $instance['is_shortcode'] ) ) { // the internal id is needed only for widgets.
890
- echo '<ul id="' . esc_attr( WIDGET_BASE_ID ) . '-' . esc_attr( $this->number ) . '-internal" class="' . esc_attr( WIDGET_BASE_ID ) . '-internal' . "\">\n";
891
- } else {
892
- echo '<ul>';
893
- }
894
-
895
- // image crop browser fallback and workaround, no polyfill.
896
- if ( $thumb ) {
897
- if ( apply_filters( 'cpw_enqueue_resources', false ) ) {
898
- frontend_script();
899
- } else {
900
- add_action( 'wp_footer', __NAMESPACE__ . '\embed_front_end_scripts' );
901
- }
902
- }
903
-
904
- // set widget filters.
905
- if ( ! isset( $instance['excerpt_filters'] ) || $instance['excerpt_filters'] ) { // pre 4.7 widgets has filters on.
906
- $this->setExcerpFilters( $instance );
907
- }
908
-
909
- foreach ( $items as $item ) {
910
- echo $item;
911
- }
912
- echo "</ul>\n";
913
-
914
- // Load more only if we think we have more items.
915
- if ( count( $items ) === (int) $instance['num'] ) {
916
- echo $this->loadMoreHTML( $instance );
917
- }
918
-
919
- echo $this->footerHTML( $instance );
920
- echo $after_widget; // Xss ok. This is how widget actually expected to behave.
921
-
922
- // remove widget filters.
923
- if ( ! isset( $instance['excerpt_filters'] ) || $instance['excerpt_filters'] ) { // pre 4.7 widgets has filters on.
924
- $this->removeExcerpFilters( $instance );
925
- }
926
-
927
- wp_reset_postdata();
928
- } elseif ( 'text' === $instance['no_match_handling'] ) {
929
- echo $before_widget; // Xss ok. This is how widget actually expected to behave.
930
- echo $this->titleHTML( $before_title, $after_title, $instance );
931
- echo esc_html( $instance['no_match_text'] );
932
- echo $this->footerHTML( $instance );
933
- echo $after_widget; // Xss ok. This is how widget actually expected to behave.
934
- }
935
- }
936
-
937
- /**
938
- * Get an array of HTML pre item, for item starting from a specific position.
939
- *
940
- * @since 4.9
941
- *
942
- * @param array $instance An array containing the settings of the widget.
943
- * @param string $singular_id The ID of the post in which the widget is rendered,
944
- * an empty string indicates the rendering context
945
- * is not singular.
946
- * @param int $start The start element (0 based).
947
- * @param int $number The maximal number of elements to return. A value of 0
948
- * Indicates to use the widget settings for that.
949
- *
950
- * @return string[] Array of HTML per element with the $start element first
951
- * $start+1 next etc. An empty array is returned if there
952
- * are no applicable items.
953
- */
954
- public function get_elements_HTML( $instance, $singular_id, $start, $number ) {
955
- $ret = array();
956
-
957
- if ( 0 === count( $instance ) ) {
958
- $instance = default_settings();
959
- }
960
-
961
- $this->instance = $instance;
962
-
963
- if($start > 0) {
964
- $instance['offset'] = $start;
965
- }
966
- $number = (int) $number; // sanitize number with the side effect of non
967
- // numbers are converted to zero.
968
- if ( 0 < $number ) {
969
- $instance['num'] = $number;
970
- }
971
- $args = $this->queryArgs( $instance );
972
- $cat_posts = new \WP_Query( $args );
973
- $current_post_id = null;
974
- if ( '' !== $singular_id ) {
975
- $current_post_id = (int) $singular_id;
976
- }
977
-
978
- while ( $cat_posts->have_posts() ) {
979
- $cat_posts->the_post();
980
- $ret[] = $this->itemHTML( $instance, $current_post_id );
981
- }
982
-
983
- wp_reset_postdata();
984
-
985
- return $ret;
986
- }
987
-
988
- /**
989
- * Update the options.
990
- *
991
- * @param array $new_instance The new settings of the widget.
992
- * @param array $old_instance The current settings of the widget.
993
- * @return array
994
- */
995
- public function update( $new_instance, $old_instance ) {
996
-
997
- $new_instance['title'] = sanitize_text_field( $new_instance['title'] ); // sanitize the title like core widgets do.
998
- if ( ! isset( $new_instance['excerpt_filters'] ) ) {
999
- $new_instance['excerpt_filters'] = '';
1000
- }
1001
- if ( current_user_can( 'unfiltered_html' ) ) {
1002
- $instance['text'] = $new_instance['template'];
1003
- } else {
1004
- $instance['text'] = wp_kses_post( $new_instance['template'] );
1005
- }
1006
-
1007
- // Set the version of the DB structure.
1008
- $new_instance['ver'] = VERSION;
1009
- return $new_instance;
1010
- }
1011
-
1012
- /**
1013
- * Output the title panel of the widget configuration form.
1014
- *
1015
- * @param array $instance The widget's settings.
1016
- * @return void
1017
- *
1018
- * @since 4.6
1019
- */
1020
- public function formTitlePanel( $instance ) {
1021
- $cat = (int) $instance['cat'];
1022
-
1023
- $hide_title = false;
1024
- if ( isset( $instance['hide_title'] ) && $instance['hide_title'] ) {
1025
- $hide_title = true;
1026
- }
1027
- ?>
1028
- <h4 data-panel="title"><?php esc_html_e( 'Title', 'category-posts' ); ?></h4>
1029
- <div class="cpwp_ident">
1030
- <?php echo $this->get_checkbox_block_html( $instance, 'hide_title', esc_html__( 'Hide title', 'category-posts' ), true ); ?>
1031
- <div class="categoryposts-data-panel-title-settings" <?php echo ( $hide_title ) ? 'style="display:none"' : ''; ?>>
1032
- <?php echo $this->get_text_input_block_html( $instance, 'title', esc_html__( 'Title', 'category-posts' ), '', true ); ?>
1033
- <?php echo $this->get_checkbox_block_html( $instance, 'title_link', esc_html__( 'Make widget title link', 'category-posts' ), 0 !== $cat ); ?>
1034
- <?php echo $this->get_text_input_block_html( $instance, 'title_link_url', esc_html__( 'Title link URL', 'category-posts' ), '', 0 === $cat ); ?>
1035
- </div>
1036
- </div>
1037
- <?php
1038
- }
1039
-
1040
- /**
1041
- * Output the filter panel of the widget configuration form.
1042
- *
1043
- * @param array $instance The parameters configured for the widget.
1044
- * @return void
1045
- *
1046
- * @since 4.6
1047
- */
1048
- public function formFilterPanel( $instance ) {
1049
- $cat = $instance['cat'];
1050
- ?>
1051
- <h4 data-panel="filter"><?php esc_html_e( 'Filter', 'category-posts' ); ?></h4>
1052
- <div>
1053
- <p>
1054
- <label>
1055
- <?php esc_html_e( 'Category', 'category-posts' ); ?>:
1056
- <?php
1057
- wp_dropdown_categories( array(
1058
- 'show_option_all' => __( 'All categories', 'category-posts' ),
1059
- 'hide_empty' => 0,
1060
- 'name' => $this->get_field_name( 'cat' ),
1061
- 'selected' => $instance['cat'],
1062
- 'class' => 'categoryposts-data-panel-filter-cat',
1063
- ) );
1064
- ?>
1065
- </label>
1066
- </p>
1067
- <?php
1068
- echo $this->get_checkbox_block_html( $instance, 'no_cat_childs', esc_html__( 'Exclude child categories', 'category-posts' ), ! empty( $instance['cat'] ) );
1069
- echo $this->get_select_block_html( $instance, 'status', esc_html__( 'Status', 'category-posts' ), array(
1070
- 'default' => esc_html__( 'WordPress Default', 'category-posts' ),
1071
- 'publish' => esc_html__( 'Published', 'category-posts' ),
1072
- 'future' => esc_html__( 'Scheduled', 'category-posts' ),
1073
- 'private' => esc_html__( 'Private', 'category-posts' ),
1074
- 'publish,future' => esc_html__( 'Published or Scheduled', 'category-posts' ),
1075
- 'private,publish' => esc_html__( 'Published or Private', 'category-posts' ),
1076
- 'private,future' => esc_html__( 'Private or Scheduled', 'category-posts' ),
1077
- 'private,publish,future' => esc_html__( 'Published, Private or Scheduled', 'category-posts' ),
1078
- ), 'default', true );
1079
- echo $this->get_number_input_block_html( $instance, 'num', esc_html__( 'Number of posts to show', 'category-posts' ), 1, '', '', true );
1080
- echo $this->get_number_input_block_html( $instance, 'offset', esc_html__( 'Start with post', 'category-posts' ), 1, '', '', true );
1081
- echo $this->get_select_block_html( $instance, 'date_range', esc_html__( 'Date Range', 'category-posts' ), array(
1082
- 'off' => esc_html__( 'Off', 'category-posts' ),
1083
- 'days_ago' => esc_html__( 'Days ago', 'category-posts' ),
1084
- 'between_dates' => esc_html__( 'Between dates', 'category-posts' ),
1085
- ), 'off', true );
1086
- ?>
1087
- <div class="cpwp_ident categoryPosts-date-range" style="display:<?php echo 'off' === $instance['date_range'] ? 'none' : 'block'; ?>">
1088
- <?php
1089
- echo $this->get_number_input_block_html( $instance, 'days_ago', esc_html__( 'Up to', 'category-posts' ), 1, '', '', 'days_ago' === $instance['date_range'] );
1090
- echo $this->get_date_input_block_html( $instance, 'start_date', esc_html__( 'After', 'category-posts' ), 'between_dates' === $instance['date_range'] );
1091
- echo $this->get_date_input_block_html( $instance, 'end_date', esc_html__( 'Before', 'category-posts' ), 'between_dates' === $instance['date_range'] );
1092
- ?>
1093
- </div>
1094
- <?php
1095
- echo $this->get_select_block_html( $instance, 'sort_by', esc_html__( 'Sort by', 'category-posts' ), array(
1096
- 'date' => esc_html__( 'Date', 'category-posts' ),
1097
- 'title' => esc_html__( 'Title', 'category-posts' ),
1098
- 'comment_count' => esc_html__( 'Number of comments', 'category-posts' ),
1099
- 'rand' => esc_html__( 'Random', 'category-posts' ),
1100
- ), 'date', true );
1101
- echo $this->get_checkbox_block_html( $instance, 'asc_sort_order', esc_html__( 'Reverse sort order (ascending)', 'category-posts' ), true );
1102
- echo $this->get_checkbox_block_html( $instance, 'exclude_current_post', esc_html__( 'Exclude current post', 'category-posts' ), true );
1103
- echo $this->get_checkbox_block_html( $instance, 'hideNoThumb', esc_html__( 'Exclude posts which have no thumbnail', 'category-posts' ), true );
1104
- ?>
1105
- </div>
1106
- <?php
1107
- }
1108
-
1109
- /**
1110
- * Generate the wrapper P around a form input element
1111
- *
1112
- * @since 4.8
1113
- * @param string $html The HTML to wrap.
1114
- * @param string $key The key to use as the prefix to the class.
1115
- * @param bool $visible Indicates if the element should be visible when rendered.
1116
- *
1117
- * @return string HTML with P element contaning the html being passed with class based on the key
1118
- * and style set to display:none if visibility is off.
1119
- */
1120
- private function get_wrap_block_html( $html, $key, $visible ) {
1121
-
1122
- $cl = ' class="' . __NAMESPACE__ . '-' . esc_attr( $key ) . '"';
1123
-
1124
- $style = '';
1125
- if ( ! $visible ) {
1126
- $style = ' style="display:none"';
1127
- }
1128
- $ret = '<p' . $cl . $style . ">\n" . $html . "</p>\n";
1129
-
1130
- return $ret;
1131
- }
1132
-
1133
- /**
1134
- * Generate a form P element containing a select element
1135
- *
1136
- * @since 4.8
1137
- * @param array $instance The instance.
1138
- * @param string $key The key in the instance array.
1139
- * @param string $label The label to display and associate with the input.
1140
- * @param array $list An array of pairs value (index) => label to be used for the options.
1141
- * The labels are expected to be html escaped.
1142
- * @param int $default The value to use if the key is not set in the instance.
1143
- * @param bool $visible Indicates if the element should be visible when rendered.
1144
- *
1145
- * @return string HTML a P element contaning the select, its label, class based on the key
1146
- * and style set to display:none if visibility is off.
1147
- */
1148
- private function get_select_block_html( $instance, $key, $label, $list, $default, $visible ) {
1149
- $value = $instance[ $key ];
1150
-
1151
- if ( ! array_key_exists( $value, $list ) ) {
1152
- $value = $default;
1153
- }
1154
-
1155
- $ret = '<label for="' . $this->get_field_id( $key ) . "\">\n" .
1156
- $label .
1157
- "</label>\n" .
1158
- '<select id="' . $this->get_field_id( $key ) . '" name="' . $this->get_field_name( $key ) . '" autocomplete="off">' . "\n";
1159
- foreach ( $list as $v => $l ) {
1160
- $ret .= '<option value="' . esc_attr( $v ) . '" ' . selected( $v, $value, false ) . '>' . $l . "</option>\n";
1161
- }
1162
- $ret .= "</select>\n";
1163
-
1164
- return $this->get_wrap_block_html( $ret, $key, $visible );
1165
- }
1166
-
1167
- /**
1168
- * Generate a form P element containing a textarea input
1169
- *
1170
- * @since 4.8
1171
- * @param array $instance The instance.
1172
- * @param string $key The key in the instance array.
1173
- * @param string $label The label to display and associate with the input (should be html escaped).
1174
- * @param string $placeholder The placeholder to use in the input (should be attribute escaped).
1175
- * @param bool $visible Indicates if the element should be visible when rendered.
1176
- * @param int $num_rows Number of rows.
1177
- *
1178
- * @return string HTML a P element containing the input, its label, class based on the key
1179
- * and style set to display:none if visibility is off.
1180
- */
1181
- private function get_textarea_html( $instance, $key, $label, $placeholder, $visible, $num_rows ) {
1182
-
1183
- $value = $instance[ $key ];
1184
-
1185
- $ret = '<label for="' . esc_attr( $this->get_field_id( $key ) ) . '">' . $label .
1186
- '<textarea rows="' . esc_attr( $num_rows ) . '" placeholder="' . $placeholder . '" id="' . esc_attr( $this->get_field_id( $key ) ) . '" name="' . esc_attr( $this->get_field_name( $key ) ) . '" autocomplete="off">' . esc_textarea( $value ) . '</textarea>' .
1187
- '</label>';
1188
-
1189
- return $this->get_wrap_block_html( $ret, $key, $visible );
1190
- }
1191
-
1192
- /**
1193
- * Generate a form P element containing a text input
1194
- *
1195
- * @since 4.8
1196
- * @param array $instance The instance.
1197
- * @param string $key The key in the instance array.
1198
- * @param string $label The label to display and associate with the input.
1199
- * Should be html escaped.
1200
- * @param string $placeholder The placeholder to use in the input. should be attribute escaped.
1201
- * @param bool $visible Indicates if the element should be visible when rendered.
1202
- *
1203
- * @return string HTML a P element contaning the input, its label, class based on the key
1204
- * and style set to display:none if visibility is off.
1205
- */
1206
- private function get_text_input_block_html( $instance, $key, $label, $placeholder, $visible ) {
1207
-
1208
- $value = $instance[ $key ];
1209
-
1210
- $ret = '<label for="' . $this->get_field_id( $key ) . "\">\n" .
1211
- $label . "\n" .
1212
- '<input placeholder="' . $placeholder . '" id="' . $this->get_field_id( $key ) . '" name="' . $this->get_field_name( $key ) . '" type="text" value="' . esc_attr( $value ) . '" autocomplete="off"/>' . "\n" .
1213
- "</label>\n";
1214
-
1215
- return $this->get_wrap_block_html( $ret, $key, $visible );
1216
- }
1217
-
1218
- /**
1219
- * Generate a form P element containing a range input
1220
- *
1221
- * @since 4.8
1222
- * @param array $instance The instance.
1223
- * @param string $key The key in the instance array.
1224
- * @param string $label The label to display and associate with the input.
1225
- * expected to be escaped.
1226
- * @param int $min The minimum value allowed to be input.
1227
- * @param int $max The maximum value allowed to be input.
1228
- * @param string $value The start value
1229
- * @param string $step The range of each step
1230
- * @param bool $visible Indicates if the element should be visible when rendered.
1231
- *
1232
- * @return string HTML a P element contaning the input, its label, class based on the key
1233
- * and style set to display:none if visibility is off.
1234
- */
1235
- private function get_range_input_block_html( $instance, $key, $label, $min, $max, $value, $step, $visible ) {
1236
-
1237
- $value = $instance[ $key ];
1238
-
1239
- $minMaxStep = '';
1240
- if ( '' !== $min ) {
1241
- $minMaxStep .= ' min="' . $min . '"';
1242
- }
1243
- if ( '' !== $max ) {
1244
- $minMaxStep .= ' max="' . $max . '"';
1245
- }
1246
- if ( '' !== $step ) {
1247
- $minMaxStep .= ' step="' . $step . '"';
1248
- }
1249
-
1250
- $ret = '<label for="' . $this->get_field_id( $key ) . "\">\n" .
1251
- esc_html( $label ) . " <span>" . $value . "%</span>\n" .
1252
- '<input id="' . esc_attr( $this->get_field_id( $key ) ) . '" value="' . $value . '" name="' . esc_attr( $this->get_field_name( $key ) ) . '" class="' . esc_attr( $key ) . '" type="range"' . $minMaxStep . ' />' . "\n" .
1253
- "</label>\n";
1254
-
1255
- return $this->get_wrap_block_html( $ret, $key, $visible );
1256
- }
1257
-
1258
- /**
1259
- * Generate a form P element containing a number input
1260
- *
1261
- * @since 4.8
1262
- * @param array $instance The instance.
1263
- * @param string $key The key in the instance array.
1264
- * @param string $label The label to display and associate with the input.
1265
- * expected to be escaped.
1266
- * @param int $min The minimum value allowed to be input.
1267
- * @param int $max The maximum value allowed to be input.
1268
- * @param string $placeholder The placeholder string to be used. expected to be escaped.
1269
- * @param bool $visible Indicates if the element should be visible when rendered.
1270
- *
1271
- * @return string HTML a P element contaning the input, its label, class based on the key
1272
- * and style set to display:none if visibility is off.
1273
- */
1274
- private function get_number_input_block_html( $instance, $key, $label, $min, $max, $placeholder, $visible ) {
1275
-
1276
- $value = $instance[ $key ];
1277
-
1278
- $minmax = '';
1279
- if ( '' !== $min ) {
1280
- $minmax .= ' min="' . $min . '"';
1281
- }
1282
- if ( '' !== $max ) {
1283
- $minmax .= ' max="' . $max . '"';
1284
- }
1285
-
1286
- $ret = '<label for="' . $this->get_field_id( $key ) . "\">\n" .
1287
- esc_html( $label ) . "\n" .
1288
- '<input placeholder="' . $placeholder . '" id="' . esc_attr( $this->get_field_id( $key ) ) . '" name="' . esc_attr( $this->get_field_name( $key ) ) . '" class="' . esc_attr( $key ) . '" type="number"' . $minmax . ' value="' . esc_attr( $value ) . '" autocomplete="off" />' . "\n" .
1289
- "</label>\n";
1290
-
1291
- return $this->get_wrap_block_html( $ret, $key, $visible );
1292
- }
1293
-
1294
- /**
1295
- * Generate a form P element containing a date input
1296
- *
1297
- * @since 4.9
1298
- * @param array $instance The instance.
1299
- * @param string $key The key in the instance array.
1300
- * @param string $label The label to display and associate with the input.
1301
- * expected to be escaped.
1302
- * @param bool $visible Indicates if the element should be visible when rendered.
1303
- *
1304
- * @return string HTML a P element containing the input, its label, class based on the key
1305
- * and style set to display:none if visibility is off.
1306
- */
1307
- private function get_date_input_block_html( $instance, $key, $label, $visible ) {
1308
-
1309
- $value = $instance[ $key ];
1310
-
1311
- $ret = '<label for="' . $this->get_field_id( $key ) . "\">\n" .
1312
- esc_html( $label ) . "\n" .
1313
- '<input id="' . esc_attr( $this->get_field_id( $key ) ) . '" name="' . esc_attr( $this->get_field_name( $key ) ) . '" class="' . esc_attr( $key ) . '" type="date" value="' . esc_attr( $value ) . '" autocomplete="off" />' . "\n" .
1314
- "</label>\n";
1315
-
1316
- return $this->get_wrap_block_html( $ret, $key, $visible );
1317
- }
1318
-
1319
- /**
1320
- * Generate a form P element containing a checkbox input
1321
- *
1322
- * @since 4.8
1323
- * @param array $instance The instance.
1324
- * @param string $key The key in the instance array.
1325
- * @param string $label The label to display and associate with the checkbox.
1326
- * should be escaped string.
1327
- * @param bool $visible Indicates if the element should be visible when rendered.
1328
- *
1329
- * @return string HTML a P element contaning the checkbox, its label, class based on the key
1330
- * and style set to display:none if visibility is off.
1331
- */
1332
- private function get_checkbox_block_html( $instance, $key, $label, $visible ) {
1333
-
1334
- if ( array_key_exists( $key, $instance ) ) {
1335
- if ( $instance[ $key ] ) {
1336
- $value = true;
1337
- } else {
1338
- $value = false;
1339
- }
1340
- }
1341
- $ret = '<label class="checkbox" for="' . esc_attr( $this->get_field_id( $key ) ) . "\">\n" .
1342
- '<input id="' . esc_attr( $this->get_field_id( $key ) ) . '" name="' . esc_attr( $this->get_field_name( $key ) ) . '" type="checkbox" ' . checked( $value, true, false ) . '/>' . "\n" .
1343
- $label .
1344
- "</label>\n";
1345
-
1346
- return $this->get_wrap_block_html( $ret, $key, $visible );
1347
- }
1348
-
1349
- /**
1350
- * Generate a form button element containing
1351
- *
1352
- * @since 4.9
1353
- * @param array $instance The instance.
1354
- * @param string $key The key in the instance array.
1355
- * @param string $label The label to display and associate with the button.
1356
- * should be escaped string.
1357
- *
1358
- * @return string HTML a button element and class based on the key.
1359
- */
1360
- private function get_button_thumb_size_html( $instance, $key, $label ) {
1361
-
1362
- $datas = "";
1363
-
1364
- switch ( $key ) {
1365
- case "thumb":
1366
- $datas = 'data-thumb-w="' . get_option( "thumbnail_size_w" ) . '" data-thumb-h="' . get_option( "thumbnail_size_h" ) . '"';
1367
- break;
1368
- case "medium":
1369
- $datas = 'data-thumb-w="' . get_option( "medium_size_w" ) . '" data-thumb-h="' . get_option( "medium_size_h" ) . '"';
1370
- break;
1371
- case "large":
1372
- $datas = 'data-thumb-w="' . get_option( "large_size_w" ) . '" data-thumb-h="' . get_option( "large_size_h" ) . '"';
1373
- break;
1374
- }
1375
- $ret = '<button type="button" ' . $datas . ' class="' . $key . ' button">' . esc_html( $label ) . "</button>\n";
1376
-
1377
- return $ret;
1378
- }
1379
-
1380
- /**
1381
- * The widget configuration form back end.
1382
- *
1383
- * @param array $instance The parameters associated with the widget.
1384
- * @return void
1385
- */
1386
- public function form( $instance ) {
1387
- if ( 0 === count( $instance ) ) { // new widget, use defaults.
1388
- $instance = default_settings();
1389
- } else { // updated widgets come from =< 4.6 excerpt filter is on.
1390
- if ( ! isset( $instance['excerpt_filters'] ) ) {
1391
- $instance['excerpt_filters'] = 'on';
1392
- }
1393
- }
1394
-
1395
- $instance = upgrade_settings( $instance );
1396
-
1397
- $hide_post_titles = $instance['hide_post_titles'];
1398
- $excerpt_more_text = $instance['excerpt_more_text'];
1399
- $excerpt_filters = $instance['excerpt_filters'];
1400
- $date_format = $instance['date_format'];
1401
- $disable_css = $instance['disable_css'];
1402
- $disable_font_styles = $instance['disable_font_styles'];
1403
- $preset_date_format = $instance['preset_date_format'];
1404
- $thumb = ! empty( $instance['thumb'] );
1405
- $thumb_w = $instance['thumb_w'];
1406
- $thumb_fluid_width = $instance['thumb_fluid_width'];
1407
- $thumb_h = $instance['thumb_h'];
1408
- $default_thunmbnail = $instance['default_thunmbnail'];
1409
- $use_css_cropping = $instance['use_css_cropping'];
1410
- $text_do_not_wrap_thumb = $instance['text_do_not_wrap_thumb'];
1411
- ?>
1412
-
1413
- <div class="category-widget-cont">
1414
- <?php if ( ! class_exists( '\\termcategoryPostsPro\\Widget' ) ) { ?>
1415
- <p><a target="_blank" href="http://tiptoppress.com/term-and-category-based-posts-widget/"><?php esc_html_e( 'Get the Pro version', 'category-posts' ); ?></a></p>
1416
- <?php
1417
- }
1418
- $this->formTitlePanel( $instance );
1419
- $this->formFilterPanel( $instance );
1420
- ?>
1421
- <h4 data-panel="details"><?php esc_html_e( 'Post details', 'category-posts' ); ?></h4>
1422
- <div class="cpwp-sub-panel">
1423
- <?php
1424
- $template = '';
1425
- if ( ! isset( $instance['template'] ) ) {
1426
- $template = convert_settings_to_template( $instance );
1427
- } else {
1428
- $template = $instance['template'];
1429
- }
1430
- ?>
1431
- <p><?php esc_html_e( 'Displayed parts', 'category-posts' ); ?></p>
1432
- <div class="cpwp_ident">
1433
- <?php
1434
- $label = esc_html__( 'Template', 'category-posts' ) .
1435
- ' <a href="#" class="dashicons toggle-template-help dashicons-editor-help imgedit-help-toggle"><span class="screen-reader-text">' .
1436
- esc_html__( 'Show template help', 'category-posts' ) . '</span></a>';
1437
- $class_placement = "";
1438
- if ( is_customize_preview() ) {
1439
- $class_placement = "customizer";
1440
- } else {
1441
- $class_placement = "admin-panel";
1442
- }
1443
- $label .= '<span class="cat-post-add_premade_templates ' . $class_placement . '">' .
1444
- '<button type="button" class="button cpwp-open-placholder-dropdown-menu"> + ' . esc_html__( 'Add Placeholder', 'category-posts' ) . '</button>' .
1445
- '<span class="cpwp-placeholder-dropdown-menu">' .
1446
- '<span data-value="NewLine">' . esc_html__( 'New line', 'category-posts' ) . '</span>' .
1447
- '<span data-value="EmptyLine">' . esc_html__( 'Empty line', 'category-posts' ) . '</span>' .
1448
- '<span data-value="title">' . esc_html__( '%title%', 'category-posts' ) . '</span>' .
1449
- '<span data-value="thumb">' . esc_html__( '%thumb%', 'category-posts' ) . '</span>' .
1450
- '<span data-value="date">' . esc_html__( '%date%', 'category-posts' ) . '</span>' .
1451
- '<span data-value="excerpt">' . esc_html__( '%excerpt%', 'category-posts' ) . '</span>' .
1452
- '<span data-value="author">' . esc_html__( '%author%', 'category-posts' ) . '</span>' .
1453
- '<span data-value="commentnum">' . esc_html__( '%commentnum%', 'category-posts' ) . '</span>' .
1454
- '<span data-value="post_tag">' . esc_html__( '%post_tag%', 'category-posts' ) . '</span>' .
1455
- '<span data-value="category">' . esc_html__( '%category%', 'category-posts' ) . '</span>' .
1456
- '</span>' .
1457
- '</span>';
1458
- ?>
1459
- <?php
1460
- echo $this->get_textarea_html( $instance, 'template', $label , '', true, 8 );
1461
- preg_match_all( get_template_regex(), $template, $matches );
1462
- $tags = array();
1463
- if ( ! empty( $matches[0] ) ) {
1464
- $tags = array_flip( $matches[0] );
1465
- }
1466
- ?>
1467
- <div class="cat-post-template-help">
1468
- <p><?php esc_html_e( 'The following text will be replaced with the relevant information. In addition you can use any text and html (if you have the permisions) anywhere you want', 'category-posts' ); ?>
1469
- </p>
1470
- <table>
1471
- <tr>
1472
- <th><?php esc_html_e( 'New line', 'category-posts' ); ?></th>
1473
- <td><?php esc_html_e( 'Space', 'category-posts' ); ?></td>
1474
- </tr>
1475
- <tr>
1476
- <th><?php esc_html_e( 'Empty line', 'category-posts' ); ?></th>
1477
- <td><?php esc_html_e( 'Next line is a paragraph', 'category-posts' ); ?></td>
1478
- </tr>
1479
- <tr>
1480
- <th>%title%</th>
1481
- <td><?php esc_html_e( 'Post title', 'category-posts' ); ?></td>
1482
- </tr>
1483
- <tr>
1484
- <th>%thumb%</th>
1485
- <td><?php esc_html_e( 'Post thumbnail possibly wrapped by text', 'category-posts' ); ?></td>
1486
- </tr>
1487
- <tr>
1488
- <th>%date%</th>
1489
- <td><?php esc_html_e( 'Post publish date', 'category-posts' ); ?></td>
1490
- </tr>
1491
- <tr>
1492
- <th>%excerpt%</th>
1493
- <td><?php esc_html_e( 'Post excerpt', 'category-posts' ); ?></td>
1494
- </tr>
1495
- <tr>
1496
- <th>%author%</th>
1497
- <td><?php esc_html_e( 'Post author', 'category-posts' ); ?></td>
1498
- </tr>
1499
- <tr>
1500
- <th>%commentnum%</th>
1501
- <td><?php esc_html_e( 'The number of comments to the post', 'category-posts' ); ?></td>
1502
- </tr>
1503
- <tr>
1504
- <th>%post_tag%</th>
1505
- <td><?php esc_html_e( 'Post tags', 'category-posts' ); ?></td>
1506
- </tr>
1507
- <tr>
1508
- <th>%category%</th>
1509
- <td><?php esc_html_e( 'Post categories', 'category-posts' ); ?></td>
1510
- </tr>
1511
- </table>
1512
- </div>
1513
- <div class="cat-post-premade_templates">
1514
- <p><label><?php esc_html_e( 'Select premade Template', 'category-posts' ); ?></label></p>
1515
- <select>
1516
- <option value="title"><?php esc_html_e( 'Only the title', 'category-posts' ); ?></option>
1517
- <option value="title_excerpt"><?php esc_html_e( 'Title and Excerpt', 'category-posts' ); ?></option>
1518
- <option value="title_thumb"><?php esc_html_e( 'Title and Thumbnail', 'category-posts' ); ?></option>
1519
- <option value="title_thum_excerpt"><?php esc_html_e( 'Title, Thumbnail and Excerpt', 'category-posts' ); ?></option>
1520
- <option value="everything"><?php esc_html_e( 'All with icons', 'category-posts' ); ?></option>
1521
- </select>
1522
- <p><button type="button" class="button"><?php esc_html_e( 'Select this template', 'category-posts' ); ?></button></p>
1523
- <?php
1524
- echo $this->get_checkbox_block_html( $instance, 'everything_is_link', esc_html__( 'Everything is a link', 'category-posts' ), true );
1525
- ?>
1526
- </div>
1527
- </div>
1528
- <?php // Excerpt settings. ?>
1529
- <div class="cpwp-sub-panel categoryposts-data-panel-excerpt" style="display:<?php echo ( isset( $tags['%excerpt%'] ) ) ? 'block' : 'none'; ?>">
1530
- <p><?php esc_html_e( 'Excerpt settings', 'category-posts' ); ?></p>
1531
- <div class="cpwp_ident">
1532
- <?php
1533
- echo $this->get_number_input_block_html( $instance, 'excerpt_lines', esc_html__( 'Lines (responsive):', 'category-posts' ), 0, '', '', true );
1534
- echo $this->get_number_input_block_html( $instance, 'excerpt_length', esc_html__( 'Length (words):', 'category-posts' ), 0, '', '', true );
1535
- echo $this->get_text_input_block_html( $instance, 'excerpt_more_text', esc_html__( '\'More ...\' text:', 'category-posts' ), esc_attr__( '...', 'category-posts' ), true );
1536
- ?>
1537
- </div>
1538
- </div>
1539
- <?php // Data settings ?>
1540
- <div class="cpwp-sub-panel categoryposts-data-panel-date" style="display:<?php echo ( isset( $tags['%date%'] ) ) ? 'block' : 'none'; ?>">
1541
- <p><?php esc_html_e( 'Date format settings', 'category-posts' ); ?></p>
1542
- <div class="cpwp_ident">
1543
- <?php
1544
- echo $this->get_select_block_html( $instance, 'preset_date_format', esc_html__( 'Date format', 'category-posts' ), array(
1545
- 'sitedateandtime' => esc_html__( 'Site date and time', 'category-posts' ),
1546
- 'sitedate' => esc_html__( 'Site date', 'category-posts' ),
1547
- 'sincepublished' => esc_html__( 'Time since published', 'category-posts' ),
1548
- 'localsitedateandtime' => esc_html__( 'Reader\'s local date and time', 'category-posts' ),
1549
- 'localsitedate' => esc_html__( 'Reader\'s local date', 'category-posts' ),
1550
- 'other' => esc_html__( 'PHP style format', 'category-posts' ),
1551
- ), 'sitedateandtime', true );
1552
- echo $this->get_text_input_block_html( $instance, 'date_format', esc_html__( 'PHP Style Date format', 'category-posts' ), 'j M Y', 'other' === $preset_date_format );
1553
- ?>
1554
- </div>
1555
- </div>
1556
- <?php // Thumbnail settings. ?>
1557
- <div class="cpwp-sub-panel categoryposts-data-panel-thumb" style="display:<?php echo ( isset( $tags['%thumb%'] ) ) ? 'block' : 'none'; ?>">
1558
- <p><?php esc_html_e( 'Thumbnail settings', 'category-posts' ); ?></p>
1559
- <div class="cpwp_ident">
1560
- <p><?php esc_html_e( 'Thumbnail dimensions (pixel)', 'category-posts' ); ?></p>
1561
- <?php
1562
- echo $this->get_number_input_block_html( $instance, 'thumb_w', esc_html__( 'Width:', 'category-posts' ), 1, '', '', true );
1563
- echo $this->get_range_input_block_html( $instance, 'thumb_fluid_width', esc_html__( 'Max-width:', 'category-posts' ), 2, 100, 100, 2, true );
1564
- echo $this->get_number_input_block_html( $instance, 'thumb_h', esc_html__( 'Height:', 'category-posts' ), 1, '', '', true );
1565
- ?>
1566
- <div class="cat-post-thumb-change-size">
1567
- <p>
1568
- <label><?php esc_html_e( 'Change size', 'category-posts' ); ?>: </label>
1569
- <span class="cpwp-right">
1570
- <?php
1571
- echo $this->get_button_thumb_size_html( $instance, 'smaller', esc_html__( '-', 'category-posts' ) );
1572
- echo $this->get_button_thumb_size_html( $instance, 'quarter', esc_html__( '1/4', 'category-posts' ) );
1573
- echo $this->get_button_thumb_size_html( $instance, 'half', esc_html__( '1/2', 'category-posts' ) );
1574
- echo $this->get_button_thumb_size_html( $instance, 'double', esc_html__( '2x', 'category-posts' ) );
1575
- echo $this->get_button_thumb_size_html( $instance, 'bigger', esc_html__( '+', 'category-posts' ) );
1576
- ?>
1577
- </span>
1578
- </p>
1579
- <p>
1580
- <label><?php esc_html_e( 'Ratio', 'category-posts' ); ?>: </label>
1581
- <span class="cpwp-right">
1582
- <?php
1583
- echo $this->get_button_thumb_size_html( $instance, 'square', esc_html__( '1:1', 'category-posts' ) );
1584
- echo $this->get_button_thumb_size_html( $instance, 'standard', esc_html__( '4:3', 'category-posts' ) );
1585
- echo $this->get_button_thumb_size_html( $instance, 'wide', esc_html__( '16:9', 'category-posts' ) );
1586
- echo $this->get_button_thumb_size_html( $instance, 'switch', esc_html__( 'switch', 'category-posts' ) );
1587
- ?>
1588
- </span>
1589
- </p>
1590
- <p>
1591
- <label><?php esc_html_e( 'Available', 'category-posts' ); ?>: </label>
1592
- <span class="cpwp-right">
1593
- <?php
1594
- echo $this->get_button_thumb_size_html( $instance, 'thumb', esc_html__( 'Thumb', 'category-posts' ) );
1595
- echo $this->get_button_thumb_size_html( $instance, 'medium', esc_html__( 'Medium', 'category-posts' ) );
1596
- echo $this->get_button_thumb_size_html( $instance, 'large', esc_html__( 'Large', 'category-posts' ) );
1597
- ?>
1598
- </span>
1599
- </p>
1600
- </div>
1601
- <?php
1602
- echo $this->get_checkbox_block_html( $instance, 'text_do_not_wrap_thumb', esc_html__( 'Do not wrap thumbnail with overflowing text', 'category-posts' ), true );
1603
- echo $this->get_checkbox_block_html( $instance, 'use_css_cropping', esc_html__( 'CSS crop to requested size', 'category-posts' ), false );
1604
- echo $this->get_select_block_html( $instance, 'thumb_hover', esc_html__( 'Animation on mouse hover:', 'category-posts' ), array(
1605
- 'none' => esc_html__( 'None', 'category-posts' ),
1606
- 'dark' => esc_html__( 'Darker', 'category-posts' ),
1607
- 'white' => esc_html__( 'Brighter', 'category-posts' ),
1608
- 'scale' => esc_html__( 'Zoom in', 'category-posts' ),
1609
- 'blur' => esc_html__( 'Blur', 'category-posts' ),
1610
- 'icon' => esc_html__( 'Icon', 'category-posts' ),
1611
- ), 'none', true);
1612
- echo $this->get_select_block_html( $instance, 'show_post_format', esc_html__( 'Indicate post format and position', 'category-posts' ), array(
1613
- 'none' => esc_html__( 'None', 'category-posts' ),
1614
- 'topleft' => esc_html__( 'Top left', 'category-posts' ),
1615
- 'bottomleft' => esc_html__( 'Bottom left', 'category-posts' ),
1616
- 'ceter' => esc_html__( 'Center', 'category-posts' ),
1617
- 'topright' => esc_html__( 'Top right', 'category-posts' ),
1618
- 'bottomright' => esc_html__( 'Bottom right', 'category-posts' ),
1619
- 'nocss' => esc_html__( 'HTML without styling', 'category-posts' ),
1620
- ), 'none', true );
1621
- ?>
1622
- <p>
1623
- <label style="display:block">
1624
- <?php esc_html_e( 'Default thumbnail: ', 'category-posts' ); ?>
1625
- </label>
1626
- <input type="hidden" class="default_thumb_id" id="<?php echo esc_attr( $this->get_field_id( 'default_thunmbnail' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'default_thunmbnail' ) ); ?>" value="<?php echo esc_attr( $default_thunmbnail ); ?>"/>
1627
- <span class="default_thumb_img">
1628
- <?php
1629
- if ( ! $default_thunmbnail ) {
1630
- esc_html_e( 'None', 'category-posts' );
1631
- } else {
1632
- $img = wp_get_attachment_image_src( $default_thunmbnail );
1633
- echo '<img width="60" height="60" src="' . esc_url( $img[0] ) . '" />';
1634
- }
1635
- ?>
1636
- </span>
1637
- </p>
1638
- <p>
1639
- <button type="button" class="cwp_default_thumb_select button upload-button">
1640
- <?php esc_html_e( 'Select image', 'category-posts' ); ?>
1641
- </button>
1642
- <button type="button" class="cwp_default_thumb_remove button upload-button" <?php echo ( ! $default_thunmbnail ) ? 'style="display:none"' : ''; ?> >
1643
- <?php esc_html_e( 'No default', 'category-posts' ); ?>
1644
- </button>
1645
- </p>
1646
- </div>
1647
- </div>
1648
- </div>
1649
- <h4 data-panel="general"><?php esc_html_e( 'General', 'category-posts' ); ?></h4>
1650
- <div>
1651
- <?php echo $this->get_checkbox_block_html( $instance, 'disable_css', esc_html__( 'Disable the built-in CSS', 'category-posts' ), true ); ?>
1652
- <?php echo $this->get_checkbox_block_html( $instance, 'disable_font_styles', esc_html__( 'Disable only font styles', 'category-posts' ), true ); ?>
1653
- <div class="cpwp_ident">
1654
- <?php
1655
- echo $this->get_select_block_html( $instance, 'no_match_handling', esc_html__( 'When there are no matches', 'category-posts' ), array(
1656
- 'nothing' => esc_html__( 'Display empty widget', 'category-posts' ),
1657
- 'hide' => esc_html__( 'Hide Widget', 'category-posts' ),
1658
- 'text' => esc_html__( 'Show text', 'category-posts' ),
1659
- ), 'nothing', true );
1660
- ?>
1661
- <div class="categoryPosts-no-match-text" style="display:<?php echo ( 'text' === $instance['no_match_handling'] ) ? 'block' : 'none'; ?>">
1662
- <?php echo $this->get_textarea_html( $instance, 'no_match_text', esc_html__( 'Text', 'category-posts' ), '', true, 4 ); ?>
1663
- </div>
1664
- </div>
1665
- <div>
1666
- <?php
1667
- echo $this->get_checkbox_block_html( $instance, 'enable_loadmore', esc_html__( 'Enable Load More', 'category-posts' ), true );
1668
- ?>
1669
- <div class="loadmore-settings" style="display:<?php echo ( $instance['enable_loadmore'] ) ? 'block' : 'none'; ?>">
1670
- <?php echo $this->get_text_input_block_html( $instance, 'loadmore_text', esc_html__( 'Button text', 'category-posts' ), '', true ); ?>
1671
- <?php echo $this->get_text_input_block_html( $instance, 'loading_text', esc_html__( 'Loading text', 'category-posts' ), '', true ); ?>
1672
- </div>
1673
- </div>
1674
- </div>
1675
- <h4 data-panel="footer"><?php esc_html_e( 'Footer', 'category-posts' ); ?></h4>
1676
- <div>
1677
- <?php echo $this->get_text_input_block_html( $instance, 'footer_link_text', esc_html__( 'Footer link text', 'category-posts' ), '', true ); ?>
1678
- <?php echo $this->get_text_input_block_html( $instance, 'footer_link', esc_html__( 'Footer link URL', 'category-posts' ), '', true ); ?>
1679
- </div>
1680
- <p><a href="<?php echo esc_url( get_edit_user_link() ) . '#' . __NAMESPACE__; ?>"><?php esc_html_e( 'Widget admin behaviour settings', 'category-posts' ); ?></a></p>
1681
- <p><a target="_blank" href="<?php echo esc_url( DOC_URL ); ?>"><?php esc_html_e( 'Documentation', 'category-posts' ); ?></a></p>
1682
- <p><a target="_blank" href="<?php echo esc_url( SUPPORT_URL ); ?>"><?php esc_html_e( 'Support', 'category-posts' ); ?></a></p>
1683
- <p><?php echo sprintf( wp_kses( __( 'We are on <a href="%1$s">Facebook</a> and <a href="%2$s">Twitter</a>.', 'category-posts' ), array( 'a' => array( 'href' => array() ) ) ), esc_url( 'https://www.facebook.com/TipTopPress' ), esc_url( 'https://twitter.com/TipTopPress' ) ); ?></p>
1684
- </div>
1685
- <?php
1686
- }
1687
- }
 
 
1
+ <?php
2
+ /**
3
+ * Implementation of the widget class.
4
+ *
5
+ * @package categoryposts.
6
+ *
7
+ * @since 4.7
8
+ */
9
+
10
+ namespace categoryPosts;
11
+
12
+ // Don't call the file directly.
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ /**
18
+ * Category Posts Widget Class
19
+ *
20
+ * Shows the single category posts with some configurable options
21
+ */
22
+ class Widget extends \WP_Widget {
23
+
24
+ /**
25
+ * Widget constructor.
26
+ */
27
+ public function __construct() {
28
+ $widget_ops = array(
29
+ 'classname' => 'cat-post-widget',
30
+ 'description' => __( 'List single category posts', 'category-posts' ),
31
+ );
32
+ parent::__construct( WIDGET_BASE_ID, __( 'Category Posts', 'category-posts' ), $widget_ops );
33
+ }
34
+
35
+ /**
36
+ * Calculate the HTML for showing the thumb of a post item.
37
+ *
38
+ * Used as a filter for the thumb wordpress API to add css based stretching and cropping
39
+ * when the image is not at the requested dimensions
40
+ *
41
+ * @param string $html The original HTML generated by the core APIS.
42
+ * @param int $post_id the ID of the post of which the thumb is a featured image.
43
+ * @param int $post_thumbnail_id The id of the featured image attachment.
44
+ * @param string|array $size The requested size identified by name or (width, height) array.
45
+ * @param mixed $attr ignored in this context.
46
+ * @return string The HTML for the thumb related to the post
47
+ *
48
+ * @since 4.1
49
+ */
50
+ public function post_thumbnail_html( $html, $post_id, $post_thumbnail_id, $size, $attr ) {
51
+
52
+ $use_css_cropping = isset( $this->instance['use_css_cropping'] ) && $this->instance['use_css_cropping'];
53
+ $thumb = isset( $this->instance['template'] ) && preg_match( '/%thumb%/', $this->instance['template'] );
54
+
55
+ if ( ! ( $use_css_cropping && $thumb ) ) {
56
+ return $html;
57
+ }
58
+ $meta = image_get_intermediate_size( $post_thumbnail_id, $size );
59
+
60
+ if ( empty( $meta ) ) {
61
+ $post_img = wp_get_attachment_metadata( $post_thumbnail_id, $size );
62
+ $meta['file'] = basename( $post_img['file'] );
63
+ }
64
+
65
+ $origfile = get_attached_file( $post_thumbnail_id, true ); // the location of the full file.
66
+ $file = dirname( $origfile ) . '/' . $meta['file']; // the location of the file displayed as thumb.
67
+ if ( file_exists( $file ) ) {
68
+ list( $width, $height ) = getimagesize( $file ); // get actual size of the thumb file.
69
+
70
+ if ( isset( $this->instance['use_css_cropping'] ) && $this->instance['use_css_cropping'] ) {
71
+ $show_post_format = isset( $this->instance['show_post_format'] ) && ( 'none' !== $this->instance['show_post_format'] );
72
+ if ( $show_post_format || $this->instance['thumb_hover'] ) {
73
+ $format = get_post_format() ? : 'standard';
74
+ $post_format_class = 'cat-post-format cat-post-format-' . $format;
75
+ }
76
+ $html = '<span class="cat-post-crop ' . $post_format_class . '">' . $html . '</span>';
77
+ } else {
78
+ // use_css_cropping is not used.
79
+ // wrap span.
80
+ $html = '<span>' . $html . '</span>';
81
+ }
82
+ }
83
+ return $html;
84
+ }
85
+
86
+ /*
87
+ * wrapper to execute the the_post_thumbnail with filters.
88
+ */
89
+ /**
90
+ * Calculate the HTML for showing the thumb of a post item.
91
+ *
92
+ * It is a wrapper to execute the the_post_thumbnail with filters
93
+ *
94
+ * @param string|array $size The requested size identified by name or (width, height) array.
95
+ *
96
+ * @return string The HTML for the thumb related to the post and empty string if it can not be calculated
97
+ *
98
+ * @since 4.1
99
+ */
100
+ public function the_post_thumbnail( $size = 'post-thumbnail' ) {
101
+ if ( empty( $size ) ) { // if junk value, make it a normal thumb.
102
+ $size = 'post-thumbnail';
103
+ } elseif ( is_array( $size ) && ( 2 === count( $size ) ) ) { // good format at least.
104
+ // normalize to ints first.
105
+ $size[0] = (int) $size[0];
106
+ $size[1] = (int) $size[1];
107
+ if ( ( 0 === $size[0] ) && ( 0 === $size[1] ) ) { // Both values zero then revert to thumbnail.
108
+ $size = array( get_option( 'thumbnail_size_w', 150 ), get_option( 'thumbnail_size_h', 150 ) );
109
+ } elseif ( ( 0 === $size[0] ) && ( 0 !== $size[1] ) ) {
110
+ // if thumb width 0 set to max/full widths for wp rendering
111
+ $post_thumb = get_the_post_thumbnail( get_the_ID(), 'full' );
112
+ preg_match( '/(?<=width=")[\d]*/', $post_thumb, $thumb_full_w );
113
+ $size[0] = $thumb_full_w[0];
114
+ } elseif ( ( 0 !== $size[0] ) && ( 0 === $size[1] ) ) {
115
+ // if thumb height 0 get full thumb for ratio and calc height with ratio
116
+ $post_thumb = get_the_post_thumbnail( get_the_ID(), 'full' );
117
+ preg_match( '/(?<=width=")[\d]*/', $post_thumb, $thumb_full_w );
118
+ preg_match( '/(?<=height=")[\d]*/', $post_thumb, $thumb_full_h );
119
+ $ratio = $thumb_full_w[0] / $thumb_full_h[0];
120
+ $size[1] = intval( $size[0] / $ratio );
121
+ }
122
+ } else {
123
+ $size = array( get_option( 'thumbnail_size_w', 150 ), get_option( 'thumbnail_size_h', 150 ) ); // yet another form of junk.
124
+ }
125
+
126
+ $post_thumbnail_id = get_post_thumbnail_id( get_the_ID() );
127
+ if ( ! $post_thumbnail_id && $this->instance['default_thunmbnail'] ) {
128
+ $post_thumbnail_id = $this->instance['default_thunmbnail'];
129
+ }
130
+
131
+ do_action( 'begin_fetch_post_thumbnail_html', get_the_ID(), $post_thumbnail_id, $size );
132
+ $html = wp_get_attachment_image( $post_thumbnail_id, $size, false, '' );
133
+ if ( ! $html ) {
134
+ $ret = '';
135
+ } else {
136
+ $ret = $this->post_thumbnail_html( $html, get_the_ID(), $post_thumbnail_id, $size, '' );
137
+ }
138
+ do_action( 'end_fetch_post_thumbnail_html', get_the_ID(), $post_thumbnail_id, $size );
139
+
140
+ return $ret;
141
+ }
142
+
143
+ /**
144
+ * Excerpt more link filter
145
+ *
146
+ * @param string $more The "more" text passed by the filter.
147
+ *
148
+ * @return string The link to the post with the "more" text configured in the widget.
149
+ */
150
+ public function excerpt_more_filter( $more ) {
151
+ return ' <a class="cat-post-excerpt-more more-link" href="' . get_permalink() . '">' . esc_html( $this->instance['excerpt_more_text'] ) . '</a>';
152
+ }
153
+
154
+ /**
155
+ * Apply the_content filter for excerpt
156
+ * This should show sharing buttons which comes with other widgets in the widget output in the same way as on the main content
157
+ *
158
+ * @param string $text The HTML with other applied excerpt filters.
159
+ *
160
+ * @return string If option hide_social_buttons is unchecked applay the_content filter.
161
+ *
162
+ * @since 4.6
163
+ */
164
+ public function apply_the_excerpt( $text ) {
165
+ $ret = apply_filters( 'the_content', $text );
166
+
167
+ return $ret;
168
+ }
169
+
170
+ /**
171
+ * Calculate the wp-query arguments matching the filter settings of the widget
172
+ *
173
+ * @param array $instance Array which contains the various settings.
174
+ * @return array The array that can be fed to wp_Query to get the relevant posts
175
+ *
176
+ * @since 4.6
177
+ */
178
+ public function queryArgs( $instance ) {
179
+
180
+ $valid_sort_orders = array( 'date', 'title', 'comment_count', 'rand' );
181
+ if ( isset( $instance['sort_by'] ) && in_array( $instance['sort_by'], $valid_sort_orders, true ) ) {
182
+ $sort_by = $instance['sort_by'];
183
+ } else {
184
+ $sort_by = 'date';
185
+ }
186
+ $sort_order = ( isset( $instance['asc_sort_order'] ) && $instance['asc_sort_order'] ) ? 'ASC' : 'DESC';
187
+
188
+ // Get array of post info.
189
+ $args = array(
190
+ 'orderby' => $sort_by,
191
+ 'order' => $sort_order,
192
+ 'ignore_sticky_posts' => 1, // Make sure we do not get stickies out of order.
193
+ 'no_found_rows' => true, // Do not count the total numbers of rows by default.
194
+ );
195
+
196
+ $non_default_valid_status = array(
197
+ 'publish',
198
+ 'future',
199
+ 'publish,future',
200
+ 'private',
201
+ 'private,publish',
202
+ 'private,publish,future',
203
+ );
204
+ if ( isset( $instance['status'] ) && in_array( $instance['status'], $non_default_valid_status, true ) ) {
205
+ $args['post_status'] = $instance['status'];
206
+ }
207
+
208
+ if ( isset( $instance['num'] ) ) {
209
+ $args['showposts'] = (int) $instance['num'];
210
+ }
211
+
212
+ if ( isset( $instance['offset'] ) && ( (int) $instance['offset'] > 1 ) ) {
213
+ $args['offset'] = (int) $instance['offset'] - 1;
214
+ }
215
+ if ( isset( $instance['cat'] ) ) {
216
+ if ( isset( $instance['no_cat_childs'] ) && $instance['no_cat_childs'] ) {
217
+ $args['category__in'] = (int) $instance['cat'];
218
+ } else {
219
+ $args['cat'] = (int) $instance['cat'];
220
+ }
221
+ }
222
+
223
+ if ( is_singular() && isset( $instance['exclude_current_post'] ) && $instance['exclude_current_post'] ) {
224
+ $args['post__not_in'] = array( get_the_ID() );
225
+ }
226
+
227
+ if ( isset( $instance['hideNoThumb'] ) && $instance['hideNoThumb'] ) {
228
+ $args = array_merge( $args, array(
229
+ 'meta_query' => array(
230
+ array(
231
+ 'key' => '_thumbnail_id',
232
+ 'compare' => 'EXISTS',
233
+ ),
234
+ ),
235
+ ) );
236
+ }
237
+
238
+ switch ( $instance['date_range'] ) {
239
+ case 'days_ago':
240
+ $ago = (int) $instance['days_ago'];
241
+
242
+ // If there is no valid integer value given, bail.
243
+ if ( 0 === $ago ) {
244
+ break;
245
+ }
246
+
247
+ $date = date( 'Y-m-d', strtotime( '-' . $ago . ' days' ) );
248
+ $args['date_query'] = array(
249
+ 'after' => $date,
250
+ 'inclusive' => true,
251
+ );
252
+ break;
253
+ case 'between_dates':
254
+ // Validation note - not doing any, assuming the query will
255
+ // fail gracefully enough for now as it is not clear what Should
256
+ // the validation be right now.
257
+ $start_date = $instance['start_date'];
258
+ $end_date = $instance['end_date'];
259
+ $args['date_query'] = array(
260
+ 'after' => $start_date,
261
+ 'before' => $end_date,
262
+ 'inclusive' => true,
263
+ );
264
+ break;
265
+ }
266
+
267
+ return $args;
268
+ }
269
+
270
+ /**
271
+ * Calculate the HTML of the title based on the widget settings
272
+ *
273
+ * @param string $before_title The sidebar configured HTML that should come
274
+ * before the title itself.
275
+ * @param string $after_title The sidebar configured HTML that should come
276
+ * after the title itself.
277
+ * @param array $instance Array which contains the various settings.
278
+ * @return string The HTML for the title area
279
+ *
280
+ * @since 4.6
281
+ */
282
+ public function titleHTML( $before_title, $after_title, $instance ) {
283
+ $ret = '';
284
+
285
+ // If no title, use the name of the category.
286
+ if ( ! isset( $instance['title'] ) || ! $instance['title'] ) {
287
+ $instance['title'] = '';
288
+ if ( 0 !== (int) $instance['cat'] ) {
289
+ $category_info = get_category( $instance['cat'] );
290
+ if ( $category_info && ! is_wp_error( $category_info ) ) {
291
+ $instance['title'] = $category_info->name;
292
+ } else {
293
+ $instance['cat'] = 0; // For further processing treat it like "all categories".
294
+ $instance['title'] = __( 'Recent Posts', 'category-posts' );
295
+ }
296
+ } else {
297
+ $instance['title'] = __( 'Recent Posts', 'category-posts' );
298
+ }
299
+ }
300
+
301
+ if ( ! ( isset( $instance['hide_title'] ) && $instance['hide_title'] ) ) {
302
+ $ret = $before_title;
303
+ if ( isset( $instance['is_shortcode'] ) ) {
304
+ $title = esc_html( $instance['title'] );
305
+ } else {
306
+ $title = apply_filters( 'widget_title', $instance['title'], $instance, WIDGET_BASE_ID );
307
+ }
308
+
309
+ if ( isset( $instance['title_link'] ) && $instance['title_link'] ) {
310
+ if ( 0 !== $instance['cat'] ) {
311
+ $ret .= '<a href="' . get_category_link( $instance['cat'] ) . '">' . $title . '</a>';
312
+ } elseif ( isset( $instance['title_link_url'] ) && $instance['title_link_url'] ) {
313
+ $ret .= '<a href="' . esc_url( $instance['title_link_url'] ) . '">' . $title . '</a>';
314
+ } else {
315
+ $ret .= '<a href="' . esc_url( $this->blog_page_url() ) . '">' . $title . '</a>';
316
+ }
317
+ } else {
318
+ $ret .= $title;
319
+ }
320
+
321
+ $ret .= $after_title;
322
+ }
323
+
324
+ return $ret;
325
+ }
326
+
327
+ /**
328
+ * Get the URL of the blog page or home page if no explicit blog page is defined.
329
+ *
330
+ * @return string The URL of the blog page
331
+ *
332
+ * @since 4.8
333
+ */
334
+ private function blog_page_url() {
335
+
336
+ $blog_page = get_option( 'page_for_posts' );
337
+ if ( $blog_page ) {
338
+ $url = get_permalink( $blog_page );
339
+ } else {
340
+ $url = home_url();
341
+ }
342
+
343
+ return $url;
344
+ }
345
+
346
+ /**
347
+ * Calculate the HTML of the load more button based on the widget settings
348
+ *
349
+ * @param array $instance Array which contains the various settings.
350
+ *
351
+ * @return string The HTML for the load more area
352
+ *
353
+ * @since 4.9
354
+ */
355
+ public function loadMoreHTML( $instance ) {
356
+
357
+ if ( ! $instance['enable_loadmore'] ) {
358
+ return '';
359
+ }
360
+
361
+ $ret = '<div class="' . __NAMESPACE__ . '-loadmore">';
362
+ $context = 0;
363
+ if ( is_singular() ) {
364
+ $context = get_the_ID();
365
+ }
366
+
367
+ wp_enqueue_script( 'jquery' );
368
+ add_action( 'wp_footer', __NAMESPACE__ . '\embed_loadmore_scripts', 100 );
369
+
370
+ // We rely on the widget number to be properly set.
371
+ // but need a slight different handling for proper widgets.
372
+ if ( is_int( $this->number ) ) {
373
+ // it is a proper widget, add the prefix.
374
+ $id = 'widget-' . $this->number;
375
+ } else {
376
+ $id = str_replace( WIDGET_BASE_ID . '-', '', $this->number );
377
+ }
378
+
379
+ $number = $instance['num'];
380
+ $start = $instance['offset'] + $number;
381
+ $loading = $instance['loading_text'];
382
+
383
+ $ret .= '<button type="button" data-loading="' . esc_attr( $loading ) . '" data-id="' . esc_attr( $id ) . '" data-start="' . esc_attr( $start ) . '" data-context="' . esc_attr( $context ) . '" data-number="' . esc_attr( $number ) . '">' . esc_html( $instance['loadmore_text'] ) . '</button>';
384
+ $ret .= '</div>';
385
+ return $ret;
386
+ }
387
+
388
+ /**
389
+ * Calculate the HTML of the footer based on the widget settings
390
+ *
391
+ * @param array $instance Array which contains the various settings.
392
+ * @return string The HTML for the footer area
393
+ *
394
+ * @since 4.6
395
+ */
396
+ public function footerHTML( $instance ) {
397
+
398
+ $ret = '';
399
+ $url = '';
400
+ $text = '';
401
+
402
+ if ( isset( $instance['footer_link'] ) ) {
403
+ $url = $instance['footer_link'];
404
+ }
405
+
406
+ if ( isset( $instance['footer_link_text'] ) ) {
407
+ $text = $instance['footer_link_text'];
408
+ }
409
+
410
+ // if url is set, but no text, just use the url as text.
411
+ if ( empty( $text ) && ! empty( $url ) ) {
412
+ $text = $url;
413
+ }
414
+
415
+ // if no url is set but just text, assume the url should be to the relevant archive page
416
+ // category archive for categories filter and home page or blog page when "all categories"
417
+ // is used.
418
+ if ( ! empty( $text ) && empty( $url ) ) {
419
+ if ( isset( $instance['cat'] ) && ( 0 !== $instance['cat'] ) && ( null !== get_category( $instance['cat'] ) ) ) {
420
+ $url = get_category_link( $instance['cat'] );
421
+ } else {
422
+ $url = $this->blog_page_url();
423
+ }
424
+ }
425
+
426
+ if ( ! empty( $url ) ) {
427
+ $ret .= '<a class="cat-post-footer-link" href="' . esc_url( $url ) . '">' . esc_html( $text ) . '</a>';
428
+ }
429
+
430
+ return $ret;
431
+ }
432
+
433
+ /**
434
+ * Current post item date string based on the format requested in the settings
435
+ *
436
+ * @param array $instance Array which contains the various settings.
437
+ * @param bool $everything_is_link Indicates whether the return string should avoid links.
438
+ *
439
+ * @since 4.8
440
+ */
441
+ public function itemDate( $instance, $everything_is_link ) {
442
+ $ret = '';
443
+
444
+ if ( ! isset( $instance['preset_date_format'] ) ) {
445
+ $preset_date_format = 'other';
446
+ } else {
447
+ $preset_date_format = $instance['preset_date_format'];
448
+ }
449
+
450
+ $attr = '';
451
+ switch ( $preset_date_format ) {
452
+ case 'sitedateandtime':
453
+ $date = get_the_time( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) );
454
+ break;
455
+ case 'localsitedateandtime':
456
+ $date = get_the_time( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ) . ' GMT';
457
+ $time = get_post_time( 'U', true );
458
+ $attr = ' data-publishtime="' . $time . '" data-format="time"';
459
+ add_action( 'wp_footer', __NAMESPACE__ . '\embed_date_scripts' );
460
+ break;
461
+ case 'sitedate':
462
+ $date = get_the_time( get_option( 'date_format' ) );
463
+ break;
464
+ case 'localsitedate':
465
+ $date = get_the_time( get_option( 'date_format' ) ) . ' GMT';
466
+ $time = get_post_time( 'U', true );
467
+ $attr = ' data-publishtime="' . $time . '" data-format="date"';
468
+ add_action( 'wp_footer', __NAMESPACE__ . '\embed_date_scripts' );
469
+ break;
470
+ case 'sincepublished':
471
+ $date = human_time_diff( get_the_time( 'U' ), current_time( 'timestamp' ) );
472
+ break;
473
+ default:
474
+ if ( isset( $instance['date_format'] ) && strlen( trim( $instance['date_format'] ) ) > 0 ) {
475
+ $date_format = $instance['date_format'];
476
+ } else {
477
+ $date_format = 'j M Y';
478
+ }
479
+ $date = get_the_time( $date_format );
480
+ break;
481
+ }
482
+ $ret .= '<span class="cat-post-date"' . $attr . '>';
483
+ if ( isset( $instance['date_link'] ) && $instance['date_link'] && ! $everything_is_link ) {
484
+ $ret .= '<a href="' . \get_the_permalink() . '">';
485
+ }
486
+ $ret .= $date;
487
+
488
+ if ( isset( $instance['date_link'] ) && $instance['date_link'] && ! $everything_is_link ) {
489
+ $ret .= '</a>';
490
+ }
491
+ $ret .= '</span>';
492
+ return $ret;
493
+ }
494
+
495
+
496
+ /**
497
+ * Calculate the HTML for showing the thumb of a post item.
498
+ * Expected to be called from a loop with globals properly set.
499
+ *
500
+ * @param array $instance Array which contains the various settings.
501
+ * @param bool $no_link indicates whether the thumb should be wrapped in a link or a span.
502
+ * @return string The HTML for the thumb related to the post
503
+ *
504
+ * @since 4.6
505
+ */
506
+ public function itemThumb( $instance, $no_link ) {
507
+ $ret = '';
508
+
509
+ if ( ( isset( $instance['default_thunmbnail'] ) && ( $instance['default_thunmbnail'] ) ) || has_post_thumbnail() ) {
510
+ $class = '';
511
+ $disable_css = isset( $instance['disable_css'] ) && $instance['disable_css'];
512
+
513
+ if ( isset( $this->instance['thumb_hover'] ) && ! $disable_css ) {
514
+ $class = 'class="cat-post-thumbnail cat-post-' . $instance['thumb_hover'] . '"';
515
+ } else {
516
+ $class = 'class="cat-post-thumbnail"';
517
+ }
518
+
519
+ $title_args = array( 'echo' => false );
520
+
521
+ if ( $no_link ) {
522
+ $ret .= '<span ' . $class . '>';
523
+ } else {
524
+ $ret .= '<a ' . $class . ' href="' . get_the_permalink() . '" title="' . the_title_attribute( $title_args ) . '">';
525
+ }
526
+
527
+ $ret .= $this->the_post_thumbnail( array( $this->instance['thumb_w'], $this->instance['thumb_h'] ) );
528
+
529
+ if ( $no_link ) {
530
+ $ret .= '</span>';
531
+ } else {
532
+ $ret .= '</a>';
533
+ }
534
+ }
535
+
536
+ return $ret;
537
+ }
538
+
539
+ /**
540
+ * Current post item categories string
541
+ *
542
+ * @param array $instance Array which contains the various settings.
543
+ * @param bool $everything_is_link Indicates whether the return string should avoid links.
544
+ *
545
+ * @since 4.8
546
+ */
547
+ public function itemCategories( $instance, $everything_is_link ) {
548
+
549
+ $ret = '<span class="cat-post-tax-category">';
550
+ $cat_ids = wp_get_post_categories( get_the_ID(), array( 'number' => 0 ) );
551
+ foreach ( $cat_ids as $cat_id ) {
552
+ if ( $everything_is_link ) {
553
+ $ret .= ' ' . get_cat_name( $cat_id );
554
+ } else {
555
+ $ret .= " <a href='" . get_category_link( $cat_id ) . "'>" . get_cat_name( $cat_id ) . '</a>';
556
+ }
557
+ }
558
+ $ret .= '</span>';
559
+ return $ret;
560
+ }
561
+
562
+ /**
563
+ * Current post item tags string
564
+ *
565
+ * @param array $instance Array which contains the various settings.
566
+ * @param bool $everything_is_link Indicates whether the return string should avoid links.
567
+ *
568
+ * @since 4.8
569
+ */
570
+ public function itemTags( $instance, $everything_is_link ) {
571
+
572
+ $ret = '<span class="cat-post-tax-tag">';
573
+ $tag_ids = wp_get_post_tags( get_the_ID(), array( 'number' => 0 ) );
574
+ foreach ( $tag_ids as $tag_id ) {
575
+ if ( $everything_is_link ) {
576
+ $ret .= ' ' . $tag_id->name;
577
+ } else {
578
+ $ret .= " <a href='" . get_tag_link( $tag_id->term_id ) . "'>" . $tag_id->name . '</a>';
579
+ }
580
+ }
581
+ $ret .= '</span>';
582
+ return $ret;
583
+ }
584
+
585
+ /**
586
+ * Current post item comment number string
587
+ *
588
+ * @param array $instance Array which contains the various settings.
589
+ * @param bool $everything_is_link Indicates whether the return string should avoid links.
590
+ *
591
+ * @since 4.8
592
+ */
593
+ public function itemCommentNum( $instance, $everything_is_link ) {
594
+ global $post;
595
+
596
+ $ret = '<span class="cat-post-comment-num">';
597
+
598
+ if ( $everything_is_link ) {
599
+ $ret .= '(' . \get_comments_number() . ')';
600
+ } else {
601
+ $link = sprintf(
602
+ '<a href="%1$s" title="%2$s">(%3$d)</a>',
603
+ esc_url( get_comments_link( $post->ID ) ),
604
+ esc_attr( sprintf( __( '(%d) comments to this post' ), get_comments_number() ) ),
605
+ get_comments_number()
606
+ );
607
+ $ret .= $link;
608
+ }
609
+
610
+ $ret .= '</span>';
611
+ return $ret;
612
+ }
613
+
614
+ /**
615
+ * Current post item author string
616
+ *
617
+ * @param array $instance Array which contains the various settings.
618
+ * @param bool $everything_is_link Indicates whether the return string should avoid links.
619
+ *
620
+ * @since 4.8
621
+ */
622
+ public function itemAuthor( $instance, $everything_is_link ) {
623
+
624
+ $ret = '<span class="cat-post-author">';
625
+
626
+ if ( $everything_is_link ) {
627
+ $ret .= get_the_author();
628
+ } else {
629
+ $link = get_the_author_posts_link();
630
+ $ret .= $link;
631
+ }
632
+ $ret .= '</span>';
633
+ return $ret;
634
+ }
635
+
636
+ /**
637
+ * Current post item excerpt string
638
+ *
639
+ * @param array $instance Array which contains the various settings.
640
+ * @param bool $everything_is_link Indicates whether the return string should avoid links.
641
+ *
642
+ * @since 4.8
643
+ */
644
+ public function itemExcerpt( $instance, $everything_is_link ) {
645
+ global $post;
646
+
647
+ // use the_excerpt filter to get the "normal" excerpt of the post
648
+ // then apply our filter to let users customize excerpts in their own way.
649
+ if ( isset( $instance['excerpt_length'] ) && ( $instance['excerpt_length'] > 0 ) ) {
650
+ $length = (int) $instance['excerpt_length'];
651
+ } else {
652
+ $length = 999; // Use the wordpress default.
653
+ }
654
+
655
+ if ( ! isset( $instance['excerpt_filters'] ) || $instance['excerpt_filters'] ) { // pre 4.7 widgets has filters on.
656
+ $excerpt = apply_filters( 'the_excerpt', \get_the_excerpt() );
657
+ } else { // if filters off replicate functionality of core generating excerpt.
658
+ $more_text = '[&hellip;]';
659
+ if ( isset( $instance['excerpt_more_text'] ) && $instance['excerpt_more_text'] ) {
660
+ $more_text = ltrim( $instance['excerpt_more_text'] );
661
+ }
662
+
663
+ if ( $everything_is_link ) {
664
+ $excerpt_more_text = ' <span class="cat-post-excerpt-more">' . $more_text . '</span>';
665
+ } else {
666
+ $excerpt_more_text = ' <a class="cat-post-excerpt-more" href="' . get_permalink() . '" title="' . sprintf( __( 'Continue reading %s' ), get_the_title() ) . '">' . $more_text . '</a>';
667
+ }
668
+ if ( '' === $post->post_excerpt ) {
669
+ $text = get_the_content( '' );
670
+ $text = strip_shortcodes( $text );
671
+ $excerpt = \wp_trim_words( $text, $length, $excerpt_more_text );
672
+ // adjust html output same way as for the normal excerpt,
673
+ // just force all functions depending on the_excerpt hook.
674
+ $excerpt = shortcode_unautop( wpautop( convert_chars( convert_smilies( wptexturize( $excerpt ) ) ) ) );
675
+ } else {
676
+ $text = $post->post_excerpt;
677
+ $excerpt = \wp_trim_words( $text, $length, $excerpt_more_text );
678
+ $excerpt = shortcode_unautop( wpautop( convert_chars( convert_smilies( wptexturize( $excerpt ) ) ) ) );
679
+ }
680
+ }
681
+ $ret = apply_filters( 'cpw_excerpt', $excerpt, $this );
682
+ return $ret;
683
+ }
684
+
685
+ /**
686
+ * Current post item title string
687
+ *
688
+ * @param array $instance Array which contains the various settings.
689
+ * @param bool $everything_is_link Indicates whether the return string should avoid links.
690
+ *
691
+ * @since 4.8
692
+ */
693
+ public function itemTitle( $instance, $everything_is_link ) {
694
+
695
+ $ret = '';
696
+
697
+ if ( $everything_is_link ) {
698
+ $ret .= '<span class="cat-post-title">' . get_the_title() . '</span>';
699
+ } else {
700
+ $ret .= '<a class="cat-post-title"';
701
+ $ret .= ' href="' . get_the_permalink() . '" rel="bookmark">' . get_the_title();
702
+ $ret .= '</a>';
703
+ }
704
+ return $ret;
705
+ }
706
+
707
+ /**
708
+ * Calculate the HTML for a post item based on the widget settings and post.
709
+ * Expected to be called in an active loop with all the globals set.
710
+ *
711
+ * @param array $instance Array which contains the various settings.
712
+ * @param null|integer $current_post_id If on singular page specifies the id of
713
+ * the post, otherwise null.
714
+ * @return string The HTML for item related to the post
715
+ *
716
+ * @since 4.6
717
+ */
718
+ public function itemHTML( $instance, $current_post_id ) {
719
+ global $post;
720
+
721
+ $everything_is_link = isset( $instance['everything_is_link'] ) && $instance['everything_is_link'];
722
+ $wrap = isset( $instance['text_do_not_wrap_thumb'] ) && $instance['text_do_not_wrap_thumb'];
723
+
724
+ $template = '';
725
+ if ( isset( $instance['template'] ) ) {
726
+ $template = $instance['template'];
727
+ } else {
728
+ $template = convert_settings_to_template( $instance );
729
+ }
730
+ $ret = '<li ';
731
+
732
+ // Current post.
733
+ if ( $current_post_id === $post->ID ) {
734
+ $ret .= "class='cat-post-item cat-post-current'";
735
+ } else {
736
+ $ret .= "class='cat-post-item'";
737
+ }
738
+ $ret .= '>'; // close the li opening tag.
739
+
740
+ if ( $everything_is_link ) {
741
+ $ret .= '<a class="cat-post-everything-is-link" href="' . get_the_permalink() . '" title="">';
742
+ }
743
+
744
+ // Try to do smart formatting for floating thumb based on its location.
745
+ if ( $wrap ) {
746
+ if ( preg_match( '#(\%thumb\%)#', $template ) && ! preg_match( '#(\%thumb\%$)#', $template ) ) {
747
+ $thumb_flex = explode( '%thumb%', $template );
748
+ if ( 1 === count( $thumb_flex ) ) {
749
+ $template = '<div class="cat-post-do-not-wrap-thumbnail">%thumb%<div>' . $thumb_flex[0] . '</div></div>';
750
+ }
751
+ if ( 2 === count( $thumb_flex ) ) {
752
+ $template = $thumb_flex[0] . '<div class="cat-post-do-not-wrap-thumbnail">%thumb%<div>' . $thumb_flex[1] . '</div></div>';
753
+ }
754
+ }
755
+ }
756
+
757
+ // Post details (Template).
758
+ $widget = $this;
759
+ $template_res = preg_replace_callback( get_template_regex(), function ( $matches ) use ( $widget, $instance, $everything_is_link ) {
760
+ switch ( $matches[0] ) {
761
+ case '%title%':
762
+ return $widget->itemTitle( $instance, $everything_is_link );
763
+ case '%author%':
764
+ return $widget->itemAuthor( $instance, $everything_is_link );
765
+ case '%commentnum%':
766
+ return $widget->itemCommentNum( $instance, $everything_is_link );
767
+ case '%date%':
768
+ return $widget->itemDate( $instance, $everything_is_link );
769
+ case '%thumb%':
770
+ return $widget->itemThumb( $instance, $everything_is_link );
771
+ case '%post_tag%':
772
+ return $widget->itemTags( $instance, $everything_is_link );
773
+ case '%category%':
774
+ return $widget->itemCategories( $instance, $everything_is_link );
775
+ case '%excerpt%':
776
+ return $widget->itemExcerpt( $instance, $everything_is_link );
777
+ default:
778
+ return $matches[0];
779
+ }
780
+ }, $template );
781
+
782
+ // Replace empty line with closing and opening DIV.
783
+ $template_res = trim( $template_res );
784
+ $template_res = str_replace( "\n\r", '</div><div>', $template_res ); // in widget areas.
785
+ $template_res = str_replace( "\n\n", '</div><div>', $template_res ); // as shortcode.
786
+ $template_res = '<div>' . $template_res . '</div>';
787
+
788
+ // replace new lines with spaces.
789
+ $template_res = str_replace( "\n\r", ' ', $template_res ); // in widget areas.
790
+ $template_res = str_replace( "\n\n", ' ', $template_res ); // as shortcode.
791
+
792
+ $ret .= $template_res;
793
+
794
+ if ( $everything_is_link ) {
795
+ $ret .= '</a>';
796
+ }
797
+
798
+ $ret .= '</li>';
799
+ return $ret;
800
+ }
801
+
802
+ /**
803
+ * Filter to set the number of words in an excerpt
804
+ *
805
+ * @param int $length The number of words as configured by wordpress core or set by previous filters.
806
+ * @return int The number of words configured for the widget,
807
+ * or the $length parameter if it is not configured or garbage value.
808
+ *
809
+ * @since 4.6
810
+ */
811
+ public function excerpt_length_filter( $length ) {
812
+ if ( isset( $this->instance['excerpt_length'] ) && $this->instance['excerpt_length'] > 0 ) {
813
+ $length = $this->instance['excerpt_length'];
814
+ }
815
+ return $length;
816
+ }
817
+
818
+ /**
819
+ * Set the proper excerpt filters based on the settings
820
+ *
821
+ * @param array $instance widget settings.
822
+ * @return void
823
+ *
824
+ * @since 4.6
825
+ */
826
+ public function setExcerpFilters( $instance ) {
827
+
828
+ if ( isset( $instance['excerpt'] ) && $instance['excerpt'] ) {
829
+
830
+ // Excerpt length filter.
831
+ if ( isset( $instance['excerpt_length'] ) && ( (int) $instance['excerpt_length'] ) > 0 ) {
832
+ add_filter( 'excerpt_length', array( $this, 'excerpt_length_filter' ) );
833
+ }
834
+
835
+ if ( isset( $instance['excerpt_more_text'] ) && ( '' !== ltrim( $instance['excerpt_more_text'] ) ) ) {
836
+ add_filter( 'excerpt_more', array( $this, 'excerpt_more_filter' ) );
837
+ }
838
+
839
+ add_filter( 'the_excerpt', array( $this, 'apply_the_excerpt' ) );
840
+ }
841
+ }
842
+
843
+ /**
844
+ * Remove the excerpt filter
845
+ *
846
+ * @param array $instance widget settings.
847
+ * @return void
848
+ *
849
+ * @since 4.6
850
+ */
851
+ public function removeExcerpFilters( $instance ) {
852
+ remove_filter( 'excerpt_length', array( $this, 'excerpt_length_filter' ) );
853
+ remove_filter( 'excerpt_more', array( $this, 'excerpt_more_filter' ) );
854
+ add_filter( 'get_the_excerpt', 'wp_trim_excerpt' );
855
+ remove_filter( 'the_excerpt', array( $this, 'apply_the_excerpt' ) );
856
+ }
857
+
858
+ /**
859
+ * The main widget display controller
860
+ *
861
+ * Called by the sidebar processing core logic to display the widget.
862
+ *
863
+ * @param array $args An array containing the "environment" setting for the widget,
864
+ * namely, the enclosing tags for the widget and its title.
865
+ * @param array $instance The settings associate with the widget.
866
+ *
867
+ * @since 4.1
868
+ */
869
+ public function widget( $args, $instance ) {
870
+
871
+ $instance = upgrade_settings( $instance );
872
+
873
+ extract( $args );
874
+
875
+ $this->instance = $instance;
876
+
877
+ $current_post_id = '';
878
+ if ( is_singular() ) {
879
+ $current_post_id = get_the_ID();
880
+ }
881
+
882
+ $items = $this->get_elements_HTML( $instance, $current_post_id, 0, 0 );
883
+
884
+ if ( ( 'nothing' === $instance['no_match_handling'] ) || ! empty( $items ) ) {
885
+ echo $before_widget; // Xss ok. This is how widget actually expected to behave.
886
+ echo $this->titleHTML( $before_title, $after_title, $instance );
887
+
888
+ $thumb = isset( $this->instance['template'] ) && preg_match( '/%thumb%/', $this->instance['template'] );
889
+
890
+ if ( ! ( isset( $instance['is_shortcode'] ) && $instance['is_shortcode'] ) ) { // the internal id is needed only for widgets.
891
+ echo '<ul id="' . esc_attr( WIDGET_BASE_ID ) . '-' . esc_attr( $this->number ) . '-internal" class="' . esc_attr( WIDGET_BASE_ID ) . '-internal' . "\">\n";
892
+ } else {
893
+ echo '<ul>';
894
+ }
895
+
896
+ // image crop browser fallback and workaround, no polyfill.
897
+ if ( $thumb ) {
898
+ if ( apply_filters( 'cpw_enqueue_resources', false ) ) {
899
+ frontend_script();
900
+ } else {
901
+ wp_enqueue_script( 'jquery' );
902
+ add_action( 'wp_footer', __NAMESPACE__ . '\embed_front_end_scripts', 100 );
903
+ }
904
+ }
905
+
906
+ // set widget filters.
907
+ if ( ! isset( $instance['excerpt_filters'] ) || $instance['excerpt_filters'] ) { // pre 4.7 widgets has filters on.
908
+ $this->setExcerpFilters( $instance );
909
+ }
910
+
911
+ foreach ( $items as $item ) {
912
+ echo $item;
913
+ }
914
+ echo "</ul>\n";
915
+
916
+ // Load more only if we think we have more items.
917
+ if ( count( $items ) === (int) $instance['num'] ) {
918
+ echo $this->loadMoreHTML( $instance );
919
+ }
920
+
921
+ echo $this->footerHTML( $instance );
922
+ echo $after_widget; // Xss ok. This is how widget actually expected to behave.
923
+
924
+ // remove widget filters.
925
+ if ( ! isset( $instance['excerpt_filters'] ) || $instance['excerpt_filters'] ) { // pre 4.7 widgets has filters on.
926
+ $this->removeExcerpFilters( $instance );
927
+ }
928
+
929
+ wp_reset_postdata();
930
+ } elseif ( 'text' === $instance['no_match_handling'] ) {
931
+ echo $before_widget; // Xss ok. This is how widget actually expected to behave.
932
+ echo $this->titleHTML( $before_title, $after_title, $instance );
933
+ echo esc_html( $instance['no_match_text'] );
934
+ echo $this->footerHTML( $instance );
935
+ echo $after_widget; // Xss ok. This is how widget actually expected to behave.
936
+ }
937
+ }
938
+
939
+ /**
940
+ * Get an array of HTML pre item, for item starting from a specific position.
941
+ *
942
+ * @since 4.9
943
+ *
944
+ * @param array $instance An array containing the settings of the widget.
945
+ * @param string $singular_id The ID of the post in which the widget is rendered,
946
+ * an empty string indicates the rendering context
947
+ * is not singular.
948
+ * @param int $start The start element (0 based).
949
+ * @param int $number The maximal number of elements to return. A value of 0
950
+ * Indicates to use the widget settings for that.
951
+ *
952
+ * @return string[] Array of HTML per element with the $start element first
953
+ * $start+1 next etc. An empty array is returned if there
954
+ * are no applicable items.
955
+ */
956
+ public function get_elements_HTML( $instance, $singular_id, $start, $number ) {
957
+ $ret = array();
958
+
959
+ if ( 0 === count( $instance ) ) {
960
+ $instance = default_settings();
961
+ }
962
+
963
+ $this->instance = $instance;
964
+
965
+ if($start > 0) {
966
+ $instance['offset'] = $start;
967
+ }
968
+ $number = (int) $number; // sanitize number with the side effect of non
969
+ // numbers are converted to zero.
970
+ if ( 0 < $number ) {
971
+ $instance['num'] = $number;
972
+ }
973
+ $args = $this->queryArgs( $instance );
974
+ $cat_posts = new \WP_Query( $args );
975
+ $current_post_id = null;
976
+ if ( '' !== $singular_id ) {
977
+ $current_post_id = (int) $singular_id;
978
+ }
979
+
980
+ while ( $cat_posts->have_posts() ) {
981
+ $cat_posts->the_post();
982
+ $ret[] = $this->itemHTML( $instance, $current_post_id );
983
+ }
984
+
985
+ wp_reset_postdata();
986
+
987
+ return $ret;
988
+ }
989
+
990
+ /**
991
+ * Update the options.
992
+ *
993
+ * @param array $new_instance The new settings of the widget.
994
+ * @param array $old_instance The current settings of the widget.
995
+ * @return array
996
+ */
997
+ public function update( $new_instance, $old_instance ) {
998
+
999
+ $new_instance['title'] = sanitize_text_field( $new_instance['title'] ); // sanitize the title like core widgets do.
1000
+ if ( ! isset( $new_instance['excerpt_filters'] ) ) {
1001
+ $new_instance['excerpt_filters'] = '';
1002
+ }
1003
+ if ( current_user_can( 'unfiltered_html' ) ) {
1004
+ $instance['text'] = $new_instance['template'];
1005
+ } else {
1006
+ $instance['text'] = wp_kses_post( $new_instance['template'] );
1007
+ }
1008
+
1009
+ // Set the version of the DB structure.
1010
+ $new_instance['ver'] = VERSION;
1011
+ return $new_instance;
1012
+ }
1013
+
1014
+ /**
1015
+ * Output the title panel of the widget configuration form.
1016
+ *
1017
+ * @param array $instance The widget's settings.
1018
+ * @return void
1019
+ *
1020
+ * @since 4.6
1021
+ */
1022
+ public function formTitlePanel( $instance ) {
1023
+ $cat = (int) $instance['cat'];
1024
+
1025
+ $hide_title = false;
1026
+ if ( isset( $instance['hide_title'] ) && $instance['hide_title'] ) {
1027
+ $hide_title = true;
1028
+ }
1029
+ ?>
1030
+ <h4 data-panel="title"><?php esc_html_e( 'Title', 'category-posts' ); ?></h4>
1031
+ <div class="cpwp_ident">
1032
+ <?php echo $this->get_checkbox_block_html( $instance, 'hide_title', esc_html__( 'Hide title', 'category-posts' ), true ); ?>
1033
+ <div class="categoryposts-data-panel-title-settings" <?php echo ( $hide_title ) ? 'style="display:none"' : ''; ?>>
1034
+ <?php echo $this->get_text_input_block_html( $instance, 'title', esc_html__( 'Title', 'category-posts' ), '', true ); ?>
1035
+ <?php echo $this->get_checkbox_block_html( $instance, 'title_link', esc_html__( 'Make widget title link', 'category-posts' ), 0 !== $cat ); ?>
1036
+ <?php echo $this->get_text_input_block_html( $instance, 'title_link_url', esc_html__( 'Title link URL', 'category-posts' ), '', 0 === $cat ); ?>
1037
+ </div>
1038
+ </div>
1039
+ <?php
1040
+ }
1041
+
1042
+ /**
1043
+ * Output the filter panel of the widget configuration form.
1044
+ *
1045
+ * @param array $instance The parameters configured for the widget.
1046
+ * @return void
1047
+ *
1048
+ * @since 4.6
1049
+ */
1050
+ public function formFilterPanel( $instance ) {
1051
+ $cat = $instance['cat'];
1052
+ ?>
1053
+ <h4 data-panel="filter"><?php esc_html_e( 'Filter', 'category-posts' ); ?></h4>
1054
+ <div>
1055
+ <p>
1056
+ <label>
1057
+ <?php esc_html_e( 'Category', 'category-posts' ); ?>:
1058
+ <?php
1059
+ wp_dropdown_categories( array(
1060
+ 'show_option_all' => __( 'All categories', 'category-posts' ),
1061
+ 'hide_empty' => 0,
1062
+ 'name' => $this->get_field_name( 'cat' ),
1063
+ 'selected' => $instance['cat'],
1064
+ 'class' => 'categoryposts-data-panel-filter-cat',
1065
+ ) );
1066
+ ?>
1067
+ </label>
1068
+ </p>
1069
+ <?php
1070
+ echo $this->get_checkbox_block_html( $instance, 'no_cat_childs', esc_html__( 'Exclude child categories', 'category-posts' ), ! empty( $instance['cat'] ) );
1071
+ echo $this->get_select_block_html( $instance, 'status', esc_html__( 'Status', 'category-posts' ), array(
1072
+ 'default' => esc_html__( 'WordPress Default', 'category-posts' ),
1073
+ 'publish' => esc_html__( 'Published', 'category-posts' ),
1074
+ 'future' => esc_html__( 'Scheduled', 'category-posts' ),
1075
+ 'private' => esc_html__( 'Private', 'category-posts' ),
1076
+ 'publish,future' => esc_html__( 'Published or Scheduled', 'category-posts' ),
1077
+ 'private,publish' => esc_html__( 'Published or Private', 'category-posts' ),
1078
+ 'private,future' => esc_html__( 'Private or Scheduled', 'category-posts' ),
1079
+ 'private,publish,future' => esc_html__( 'Published, Private or Scheduled', 'category-posts' ),
1080
+ ), 'default', true );
1081
+ echo $this->get_number_input_block_html( $instance, 'num', esc_html__( 'Number of posts to show', 'category-posts' ), 1, '', '', true );
1082
+ echo $this->get_number_input_block_html( $instance, 'offset', esc_html__( 'Start with post', 'category-posts' ), 1, '', '', true );
1083
+ echo $this->get_select_block_html( $instance, 'date_range', esc_html__( 'Date Range', 'category-posts' ), array(
1084
+ 'off' => esc_html__( 'Off', 'category-posts' ),
1085
+ 'days_ago' => esc_html__( 'Days ago', 'category-posts' ),
1086
+ 'between_dates' => esc_html__( 'Between dates', 'category-posts' ),
1087
+ ), 'off', true );
1088
+ ?>
1089
+ <div class="cpwp_ident categoryPosts-date-range" style="display:<?php echo 'off' === $instance['date_range'] ? 'none' : 'block'; ?>">
1090
+ <?php
1091
+ echo $this->get_number_input_block_html( $instance, 'days_ago', esc_html__( 'Up to', 'category-posts' ), 1, '', '', 'days_ago' === $instance['date_range'] );
1092
+ echo $this->get_date_input_block_html( $instance, 'start_date', esc_html__( 'After', 'category-posts' ), 'between_dates' === $instance['date_range'] );
1093
+ echo $this->get_date_input_block_html( $instance, 'end_date', esc_html__( 'Before', 'category-posts' ), 'between_dates' === $instance['date_range'] );
1094
+ ?>
1095
+ </div>
1096
+ <?php
1097
+ echo $this->get_select_block_html( $instance, 'sort_by', esc_html__( 'Sort by', 'category-posts' ), array(
1098
+ 'date' => esc_html__( 'Date', 'category-posts' ),
1099
+ 'title' => esc_html__( 'Title', 'category-posts' ),
1100
+ 'comment_count' => esc_html__( 'Number of comments', 'category-posts' ),
1101
+ 'rand' => esc_html__( 'Random', 'category-posts' ),
1102
+ ), 'date', true );
1103
+ echo $this->get_checkbox_block_html( $instance, 'asc_sort_order', esc_html__( 'Reverse sort order (ascending)', 'category-posts' ), true );
1104
+ echo $this->get_checkbox_block_html( $instance, 'exclude_current_post', esc_html__( 'Exclude current post', 'category-posts' ), true );
1105
+ echo $this->get_checkbox_block_html( $instance, 'hideNoThumb', esc_html__( 'Exclude posts which have no thumbnail', 'category-posts' ), true );
1106
+ ?>
1107
+ </div>
1108
+ <?php
1109
+ }
1110
+
1111
+ /**
1112
+ * Generate the wrapper P around a form input element
1113
+ *
1114
+ * @since 4.8
1115
+ * @param string $html The HTML to wrap.
1116
+ * @param string $key The key to use as the prefix to the class.
1117
+ * @param bool $visible Indicates if the element should be visible when rendered.
1118
+ *
1119
+ * @return string HTML with P element contaning the html being passed with class based on the key
1120
+ * and style set to display:none if visibility is off.
1121
+ */
1122
+ private function get_wrap_block_html( $html, $key, $visible ) {
1123
+
1124
+ $cl = ' class="' . __NAMESPACE__ . '-' . esc_attr( $key ) . '"';
1125
+
1126
+ $style = '';
1127
+ if ( ! $visible ) {
1128
+ $style = ' style="display:none"';
1129
+ }
1130
+ $ret = '<p' . $cl . $style . ">\n" . $html . "</p>\n";
1131
+
1132
+ return $ret;
1133
+ }
1134
+
1135
+ /**
1136
+ * Generate a form P element containing a select element
1137
+ *
1138
+ * @since 4.8
1139
+ * @param array $instance The instance.
1140
+ * @param string $key The key in the instance array.
1141
+ * @param string $label The label to display and associate with the input.
1142
+ * @param array $list An array of pairs value (index) => label to be used for the options.
1143
+ * The labels are expected to be html escaped.
1144
+ * @param int $default The value to use if the key is not set in the instance.
1145
+ * @param bool $visible Indicates if the element should be visible when rendered.
1146
+ *
1147
+ * @return string HTML a P element contaning the select, its label, class based on the key
1148
+ * and style set to display:none if visibility is off.
1149
+ */
1150
+ private function get_select_block_html( $instance, $key, $label, $list, $default, $visible ) {
1151
+ $value = $instance[ $key ];
1152
+
1153
+ if ( ! array_key_exists( $value, $list ) ) {
1154
+ $value = $default;
1155
+ }
1156
+
1157
+ $ret = '<label for="' . $this->get_field_id( $key ) . "\">\n" .
1158
+ $label .
1159
+ "</label>\n" .
1160
+ '<select id="' . $this->get_field_id( $key ) . '" name="' . $this->get_field_name( $key ) . '" autocomplete="off">' . "\n";
1161
+ foreach ( $list as $v => $l ) {
1162
+ $ret .= '<option value="' . esc_attr( $v ) . '" ' . selected( $v, $value, false ) . '>' . $l . "</option>\n";
1163
+ }
1164
+ $ret .= "</select>\n";
1165
+
1166
+ return $this->get_wrap_block_html( $ret, $key, $visible );
1167
+ }
1168
+
1169
+ /**
1170
+ * Generate a form P element containing a textarea input
1171
+ *
1172
+ * @since 4.8
1173
+ * @param array $instance The instance.
1174
+ * @param string $key The key in the instance array.
1175
+ * @param string $label The label to display and associate with the input (should be html escaped).
1176
+ * @param string $placeholder The placeholder to use in the input (should be attribute escaped).
1177
+ * @param bool $visible Indicates if the element should be visible when rendered.
1178
+ * @param int $num_rows Number of rows.
1179
+ *
1180
+ * @return string HTML a P element containing the input, its label, class based on the key
1181
+ * and style set to display:none if visibility is off.
1182
+ */
1183
+ private function get_textarea_html( $instance, $key, $label, $placeholder, $visible, $num_rows ) {
1184
+
1185
+ $value = $instance[ $key ];
1186
+
1187
+ $ret = '<label for="' . esc_attr( $this->get_field_id( $key ) ) . '">' . $label .
1188
+ '<textarea rows="' . esc_attr( $num_rows ) . '" placeholder="' . $placeholder . '" id="' . esc_attr( $this->get_field_id( $key ) ) . '" name="' . esc_attr( $this->get_field_name( $key ) ) . '" autocomplete="off">' . esc_textarea( $value ) . '</textarea>' .
1189
+ '</label>';
1190
+
1191
+ return $this->get_wrap_block_html( $ret, $key, $visible );
1192
+ }
1193
+
1194
+ /**
1195
+ * Generate a form P element containing a text input
1196
+ *
1197
+ * @since 4.8
1198
+ * @param array $instance The instance.
1199
+ * @param string $key The key in the instance array.
1200
+ * @param string $label The label to display and associate with the input.
1201
+ * Should be html escaped.
1202
+ * @param string $placeholder The placeholder to use in the input. should be attribute escaped.
1203
+ * @param bool $visible Indicates if the element should be visible when rendered.
1204
+ *
1205
+ * @return string HTML a P element contaning the input, its label, class based on the key
1206
+ * and style set to display:none if visibility is off.
1207
+ */
1208
+ private function get_text_input_block_html( $instance, $key, $label, $placeholder, $visible ) {
1209
+
1210
+ $value = $instance[ $key ];
1211
+
1212
+ $ret = '<label for="' . $this->get_field_id( $key ) . "\">\n" .
1213
+ $label . "\n" .
1214
+ '<input placeholder="' . $placeholder . '" id="' . $this->get_field_id( $key ) . '" name="' . $this->get_field_name( $key ) . '" type="text" value="' . esc_attr( $value ) . '" autocomplete="off"/>' . "\n" .
1215
+ "</label>\n";
1216
+
1217
+ return $this->get_wrap_block_html( $ret, $key, $visible );
1218
+ }
1219
+
1220
+ /**
1221
+ * Generate a form P element containing a range input
1222
+ *
1223
+ * @since 4.8
1224
+ * @param array $instance The instance.
1225
+ * @param string $key The key in the instance array.
1226
+ * @param string $label The label to display and associate with the input.
1227
+ * expected to be escaped.
1228
+ * @param int $min The minimum value allowed to be input.
1229
+ * @param int $max The maximum value allowed to be input.
1230
+ * @param string $value The start value
1231
+ * @param string $step The range of each step
1232
+ * @param bool $visible Indicates if the element should be visible when rendered.
1233
+ *
1234
+ * @return string HTML a P element contaning the input, its label, class based on the key
1235
+ * and style set to display:none if visibility is off.
1236
+ */
1237
+ private function get_range_input_block_html( $instance, $key, $label, $min, $max, $value, $step, $visible ) {
1238
+
1239
+ $value = $instance[ $key ];
1240
+
1241
+ $minMaxStep = '';
1242
+ if ( '' !== $min ) {
1243
+ $minMaxStep .= ' min="' . $min . '"';
1244
+ }
1245
+ if ( '' !== $max ) {
1246
+ $minMaxStep .= ' max="' . $max . '"';
1247
+ }
1248
+ if ( '' !== $step ) {
1249
+ $minMaxStep .= ' step="' . $step . '"';
1250
+ }
1251
+
1252
+ $ret = '<label for="' . $this->get_field_id( $key ) . "\">\n" .
1253
+ esc_html( $label ) . " <span>" . $value . "%</span>\n" .
1254
+ '<input id="' . esc_attr( $this->get_field_id( $key ) ) . '" value="' . $value . '" name="' . esc_attr( $this->get_field_name( $key ) ) . '" class="' . esc_attr( $key ) . '" type="range"' . $minMaxStep . ' />' . "\n" .
1255
+ "</label>\n";
1256
+
1257
+ return $this->get_wrap_block_html( $ret, $key, $visible );
1258
+ }
1259
+
1260
+ /**
1261
+ * Generate a form P element containing a number input
1262
+ *
1263
+ * @since 4.8
1264
+ * @param array $instance The instance.
1265
+ * @param string $key The key in the instance array.
1266
+ * @param string $label The label to display and associate with the input.
1267
+ * expected to be escaped.
1268
+ * @param int $min The minimum value allowed to be input.
1269
+ * @param int $max The maximum value allowed to be input.
1270
+ * @param string $placeholder The placeholder string to be used. expected to be escaped.
1271
+ * @param bool $visible Indicates if the element should be visible when rendered.
1272
+ *
1273
+ * @return string HTML a P element contaning the input, its label, class based on the key
1274
+ * and style set to display:none if visibility is off.
1275
+ */
1276
+ private function get_number_input_block_html( $instance, $key, $label, $min, $max, $placeholder, $visible ) {
1277
+
1278
+ $value = $instance[ $key ];
1279
+
1280
+ $minmax = '';
1281
+ if ( '' !== $min ) {
1282
+ $minmax .= ' min="' . $min . '"';
1283
+ }
1284
+ if ( '' !== $max ) {
1285
+ $minmax .= ' max="' . $max . '"';
1286
+ }
1287
+
1288
+ $ret = '<label for="' . $this->get_field_id( $key ) . "\">\n" .
1289
+ esc_html( $label ) . "\n" .
1290
+ '<input placeholder="' . $placeholder . '" id="' . esc_attr( $this->get_field_id( $key ) ) . '" name="' . esc_attr( $this->get_field_name( $key ) ) . '" class="' . esc_attr( $key ) . '" type="number"' . $minmax . ' value="' . esc_attr( $value ) . '" autocomplete="off" />' . "\n" .
1291
+ "</label>\n";
1292
+
1293
+ return $this->get_wrap_block_html( $ret, $key, $visible );
1294
+ }
1295
+
1296
+ /**
1297
+ * Generate a form P element containing a date input
1298
+ *
1299
+ * @since 4.9
1300
+ * @param array $instance The instance.
1301
+ * @param string $key The key in the instance array.
1302
+ * @param string $label The label to display and associate with the input.
1303
+ * expected to be escaped.
1304
+ * @param bool $visible Indicates if the element should be visible when rendered.
1305
+ *
1306
+ * @return string HTML a P element containing the input, its label, class based on the key
1307
+ * and style set to display:none if visibility is off.
1308
+ */
1309
+ private function get_date_input_block_html( $instance, $key, $label, $visible ) {
1310
+
1311
+ $value = $instance[ $key ];
1312
+
1313
+ $ret = '<label for="' . $this->get_field_id( $key ) . "\">\n" .
1314
+ esc_html( $label ) . "\n" .
1315
+ '<input id="' . esc_attr( $this->get_field_id( $key ) ) . '" name="' . esc_attr( $this->get_field_name( $key ) ) . '" class="' . esc_attr( $key ) . '" type="date" value="' . esc_attr( $value ) . '" autocomplete="off" />' . "\n" .
1316
+ "</label>\n";
1317
+
1318
+ return $this->get_wrap_block_html( $ret, $key, $visible );
1319
+ }
1320
+
1321
+ /**
1322
+ * Generate a form P element containing a checkbox input
1323
+ *
1324
+ * @since 4.8
1325
+ * @param array $instance The instance.
1326
+ * @param string $key The key in the instance array.
1327
+ * @param string $label The label to display and associate with the checkbox.
1328
+ * should be escaped string.
1329
+ * @param bool $visible Indicates if the element should be visible when rendered.
1330
+ *
1331
+ * @return string HTML a P element contaning the checkbox, its label, class based on the key
1332
+ * and style set to display:none if visibility is off.
1333
+ */
1334
+ private function get_checkbox_block_html( $instance, $key, $label, $visible ) {
1335
+
1336
+ if ( array_key_exists( $key, $instance ) ) {
1337
+ if ( $instance[ $key ] ) {
1338
+ $value = true;
1339
+ } else {
1340
+ $value = false;
1341
+ }
1342
+ }
1343
+ $ret = '<label class="checkbox" for="' . esc_attr( $this->get_field_id( $key ) ) . "\">\n" .
1344
+ '<input id="' . esc_attr( $this->get_field_id( $key ) ) . '" name="' . esc_attr( $this->get_field_name( $key ) ) . '" type="checkbox" ' . checked( $value, true, false ) . '/>' . "\n" .
1345
+ $label .
1346
+ "</label>\n";
1347
+
1348
+ return $this->get_wrap_block_html( $ret, $key, $visible );
1349
+ }
1350
+
1351
+ /**
1352
+ * Generate a form button element containing
1353
+ *
1354
+ * @since 4.9
1355
+ * @param array $instance The instance.
1356
+ * @param string $key The key in the instance array.
1357
+ * @param string $label The label to display and associate with the button.
1358
+ * should be escaped string.
1359
+ *
1360
+ * @return string HTML a button element and class based on the key.
1361
+ */
1362
+ private function get_button_thumb_size_html( $instance, $key, $label ) {
1363
+
1364
+ $datas = "";
1365
+
1366
+ switch ( $key ) {
1367
+ case "thumb":
1368
+ $datas = 'data-thumb-w="' . get_option( "thumbnail_size_w" ) . '" data-thumb-h="' . get_option( "thumbnail_size_h" ) . '"';
1369
+ break;
1370
+ case "medium":
1371
+ $datas = 'data-thumb-w="' . get_option( "medium_size_w" ) . '" data-thumb-h="' . get_option( "medium_size_h" ) . '"';
1372
+ break;
1373
+ case "large":
1374
+ $datas = 'data-thumb-w="' . get_option( "large_size_w" ) . '" data-thumb-h="' . get_option( "large_size_h" ) . '"';
1375
+ break;
1376
+ }
1377
+ $ret = '<button type="button" ' . $datas . ' class="' . $key . ' button">' . esc_html( $label ) . "</button>\n";
1378
+
1379
+ return $ret;
1380
+ }
1381
+
1382
+ /**
1383
+ * The widget configuration form back end.
1384
+ *
1385
+ * @param array $instance The parameters associated with the widget.
1386
+ * @return void
1387
+ */
1388
+ public function form( $instance ) {
1389
+ if ( 0 === count( $instance ) ) { // new widget, use defaults.
1390
+ $instance = default_settings();
1391
+ } else { // updated widgets come from =< 4.6 excerpt filter is on.
1392
+ if ( ! isset( $instance['excerpt_filters'] ) ) {
1393
+ $instance['excerpt_filters'] = 'on';
1394
+ }
1395
+ }
1396
+
1397
+ $instance = upgrade_settings( $instance );
1398
+
1399
+ $hide_post_titles = $instance['hide_post_titles'];
1400
+ $excerpt_more_text = $instance['excerpt_more_text'];
1401
+ $excerpt_filters = $instance['excerpt_filters'];
1402
+ $date_format = $instance['date_format'];
1403
+ $disable_css = $instance['disable_css'];
1404
+ $disable_font_styles = $instance['disable_font_styles'];
1405
+ $preset_date_format = $instance['preset_date_format'];
1406
+ $thumb = ! empty( $instance['thumb'] );
1407
+ $thumb_w = $instance['thumb_w'];
1408
+ $thumb_fluid_width = $instance['thumb_fluid_width'];
1409
+ $thumb_h = $instance['thumb_h'];
1410
+ $default_thunmbnail = $instance['default_thunmbnail'];
1411
+ $use_css_cropping = $instance['use_css_cropping'];
1412
+ $text_do_not_wrap_thumb = $instance['text_do_not_wrap_thumb'];
1413
+ ?>
1414
+
1415
+ <div class="category-widget-cont">
1416
+ <?php if ( ! class_exists( '\\termcategoryPostsPro\\Widget' ) ) { ?>
1417
+ <p><a target="_blank" href="http://tiptoppress.com/term-and-category-based-posts-widget/"><?php esc_html_e( 'Get the Pro version', 'category-posts' ); ?></a></p>
1418
+ <?php
1419
+ }
1420
+ $this->formTitlePanel( $instance );
1421
+ $this->formFilterPanel( $instance );
1422
+ ?>
1423
+ <h4 data-panel="details"><?php esc_html_e( 'Post details', 'category-posts' ); ?></h4>
1424
+ <div class="cpwp-sub-panel">
1425
+ <?php
1426
+ $template = '';
1427
+ if ( ! isset( $instance['template'] ) ) {
1428
+ $template = convert_settings_to_template( $instance );
1429
+ } else {
1430
+ $template = $instance['template'];
1431
+ }
1432
+ ?>
1433
+ <p><?php esc_html_e( 'Displayed parts', 'category-posts' ); ?></p>
1434
+ <div class="cpwp_ident">
1435
+ <?php
1436
+ $label = esc_html__( 'Template', 'category-posts' ) .
1437
+ ' <a href="#" class="dashicons toggle-template-help dashicons-editor-help imgedit-help-toggle"><span class="screen-reader-text">' .
1438
+ esc_html__( 'Show template help', 'category-posts' ) . '</span></a>';
1439
+ $class_placement = "";
1440
+ if ( is_customize_preview() ) {
1441
+ $class_placement = "customizer";
1442
+ } else {
1443
+ $class_placement = "admin-panel";
1444
+ }
1445
+ $label .= '<span class="cat-post-add_premade_templates ' . $class_placement . '">' .
1446
+ '<button type="button" class="button cpwp-open-placholder-dropdown-menu"> + ' . esc_html__( 'Add Placeholder', 'category-posts' ) . '</button>' .
1447
+ '<span class="cpwp-placeholder-dropdown-menu">' .
1448
+ '<span data-value="NewLine">' . esc_html__( 'New line', 'category-posts' ) . '</span>' .
1449
+ '<span data-value="EmptyLine">' . esc_html__( 'Empty line', 'category-posts' ) . '</span>' .
1450
+ '<span data-value="title">' . esc_html__( '%title%', 'category-posts' ) . '</span>' .
1451
+ '<span data-value="thumb">' . esc_html__( '%thumb%', 'category-posts' ) . '</span>' .
1452
+ '<span data-value="date">' . esc_html__( '%date%', 'category-posts' ) . '</span>' .
1453
+ '<span data-value="excerpt">' . esc_html__( '%excerpt%', 'category-posts' ) . '</span>' .
1454
+ '<span data-value="author">' . esc_html__( '%author%', 'category-posts' ) . '</span>' .
1455
+ '<span data-value="commentnum">' . esc_html__( '%commentnum%', 'category-posts' ) . '</span>' .
1456
+ '<span data-value="post_tag">' . esc_html__( '%post_tag%', 'category-posts' ) . '</span>' .
1457
+ '<span data-value="category">' . esc_html__( '%category%', 'category-posts' ) . '</span>' .
1458
+ '</span>' .
1459
+ '</span>';
1460
+ ?>
1461
+ <?php
1462
+ echo $this->get_textarea_html( $instance, 'template', $label , '', true, 8 );
1463
+ preg_match_all( get_template_regex(), $template, $matches );
1464
+ $tags = array();
1465
+ if ( ! empty( $matches[0] ) ) {
1466
+ $tags = array_flip( $matches[0] );
1467
+ }
1468
+ ?>
1469
+ <div class="cat-post-template-help">
1470
+ <p><?php esc_html_e( 'The following text will be replaced with the relevant information. In addition you can use any text and html (if you have the permisions) anywhere you want', 'category-posts' ); ?>
1471
+ </p>
1472
+ <table>
1473
+ <tr>
1474
+ <th><?php esc_html_e( 'New line', 'category-posts' ); ?></th>
1475
+ <td><?php esc_html_e( 'Space', 'category-posts' ); ?></td>
1476
+ </tr>
1477
+ <tr>
1478
+ <th><?php esc_html_e( 'Empty line', 'category-posts' ); ?></th>
1479
+ <td><?php esc_html_e( 'Next line is a paragraph', 'category-posts' ); ?></td>
1480
+ </tr>
1481
+ <tr>
1482
+ <th>%title%</th>
1483
+ <td><?php esc_html_e( 'Post title', 'category-posts' ); ?></td>
1484
+ </tr>
1485
+ <tr>
1486
+ <th>%thumb%</th>
1487
+ <td><?php esc_html_e( 'Post thumbnail possibly wrapped by text', 'category-posts' ); ?></td>
1488
+ </tr>
1489
+ <tr>
1490
+ <th>%date%</th>
1491
+ <td><?php esc_html_e( 'Post publish date', 'category-posts' ); ?></td>
1492
+ </tr>
1493
+ <tr>
1494
+ <th>%excerpt%</th>
1495
+ <td><?php esc_html_e( 'Post excerpt', 'category-posts' ); ?></td>
1496
+ </tr>
1497
+ <tr>
1498
+ <th>%author%</th>
1499
+ <td><?php esc_html_e( 'Post author', 'category-posts' ); ?></td>
1500
+ </tr>
1501
+ <tr>
1502
+ <th>%commentnum%</th>
1503
+ <td><?php esc_html_e( 'The number of comments to the post', 'category-posts' ); ?></td>
1504
+ </tr>
1505
+ <tr>
1506
+ <th>%post_tag%</th>
1507
+ <td><?php esc_html_e( 'Post tags', 'category-posts' ); ?></td>
1508
+ </tr>
1509
+ <tr>
1510
+ <th>%category%</th>
1511
+ <td><?php esc_html_e( 'Post categories', 'category-posts' ); ?></td>
1512
+ </tr>
1513
+ </table>
1514
+ </div>
1515
+ <div class="cat-post-premade_templates">
1516
+ <p><label><?php esc_html_e( 'Select premade Template', 'category-posts' ); ?></label></p>
1517
+ <select>
1518
+ <option value="title"><?php esc_html_e( 'Only the title', 'category-posts' ); ?></option>
1519
+ <option value="title_excerpt"><?php esc_html_e( 'Title and Excerpt', 'category-posts' ); ?></option>
1520
+ <option value="title_thumb"><?php esc_html_e( 'Title and Thumbnail', 'category-posts' ); ?></option>
1521
+ <option value="title_thum_excerpt"><?php esc_html_e( 'Title, Thumbnail and Excerpt', 'category-posts' ); ?></option>
1522
+ <option value="everything"><?php esc_html_e( 'All with icons', 'category-posts' ); ?></option>
1523
+ </select>
1524
+ <p><button type="button" class="button"><?php esc_html_e( 'Select this template', 'category-posts' ); ?></button></p>
1525
+ <?php
1526
+ echo $this->get_checkbox_block_html( $instance, 'everything_is_link', esc_html__( 'Everything is a link', 'category-posts' ), true );
1527
+ ?>
1528
+ </div>
1529
+ </div>
1530
+ <?php // Excerpt settings. ?>
1531
+ <div class="cpwp-sub-panel categoryposts-data-panel-excerpt" style="display:<?php echo ( isset( $tags['%excerpt%'] ) ) ? 'block' : 'none'; ?>">
1532
+ <p><?php esc_html_e( 'Excerpt settings', 'category-posts' ); ?></p>
1533
+ <div class="cpwp_ident">
1534
+ <?php
1535
+ echo $this->get_number_input_block_html( $instance, 'excerpt_lines', esc_html__( 'Lines (responsive):', 'category-posts' ), 0, '', '', true );
1536
+ echo $this->get_number_input_block_html( $instance, 'excerpt_length', esc_html__( 'Length (words):', 'category-posts' ), 0, '', '', true );
1537
+ echo $this->get_text_input_block_html( $instance, 'excerpt_more_text', esc_html__( '\'More ...\' text:', 'category-posts' ), esc_attr__( '...', 'category-posts' ), true );
1538
+ ?>
1539
+ </div>
1540
+ </div>
1541
+ <?php // Data settings ?>
1542
+ <div class="cpwp-sub-panel categoryposts-data-panel-date" style="display:<?php echo ( isset( $tags['%date%'] ) ) ? 'block' : 'none'; ?>">
1543
+ <p><?php esc_html_e( 'Date format settings', 'category-posts' ); ?></p>
1544
+ <div class="cpwp_ident">
1545
+ <?php
1546
+ echo $this->get_select_block_html( $instance, 'preset_date_format', esc_html__( 'Date format', 'category-posts' ), array(
1547
+ 'sitedateandtime' => esc_html__( 'Site date and time', 'category-posts' ),
1548
+ 'sitedate' => esc_html__( 'Site date', 'category-posts' ),
1549
+ 'sincepublished' => esc_html__( 'Time since published', 'category-posts' ),
1550
+ 'localsitedateandtime' => esc_html__( 'Reader\'s local date and time', 'category-posts' ),
1551
+ 'localsitedate' => esc_html__( 'Reader\'s local date', 'category-posts' ),
1552
+ 'other' => esc_html__( 'PHP style format', 'category-posts' ),
1553
+ ), 'sitedateandtime', true );
1554
+ echo $this->get_text_input_block_html( $instance, 'date_format', esc_html__( 'PHP Style Date format', 'category-posts' ), 'j M Y', 'other' === $preset_date_format );
1555
+ ?>
1556
+ </div>
1557
+ </div>
1558
+ <?php // Thumbnail settings. ?>
1559
+ <div class="cpwp-sub-panel categoryposts-data-panel-thumb" style="display:<?php echo ( isset( $tags['%thumb%'] ) ) ? 'block' : 'none'; ?>">
1560
+ <p><?php esc_html_e( 'Thumbnail settings', 'category-posts' ); ?></p>
1561
+ <div class="cpwp_ident">
1562
+ <p><?php esc_html_e( 'Thumbnail dimensions (pixel)', 'category-posts' ); ?></p>
1563
+ <?php
1564
+ echo $this->get_number_input_block_html( $instance, 'thumb_w', esc_html__( 'Width:', 'category-posts' ), 1, '', '', true );
1565
+ echo $this->get_range_input_block_html( $instance, 'thumb_fluid_width', esc_html__( 'Max-width:', 'category-posts' ), 2, 100, 100, 2, true );
1566
+ echo $this->get_number_input_block_html( $instance, 'thumb_h', esc_html__( 'Height:', 'category-posts' ), 1, '', '', true );
1567
+ ?>
1568
+ <div class="cat-post-thumb-change-size">
1569
+ <p>
1570
+ <label><?php esc_html_e( 'Change size', 'category-posts' ); ?>: </label>
1571
+ <span class="cpwp-right">
1572
+ <?php
1573
+ echo $this->get_button_thumb_size_html( $instance, 'smaller', esc_html__( '-', 'category-posts' ) );
1574
+ echo $this->get_button_thumb_size_html( $instance, 'quarter', esc_html__( '1/4', 'category-posts' ) );
1575
+ echo $this->get_button_thumb_size_html( $instance, 'half', esc_html__( '1/2', 'category-posts' ) );
1576
+ echo $this->get_button_thumb_size_html( $instance, 'double', esc_html__( '2x', 'category-posts' ) );
1577
+ echo $this->get_button_thumb_size_html( $instance, 'bigger', esc_html__( '+', 'category-posts' ) );
1578
+ ?>
1579
+ </span>
1580
+ </p>
1581
+ <p>
1582
+ <label><?php esc_html_e( 'Ratio', 'category-posts' ); ?>: </label>
1583
+ <span class="cpwp-right">
1584
+ <?php
1585
+ echo $this->get_button_thumb_size_html( $instance, 'square', esc_html__( '1:1', 'category-posts' ) );
1586
+ echo $this->get_button_thumb_size_html( $instance, 'standard', esc_html__( '4:3', 'category-posts' ) );
1587
+ echo $this->get_button_thumb_size_html( $instance, 'wide', esc_html__( '16:9', 'category-posts' ) );
1588
+ echo $this->get_button_thumb_size_html( $instance, 'switch', esc_html__( 'switch', 'category-posts' ) );
1589
+ ?>
1590
+ </span>
1591
+ </p>
1592
+ <p>
1593
+ <label><?php esc_html_e( 'Available', 'category-posts' ); ?>: </label>
1594
+ <span class="cpwp-right">
1595
+ <?php
1596
+ echo $this->get_button_thumb_size_html( $instance, 'thumb', esc_html__( 'Thumb', 'category-posts' ) );
1597
+ echo $this->get_button_thumb_size_html( $instance, 'medium', esc_html__( 'Medium', 'category-posts' ) );
1598
+ echo $this->get_button_thumb_size_html( $instance, 'large', esc_html__( 'Large', 'category-posts' ) );
1599
+ ?>
1600
+ </span>
1601
+ </p>
1602
+ </div>
1603
+ <?php
1604
+ echo $this->get_checkbox_block_html( $instance, 'text_do_not_wrap_thumb', esc_html__( 'Do not wrap thumbnail with overflowing text', 'category-posts' ), true );
1605
+ echo $this->get_checkbox_block_html( $instance, 'use_css_cropping', esc_html__( 'CSS crop to requested size', 'category-posts' ), false );
1606
+ echo $this->get_select_block_html( $instance, 'thumb_hover', esc_html__( 'Animation on mouse hover:', 'category-posts' ), array(
1607
+ 'none' => esc_html__( 'None', 'category-posts' ),
1608
+ 'dark' => esc_html__( 'Darker', 'category-posts' ),
1609
+ 'white' => esc_html__( 'Brighter', 'category-posts' ),
1610
+ 'scale' => esc_html__( 'Zoom in', 'category-posts' ),
1611
+ 'blur' => esc_html__( 'Blur', 'category-posts' ),
1612
+ 'icon' => esc_html__( 'Icon', 'category-posts' ),
1613
+ ), 'none', true);
1614
+ echo $this->get_select_block_html( $instance, 'show_post_format', esc_html__( 'Indicate post format and position', 'category-posts' ), array(
1615
+ 'none' => esc_html__( 'None', 'category-posts' ),
1616
+ 'topleft' => esc_html__( 'Top left', 'category-posts' ),
1617
+ 'bottomleft' => esc_html__( 'Bottom left', 'category-posts' ),
1618
+ 'ceter' => esc_html__( 'Center', 'category-posts' ),
1619
+ 'topright' => esc_html__( 'Top right', 'category-posts' ),
1620
+ 'bottomright' => esc_html__( 'Bottom right', 'category-posts' ),
1621
+ 'nocss' => esc_html__( 'HTML without styling', 'category-posts' ),
1622
+ ), 'none', true );
1623
+ ?>
1624
+ <p>
1625
+ <label style="display:block">
1626
+ <?php esc_html_e( 'Default thumbnail: ', 'category-posts' ); ?>
1627
+ </label>
1628
+ <input type="hidden" class="default_thumb_id" id="<?php echo esc_attr( $this->get_field_id( 'default_thunmbnail' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'default_thunmbnail' ) ); ?>" value="<?php echo esc_attr( $default_thunmbnail ); ?>"/>
1629
+ <span class="default_thumb_img">
1630
+ <?php
1631
+ if ( ! $default_thunmbnail ) {
1632
+ esc_html_e( 'None', 'category-posts' );
1633
+ } else {
1634
+ $img = wp_get_attachment_image_src( $default_thunmbnail );
1635
+ echo '<img width="60" height="60" src="' . esc_url( $img[0] ) . '" />';
1636
+ }
1637
+ ?>
1638
+ </span>
1639
+ </p>
1640
+ <p>
1641
+ <button type="button" class="cwp_default_thumb_select button upload-button">
1642
+ <?php esc_html_e( 'Select image', 'category-posts' ); ?>
1643
+ </button>
1644
+ <button type="button" class="cwp_default_thumb_remove button upload-button" <?php echo ( ! $default_thunmbnail ) ? 'style="display:none"' : ''; ?> >
1645
+ <?php esc_html_e( 'No default', 'category-posts' ); ?>
1646
+ </button>
1647
+ </p>
1648
+ </div>
1649
+ </div>
1650
+ </div>
1651
+ <h4 data-panel="general"><?php esc_html_e( 'General', 'category-posts' ); ?></h4>
1652
+ <div>
1653
+ <?php echo $this->get_checkbox_block_html( $instance, 'disable_css', esc_html__( 'Disable the built-in CSS', 'category-posts' ), true ); ?>
1654
+ <?php echo $this->get_checkbox_block_html( $instance, 'disable_font_styles', esc_html__( 'Disable only font styles', 'category-posts' ), true ); ?>
1655
+ <div class="cpwp_ident">
1656
+ <?php
1657
+ echo $this->get_select_block_html( $instance, 'no_match_handling', esc_html__( 'When there are no matches', 'category-posts' ), array(
1658
+ 'nothing' => esc_html__( 'Display empty widget', 'category-posts' ),
1659
+ 'hide' => esc_html__( 'Hide Widget', 'category-posts' ),
1660
+ 'text' => esc_html__( 'Show text', 'category-posts' ),
1661
+ ), 'nothing', true );
1662
+ ?>
1663
+ <div class="categoryPosts-no-match-text" style="display:<?php echo ( 'text' === $instance['no_match_handling'] ) ? 'block' : 'none'; ?>">
1664
+ <?php echo $this->get_textarea_html( $instance, 'no_match_text', esc_html__( 'Text', 'category-posts' ), '', true, 4 ); ?>
1665
+ </div>
1666
+ </div>
1667
+ <div>
1668
+ <?php
1669
+ echo $this->get_checkbox_block_html( $instance, 'enable_loadmore', esc_html__( 'Enable Load More', 'category-posts' ), true );
1670
+ ?>
1671
+ <div class="loadmore-settings" style="display:<?php echo ( $instance['enable_loadmore'] ) ? 'block' : 'none'; ?>">
1672
+ <?php echo $this->get_text_input_block_html( $instance, 'loadmore_text', esc_html__( 'Button text', 'category-posts' ), '', true ); ?>
1673
+ <?php echo $this->get_text_input_block_html( $instance, 'loading_text', esc_html__( 'Loading text', 'category-posts' ), '', true ); ?>
1674
+ </div>
1675
+ </div>
1676
+ </div>
1677
+ <h4 data-panel="footer"><?php esc_html_e( 'Footer', 'category-posts' ); ?></h4>
1678
+ <div>
1679
+ <?php echo $this->get_text_input_block_html( $instance, 'footer_link_text', esc_html__( 'Footer link text', 'category-posts' ), '', true ); ?>
1680
+ <?php echo $this->get_text_input_block_html( $instance, 'footer_link', esc_html__( 'Footer link URL', 'category-posts' ), '', true ); ?>
1681
+ </div>
1682
+ <p><a href="<?php echo esc_url( get_edit_user_link() ) . '#' . __NAMESPACE__; ?>"><?php esc_html_e( 'Widget admin behaviour settings', 'category-posts' ); ?></a></p>
1683
+ <p><a target="_blank" href="<?php echo esc_url( DOC_URL ); ?>"><?php esc_html_e( 'Documentation', 'category-posts' ); ?></a></p>
1684
+ <p><a target="_blank" href="<?php echo esc_url( SUPPORT_URL ); ?>"><?php esc_html_e( 'Support', 'category-posts' ); ?></a></p>
1685
+ <p><?php echo sprintf( wp_kses( __( 'We are on <a href="%1$s">Facebook</a> and <a href="%2$s">Twitter</a>.', 'category-posts' ), array( 'a' => array( 'href' => array() ) ) ), esc_url( 'https://www.facebook.com/TipTopPress' ), esc_url( 'https://twitter.com/TipTopPress' ) ); ?></p>
1686
+ </div>
1687
+ <?php
1688
+ }
1689
+ }
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://wordpress.org/support/plugin/category-posts/reviews/
4
  Tags: category, categories, posts, widget, posts widget, recent posts, category recent posts, shortcode, sidebar, excerpt, multiple widgets
5
  Requires at least: 2.8
6
  Tested up to: 5.4
7
- Stable tag: 4.9.4
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -126,6 +126,9 @@ The FireFox browser has a coverage of 5%, which we find little. For this 5%, we
126
  == Changelog ==
127
  [Read more on our blog ...](http://tiptoppress.com/category/category-posts-widget)
128
 
 
 
 
129
  = 4.9.4 - March 2th 2020 =
130
  * Fixed Delete global click event
131
 
4
  Tags: category, categories, posts, widget, posts widget, recent posts, category recent posts, shortcode, sidebar, excerpt, multiple widgets
5
  Requires at least: 2.8
6
  Tested up to: 5.4
7
+ Stable tag: 4.9.5
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
126
  == Changelog ==
127
  [Read more on our blog ...](http://tiptoppress.com/category/category-posts-widget)
128
 
129
+ = 4.9.5 - May 12th 2020 =
130
+ * Fixed Widget_Title filter missing parameters
131
+
132
  = 4.9.4 - March 2th 2020 =
133
  * Fixed Delete global click event
134