Category Posts Widget - Version 4.7.4

Version Description

  • October 21th 2017 =
  • Bugfix for filter by post status (note private)
Download this release

Release Info

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

Code changes from version 4.7.3 to 4.7.4

Files changed (2) hide show
  1. cat-posts.php +301 -300
  2. readme.txt +10 -3
cat-posts.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: Category Posts Widget
4
  Plugin URI: https://wordpress.org/plugins/category-posts/
5
  Description: Adds a widget that shows the most recent posts from a single category.
6
  Author: TipTopPress
7
- Version: 4.7.3
8
  Author URI: http://tiptoppress.com
9
  Text Domain: category-posts
10
  Domain Path: /languages
@@ -15,7 +15,7 @@ namespace categoryPosts;
15
  // Don't call the file directly
16
  if ( !defined( 'ABSPATH' ) ) exit;
17
 
18
- const CAT_POST_VERSION = "4.7.3";
19
  const CAT_POST_DOC_URL = "http://tiptoppress.com/category-posts-widget/documentation-4-7?utm_source=widget_cpw&utm_campaign=documentation_4_7_cpw&utm_medium=form";
20
 
21
  const SHORTCODE_NAME = 'catposts';
@@ -24,7 +24,7 @@ const WIDGET_BASE_ID = 'category-posts';
24
 
25
  /***
26
  * Adds the "Customize" link to the Toolbar on edit mode.
27
- *
28
  * @since 4.6
29
  **/
30
  function wp_admin_bar_customize_menu() {
@@ -32,20 +32,20 @@ function wp_admin_bar_customize_menu() {
32
 
33
  if ( !isset($_GET['action']) || $_GET['action'] !== 'edit' )
34
  return;
35
-
36
  if ( !current_user_can( 'customize' ) || !is_admin() || !is_user_logged_in() || !is_admin_bar_showing() )
37
  return;
38
 
39
  $current_url = "";
40
  if ( isset( $_GET['post'] ) && $_GET['post'] !== '' )
41
- $current_url = get_permalink( $_GET['post'] );
42
  $customize_url = add_query_arg( 'url', urlencode( $current_url ), wp_customize_url() );
43
 
44
- $p = isset( $_GET['post'] ) && ! empty( $_GET['post'] ) ? get_post( $_GET['post']) : false;
45
  $names = $p ? shortcode_names( SHORTCODE_NAME, $p->post_content ) : array();
46
  if( empty($names) )
47
  return;
48
-
49
  $wp_admin_bar->add_menu( array(
50
  'id' => 'customize',
51
  'title' => __( 'Customize' ),
@@ -59,11 +59,11 @@ function wp_admin_bar_customize_menu() {
59
  add_action('admin_bar_menu',__NAMESPACE__.'\wp_admin_bar_customize_menu', 35);
60
 
61
  function wp_head() {
62
-
63
  $widgetRepository = new virtualWidgetsRepository;
64
-
65
  $rules = array();
66
-
67
  foreach ($widgetRepository->getShortcodes() as $widget) {
68
  $widget->getCSSRules(true,$rules);
69
  }
@@ -71,7 +71,7 @@ function wp_head() {
71
  foreach ($widgetRepository->getWidgets() as $widget) {
72
  $widget->getCSSRules(false,$rules);
73
  }
74
-
75
  if (!empty($rules)) {
76
  ?>
77
  <style type="text/css">
@@ -89,9 +89,9 @@ add_action('wp_head',__NAMESPACE__.'\register_virtual_widgets',0);
89
 
90
  /**
91
  * Register virtual widgets for all widgets and shortcodes that are going to be displayed on the page
92
- *
93
  * @return void
94
- *
95
  * @since 4.7
96
  */
97
  function register_virtual_widgets() {
@@ -99,23 +99,23 @@ function register_virtual_widgets() {
99
  global $wp_registered_widgets;
100
 
101
  $repository = new virtualWidgetsRepository;
102
-
103
  // check first for shortcode settings
104
  if (is_singular()) {
105
  $names = shortcode_names(SHORTCODE_NAME,$post->post_content);
106
-
107
  foreach ($names as $name) {
108
  $meta = shortcode_settings($name);
109
  if (is_array($meta)) {
110
  $id = WIDGET_BASE_ID.'-shortcode-'.get_the_ID(); // needed to make a unique id for the widget html element
111
  if ($name != '') // if not defualt name append to the id
112
- $id .= '-' . sanitize_title($name); // sanitize to be on the safe side, not sure where when and how this will be used
113
 
114
  $repository->addShortcode($name, new virtualWidget($id,WIDGET_BASE_ID.'-shortcode',$meta));
115
  }
116
  }
117
  }
118
-
119
  $sidebars_widgets = wp_get_sidebars_widgets();
120
 
121
  if ( is_array($sidebars_widgets) ) {
@@ -144,20 +144,20 @@ add_action('wp_head',__NAMESPACE__.'\wp_head');
144
 
145
  /*
146
  Enqueue widget related scripts for the widget admin page and customizer
147
- */
148
  function admin_scripts($hook) {
149
-
150
  if ($hook == 'widgets.php') { // enqueue only for widget admin and customizer
151
-
152
  // control open and close the widget section
153
  wp_register_script( 'category-posts-widget-admin-js', plugins_url('js/admin/category-posts-widget.js',__FILE__),array('jquery'),CAT_POST_VERSION,true );
154
- wp_enqueue_script( 'category-posts-widget-admin-js' );
155
-
156
  $user_data = array('accordion' => false);
157
  $meta = get_user_meta(get_current_user_id(),__NAMESPACE__,true);
158
  if (is_array($meta) && isset($meta['panels']))
159
  $user_data['accordion'] = true;
160
-
161
  wp_localize_script('category-posts-widget-admin-js',__NAMESPACE__,$user_data);
162
  wp_enqueue_media();
163
  wp_localize_script( 'category-posts-widget-admin-js', 'cwp_default_thumb_selection', array(
@@ -165,7 +165,7 @@ function admin_scripts($hook) {
165
  'button_title' => __( 'Select', 'category-posts' ),
166
  'none' => __( 'None', 'category-posts' ),
167
  ) );
168
- }
169
  }
170
 
171
  add_action('admin_enqueue_scripts', __NAMESPACE__.'\admin_scripts'); // "called on widgets.php and costumizer since 3.9
@@ -181,7 +181,7 @@ add_action( 'admin_init', __NAMESPACE__.'\load_textdomain' );
181
  * @since 4.1
182
  **/
183
  function load_textdomain() {
184
- load_plugin_textdomain( 'category-posts', false, plugin_basename( dirname( __FILE__ ) ) . '/languages' );
185
  }
186
 
187
  /**
@@ -189,7 +189,7 @@ function load_textdomain() {
189
  *
190
  */
191
  add_action( 'admin_print_styles-widgets.php', __NAMESPACE__.'\admin_styles' );
192
-
193
  function admin_styles() {
194
  ?>
195
  <style>
@@ -200,7 +200,7 @@ function admin_styles() {
200
  border: 1px solid #E5E5E5;
201
  }
202
  .category-widget-cont h4:first-child {
203
- margin-top: 10px;
204
  }
205
  .category-widget-cont h4:last-of-type {
206
  margin-bottom: 10px;
@@ -216,24 +216,24 @@ function admin_styles() {
216
  -ms-transition: all 600ms;
217
  -webkit-transition: all 600ms;
218
  -moz-transition: all 600ms;
219
- transition: all 600ms;
220
- }
221
  .category-widget-cont h4.open:after {
222
  -ms-transition: all 600ms;
223
  -webkit-transition: all 600ms;
224
  -moz-transition: all 600ms;
225
- transition: all 600ms;
226
  -ms-transform: rotate(180deg);
227
  -webkit-transform: rotate(180deg);
228
  -moz-transform: rotate(180deg);
229
  transform: rotate(180deg);
230
- }
231
  .category-widget-cont > div {
232
  display:none;
233
- }
234
  .category-widget-cont > div.open {
235
  display:block;
236
- }
237
  </style>
238
  <?php
239
  }
@@ -247,17 +247,17 @@ function admin_styles() {
247
  * return: an array with the width and height of the element containing the image
248
  */
249
  function get_image_size( $thumb_w,$thumb_h,$image_w,$image_h) {
250
-
251
  $image_size = array('image_h' => $thumb_h, 'image_w' => $thumb_w, 'marginAttr' => '', 'marginVal' => '');
252
  $relation_thumbnail = $thumb_w / $thumb_h;
253
  $relation_cropped = $image_w / $image_h;
254
-
255
  if ($relation_thumbnail < $relation_cropped) {
256
  // crop left and right site
257
  // thumbnail width/height ration is smaller, need to inflate the height of the image to thumb height
258
  // and adjust width to keep aspect ration of image
259
  $image_size['image_h'] = $thumb_h;
260
- $image_size['image_w'] = $thumb_h / $image_h * $image_w;
261
  $image_size['marginAttr'] = 'margin-left';
262
  $image_size['marginVal'] = ($image_size['image_w'] - $thumb_w) / 2;
263
  } else {
@@ -265,11 +265,11 @@ function get_image_size( $thumb_w,$thumb_h,$image_w,$image_h) {
265
  // thumbnail width/height ration is bigger, need to inflate the width of the image to thumb width
266
  // and adjust height to keep aspect ration of image
267
  $image_size['image_w'] = $thumb_w;
268
- $image_size['image_h'] = $thumb_w / $image_w * $image_h;
269
  $image_size['marginAttr'] = 'margin-top';
270
  $image_size['marginVal'] = ($image_size['image_h'] - $thumb_h) / 2;
271
  }
272
-
273
  return $image_size;
274
  }
275
 
@@ -305,8 +305,8 @@ class Widget extends \WP_Widget {
305
  return $html; // bail out if no full dimensions defined
306
 
307
  $meta = image_get_intermediate_size($post_thumbnail_id,$size);
308
-
309
- if ( empty( $meta )) {
310
  $post_img = wp_get_attachment_metadata($post_thumbnail_id, $size);
311
  $meta['file'] = basename( $post_img['file'] );
312
  }
@@ -317,22 +317,22 @@ class Widget extends \WP_Widget {
317
  list( $width, $height ) = getimagesize($file); // get actual size of the thumb file
318
 
319
  if (isset($this->instance['use_css_cropping']) && $this->instance['use_css_cropping']) {
320
- $image = get_image_size($this->instance['thumb_w'],$this->instance['thumb_h'],$width,$height);
321
 
322
  // replace srcset
323
  $array = array();
324
  preg_match( '/width="([^"]*)"/i', $html, $array ) ;
325
  $pattern = "/".$array[1]."w/";
326
- $html = preg_replace($pattern, $image['image_w']."w", $html);
327
  // replace size
328
  $pattern = "/".$array[1]."px/";
329
- $html = preg_replace($pattern, $image['image_w']."px", $html);
330
  // replace width
331
  $pattern = "/width=\"[0-9]*\"/";
332
  $html = preg_replace($pattern, "width='".$image['image_w']."'", $html);
333
  // replace height
334
  $pattern = "/height=\"[0-9]*\"/";
335
- $html = preg_replace($pattern, "height='".$image['image_h']."'", $html);
336
  // set margin
337
  $html = str_replace('<img ','<img style="'.$image['marginAttr'].':-'.$image['marginVal'].'px;height:'.$image['image_h']
338
  .'px;clip:rect(auto,'.($this->instance['thumb_w']+$image['marginVal']).'px,auto,'.$image['marginVal']
@@ -348,7 +348,7 @@ class Widget extends \WP_Widget {
348
  }
349
  return $html;
350
  }
351
-
352
  /*
353
  wrapper to execute the the_post_thumbnail with filters
354
  */
@@ -382,8 +382,8 @@ class Widget extends \WP_Widget {
382
  $post_thumbnail_id = get_post_thumbnail_id( get_the_ID() );
383
  if (!$post_thumbnail_id && $this->instance['default_thunmbnail'])
384
  $post_thumbnail_id = $this->instance['default_thunmbnail'];
385
-
386
- do_action( 'begin_fetch_post_thumbnail_html', get_the_ID(), $post_thumbnail_id, $size );
387
  $html = wp_get_attachment_image( $post_thumbnail_id, $size, false, '' );
388
  if (!$html)
389
  $ret = '';
@@ -393,7 +393,7 @@ class Widget extends \WP_Widget {
393
 
394
  return $ret;
395
  }
396
-
397
  /**
398
  * Excerpt more link filter
399
  */
@@ -410,7 +410,7 @@ class Widget extends \WP_Widget {
410
  * @return string If option hide_social_buttons is unchecked applay the_content filter
411
  *
412
  * @since 4.6
413
- */
414
  function apply_the_excerpt($text) {
415
  $ret = "";
416
  if (isset($this->instance["hide_social_buttons"]) && $this->instance["hide_social_buttons"])
@@ -419,7 +419,7 @@ class Widget extends \WP_Widget {
419
  $ret = apply_filters('the_content', $text);
420
  return $ret;
421
  }
422
-
423
  /**
424
  * Excerpt allow HTML
425
  */
@@ -443,7 +443,7 @@ class Widget extends \WP_Widget {
443
  '&lt;p&gt;',
444
  '&lt;img&gt;',
445
  '&lt;script&gt;',
446
- '&lt;style&gt;',
447
  '&lt;video&gt;',
448
  '&lt;audio&gt;'
449
  );
@@ -451,18 +451,18 @@ class Widget extends \WP_Widget {
451
  foreach ($cphtml as $index => $name) {
452
  if (in_array((string)($index),$this->instance['excerpt_allowed_elements'],true))
453
  $allowed_HTML .= $cphtml[$index];
454
- }
455
  $text = strip_tags($text, htmlspecialchars_decode($allowed_HTML));
456
- $excerpt_length = $new_excerpt_length;
457
 
458
  if( !empty($this->instance["excerpt_more_text"]) ) {
459
- $excerpt_more = $this->excerpt_more_filter($this->instance["excerpt_more_text"]);
460
  }else if($filterName = key($wp_filter['excerpt_more'][10])) {
461
  $excerpt_more = $wp_filter['excerpt_more'][10][$filterName]['function'](0);
462
  }else {
463
  $excerpt_more = '[...]';
464
  }
465
-
466
  $words = explode(' ', $text, $excerpt_length + 1);
467
  if (count($words)> $excerpt_length) {
468
  array_pop($words);
@@ -473,7 +473,7 @@ class Widget extends \WP_Widget {
473
 
474
  return '<p>' . $text . '</p>';
475
  }
476
-
477
  /**
478
  * Calculate the HTML for showing the thumb of a post item.
479
  * Expected to be called from a loop with globals properly set
@@ -486,7 +486,7 @@ class Widget extends \WP_Widget {
486
  */
487
  function show_thumb($instance,$no_link) {
488
  $ret = '';
489
-
490
  if ( isset( $instance["thumb"] ) && $instance["thumb"] &&
491
  ((isset($instance['default_thunmbnail']) && ($instance['default_thunmbnail']!= 0)) || has_post_thumbnail()) ) {
492
 
@@ -494,14 +494,14 @@ class Widget extends \WP_Widget {
494
  $use_css_cropping = isset($this->instance['use_css_cropping']) && $this->instance['use_css_cropping'];
495
  $disable_css = !(isset($this->instance['disable_css']) && $this->instance['disable_css']);
496
 
497
- if( $use_css_cropping || $disable_css) {
498
  if( isset($this->instance['thumb_hover'] )) {
499
  $class = "class=\"cat-post-thumbnail cat-post-" . $instance['thumb_hover'] . "\"";
500
  } else {
501
  $class = "class=\"cat-post-thumbnail\"";
502
  }
503
  }
504
-
505
  $title_args = array('echo'=>false);
506
 
507
  if ($no_link)
@@ -519,7 +519,7 @@ class Widget extends \WP_Widget {
519
 
520
  return $ret;
521
  }
522
-
523
  /**
524
  * Calculate the wp-query arguments matching the filter settings of the widget
525
  *
@@ -536,39 +536,39 @@ class Widget extends \WP_Widget {
536
  $sort_by = 'date';
537
  }
538
  $sort_order = (isset( $instance['asc_sort_order'] ) && $instance['asc_sort_order']) ? 'ASC' : 'DESC';
539
-
540
  // Get array of post info.
541
  $args = array(
542
  'orderby' => $sort_by,
543
  'order' => $sort_order
544
  );
545
 
546
- $valid_status = array('publish', 'future', 'both');
547
- if ( isset($instance['status']) && in_array($instance['status'],$valid_status) ) {
548
- $status = $instance['status'];
549
- if ($status == 'both') {
550
- $args['post_status'] = array('publish', 'future');
551
- } else {
552
- $args['post_status'] = $status;
553
- }
554
- } else {
555
- $args['post_status'] = 'publish';
556
- }
557
-
558
- if (isset($instance["num"]))
559
  $args['showposts'] = (int) $instance["num"];
560
-
561
- if (isset($instance["offset"]) && ((int) $instance["offset"] > 1))
562
  $args['offset'] = (int) $instance["offset"] - 1;
563
-
564
  if (isset($instance["cat"])) {
565
  if (isset($instance["no_cat_childs"]) && $instance["no_cat_childs"])
566
- $args['category__in'] = (int) $instance["cat"];
567
  else
568
- $args['cat'] = (int) $instance["cat"];
569
  }
570
 
571
- if (is_singular() && isset( $instance['exclude_current_post'] ) && $instance['exclude_current_post'])
572
  $args['post__not_in'] = array(get_the_ID());
573
 
574
  if( isset( $instance['hideNoThumb'] ) && $instance['hideNoThumb']) {
@@ -577,13 +577,13 @@ class Widget extends \WP_Widget {
577
  'key' => '_thumbnail_id',
578
  'compare' => 'EXISTS' )
579
  )
580
- )
581
  );
582
  }
583
-
584
  return $args;
585
  }
586
-
587
  /**
588
  * Calculate the HTML of the title based on the widget settings
589
  *
@@ -598,7 +598,7 @@ class Widget extends \WP_Widget {
598
  */
599
  function titleHTML($before_title,$after_title,$instance) {
600
  $ret = '';
601
-
602
  // If not title, use the name of the category.
603
  if( !isset($instance["title"]) || !$instance["title"] ) {
604
  $instance["title"] = '';
@@ -606,11 +606,11 @@ class Widget extends \WP_Widget {
606
  $category_info = get_category($instance["cat"]);
607
  if ($category_info && !is_wp_error($category_info))
608
  $instance["title"] = $category_info->name;
609
- else
610
  $instance["title"] = __('Recent Posts','category-posts');
611
- } else
612
  $instance["title"] = __('Recent Posts','category-posts');
613
- }
614
 
615
  if( !(isset ( $instance["hide_title"] ) && $instance["hide_title"])) {
616
  $ret = $before_title;
@@ -618,12 +618,12 @@ class Widget extends \WP_Widget {
618
  $title = esc_html($instance["title"]);
619
  else
620
  $title = apply_filters( 'widget_title', $instance["title"] );
621
-
622
  if( isset ( $instance["title_link"]) && $instance["title_link"]) {
623
  if (isset($instance["cat"]) && (get_category($instance["cat"]) != null)) {
624
  $ret .= '<a href="' . get_category_link($instance["cat"]) . '">' . $title . '</a>';
625
  } else {
626
- // link to posts page if category not found.
627
  // this maybe the blog page or home page
628
  $blog_page = get_option('page_for_posts');
629
  if ($blog_page)
@@ -631,9 +631,9 @@ class Widget extends \WP_Widget {
631
  else
632
  $ret .= '<a href="' . home_url() . '">' . $title . '</a>';
633
  }
634
- } else
635
  $ret .= $title;
636
-
637
  $ret .= $after_title;
638
  }
639
 
@@ -653,17 +653,17 @@ class Widget extends \WP_Widget {
653
  $ret = "";
654
  $url = '';
655
  $text = '';
656
-
657
  if (isset ( $instance["footer_link"] ))
658
  $url = $instance["footer_link"];
659
-
660
  if (isset ( $instance["footer_link_text"] ))
661
  $text = $instance["footer_link_text"];
662
 
663
  // if url is set, but no text, just use the url as text
664
  if (empty($text) && !empty($url))
665
  $text = $url;
666
-
667
  // if no url is set but just text, assume the url should be to the relevant archive page
668
  // category archive for categories filter and home page or blog page when "all categories"
669
  // is used
@@ -678,13 +678,13 @@ class Widget extends \WP_Widget {
678
  $url = home_url();
679
  }
680
  }
681
-
682
  if (!empty($url))
683
  $ret .= '<a class="cat-post-footer-link" href="' . esc_url($url) . '">' . esc_html($text) . '</a>';
684
-
685
  return $ret;
686
  }
687
-
688
  /**
689
  * Calculate the HTML for a post item based on the widget settings and post.
690
  * Expected to be called in an active loop with all the globals set
@@ -698,37 +698,37 @@ class Widget extends \WP_Widget {
698
  */
699
  function itemHTML($instance,$current_post_id) {
700
  global $post;
701
-
702
  $everything_is_link = isset( $instance['everything_is_link'] ) && $instance['everything_is_link'];
703
  $disable_css = isset($instance['disable_css']) && $instance['disable_css'];
704
-
705
  $ret = '<li ';
706
-
707
  // Current post
708
- if ( $current_post_id == $post->ID ) {
709
- $ret .= "class='cat-post-item cat-post-current'";
710
  } else {
711
  $ret .= "class='cat-post-item'";
712
  }
713
  $ret.='>'; // close the li opening tag
714
-
715
  if ($everything_is_link) {
716
  $ret .= '<a class="cat-post-everything-is-link" href="'.get_the_permalink().'" title="">';
717
  }
718
-
719
  // Thumbnail position to top
720
  if( isset( $instance["thumbTop"] ) && $instance["thumbTop"]) {
721
- $ret .= $this->show_thumb($instance,$everything_is_link);
722
  }
723
-
724
  // Title
725
- if( !(isset( $instance['hide_post_titles'] ) && $instance['hide_post_titles'])) {
726
  if ($everything_is_link) {
727
  $ret .= '<span class="cat-post-title">'.get_the_title().'</span>';
728
  } else {
729
  $ret .= '<a class="post-title';
730
- if (!$disable_css) {
731
- $ret .= " cat-post-title";
732
  }
733
  $ret .= '" href="'.get_the_permalink().'" rel="bookmark">'.get_the_title();
734
  $ret .= '</a> ';
@@ -737,26 +737,26 @@ class Widget extends \WP_Widget {
737
 
738
  // Date
739
  if ( isset( $instance['date']) && $instance['date']) {
740
- if ( isset( $instance['date_format'] ) && strlen( trim( $instance['date_format'] ) ) > 0 ) {
741
- $date_format = $instance['date_format'];
742
  } else {
743
- $date_format = "j M Y";
744
- }
745
  $ret .= '<p class="post-date';
746
- if (!$disable_css) {
747
  $ret .= " cat-post-date";
748
- }
749
  $ret .= '">';
750
- if ( isset ( $instance["date_link"] ) && $instance["date_link"] && !$everything_is_link) {
751
  $ret .= '<a href="'.\get_the_permalink().'">';
752
  }
753
  $ret .= get_the_time($date_format);
754
- if ( isset ( $instance["date_link"] ) && $instance["date_link"] && !$everything_is_link ) {
755
  $ret .= '</a>';
756
  }
757
  $ret .= '</p>';
758
  }
759
-
760
  // Thumbnail position normal
761
  if( !(isset( $instance["thumbTop"] ) && $instance["thumbTop"])) {
762
  $ret .= $this->show_thumb($instance,$everything_is_link);
@@ -768,7 +768,7 @@ class Widget extends \WP_Widget {
768
  // then apply our filter to let users customize excerpts in their own way
769
  if (isset($instance['excerpt_length']) && ($instance['excerpt_length'] > 0))
770
  $length = (int) $instance['excerpt_length'];
771
- else
772
  $length = 55; // use default
773
 
774
  if (!isset($instance['excerpt_filters']) || $instance['excerpt_filters']) { // pre 4.7 widgets has filters on
@@ -786,22 +786,22 @@ class Widget extends \WP_Widget {
786
  else
787
  $excerpt_more_text = ' <a class="cat-post-excerpt-more" href="'. get_permalink() . '" title="'.sprintf(__('Continue reading %s'),get_the_title()).'">' . $more_text . '</a>';
788
  $excerpt = \wp_trim_words( $text, $length, $excerpt_more_text );
789
- // adjust html output same way as for the normal excerpt,
790
  // just force all functions depending on the_excerpt hook
791
  $excerpt = shortcode_unautop(wpautop(convert_chars(convert_smilies(wptexturize($excerpt)))));
792
  } else {
793
- $excerpt = shortcode_unautop(wpautop(convert_chars(convert_smilies(wptexturize($post->post_excerpt)))));
794
  }
795
  }
796
  $ret .= apply_filters('cpw_excerpt',$excerpt);
797
  }
798
-
799
  // Comments
800
  if ( isset( $instance['comment_num'] ) && $instance['comment_num']) {
801
  $ret .= '<p class="comment-num';
802
  if (!$disable_css) {
803
- $ret .= " cat-post-comment-num";
804
- }
805
  $ret .= '">';
806
  $ret .= '('.\get_comments_number().')';
807
  $ret .= '</p>';
@@ -810,9 +810,9 @@ class Widget extends \WP_Widget {
810
  // Author
811
  if ( isset( $instance['author'] ) && $instance['author']) {
812
  $ret .= '<p class="post-author';
813
- if (!$disable_css) {
814
- $ret .= " cat-post-author";
815
- }
816
  $ret .= '">';
817
  global $authordata;
818
  if ($everything_is_link) {
@@ -824,24 +824,24 @@ class Widget extends \WP_Widget {
824
  esc_attr( sprintf( __( 'Posts by %s' ), get_the_author() ) ),
825
  get_the_author()
826
  );
827
- $ret .= $link;
828
  }
829
  $ret .= '</p>';
830
  }
831
-
832
  if ($everything_is_link) {
833
  $ret .= '</a>';
834
  }
835
-
836
  $ret .= '</li>';
837
  return $ret;
838
  }
839
-
840
  /**
841
  * Filter to set the number of words in an excerpt
842
  *
843
  * @param int $length The number of words as configured by wordpress core or set by previous filters
844
- * @return int The number of words configured for the widget,
845
  * or the $length parameter if it is not configured or garbage value
846
  *
847
  * @since 4.6
@@ -852,7 +852,7 @@ class Widget extends \WP_Widget {
852
 
853
  return $length;
854
  }
855
-
856
  /**
857
  * Set the proper excerpt filters based on the settings
858
  *
@@ -862,14 +862,14 @@ class Widget extends \WP_Widget {
862
  * @since 4.6
863
  */
864
  function setExcerpFilters($instance) {
865
-
866
  if (isset($instance['excerpt']) && $instance['excerpt']) {
867
-
868
  // Excerpt length filter
869
  if ( isset($instance["excerpt_length"]) && ((int) $instance["excerpt_length"]) > 0) {
870
  add_filter('excerpt_length', array($this,'excerpt_length_filter'));
871
  }
872
-
873
  if( isset($instance["excerpt_more_text"]) && ltrim($instance["excerpt_more_text"]) != '') {
874
  add_filter('excerpt_more', array($this,'excerpt_more_filter'));
875
  }
@@ -882,7 +882,7 @@ class Widget extends \WP_Widget {
882
  }
883
  }
884
  }
885
-
886
  /**
887
  * Remove the excerpt filter
888
  *
@@ -898,14 +898,14 @@ class Widget extends \WP_Widget {
898
  remove_filter('the_excerpt', array($this,'allow_html_excerpt'));
899
  remove_filter('the_excerpt', array($this,'apply_the_excerpt'));
900
  }
901
-
902
  /**
903
  * The main widget display controller
904
  *
905
  * Called by the sidebar processing core logic to display the widget
906
  *
907
  * @param array $args An array containing the "environment" setting for the widget,
908
- * namely, the enclosing tags for the widget and its title.
909
  * @param array $instance The settings associate with the widget
910
  *
911
  * @since 4.1
@@ -914,11 +914,11 @@ class Widget extends \WP_Widget {
914
 
915
  extract( $args );
916
  $this->instance = $instance;
917
-
918
  $args = $this->queryArgs($instance);
919
  $cat_posts = new \WP_Query( $args );
920
-
921
- if ( !isset ( $instance["hide_if_empty"] ) || !$instance["hide_if_empty"] || $cat_posts->have_posts() ) {
922
  echo $before_widget;
923
  echo $this->titleHTML($before_title,$after_title,$instance);
924
 
@@ -928,26 +928,26 @@ class Widget extends \WP_Widget {
928
 
929
  if (!(isset($instance['is_shortcode']) && $instance['is_shortcode'])) // the intenal id is needed only for widgets
930
  echo '<ul id="'.WIDGET_BASE_ID.'-'.$this->number.'-internal'.'" class="'.WIDGET_BASE_ID.'-internal'."\">\n";
931
- else
932
  echo '<ul>';
933
 
934
  if (!isset($instance['excerpt_filters']) || $instance['excerpt_filters']) // pre 4.7 widgets has filters on
935
- $this->setExcerpFilters($instance);
936
  while ( $cat_posts->have_posts() )
937
  {
938
- $cat_posts->the_post();
939
  echo $this->itemHTML($instance,$current_post_id);
940
  }
941
  echo "</ul>\n";
942
 
943
  echo $this->footerHTML($instance);
944
  echo $after_widget;
945
-
946
  if (!isset($instance['excerpt_filters']) || $instance['excerpt_filters']) // pre 4.7 widgets has filters on
947
  $this->removeExcerpFilters($instance);
948
-
949
  wp_reset_postdata();
950
-
951
  $use_css_cropping = isset($this->instance['use_css_cropping']) && $this->instance['use_css_cropping'];
952
 
953
  if ($use_css_cropping){
@@ -960,17 +960,17 @@ class Widget extends \WP_Widget {
960
  // and the number format expected at the rest of the places
961
  if (is_numeric($number))
962
  $number = WIDGET_BASE_ID .'-'.$number;
963
-
964
  // add Javascript to change change cropped image dimensions on load and window resize
965
  $thumb_w = $this->instance['thumb_w'];
966
  $thumb_h = $this->instance['thumb_h'];
967
- add_filter('cpw_crop_widgets', function ($a) use ($number, $thumb_w, $thumb_h) {
968
  $a[$number] = $thumb_w / $thumb_h;
969
  return $a;
970
  });
971
  }
972
- }
973
- }
974
 
975
  /**
976
  * Update the options
@@ -1003,8 +1003,8 @@ class Widget extends \WP_Widget {
1003
  ));
1004
  $title = $instance['title'];
1005
  $hide_title = $instance['hide_title'];
1006
- $title_link = $instance['title_link'];
1007
- ?>
1008
  <h4 data-panel="title"><?php _e('Title','category-posts')?></h4>
1009
  <div>
1010
  <p>
@@ -1025,10 +1025,10 @@ class Widget extends \WP_Widget {
1025
  <?php _e( 'Hide title','category-posts' ); ?>
1026
  </label>
1027
  </p>
1028
- </div>
1029
- <?php
1030
  }
1031
-
1032
  /**
1033
  * Output the filter panel of the widget configuration form.
1034
  *
@@ -1089,9 +1089,10 @@ class Widget extends \WP_Widget {
1089
  <label for="<?php echo $this->get_field_id("status"); ?>">
1090
  <?php _e('Status','category-posts'); ?>:
1091
  <select id="<?php echo $this->get_field_id("status"); ?>" name="<?php echo $this->get_field_name("status"); ?>">
 
1092
  <option value="publish"<?php selected( $instance["status"], "publish" ); ?>><?php _e('Published','category-posts')?></option>
1093
  <option value="future"<?php selected( $instance["status"], "future" ); ?>><?php _e('Scheduled','category-posts')?></option>
1094
- <option value="both"<?php selected( $instance["status"], "both" ); ?>><?php _e('Published & Scheduled','category-posts')?></option>
1095
  </select>
1096
  </label>
1097
  </p>
@@ -1123,11 +1124,11 @@ class Widget extends \WP_Widget {
1123
  <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("hideNoThumb"); ?>" name="<?php echo $this->get_field_name("hideNoThumb"); ?>"<?php checked( (bool) $instance["hideNoThumb"], true ); ?> />
1124
  <?php _e( 'Exclude posts which have no thumbnail','category-posts' ); ?>
1125
  </label>
1126
- </p>
1127
- </div>
1128
  <?php
1129
  }
1130
-
1131
  /**
1132
  * Output the filter panel of the widget configuration form.
1133
  *
@@ -1153,7 +1154,7 @@ class Widget extends \WP_Widget {
1153
  $use_css_cropping = $instance['use_css_cropping'];
1154
  $thumb_hover = $instance['thumb_hover'];
1155
  $default_thunmbnail = $instance['default_thunmbnail'];
1156
- ?>
1157
  <h4 data-panel="thumbnail"><?php _e('Thumbnails','category-posts')?></h4>
1158
  <div>
1159
  <p>
@@ -1174,7 +1175,7 @@ class Widget extends \WP_Widget {
1174
  <label for="<?php echo $this->get_field_id("thumb_w"); ?>">
1175
  <?php _e('Width:','category-posts')?> <input class="widefat" style="width:30%;" type="number" min="1" id="<?php echo $this->get_field_id("thumb_w"); ?>" name="<?php echo $this->get_field_name("thumb_w"); ?>" value="<?php echo esc_attr($instance["thumb_w"]); ?>" />
1176
  </label>
1177
-
1178
  <label for="<?php echo $this->get_field_id("thumb_h"); ?>">
1179
  <?php _e('Height:','category-posts')?> <input class="widefat" style="width:30%;" type="number" min="1" id="<?php echo $this->get_field_id("thumb_h"); ?>" name="<?php echo $this->get_field_name("thumb_h"); ?>" value="<?php echo esc_attr($instance["thumb_h"]); ?>" />
1180
  </label>
@@ -1205,7 +1206,7 @@ class Widget extends \WP_Widget {
1205
  <input type="hidden" class="default_thumb_id" id="<?php echo $this->get_field_id("default_thunmbnail"); ?>" name="<?php echo $this->get_field_name("default_thunmbnail"); ?>" value="<?php echo esc_attr($default_thunmbnail)?>"/>
1206
  <span class="default_thumb_img">
1207
  <?php
1208
- if (!$default_thunmbnail)
1209
  _e('None','category-posts');
1210
  else {
1211
  $img = wp_get_attachment_image_src($default_thunmbnail);
@@ -1221,11 +1222,11 @@ class Widget extends \WP_Widget {
1221
  <button type="button" class="cwp_default_thumb_remove button upload-button" <?php if (!$default_thunmbnail) echo 'style="display:none"' ?> >
1222
  <?php _e('No default','category-posts')?>
1223
  </button>
1224
- </p>
1225
  </div>
1226
  <?php
1227
  }
1228
-
1229
  /**
1230
  * The widget configuration form back end.
1231
  *
@@ -1275,10 +1276,10 @@ class Widget extends \WP_Widget {
1275
  $disable_css = $instance['disable_css'];
1276
  $disable_font_styles = $instance['disable_font_styles'];
1277
  $hide_if_empty = $instance['hide_if_empty'];
1278
-
1279
  $cat = $instance['cat'];
1280
 
1281
-
1282
  if (!isset($style_done)) { // what an ugly hack, but can't figure out how to do it nicer on 4.3
1283
  ?>
1284
  <style type="text/css">
@@ -1308,7 +1309,7 @@ class Widget extends \WP_Widget {
1308
  $style_done = true;
1309
  }
1310
  ?>
1311
-
1312
  <div class="category-widget-cont">
1313
  <p><a target="_blank" href="http://tiptoppress.com/term-and-category-based-posts-widget/?utm_source=widget_cpw&utm_campaign=get_pro_cpw&utm_medium=form"><?php _e('Get the Pro version','category-posts'); ?></a></p>
1314
  <?php
@@ -1425,7 +1426,7 @@ class Widget extends \WP_Widget {
1425
  </label>
1426
  </p>
1427
  </div>
1428
- <p><a href="<?php echo get_edit_user_link().'#'.__NAMESPACE__ ?>"><?php _e('Widget admin behaviour settings','category-posts')?></a></p>
1429
  <p><a target="_blank" href="<?php echo CAT_POST_DOC_URL ?>"><?php _e('Documentation','category-posts'); ?></a></p>
1430
  <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' ) ); ?></br></br></p>
1431
  </div>
@@ -1437,9 +1438,9 @@ class Widget extends \WP_Widget {
1437
 
1438
  /**
1439
  * Applied to the list of links to display on the plugins page (beside the activate/deactivate links).
1440
- *
1441
  * @return array of the widget links
1442
- *
1443
  * @since 4.6.3
1444
  */
1445
  add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), __NAMESPACE__.'\add_action_links' );
@@ -1448,9 +1449,9 @@ function add_action_links ( $links ) {
1448
  $pro_link = array(
1449
  '<a target="_blank" href="http://tiptoppress.com/term-and-category-based-posts-widget/?utm_source=widget_cpw&utm_campaign=get_pro_cpw&utm_medium=action_link">'.__('Get the Pro version','category-posts').'</a>',
1450
  );
1451
-
1452
  $links = array_merge($pro_link, $links);
1453
-
1454
  return $links;
1455
  }
1456
 
@@ -1462,7 +1463,7 @@ add_action( 'widgets_init', __NAMESPACE__.'\register_widget' );
1462
 
1463
  /**
1464
  * Output js code to handle responsive thumbnails
1465
- *
1466
  * @return void
1467
  *
1468
  * @since 4.7
@@ -1479,13 +1480,13 @@ function change_cropped_image_dimensions() {
1479
  <?php // namespace ?>
1480
  var cwp_namespace = window.cwp_namespace || {};
1481
  cwp_namespace.fluid_images = cwp_namespace.fluid_images || {};
1482
-
1483
  cwp_namespace.fluid_images = {
1484
 
1485
- <?php /* variables */ ?>
1486
  Widgets : {},
1487
  widget : null,
1488
-
1489
  <?php /* class */ ?>
1490
  Span : function (_self, _imageRatio) {
1491
 
@@ -1493,8 +1494,8 @@ function change_cropped_image_dimensions() {
1493
  this.self = _self;
1494
  this.imageRatio = _imageRatio;
1495
  },
1496
-
1497
- <?php /* class */ ?>
1498
  WidgetPosts : function (widget, ratio) {
1499
 
1500
  <?php /* variables */ ?>
@@ -1521,15 +1522,15 @@ function change_cropped_image_dimensions() {
1521
  this.allSpans.width( this.listItemWidth );
1522
  var spanHeight = this.listItemWidth / this.ratio;
1523
  this.allSpans.height( spanHeight );
1524
-
1525
- for( var index in this.Spans ){
1526
  var imageHeight = this.listItemWidth / this.Spans[index].imageRatio;
1527
  jQuery(this.Spans[index].self).find( 'img' ).css({
1528
  height: imageHeight,
1529
  marginTop: -(imageHeight - spanHeight) / 2
1530
- });
1531
  };
1532
- }
1533
  }
1534
  },
1535
  }
@@ -1538,7 +1539,7 @@ function change_cropped_image_dimensions() {
1538
  /***
1539
  * cpw_crop_widgets is an internal filter that is used
1540
  * to gather the ids of the widgets to which apply cropping
1541
- *
1542
  * For eaier prevention of duplication, the widget id number should be an index
1543
  * in the array while the ratio of width/height be the value
1544
  */
@@ -1548,31 +1549,31 @@ function change_cropped_image_dimensions() {
1548
  cwp_namespace.fluid_images.widget = jQuery('#<?php echo $number?>');
1549
  cwp_namespace.fluid_images.Widgets['<?php echo $number?>'] = new cwp_namespace.fluid_images.WidgetPosts(cwp_namespace.fluid_images.widget,<?php echo $ratio?>);
1550
  <?php } ?>
1551
-
1552
  <?php /* do on page load or on resize the browser window */ echo "\r\n" ?>
1553
  jQuery(window).on('load resize', function() {
1554
  for (var widget in cwp_namespace.fluid_images.Widgets) {
1555
  cwp_namespace.fluid_images.Widgets[widget].changeImageSize();
1556
  }
1557
- });
1558
  });
1559
  }
1560
  </script>
1561
- <?php
1562
  }
1563
 
1564
  // shortcode section
1565
 
1566
  /**
1567
  * Get shortcode settings taking into account if it is being customized
1568
- *
1569
  * When not customized returns the settings as stored in the meta, but when
1570
  * it is customized returns the setting stored in the virtual option used by the customizer
1571
- *
1572
  * @parm string name The name of the shortcode to retun, empty string indicates the nameless
1573
- *
1574
  * @return array the shortcode settings if a short code exists or empty string, empty array if name not found
1575
- *
1576
  * @since 4.6
1577
  */
1578
  function shortcode_settings($name) {
@@ -1583,41 +1584,41 @@ function shortcode_settings($name) {
1583
 
1584
  if (!isset($meta[$name])) // name do not exists? return empty array
1585
  return array();
1586
-
1587
  $instance = $meta[$name];
1588
  if (is_customize_preview()) {
1589
  $o=get_option('_virtual-'.WIDGET_BASE_ID);
1590
  if (is_array($o))
1591
  $instance=$o[get_the_ID()][$name];
1592
  }
1593
-
1594
  return $instance;
1595
  }
1596
 
1597
  /**
1598
  * Handle the shortcode
1599
- *
1600
  * @param array $attr Array of the attributes to the short code, none is expected
1601
  * @param string $content The content enclosed in the shortcode, none is expected
1602
- *
1603
  * @return string An HTML of the "widget" based on its settings, actual or customized
1604
- *
1605
  */
1606
  function shortcode($attr,$content=null) {
1607
  $repository = new virtualWidgetsRepository;
1608
-
1609
  $shortcodes = $repository->getShortcodes();
1610
-
1611
  $name = '';
1612
  if (isset($attr['name']))
1613
  $name = $attr['name'];
1614
-
1615
  if (is_singular()) {
1616
  if (isset($shortcodes[$name])) {
1617
  return $shortcodes[$name]->getHTML();
1618
- }
1619
  }
1620
-
1621
  return '';
1622
  }
1623
 
@@ -1625,20 +1626,20 @@ add_shortcode(SHORTCODE_NAME,__NAMESPACE__.'\shortcode');
1625
 
1626
  /**
1627
  * Find if a specific shortcode is used in a content
1628
- *
1629
  * @param string $shortcode_name The name of the shortcode
1630
  * #param string The content to look at
1631
- *
1632
- * @return array An array containing the name attributes of the shortcodes. Empty array is
1633
  * an indication there were no shourcodes
1634
- *
1635
  * @since 4.7
1636
- *
1637
  */
1638
  function shortcode_names($shortcode_name,$content) {
1639
 
1640
  $names = array();
1641
-
1642
  $regex_pattern = get_shortcode_regex();
1643
  if (preg_match_all ('/'.$regex_pattern.'/s', $content, $matches)) {
1644
  foreach ($matches[2] as $k=>$shortcode) {
@@ -1651,13 +1652,13 @@ function shortcode_names($shortcode_name,$content) {
1651
  }
1652
  }
1653
  }
1654
-
1655
  return $names;
1656
  }
1657
 
1658
  /**
1659
  * Organized way to have rhw default widget settings accessible
1660
- *
1661
  * @since 4.6
1662
  */
1663
  function default_settings() {
@@ -1702,13 +1703,13 @@ function default_settings() {
1702
 
1703
  /**
1704
  * Manipulate the relevant meta related to the short code when a post is save
1705
- *
1706
  * If A post has a short code, a meta holder is created, If it does not the meta holder is deleted
1707
- *
1708
  * @param integer $pid The post ID of the post being saved
1709
  * @param WP_Post $post The post being saved
1710
  * @return void
1711
- *
1712
  * @since 4.6
1713
  */
1714
  function save_post($pid,$post) {
@@ -1716,15 +1717,15 @@ function save_post($pid,$post) {
1716
  // ignore revisions and auto saves
1717
  if ( wp_is_post_revision( $pid ) || wp_is_post_autosave($pid))
1718
  return;
1719
-
1720
  $meta = get_post_meta($pid,SHORTCODE_META,true);
1721
  if (empty($meta))
1722
  $meta = array();
1723
-
1724
  // check if only one shortcode format - non array of arrays, and convert it
1725
  if (!empty($meta) && !is_array(reset($meta)))
1726
  $meta = array ('' => $meta); // the coversion
1727
-
1728
  $old_names = array_keys($meta); // keep list of curren shorcodes names to delete lter whatever was deleted
1729
  $names = shortcode_names(SHORTCODE_NAME,$post->post_content);
1730
 
@@ -1732,7 +1733,7 @@ function save_post($pid,$post) {
1732
  $to_delete = array_diff($old_names,$names);
1733
  foreach ($to_delete as $k)
1734
  unset($meta[$k]);
1735
-
1736
  foreach ($names as $name) {
1737
  if (!isset($meta[$name])) {
1738
  $meta[$name] = default_settings();
@@ -1740,7 +1741,7 @@ function save_post($pid,$post) {
1740
  }
1741
 
1742
  delete_post_meta($pid,SHORTCODE_META);
1743
- if (!empty($meta))
1744
  add_post_meta($pid,SHORTCODE_META,$meta,true);
1745
  }
1746
 
@@ -1751,7 +1752,7 @@ function customize_register($wp_customize) {
1751
  class shortCodeControl extends \WP_Customize_Control {
1752
  public $form;
1753
  public $title_postfix;
1754
-
1755
  public function render_content() {
1756
  $widget_title = 'Category Posts Shortcode'.$this->title_postfix;
1757
  ?>
@@ -1767,7 +1768,7 @@ function customize_register($wp_customize) {
1767
  </div>
1768
  <?php
1769
  }
1770
- }
1771
 
1772
  $args = array(
1773
  'post_type' => 'any',
@@ -1777,50 +1778,50 @@ function customize_register($wp_customize) {
1777
  'meta_query' => array(
1778
  array(
1779
  'key' => SHORTCODE_META,
1780
- 'compare' => 'EXISTS'
1781
  )
1782
  ),
1783
-
1784
  );
1785
  $posts = get_posts($args);
1786
-
1787
  if (count($posts) > 0) {
1788
  $wp_customize->add_panel( __NAMESPACE__, array(
1789
  'title' => __( 'Category Posts Shortcode', 'category-posts' ),
1790
  'priority' => 300,
1791
  'capability' => 'edit_theme_options',
1792
  ) );
1793
-
1794
  foreach($posts as $p) {
1795
  $widget = new Widget();
1796
  $meta = get_post_meta($p->ID,SHORTCODE_META,true);
1797
  if (!is_array($meta))
1798
  continue;
1799
-
1800
  if (!is_array(reset($meta))) // 4.6 format
1801
  $meta = array('' => $meta);
1802
-
1803
  foreach ($meta as $k => $m) {
1804
  $m = wp_parse_args($m,default_settings());
1805
-
1806
  if (count($meta) == 0) { // new widget, use defaults
1807
  ;
1808
  } else { // updated widgets come from =< 4.6 excerpt filter is on
1809
  if (!isset($m['excerpt_filters']))
1810
  $m['excerpt_filters'] = 'on';
1811
  }
1812
-
1813
  $section_title = $k;
1814
  if ($section_title == '')
1815
  $section_title = __('[shortcode]', 'category-posts');
1816
-
1817
  $wp_customize->add_section( __NAMESPACE__.'-'.$p->id.'-'.$k, array(
1818
  'title' => $section_title,
1819
  'priority' => 10,
1820
  'capability' => 'edit_theme_options',
1821
  'panel' => __NAMESPACE__,
1822
  ) );
1823
-
1824
  ob_start();
1825
  $widget->number = $p->ID.'_'.$k;
1826
  $widget->form($m);
@@ -1857,7 +1858,7 @@ function customize_register($wp_customize) {
1857
  '_virtual-'.WIDGET_BASE_ID.'['.$p->ID.']['.$k.'][title]',
1858
  $args
1859
  );
1860
-
1861
  if ($k != '')
1862
  $sc->title_postfix = ' '.$k;
1863
  $wp_customize->add_control($sc);
@@ -1873,9 +1874,9 @@ add_action( 'customize_register', __NAMESPACE__.'\customize_register' );
1873
  *
1874
  * The customizer actually saves only the changed values, so a merge needs to be done.
1875
  * After everything is updated the virtual option is deleted to leave a clean slate
1876
- *
1877
  * @return void
1878
- *
1879
  * @since 4.6
1880
  */
1881
  function customize_save_after() {
@@ -1886,7 +1887,7 @@ function customize_save_after() {
1886
  $meta = get_post_meta($pid,SHORTCODE_META,true);
1887
  if (!empty($meta) && !is_array(reset($meta)))
1888
  $meta = array ('' => $meta); // the coversion
1889
-
1890
  foreach ($instance as $name=>$new) {
1891
  if (isset($meta[$name])) // unlikely but maybe that short code was deleted by other session
1892
  $meta[$name] = array_merge($meta[$name],$new);
@@ -1894,7 +1895,7 @@ function customize_save_after() {
1894
  }
1895
  update_post_meta($pid,SHORTCODE_META, $meta);
1896
  }
1897
-
1898
  delete_option('_virtual-'.WIDGET_BASE_ID);
1899
  }
1900
 
@@ -1904,14 +1905,14 @@ add_action('customize_save_after', __NAMESPACE__.'\customize_save_after', 100);
1904
 
1905
  /**
1906
  * Uninstall handler, cleanup DB from options and meta
1907
- *
1908
  * @return void
1909
- *
1910
  * @since 4.7
1911
  */
1912
  function uninstall() {
1913
  delete_option('widget-'.WIDGET_BASE_ID); // delete the option storing the widget options
1914
- delete_post_meta_by_key( SHORTCODE_META ); // delete the meta storing the shortcode
1915
  delete_metadata( 'user', 0, __NAMESPACE__, '', true ); // delete all user metadata
1916
  }
1917
 
@@ -1919,9 +1920,9 @@ register_uninstall_hook(__FILE__, __NAMESPACE__.'uninstall');
1919
 
1920
  /**
1921
  * Register the tinymce shortcode plugin
1922
- *
1923
  * @param array $plugin_array An array containing the current plugins to be used by tinymce
1924
- *
1925
  * @return array An array containing the plugins to be used by tinymce, our plugin added to the $plugin_array parameter
1926
  *
1927
  * @since 4.7
@@ -1936,7 +1937,7 @@ function mce_external_plugins($plugin_array)
1936
  else
1937
  $plugin_array[__NAMESPACE__] = plugins_url('js/admin/tinymce.js?ver='.CAT_POST_VERSION,__FILE__);
1938
  }
1939
-
1940
  return $plugin_array;
1941
  }
1942
 
@@ -1944,9 +1945,9 @@ add_filter("mce_external_plugins", __NAMESPACE__."\mce_external_plugins");
1944
 
1945
  /**
1946
  * Register the tinymce buttons for the add shortcode
1947
- *
1948
  * @param array $buttons An array containing the current buttons to be used by tinymce
1949
- *
1950
  * @return array An array containing the buttons to be used by tinymce, our button added to the $buttons parameter
1951
  *
1952
  * @since 4.7
@@ -1968,11 +1969,11 @@ add_filter("mce_buttons", __NAMESPACE__."\mce_buttons");
1968
 
1969
  /**
1970
  * Register the tinymcetranslation file
1971
- *
1972
  * @param array $locales An array containing the current translations to be used by tinymce
1973
- *
1974
  * @return array An array containing the translations to be used by tinymce, our localization added to the $locale parameter
1975
- *
1976
  * @since 4.7
1977
  */
1978
  function mce_external_languages($locales) {
@@ -1984,7 +1985,7 @@ function mce_external_languages($locales) {
1984
  $locales['category-posts'] = plugin_dir_path ( __FILE__ ) . 'tinymce_translations.php';
1985
  return $locales;
1986
  }
1987
-
1988
  add_filter( 'mce_external_languages', __NAMESPACE__.'\mce_external_languages');
1989
 
1990
  // user profile related functions
@@ -1992,7 +1993,7 @@ add_filter( 'mce_external_languages', __NAMESPACE__.'\mce_external_languages');
1992
  add_action( 'show_user_profile', __NAMESPACE__.'\show_user_profile' );
1993
  add_action( 'edit_user_profile', __NAMESPACE__.'\show_user_profile' );
1994
 
1995
- function show_user_profile( $user ) {
1996
 
1997
  if ( !current_user_can( 'edit_user', $user->ID ) )
1998
  return;
@@ -2001,14 +2002,14 @@ function show_user_profile( $user ) {
2001
  return;
2002
 
2003
  $meta = get_the_author_meta( __NAMESPACE__, $user->ID );
2004
-
2005
  if (empty($meta))
2006
  $meta = array();
2007
-
2008
  $accordion = false;
2009
  if (isset($meta['panels']))
2010
  $accordion = true;
2011
-
2012
  $editor = false;
2013
  if (isset($meta['editor']))
2014
  $editor = true;
@@ -2031,7 +2032,7 @@ function show_user_profile( $user ) {
2031
  </td>
2032
  </tr>
2033
  </table>
2034
- <?php
2035
  }
2036
 
2037
  add_action( 'personal_options_update', __NAMESPACE__.'\personal_options_update' );
@@ -2044,38 +2045,38 @@ function personal_options_update( $user_id ) {
2044
 
2045
  if ( !current_user_can( 'edit_theme_options', $user_id ) )
2046
  return;
2047
-
2048
  if (isset($_POST[__NAMESPACE__]))
2049
  update_user_meta( $user_id, __NAMESPACE__, $_POST[__NAMESPACE__] );
2050
  else
2051
- delete_user_meta( $user_id, __NAMESPACE__);
2052
  }
2053
 
2054
  // external API
2055
 
2056
  /**
2057
- * Class that represent a virtual widget. Each widget being created will have relevant
2058
  * CSS output in the header, but strill requires a call for getHTML method or renderHTML
2059
  * to get or output the HTML
2060
- *
2061
  * @since 4.7
2062
  */
2063
  class virtualWidget {
2064
  private static $collection = array();
2065
  private $id;
2066
  private $class;
2067
-
2068
  /**
2069
  * Construct the virtual widget. This should happen before wp_head action with priority
2070
  * 10 is executed if any CSS output should be generated.
2071
- *
2072
  * @param string $id The identifier use as the id of the root html element when the HTML
2073
  * is generated
2074
- *
2075
  * @param string $class The class name to be use us the class attribute on the root html element
2076
- *
2077
  * @param array $args The setting to be applied to the widget
2078
- *
2079
  * @since 4.7
2080
  */
2081
  function __construct($id, $class, $args) {
@@ -2083,20 +2084,20 @@ class virtualWidget {
2083
  $this->class = $class;
2084
  self::$collection[$id] = wp_parse_args($args,default_settings());
2085
  }
2086
-
2087
  function __destruct() {
2088
  unset(self::$collection[$this->id]);
2089
  }
2090
 
2091
  /**
2092
  * return the HTML of the widget as is generated based on the settings passed at construction time
2093
- *
2094
  * @return string
2095
- *
2096
  * @since 4.7
2097
  */
2098
  function getHTML() {
2099
-
2100
  $widget=new Widget();
2101
  $widget->number = $this->id; // needed to make a unique id for the widget html element
2102
  ob_start();
@@ -2110,16 +2111,16 @@ class virtualWidget {
2110
  ), $args);
2111
  $ret = ob_get_clean();
2112
  $ret = '<div id="'.esc_attr($this->id).'" class="'.esc_attr($this->class).'">'.$ret.'</div>';
2113
- return $ret;
2114
  }
2115
-
2116
  /**
2117
- * Output the widget HTML
2118
- *
2119
  * Just a wrapper that output getHTML
2120
- *
2121
  * @return void
2122
- *
2123
  * @since 4.7
2124
  */
2125
  function renderHTML() {
@@ -2128,19 +2129,19 @@ class virtualWidget {
2128
 
2129
  /**
2130
  * Calculate the CSS rules required for the widget as is generated based on the settings passed at construction time
2131
- *
2132
  * @return string
2133
- *
2134
  * @since 4.7
2135
  */
2136
- function getCSSRules($is_shortcode,&$ret) {
2137
  $settings = self::$collection[$this->id];
2138
  $widget_id = $this->id;
2139
  if (!$is_shortcode)
2140
  $widget_id .= '-internal';
2141
-
2142
  if (!(isset($settings['disable_css']) && $settings['disable_css'])) { // checks if css disable is not set
2143
-
2144
  $rules = array( // rules that should be applied to all widgets
2145
  '.cat-post-item img {max-width: initial; max-height: initial;}',
2146
  '.cat-post-current .cat-post-title {text-transform: uppercase;}',
@@ -2150,7 +2151,7 @@ class virtualWidget {
2150
  '.cat-post-item:before {content: ""; display: table; clear: both;}',
2151
  '.cat-post-item img {margin: initial;}',
2152
  );
2153
-
2154
  if (!(isset($settings['disable_font_styles']) && $settings['disable_font_styles'])) { // checks if disable font styles is not set
2155
  // add general rules which apply to font styling
2156
  $rules[] = '.cat-post-title {font-size: 15px;}';
@@ -2158,11 +2159,11 @@ class virtualWidget {
2158
  $rules[] = '.cat-post-date {font-size: 12px; line-height: 18px; font-style: italic; margin-bottom: 10px;}';
2159
  $rules[] = '.cat-post-comment-num {font-size: 12px; line-height: 18px;}';
2160
  } else {
2161
- $rules[] = '.cat-post-date {margin-bottom: 10px;}';
2162
  }
2163
 
2164
  /*
2165
- the twenty seventeen theme have a border between the LI elements of a widget,
2166
  so remove our border if we detect its use to avoid conflicting styling
2167
  */
2168
  if (!$is_shortcode && function_exists('twentyseventeen_setup')) {
@@ -2221,7 +2222,7 @@ class virtualWidget {
2221
  bigger (add to the padding) use only top for now */
2222
  }
2223
  }
2224
-
2225
  if ((isset($settings['use_css_cropping']) && $settings['use_css_cropping']) || !(isset($settings['disable_css']) && $settings['disable_css'])) {
2226
  if (isset($settings['use_css_cropping']) && $settings['use_css_cropping'])
2227
  $ret[] = '#'.$widget_id.' .cat-post-crop {overflow: hidden; display:block}';
@@ -2232,12 +2233,12 @@ class virtualWidget {
2232
  }
2233
 
2234
  /**
2235
- * Output the widget CSS
2236
- *
2237
  * Just a wrapper that output getCSSRules
2238
- *
2239
  * @return void
2240
- *
2241
  * @since 4.7
2242
  */
2243
  function outputCSS($is_shortcode) {
@@ -2249,44 +2250,44 @@ class virtualWidget {
2249
  }
2250
  /**
2251
  * Get the id the virtual widget was registered with
2252
- *
2253
  * @return string
2254
- *
2255
  * @since 4.7
2256
  */
2257
  function id() {
2258
  return $this->id;
2259
  }
2260
-
2261
  /**
2262
  * Get all the setting of the virtual widgets in an array
2263
- *
2264
  * @return array
2265
- *
2266
  * @since 4.7
2267
  */
2268
  static function getAllSettings() {
2269
  return self::$collection;
2270
  }
2271
-
2272
  }
2273
 
2274
  /**
2275
  * Class that implement a simple repository for the virtual widgets representing
2276
  * actuall shortcode and widgets
2277
- *
2278
  * @since 4.7
2279
  */
2280
  class virtualWidgetsRepository {
2281
  private static $shortcodeCollection = array();
2282
  private static $widgetCollection = array();
2283
-
2284
  /**
2285
  * Add a virtual widget representing a shortcode to the repository
2286
- *
2287
  * @param string $index A name to identify the specific shortcode
2288
  * @param virtualWidget The virstual widget for it
2289
- *
2290
  * @since 4.7
2291
  */
2292
  function addShortcode($index,$widget) {
@@ -2295,9 +2296,9 @@ class virtualWidgetsRepository {
2295
 
2296
  /**
2297
  * Get all the virtual widgets representing actual shortcodes
2298
- *
2299
  * @return array
2300
- *
2301
  * @since 4.7
2302
  */
2303
  function getShortcodes() {
@@ -2306,10 +2307,10 @@ class virtualWidgetsRepository {
2306
 
2307
  /**
2308
  * Add a virtual widget representing awidget to the repository
2309
- *
2310
  * @param string $index A name to identify the specific widget
2311
  * @param virtualWidget The virstual widget for it
2312
- *
2313
  * @since 4.7
2314
  */
2315
  function addWidget($index,$widget) {
@@ -2318,9 +2319,9 @@ class virtualWidgetsRepository {
2318
 
2319
  /**
2320
  * Get all the virtual widgets representing actual widgets
2321
- *
2322
  * @return array
2323
- *
2324
  * @since 4.7
2325
  */
2326
  function getWidgets() {
4
  Plugin URI: https://wordpress.org/plugins/category-posts/
5
  Description: Adds a widget that shows the most recent posts from a single category.
6
  Author: TipTopPress
7
+ Version: 4.7.4
8
  Author URI: http://tiptoppress.com
9
  Text Domain: category-posts
10
  Domain Path: /languages
15
  // Don't call the file directly
16
  if ( !defined( 'ABSPATH' ) ) exit;
17
 
18
+ const CAT_POST_VERSION = "4.7.4";
19
  const CAT_POST_DOC_URL = "http://tiptoppress.com/category-posts-widget/documentation-4-7?utm_source=widget_cpw&utm_campaign=documentation_4_7_cpw&utm_medium=form";
20
 
21
  const SHORTCODE_NAME = 'catposts';
24
 
25
  /***
26
  * Adds the "Customize" link to the Toolbar on edit mode.
27
+ *
28
  * @since 4.6
29
  **/
30
  function wp_admin_bar_customize_menu() {
32
 
33
  if ( !isset($_GET['action']) || $_GET['action'] !== 'edit' )
34
  return;
35
+
36
  if ( !current_user_can( 'customize' ) || !is_admin() || !is_user_logged_in() || !is_admin_bar_showing() )
37
  return;
38
 
39
  $current_url = "";
40
  if ( isset( $_GET['post'] ) && $_GET['post'] !== '' )
41
+ $current_url = get_permalink( $_GET['post'] );
42
  $customize_url = add_query_arg( 'url', urlencode( $current_url ), wp_customize_url() );
43
 
44
+ $p = isset( $_GET['post'] ) && ! empty( $_GET['post'] ) ? get_post( $_GET['post']) : false;
45
  $names = $p ? shortcode_names( SHORTCODE_NAME, $p->post_content ) : array();
46
  if( empty($names) )
47
  return;
48
+
49
  $wp_admin_bar->add_menu( array(
50
  'id' => 'customize',
51
  'title' => __( 'Customize' ),
59
  add_action('admin_bar_menu',__NAMESPACE__.'\wp_admin_bar_customize_menu', 35);
60
 
61
  function wp_head() {
62
+
63
  $widgetRepository = new virtualWidgetsRepository;
64
+
65
  $rules = array();
66
+
67
  foreach ($widgetRepository->getShortcodes() as $widget) {
68
  $widget->getCSSRules(true,$rules);
69
  }
71
  foreach ($widgetRepository->getWidgets() as $widget) {
72
  $widget->getCSSRules(false,$rules);
73
  }
74
+
75
  if (!empty($rules)) {
76
  ?>
77
  <style type="text/css">
89
 
90
  /**
91
  * Register virtual widgets for all widgets and shortcodes that are going to be displayed on the page
92
+ *
93
  * @return void
94
+ *
95
  * @since 4.7
96
  */
97
  function register_virtual_widgets() {
99
  global $wp_registered_widgets;
100
 
101
  $repository = new virtualWidgetsRepository;
102
+
103
  // check first for shortcode settings
104
  if (is_singular()) {
105
  $names = shortcode_names(SHORTCODE_NAME,$post->post_content);
106
+
107
  foreach ($names as $name) {
108
  $meta = shortcode_settings($name);
109
  if (is_array($meta)) {
110
  $id = WIDGET_BASE_ID.'-shortcode-'.get_the_ID(); // needed to make a unique id for the widget html element
111
  if ($name != '') // if not defualt name append to the id
112
+ $id .= '-' . sanitize_title($name); // sanitize to be on the safe side, not sure where when and how this will be used
113
 
114
  $repository->addShortcode($name, new virtualWidget($id,WIDGET_BASE_ID.'-shortcode',$meta));
115
  }
116
  }
117
  }
118
+
119
  $sidebars_widgets = wp_get_sidebars_widgets();
120
 
121
  if ( is_array($sidebars_widgets) ) {
144
 
145
  /*
146
  Enqueue widget related scripts for the widget admin page and customizer
147
+ */
148
  function admin_scripts($hook) {
149
+
150
  if ($hook == 'widgets.php') { // enqueue only for widget admin and customizer
151
+
152
  // control open and close the widget section
153
  wp_register_script( 'category-posts-widget-admin-js', plugins_url('js/admin/category-posts-widget.js',__FILE__),array('jquery'),CAT_POST_VERSION,true );
154
+ wp_enqueue_script( 'category-posts-widget-admin-js' );
155
+
156
  $user_data = array('accordion' => false);
157
  $meta = get_user_meta(get_current_user_id(),__NAMESPACE__,true);
158
  if (is_array($meta) && isset($meta['panels']))
159
  $user_data['accordion'] = true;
160
+
161
  wp_localize_script('category-posts-widget-admin-js',__NAMESPACE__,$user_data);
162
  wp_enqueue_media();
163
  wp_localize_script( 'category-posts-widget-admin-js', 'cwp_default_thumb_selection', array(
165
  'button_title' => __( 'Select', 'category-posts' ),
166
  'none' => __( 'None', 'category-posts' ),
167
  ) );
168
+ }
169
  }
170
 
171
  add_action('admin_enqueue_scripts', __NAMESPACE__.'\admin_scripts'); // "called on widgets.php and costumizer since 3.9
181
  * @since 4.1
182
  **/
183
  function load_textdomain() {
184
+ load_plugin_textdomain( 'category-posts', false, plugin_basename( dirname( __FILE__ ) ) . '/languages' );
185
  }
186
 
187
  /**
189
  *
190
  */
191
  add_action( 'admin_print_styles-widgets.php', __NAMESPACE__.'\admin_styles' );
192
+
193
  function admin_styles() {
194
  ?>
195
  <style>
200
  border: 1px solid #E5E5E5;
201
  }
202
  .category-widget-cont h4:first-child {
203
+ margin-top: 10px;
204
  }
205
  .category-widget-cont h4:last-of-type {
206
  margin-bottom: 10px;
216
  -ms-transition: all 600ms;
217
  -webkit-transition: all 600ms;
218
  -moz-transition: all 600ms;
219
+ transition: all 600ms;
220
+ }
221
  .category-widget-cont h4.open:after {
222
  -ms-transition: all 600ms;
223
  -webkit-transition: all 600ms;
224
  -moz-transition: all 600ms;
225
+ transition: all 600ms;
226
  -ms-transform: rotate(180deg);
227
  -webkit-transform: rotate(180deg);
228
  -moz-transform: rotate(180deg);
229
  transform: rotate(180deg);
230
+ }
231
  .category-widget-cont > div {
232
  display:none;
233
+ }
234
  .category-widget-cont > div.open {
235
  display:block;
236
+ }
237
  </style>
238
  <?php
239
  }
247
  * return: an array with the width and height of the element containing the image
248
  */
249
  function get_image_size( $thumb_w,$thumb_h,$image_w,$image_h) {
250
+
251
  $image_size = array('image_h' => $thumb_h, 'image_w' => $thumb_w, 'marginAttr' => '', 'marginVal' => '');
252
  $relation_thumbnail = $thumb_w / $thumb_h;
253
  $relation_cropped = $image_w / $image_h;
254
+
255
  if ($relation_thumbnail < $relation_cropped) {
256
  // crop left and right site
257
  // thumbnail width/height ration is smaller, need to inflate the height of the image to thumb height
258
  // and adjust width to keep aspect ration of image
259
  $image_size['image_h'] = $thumb_h;
260
+ $image_size['image_w'] = $thumb_h / $image_h * $image_w;
261
  $image_size['marginAttr'] = 'margin-left';
262
  $image_size['marginVal'] = ($image_size['image_w'] - $thumb_w) / 2;
263
  } else {
265
  // thumbnail width/height ration is bigger, need to inflate the width of the image to thumb width
266
  // and adjust height to keep aspect ration of image
267
  $image_size['image_w'] = $thumb_w;
268
+ $image_size['image_h'] = $thumb_w / $image_w * $image_h;
269
  $image_size['marginAttr'] = 'margin-top';
270
  $image_size['marginVal'] = ($image_size['image_h'] - $thumb_h) / 2;
271
  }
272
+
273
  return $image_size;
274
  }
275
 
305
  return $html; // bail out if no full dimensions defined
306
 
307
  $meta = image_get_intermediate_size($post_thumbnail_id,$size);
308
+
309
+ if ( empty( $meta )) {
310
  $post_img = wp_get_attachment_metadata($post_thumbnail_id, $size);
311
  $meta['file'] = basename( $post_img['file'] );
312
  }
317
  list( $width, $height ) = getimagesize($file); // get actual size of the thumb file
318
 
319
  if (isset($this->instance['use_css_cropping']) && $this->instance['use_css_cropping']) {
320
+ $image = get_image_size($this->instance['thumb_w'],$this->instance['thumb_h'],$width,$height);
321
 
322
  // replace srcset
323
  $array = array();
324
  preg_match( '/width="([^"]*)"/i', $html, $array ) ;
325
  $pattern = "/".$array[1]."w/";
326
+ $html = preg_replace($pattern, $image['image_w']."w", $html);
327
  // replace size
328
  $pattern = "/".$array[1]."px/";
329
+ $html = preg_replace($pattern, $image['image_w']."px", $html);
330
  // replace width
331
  $pattern = "/width=\"[0-9]*\"/";
332
  $html = preg_replace($pattern, "width='".$image['image_w']."'", $html);
333
  // replace height
334
  $pattern = "/height=\"[0-9]*\"/";
335
+ $html = preg_replace($pattern, "height='".$image['image_h']."'", $html);
336
  // set margin
337
  $html = str_replace('<img ','<img style="'.$image['marginAttr'].':-'.$image['marginVal'].'px;height:'.$image['image_h']
338
  .'px;clip:rect(auto,'.($this->instance['thumb_w']+$image['marginVal']).'px,auto,'.$image['marginVal']
348
  }
349
  return $html;
350
  }
351
+
352
  /*
353
  wrapper to execute the the_post_thumbnail with filters
354
  */
382
  $post_thumbnail_id = get_post_thumbnail_id( get_the_ID() );
383
  if (!$post_thumbnail_id && $this->instance['default_thunmbnail'])
384
  $post_thumbnail_id = $this->instance['default_thunmbnail'];
385
+
386
+ do_action( 'begin_fetch_post_thumbnail_html', get_the_ID(), $post_thumbnail_id, $size );
387
  $html = wp_get_attachment_image( $post_thumbnail_id, $size, false, '' );
388
  if (!$html)
389
  $ret = '';
393
 
394
  return $ret;
395
  }
396
+
397
  /**
398
  * Excerpt more link filter
399
  */
410
  * @return string If option hide_social_buttons is unchecked applay the_content filter
411
  *
412
  * @since 4.6
413
+ */
414
  function apply_the_excerpt($text) {
415
  $ret = "";
416
  if (isset($this->instance["hide_social_buttons"]) && $this->instance["hide_social_buttons"])
419
  $ret = apply_filters('the_content', $text);
420
  return $ret;
421
  }
422
+
423
  /**
424
  * Excerpt allow HTML
425
  */
443
  '&lt;p&gt;',
444
  '&lt;img&gt;',
445
  '&lt;script&gt;',
446
+ '&lt;style&gt;',
447
  '&lt;video&gt;',
448
  '&lt;audio&gt;'
449
  );
451
  foreach ($cphtml as $index => $name) {
452
  if (in_array((string)($index),$this->instance['excerpt_allowed_elements'],true))
453
  $allowed_HTML .= $cphtml[$index];
454
+ }
455
  $text = strip_tags($text, htmlspecialchars_decode($allowed_HTML));
456
+ $excerpt_length = $new_excerpt_length;
457
 
458
  if( !empty($this->instance["excerpt_more_text"]) ) {
459
+ $excerpt_more = $this->excerpt_more_filter($this->instance["excerpt_more_text"]);
460
  }else if($filterName = key($wp_filter['excerpt_more'][10])) {
461
  $excerpt_more = $wp_filter['excerpt_more'][10][$filterName]['function'](0);
462
  }else {
463
  $excerpt_more = '[...]';
464
  }
465
+
466
  $words = explode(' ', $text, $excerpt_length + 1);
467
  if (count($words)> $excerpt_length) {
468
  array_pop($words);
473
 
474
  return '<p>' . $text . '</p>';
475
  }
476
+
477
  /**
478
  * Calculate the HTML for showing the thumb of a post item.
479
  * Expected to be called from a loop with globals properly set
486
  */
487
  function show_thumb($instance,$no_link) {
488
  $ret = '';
489
+
490
  if ( isset( $instance["thumb"] ) && $instance["thumb"] &&
491
  ((isset($instance['default_thunmbnail']) && ($instance['default_thunmbnail']!= 0)) || has_post_thumbnail()) ) {
492
 
494
  $use_css_cropping = isset($this->instance['use_css_cropping']) && $this->instance['use_css_cropping'];
495
  $disable_css = !(isset($this->instance['disable_css']) && $this->instance['disable_css']);
496
 
497
+ if( $use_css_cropping || $disable_css) {
498
  if( isset($this->instance['thumb_hover'] )) {
499
  $class = "class=\"cat-post-thumbnail cat-post-" . $instance['thumb_hover'] . "\"";
500
  } else {
501
  $class = "class=\"cat-post-thumbnail\"";
502
  }
503
  }
504
+
505
  $title_args = array('echo'=>false);
506
 
507
  if ($no_link)
519
 
520
  return $ret;
521
  }
522
+
523
  /**
524
  * Calculate the wp-query arguments matching the filter settings of the widget
525
  *
536
  $sort_by = 'date';
537
  }
538
  $sort_order = (isset( $instance['asc_sort_order'] ) && $instance['asc_sort_order']) ? 'ASC' : 'DESC';
539
+
540
  // Get array of post info.
541
  $args = array(
542
  'orderby' => $sort_by,
543
  'order' => $sort_order
544
  );
545
 
546
+ $non_default_valid_status = array(
547
+ 'publish',
548
+ 'future',
549
+ 'publish,future',
550
+ 'private',
551
+ 'private,publish',
552
+ 'private,publish,future',
553
+ );
554
+ if ( isset( $instance['status'] ) && in_array( $instance['status'], $non_default_valid_status, true ) ) {
555
+ $args['post_status'] = $instance['status'];
556
+ }
557
+
558
+ if (isset($instance["num"]))
559
  $args['showposts'] = (int) $instance["num"];
560
+
561
+ if (isset($instance["offset"]) && ((int) $instance["offset"] > 1))
562
  $args['offset'] = (int) $instance["offset"] - 1;
563
+
564
  if (isset($instance["cat"])) {
565
  if (isset($instance["no_cat_childs"]) && $instance["no_cat_childs"])
566
+ $args['category__in'] = (int) $instance["cat"];
567
  else
568
+ $args['cat'] = (int) $instance["cat"];
569
  }
570
 
571
+ if (is_singular() && isset( $instance['exclude_current_post'] ) && $instance['exclude_current_post'])
572
  $args['post__not_in'] = array(get_the_ID());
573
 
574
  if( isset( $instance['hideNoThumb'] ) && $instance['hideNoThumb']) {
577
  'key' => '_thumbnail_id',
578
  'compare' => 'EXISTS' )
579
  )
580
+ )
581
  );
582
  }
583
+
584
  return $args;
585
  }
586
+
587
  /**
588
  * Calculate the HTML of the title based on the widget settings
589
  *
598
  */
599
  function titleHTML($before_title,$after_title,$instance) {
600
  $ret = '';
601
+
602
  // If not title, use the name of the category.
603
  if( !isset($instance["title"]) || !$instance["title"] ) {
604
  $instance["title"] = '';
606
  $category_info = get_category($instance["cat"]);
607
  if ($category_info && !is_wp_error($category_info))
608
  $instance["title"] = $category_info->name;
609
+ else
610
  $instance["title"] = __('Recent Posts','category-posts');
611
+ } else
612
  $instance["title"] = __('Recent Posts','category-posts');
613
+ }
614
 
615
  if( !(isset ( $instance["hide_title"] ) && $instance["hide_title"])) {
616
  $ret = $before_title;
618
  $title = esc_html($instance["title"]);
619
  else
620
  $title = apply_filters( 'widget_title', $instance["title"] );
621
+
622
  if( isset ( $instance["title_link"]) && $instance["title_link"]) {
623
  if (isset($instance["cat"]) && (get_category($instance["cat"]) != null)) {
624
  $ret .= '<a href="' . get_category_link($instance["cat"]) . '">' . $title . '</a>';
625
  } else {
626
+ // link to posts page if category not found.
627
  // this maybe the blog page or home page
628
  $blog_page = get_option('page_for_posts');
629
  if ($blog_page)
631
  else
632
  $ret .= '<a href="' . home_url() . '">' . $title . '</a>';
633
  }
634
+ } else
635
  $ret .= $title;
636
+
637
  $ret .= $after_title;
638
  }
639
 
653
  $ret = "";
654
  $url = '';
655
  $text = '';
656
+
657
  if (isset ( $instance["footer_link"] ))
658
  $url = $instance["footer_link"];
659
+
660
  if (isset ( $instance["footer_link_text"] ))
661
  $text = $instance["footer_link_text"];
662
 
663
  // if url is set, but no text, just use the url as text
664
  if (empty($text) && !empty($url))
665
  $text = $url;
666
+
667
  // if no url is set but just text, assume the url should be to the relevant archive page
668
  // category archive for categories filter and home page or blog page when "all categories"
669
  // is used
678
  $url = home_url();
679
  }
680
  }
681
+
682
  if (!empty($url))
683
  $ret .= '<a class="cat-post-footer-link" href="' . esc_url($url) . '">' . esc_html($text) . '</a>';
684
+
685
  return $ret;
686
  }
687
+
688
  /**
689
  * Calculate the HTML for a post item based on the widget settings and post.
690
  * Expected to be called in an active loop with all the globals set
698
  */
699
  function itemHTML($instance,$current_post_id) {
700
  global $post;
701
+
702
  $everything_is_link = isset( $instance['everything_is_link'] ) && $instance['everything_is_link'];
703
  $disable_css = isset($instance['disable_css']) && $instance['disable_css'];
704
+
705
  $ret = '<li ';
706
+
707
  // Current post
708
+ if ( $current_post_id == $post->ID ) {
709
+ $ret .= "class='cat-post-item cat-post-current'";
710
  } else {
711
  $ret .= "class='cat-post-item'";
712
  }
713
  $ret.='>'; // close the li opening tag
714
+
715
  if ($everything_is_link) {
716
  $ret .= '<a class="cat-post-everything-is-link" href="'.get_the_permalink().'" title="">';
717
  }
718
+
719
  // Thumbnail position to top
720
  if( isset( $instance["thumbTop"] ) && $instance["thumbTop"]) {
721
+ $ret .= $this->show_thumb($instance,$everything_is_link);
722
  }
723
+
724
  // Title
725
+ if( !(isset( $instance['hide_post_titles'] ) && $instance['hide_post_titles'])) {
726
  if ($everything_is_link) {
727
  $ret .= '<span class="cat-post-title">'.get_the_title().'</span>';
728
  } else {
729
  $ret .= '<a class="post-title';
730
+ if (!$disable_css) {
731
+ $ret .= " cat-post-title";
732
  }
733
  $ret .= '" href="'.get_the_permalink().'" rel="bookmark">'.get_the_title();
734
  $ret .= '</a> ';
737
 
738
  // Date
739
  if ( isset( $instance['date']) && $instance['date']) {
740
+ if ( isset( $instance['date_format'] ) && strlen( trim( $instance['date_format'] ) ) > 0 ) {
741
+ $date_format = $instance['date_format'];
742
  } else {
743
+ $date_format = "j M Y";
744
+ }
745
  $ret .= '<p class="post-date';
746
+ if (!$disable_css) {
747
  $ret .= " cat-post-date";
748
+ }
749
  $ret .= '">';
750
+ if ( isset ( $instance["date_link"] ) && $instance["date_link"] && !$everything_is_link) {
751
  $ret .= '<a href="'.\get_the_permalink().'">';
752
  }
753
  $ret .= get_the_time($date_format);
754
+ if ( isset ( $instance["date_link"] ) && $instance["date_link"] && !$everything_is_link ) {
755
  $ret .= '</a>';
756
  }
757
  $ret .= '</p>';
758
  }
759
+
760
  // Thumbnail position normal
761
  if( !(isset( $instance["thumbTop"] ) && $instance["thumbTop"])) {
762
  $ret .= $this->show_thumb($instance,$everything_is_link);
768
  // then apply our filter to let users customize excerpts in their own way
769
  if (isset($instance['excerpt_length']) && ($instance['excerpt_length'] > 0))
770
  $length = (int) $instance['excerpt_length'];
771
+ else
772
  $length = 55; // use default
773
 
774
  if (!isset($instance['excerpt_filters']) || $instance['excerpt_filters']) { // pre 4.7 widgets has filters on
786
  else
787
  $excerpt_more_text = ' <a class="cat-post-excerpt-more" href="'. get_permalink() . '" title="'.sprintf(__('Continue reading %s'),get_the_title()).'">' . $more_text . '</a>';
788
  $excerpt = \wp_trim_words( $text, $length, $excerpt_more_text );
789
+ // adjust html output same way as for the normal excerpt,
790
  // just force all functions depending on the_excerpt hook
791
  $excerpt = shortcode_unautop(wpautop(convert_chars(convert_smilies(wptexturize($excerpt)))));
792
  } else {
793
+ $excerpt = shortcode_unautop(wpautop(convert_chars(convert_smilies(wptexturize($post->post_excerpt)))));
794
  }
795
  }
796
  $ret .= apply_filters('cpw_excerpt',$excerpt);
797
  }
798
+
799
  // Comments
800
  if ( isset( $instance['comment_num'] ) && $instance['comment_num']) {
801
  $ret .= '<p class="comment-num';
802
  if (!$disable_css) {
803
+ $ret .= " cat-post-comment-num";
804
+ }
805
  $ret .= '">';
806
  $ret .= '('.\get_comments_number().')';
807
  $ret .= '</p>';
810
  // Author
811
  if ( isset( $instance['author'] ) && $instance['author']) {
812
  $ret .= '<p class="post-author';
813
+ if (!$disable_css) {
814
+ $ret .= " cat-post-author";
815
+ }
816
  $ret .= '">';
817
  global $authordata;
818
  if ($everything_is_link) {
824
  esc_attr( sprintf( __( 'Posts by %s' ), get_the_author() ) ),
825
  get_the_author()
826
  );
827
+ $ret .= $link;
828
  }
829
  $ret .= '</p>';
830
  }
831
+
832
  if ($everything_is_link) {
833
  $ret .= '</a>';
834
  }
835
+
836
  $ret .= '</li>';
837
  return $ret;
838
  }
839
+
840
  /**
841
  * Filter to set the number of words in an excerpt
842
  *
843
  * @param int $length The number of words as configured by wordpress core or set by previous filters
844
+ * @return int The number of words configured for the widget,
845
  * or the $length parameter if it is not configured or garbage value
846
  *
847
  * @since 4.6
852
 
853
  return $length;
854
  }
855
+
856
  /**
857
  * Set the proper excerpt filters based on the settings
858
  *
862
  * @since 4.6
863
  */
864
  function setExcerpFilters($instance) {
865
+
866
  if (isset($instance['excerpt']) && $instance['excerpt']) {
867
+
868
  // Excerpt length filter
869
  if ( isset($instance["excerpt_length"]) && ((int) $instance["excerpt_length"]) > 0) {
870
  add_filter('excerpt_length', array($this,'excerpt_length_filter'));
871
  }
872
+
873
  if( isset($instance["excerpt_more_text"]) && ltrim($instance["excerpt_more_text"]) != '') {
874
  add_filter('excerpt_more', array($this,'excerpt_more_filter'));
875
  }
882
  }
883
  }
884
  }
885
+
886
  /**
887
  * Remove the excerpt filter
888
  *
898
  remove_filter('the_excerpt', array($this,'allow_html_excerpt'));
899
  remove_filter('the_excerpt', array($this,'apply_the_excerpt'));
900
  }
901
+
902
  /**
903
  * The main widget display controller
904
  *
905
  * Called by the sidebar processing core logic to display the widget
906
  *
907
  * @param array $args An array containing the "environment" setting for the widget,
908
+ * namely, the enclosing tags for the widget and its title.
909
  * @param array $instance The settings associate with the widget
910
  *
911
  * @since 4.1
914
 
915
  extract( $args );
916
  $this->instance = $instance;
917
+
918
  $args = $this->queryArgs($instance);
919
  $cat_posts = new \WP_Query( $args );
920
+
921
+ if ( !isset ( $instance["hide_if_empty"] ) || !$instance["hide_if_empty"] || $cat_posts->have_posts() ) {
922
  echo $before_widget;
923
  echo $this->titleHTML($before_title,$after_title,$instance);
924
 
928
 
929
  if (!(isset($instance['is_shortcode']) && $instance['is_shortcode'])) // the intenal id is needed only for widgets
930
  echo '<ul id="'.WIDGET_BASE_ID.'-'.$this->number.'-internal'.'" class="'.WIDGET_BASE_ID.'-internal'."\">\n";
931
+ else
932
  echo '<ul>';
933
 
934
  if (!isset($instance['excerpt_filters']) || $instance['excerpt_filters']) // pre 4.7 widgets has filters on
935
+ $this->setExcerpFilters($instance);
936
  while ( $cat_posts->have_posts() )
937
  {
938
+ $cat_posts->the_post();
939
  echo $this->itemHTML($instance,$current_post_id);
940
  }
941
  echo "</ul>\n";
942
 
943
  echo $this->footerHTML($instance);
944
  echo $after_widget;
945
+
946
  if (!isset($instance['excerpt_filters']) || $instance['excerpt_filters']) // pre 4.7 widgets has filters on
947
  $this->removeExcerpFilters($instance);
948
+
949
  wp_reset_postdata();
950
+
951
  $use_css_cropping = isset($this->instance['use_css_cropping']) && $this->instance['use_css_cropping'];
952
 
953
  if ($use_css_cropping){
960
  // and the number format expected at the rest of the places
961
  if (is_numeric($number))
962
  $number = WIDGET_BASE_ID .'-'.$number;
963
+
964
  // add Javascript to change change cropped image dimensions on load and window resize
965
  $thumb_w = $this->instance['thumb_w'];
966
  $thumb_h = $this->instance['thumb_h'];
967
+ add_filter('cpw_crop_widgets', function ($a) use ($number, $thumb_w, $thumb_h) {
968
  $a[$number] = $thumb_w / $thumb_h;
969
  return $a;
970
  });
971
  }
972
+ }
973
+ }
974
 
975
  /**
976
  * Update the options
1003
  ));
1004
  $title = $instance['title'];
1005
  $hide_title = $instance['hide_title'];
1006
+ $title_link = $instance['title_link'];
1007
+ ?>
1008
  <h4 data-panel="title"><?php _e('Title','category-posts')?></h4>
1009
  <div>
1010
  <p>
1025
  <?php _e( 'Hide title','category-posts' ); ?>
1026
  </label>
1027
  </p>
1028
+ </div>
1029
+ <?php
1030
  }
1031
+
1032
  /**
1033
  * Output the filter panel of the widget configuration form.
1034
  *
1089
  <label for="<?php echo $this->get_field_id("status"); ?>">
1090
  <?php _e('Status','category-posts'); ?>:
1091
  <select id="<?php echo $this->get_field_id("status"); ?>" name="<?php echo $this->get_field_name("status"); ?>">
1092
+ <option value=""<?php selected( $instance["status"], "" ); ?>><?php _e('WordPress Default','category-posts')?></option>
1093
  <option value="publish"<?php selected( $instance["status"], "publish" ); ?>><?php _e('Published','category-posts')?></option>
1094
  <option value="future"<?php selected( $instance["status"], "future" ); ?>><?php _e('Scheduled','category-posts')?></option>
1095
+ <option value="publish,future"<?php selected( $instance["status"], "publish,future" ); ?>><?php _e('Published or Scheduled','category-posts')?></option>
1096
  </select>
1097
  </label>
1098
  </p>
1124
  <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("hideNoThumb"); ?>" name="<?php echo $this->get_field_name("hideNoThumb"); ?>"<?php checked( (bool) $instance["hideNoThumb"], true ); ?> />
1125
  <?php _e( 'Exclude posts which have no thumbnail','category-posts' ); ?>
1126
  </label>
1127
+ </p>
1128
+ </div>
1129
  <?php
1130
  }
1131
+
1132
  /**
1133
  * Output the filter panel of the widget configuration form.
1134
  *
1154
  $use_css_cropping = $instance['use_css_cropping'];
1155
  $thumb_hover = $instance['thumb_hover'];
1156
  $default_thunmbnail = $instance['default_thunmbnail'];
1157
+ ?>
1158
  <h4 data-panel="thumbnail"><?php _e('Thumbnails','category-posts')?></h4>
1159
  <div>
1160
  <p>
1175
  <label for="<?php echo $this->get_field_id("thumb_w"); ?>">
1176
  <?php _e('Width:','category-posts')?> <input class="widefat" style="width:30%;" type="number" min="1" id="<?php echo $this->get_field_id("thumb_w"); ?>" name="<?php echo $this->get_field_name("thumb_w"); ?>" value="<?php echo esc_attr($instance["thumb_w"]); ?>" />
1177
  </label>
1178
+
1179
  <label for="<?php echo $this->get_field_id("thumb_h"); ?>">
1180
  <?php _e('Height:','category-posts')?> <input class="widefat" style="width:30%;" type="number" min="1" id="<?php echo $this->get_field_id("thumb_h"); ?>" name="<?php echo $this->get_field_name("thumb_h"); ?>" value="<?php echo esc_attr($instance["thumb_h"]); ?>" />
1181
  </label>
1206
  <input type="hidden" class="default_thumb_id" id="<?php echo $this->get_field_id("default_thunmbnail"); ?>" name="<?php echo $this->get_field_name("default_thunmbnail"); ?>" value="<?php echo esc_attr($default_thunmbnail)?>"/>
1207
  <span class="default_thumb_img">
1208
  <?php
1209
+ if (!$default_thunmbnail)
1210
  _e('None','category-posts');
1211
  else {
1212
  $img = wp_get_attachment_image_src($default_thunmbnail);
1222
  <button type="button" class="cwp_default_thumb_remove button upload-button" <?php if (!$default_thunmbnail) echo 'style="display:none"' ?> >
1223
  <?php _e('No default','category-posts')?>
1224
  </button>
1225
+ </p>
1226
  </div>
1227
  <?php
1228
  }
1229
+
1230
  /**
1231
  * The widget configuration form back end.
1232
  *
1276
  $disable_css = $instance['disable_css'];
1277
  $disable_font_styles = $instance['disable_font_styles'];
1278
  $hide_if_empty = $instance['hide_if_empty'];
1279
+
1280
  $cat = $instance['cat'];
1281
 
1282
+
1283
  if (!isset($style_done)) { // what an ugly hack, but can't figure out how to do it nicer on 4.3
1284
  ?>
1285
  <style type="text/css">
1309
  $style_done = true;
1310
  }
1311
  ?>
1312
+
1313
  <div class="category-widget-cont">
1314
  <p><a target="_blank" href="http://tiptoppress.com/term-and-category-based-posts-widget/?utm_source=widget_cpw&utm_campaign=get_pro_cpw&utm_medium=form"><?php _e('Get the Pro version','category-posts'); ?></a></p>
1315
  <?php
1426
  </label>
1427
  </p>
1428
  </div>
1429
+ <p><a href="<?php echo get_edit_user_link().'#'.__NAMESPACE__ ?>"><?php _e('Widget admin behaviour settings','category-posts')?></a></p>
1430
  <p><a target="_blank" href="<?php echo CAT_POST_DOC_URL ?>"><?php _e('Documentation','category-posts'); ?></a></p>
1431
  <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' ) ); ?></br></br></p>
1432
  </div>
1438
 
1439
  /**
1440
  * Applied to the list of links to display on the plugins page (beside the activate/deactivate links).
1441
+ *
1442
  * @return array of the widget links
1443
+ *
1444
  * @since 4.6.3
1445
  */
1446
  add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), __NAMESPACE__.'\add_action_links' );
1449
  $pro_link = array(
1450
  '<a target="_blank" href="http://tiptoppress.com/term-and-category-based-posts-widget/?utm_source=widget_cpw&utm_campaign=get_pro_cpw&utm_medium=action_link">'.__('Get the Pro version','category-posts').'</a>',
1451
  );
1452
+
1453
  $links = array_merge($pro_link, $links);
1454
+
1455
  return $links;
1456
  }
1457
 
1463
 
1464
  /**
1465
  * Output js code to handle responsive thumbnails
1466
+ *
1467
  * @return void
1468
  *
1469
  * @since 4.7
1480
  <?php // namespace ?>
1481
  var cwp_namespace = window.cwp_namespace || {};
1482
  cwp_namespace.fluid_images = cwp_namespace.fluid_images || {};
1483
+
1484
  cwp_namespace.fluid_images = {
1485
 
1486
+ <?php /* variables */ ?>
1487
  Widgets : {},
1488
  widget : null,
1489
+
1490
  <?php /* class */ ?>
1491
  Span : function (_self, _imageRatio) {
1492
 
1494
  this.self = _self;
1495
  this.imageRatio = _imageRatio;
1496
  },
1497
+
1498
+ <?php /* class */ ?>
1499
  WidgetPosts : function (widget, ratio) {
1500
 
1501
  <?php /* variables */ ?>
1522
  this.allSpans.width( this.listItemWidth );
1523
  var spanHeight = this.listItemWidth / this.ratio;
1524
  this.allSpans.height( spanHeight );
1525
+
1526
+ for( var index in this.Spans ){
1527
  var imageHeight = this.listItemWidth / this.Spans[index].imageRatio;
1528
  jQuery(this.Spans[index].self).find( 'img' ).css({
1529
  height: imageHeight,
1530
  marginTop: -(imageHeight - spanHeight) / 2
1531
+ });
1532
  };
1533
+ }
1534
  }
1535
  },
1536
  }
1539
  /***
1540
  * cpw_crop_widgets is an internal filter that is used
1541
  * to gather the ids of the widgets to which apply cropping
1542
+ *
1543
  * For eaier prevention of duplication, the widget id number should be an index
1544
  * in the array while the ratio of width/height be the value
1545
  */
1549
  cwp_namespace.fluid_images.widget = jQuery('#<?php echo $number?>');
1550
  cwp_namespace.fluid_images.Widgets['<?php echo $number?>'] = new cwp_namespace.fluid_images.WidgetPosts(cwp_namespace.fluid_images.widget,<?php echo $ratio?>);
1551
  <?php } ?>
1552
+
1553
  <?php /* do on page load or on resize the browser window */ echo "\r\n" ?>
1554
  jQuery(window).on('load resize', function() {
1555
  for (var widget in cwp_namespace.fluid_images.Widgets) {
1556
  cwp_namespace.fluid_images.Widgets[widget].changeImageSize();
1557
  }
1558
+ });
1559
  });
1560
  }
1561
  </script>
1562
+ <?php
1563
  }
1564
 
1565
  // shortcode section
1566
 
1567
  /**
1568
  * Get shortcode settings taking into account if it is being customized
1569
+ *
1570
  * When not customized returns the settings as stored in the meta, but when
1571
  * it is customized returns the setting stored in the virtual option used by the customizer
1572
+ *
1573
  * @parm string name The name of the shortcode to retun, empty string indicates the nameless
1574
+ *
1575
  * @return array the shortcode settings if a short code exists or empty string, empty array if name not found
1576
+ *
1577
  * @since 4.6
1578
  */
1579
  function shortcode_settings($name) {
1584
 
1585
  if (!isset($meta[$name])) // name do not exists? return empty array
1586
  return array();
1587
+
1588
  $instance = $meta[$name];
1589
  if (is_customize_preview()) {
1590
  $o=get_option('_virtual-'.WIDGET_BASE_ID);
1591
  if (is_array($o))
1592
  $instance=$o[get_the_ID()][$name];
1593
  }
1594
+
1595
  return $instance;
1596
  }
1597
 
1598
  /**
1599
  * Handle the shortcode
1600
+ *
1601
  * @param array $attr Array of the attributes to the short code, none is expected
1602
  * @param string $content The content enclosed in the shortcode, none is expected
1603
+ *
1604
  * @return string An HTML of the "widget" based on its settings, actual or customized
1605
+ *
1606
  */
1607
  function shortcode($attr,$content=null) {
1608
  $repository = new virtualWidgetsRepository;
1609
+
1610
  $shortcodes = $repository->getShortcodes();
1611
+
1612
  $name = '';
1613
  if (isset($attr['name']))
1614
  $name = $attr['name'];
1615
+
1616
  if (is_singular()) {
1617
  if (isset($shortcodes[$name])) {
1618
  return $shortcodes[$name]->getHTML();
1619
+ }
1620
  }
1621
+
1622
  return '';
1623
  }
1624
 
1626
 
1627
  /**
1628
  * Find if a specific shortcode is used in a content
1629
+ *
1630
  * @param string $shortcode_name The name of the shortcode
1631
  * #param string The content to look at
1632
+ *
1633
+ * @return array An array containing the name attributes of the shortcodes. Empty array is
1634
  * an indication there were no shourcodes
1635
+ *
1636
  * @since 4.7
1637
+ *
1638
  */
1639
  function shortcode_names($shortcode_name,$content) {
1640
 
1641
  $names = array();
1642
+
1643
  $regex_pattern = get_shortcode_regex();
1644
  if (preg_match_all ('/'.$regex_pattern.'/s', $content, $matches)) {
1645
  foreach ($matches[2] as $k=>$shortcode) {
1652
  }
1653
  }
1654
  }
1655
+
1656
  return $names;
1657
  }
1658
 
1659
  /**
1660
  * Organized way to have rhw default widget settings accessible
1661
+ *
1662
  * @since 4.6
1663
  */
1664
  function default_settings() {
1703
 
1704
  /**
1705
  * Manipulate the relevant meta related to the short code when a post is save
1706
+ *
1707
  * If A post has a short code, a meta holder is created, If it does not the meta holder is deleted
1708
+ *
1709
  * @param integer $pid The post ID of the post being saved
1710
  * @param WP_Post $post The post being saved
1711
  * @return void
1712
+ *
1713
  * @since 4.6
1714
  */
1715
  function save_post($pid,$post) {
1717
  // ignore revisions and auto saves
1718
  if ( wp_is_post_revision( $pid ) || wp_is_post_autosave($pid))
1719
  return;
1720
+
1721
  $meta = get_post_meta($pid,SHORTCODE_META,true);
1722
  if (empty($meta))
1723
  $meta = array();
1724
+
1725
  // check if only one shortcode format - non array of arrays, and convert it
1726
  if (!empty($meta) && !is_array(reset($meta)))
1727
  $meta = array ('' => $meta); // the coversion
1728
+
1729
  $old_names = array_keys($meta); // keep list of curren shorcodes names to delete lter whatever was deleted
1730
  $names = shortcode_names(SHORTCODE_NAME,$post->post_content);
1731
 
1733
  $to_delete = array_diff($old_names,$names);
1734
  foreach ($to_delete as $k)
1735
  unset($meta[$k]);
1736
+
1737
  foreach ($names as $name) {
1738
  if (!isset($meta[$name])) {
1739
  $meta[$name] = default_settings();
1741
  }
1742
 
1743
  delete_post_meta($pid,SHORTCODE_META);
1744
+ if (!empty($meta))
1745
  add_post_meta($pid,SHORTCODE_META,$meta,true);
1746
  }
1747
 
1752
  class shortCodeControl extends \WP_Customize_Control {
1753
  public $form;
1754
  public $title_postfix;
1755
+
1756
  public function render_content() {
1757
  $widget_title = 'Category Posts Shortcode'.$this->title_postfix;
1758
  ?>
1768
  </div>
1769
  <?php
1770
  }
1771
+ }
1772
 
1773
  $args = array(
1774
  'post_type' => 'any',
1778
  'meta_query' => array(
1779
  array(
1780
  'key' => SHORTCODE_META,
1781
+ 'compare' => 'EXISTS'
1782
  )
1783
  ),
1784
+
1785
  );
1786
  $posts = get_posts($args);
1787
+
1788
  if (count($posts) > 0) {
1789
  $wp_customize->add_panel( __NAMESPACE__, array(
1790
  'title' => __( 'Category Posts Shortcode', 'category-posts' ),
1791
  'priority' => 300,
1792
  'capability' => 'edit_theme_options',
1793
  ) );
1794
+
1795
  foreach($posts as $p) {
1796
  $widget = new Widget();
1797
  $meta = get_post_meta($p->ID,SHORTCODE_META,true);
1798
  if (!is_array($meta))
1799
  continue;
1800
+
1801
  if (!is_array(reset($meta))) // 4.6 format
1802
  $meta = array('' => $meta);
1803
+
1804
  foreach ($meta as $k => $m) {
1805
  $m = wp_parse_args($m,default_settings());
1806
+
1807
  if (count($meta) == 0) { // new widget, use defaults
1808
  ;
1809
  } else { // updated widgets come from =< 4.6 excerpt filter is on
1810
  if (!isset($m['excerpt_filters']))
1811
  $m['excerpt_filters'] = 'on';
1812
  }
1813
+
1814
  $section_title = $k;
1815
  if ($section_title == '')
1816
  $section_title = __('[shortcode]', 'category-posts');
1817
+
1818
  $wp_customize->add_section( __NAMESPACE__.'-'.$p->id.'-'.$k, array(
1819
  'title' => $section_title,
1820
  'priority' => 10,
1821
  'capability' => 'edit_theme_options',
1822
  'panel' => __NAMESPACE__,
1823
  ) );
1824
+
1825
  ob_start();
1826
  $widget->number = $p->ID.'_'.$k;
1827
  $widget->form($m);
1858
  '_virtual-'.WIDGET_BASE_ID.'['.$p->ID.']['.$k.'][title]',
1859
  $args
1860
  );
1861
+
1862
  if ($k != '')
1863
  $sc->title_postfix = ' '.$k;
1864
  $wp_customize->add_control($sc);
1874
  *
1875
  * The customizer actually saves only the changed values, so a merge needs to be done.
1876
  * After everything is updated the virtual option is deleted to leave a clean slate
1877
+ *
1878
  * @return void
1879
+ *
1880
  * @since 4.6
1881
  */
1882
  function customize_save_after() {
1887
  $meta = get_post_meta($pid,SHORTCODE_META,true);
1888
  if (!empty($meta) && !is_array(reset($meta)))
1889
  $meta = array ('' => $meta); // the coversion
1890
+
1891
  foreach ($instance as $name=>$new) {
1892
  if (isset($meta[$name])) // unlikely but maybe that short code was deleted by other session
1893
  $meta[$name] = array_merge($meta[$name],$new);
1895
  }
1896
  update_post_meta($pid,SHORTCODE_META, $meta);
1897
  }
1898
+
1899
  delete_option('_virtual-'.WIDGET_BASE_ID);
1900
  }
1901
 
1905
 
1906
  /**
1907
  * Uninstall handler, cleanup DB from options and meta
1908
+ *
1909
  * @return void
1910
+ *
1911
  * @since 4.7
1912
  */
1913
  function uninstall() {
1914
  delete_option('widget-'.WIDGET_BASE_ID); // delete the option storing the widget options
1915
+ delete_post_meta_by_key( SHORTCODE_META ); // delete the meta storing the shortcode
1916
  delete_metadata( 'user', 0, __NAMESPACE__, '', true ); // delete all user metadata
1917
  }
1918
 
1920
 
1921
  /**
1922
  * Register the tinymce shortcode plugin
1923
+ *
1924
  * @param array $plugin_array An array containing the current plugins to be used by tinymce
1925
+ *
1926
  * @return array An array containing the plugins to be used by tinymce, our plugin added to the $plugin_array parameter
1927
  *
1928
  * @since 4.7
1937
  else
1938
  $plugin_array[__NAMESPACE__] = plugins_url('js/admin/tinymce.js?ver='.CAT_POST_VERSION,__FILE__);
1939
  }
1940
+
1941
  return $plugin_array;
1942
  }
1943
 
1945
 
1946
  /**
1947
  * Register the tinymce buttons for the add shortcode
1948
+ *
1949
  * @param array $buttons An array containing the current buttons to be used by tinymce
1950
+ *
1951
  * @return array An array containing the buttons to be used by tinymce, our button added to the $buttons parameter
1952
  *
1953
  * @since 4.7
1969
 
1970
  /**
1971
  * Register the tinymcetranslation file
1972
+ *
1973
  * @param array $locales An array containing the current translations to be used by tinymce
1974
+ *
1975
  * @return array An array containing the translations to be used by tinymce, our localization added to the $locale parameter
1976
+ *
1977
  * @since 4.7
1978
  */
1979
  function mce_external_languages($locales) {
1985
  $locales['category-posts'] = plugin_dir_path ( __FILE__ ) . 'tinymce_translations.php';
1986
  return $locales;
1987
  }
1988
+
1989
  add_filter( 'mce_external_languages', __NAMESPACE__.'\mce_external_languages');
1990
 
1991
  // user profile related functions
1993
  add_action( 'show_user_profile', __NAMESPACE__.'\show_user_profile' );
1994
  add_action( 'edit_user_profile', __NAMESPACE__.'\show_user_profile' );
1995
 
1996
+ function show_user_profile( $user ) {
1997
 
1998
  if ( !current_user_can( 'edit_user', $user->ID ) )
1999
  return;
2002
  return;
2003
 
2004
  $meta = get_the_author_meta( __NAMESPACE__, $user->ID );
2005
+
2006
  if (empty($meta))
2007
  $meta = array();
2008
+
2009
  $accordion = false;
2010
  if (isset($meta['panels']))
2011
  $accordion = true;
2012
+
2013
  $editor = false;
2014
  if (isset($meta['editor']))
2015
  $editor = true;
2032
  </td>
2033
  </tr>
2034
  </table>
2035
+ <?php
2036
  }
2037
 
2038
  add_action( 'personal_options_update', __NAMESPACE__.'\personal_options_update' );
2045
 
2046
  if ( !current_user_can( 'edit_theme_options', $user_id ) )
2047
  return;
2048
+
2049
  if (isset($_POST[__NAMESPACE__]))
2050
  update_user_meta( $user_id, __NAMESPACE__, $_POST[__NAMESPACE__] );
2051
  else
2052
+ delete_user_meta( $user_id, __NAMESPACE__);
2053
  }
2054
 
2055
  // external API
2056
 
2057
  /**
2058
+ * Class that represent a virtual widget. Each widget being created will have relevant
2059
  * CSS output in the header, but strill requires a call for getHTML method or renderHTML
2060
  * to get or output the HTML
2061
+ *
2062
  * @since 4.7
2063
  */
2064
  class virtualWidget {
2065
  private static $collection = array();
2066
  private $id;
2067
  private $class;
2068
+
2069
  /**
2070
  * Construct the virtual widget. This should happen before wp_head action with priority
2071
  * 10 is executed if any CSS output should be generated.
2072
+ *
2073
  * @param string $id The identifier use as the id of the root html element when the HTML
2074
  * is generated
2075
+ *
2076
  * @param string $class The class name to be use us the class attribute on the root html element
2077
+ *
2078
  * @param array $args The setting to be applied to the widget
2079
+ *
2080
  * @since 4.7
2081
  */
2082
  function __construct($id, $class, $args) {
2084
  $this->class = $class;
2085
  self::$collection[$id] = wp_parse_args($args,default_settings());
2086
  }
2087
+
2088
  function __destruct() {
2089
  unset(self::$collection[$this->id]);
2090
  }
2091
 
2092
  /**
2093
  * return the HTML of the widget as is generated based on the settings passed at construction time
2094
+ *
2095
  * @return string
2096
+ *
2097
  * @since 4.7
2098
  */
2099
  function getHTML() {
2100
+
2101
  $widget=new Widget();
2102
  $widget->number = $this->id; // needed to make a unique id for the widget html element
2103
  ob_start();
2111
  ), $args);
2112
  $ret = ob_get_clean();
2113
  $ret = '<div id="'.esc_attr($this->id).'" class="'.esc_attr($this->class).'">'.$ret.'</div>';
2114
+ return $ret;
2115
  }
2116
+
2117
  /**
2118
+ * Output the widget HTML
2119
+ *
2120
  * Just a wrapper that output getHTML
2121
+ *
2122
  * @return void
2123
+ *
2124
  * @since 4.7
2125
  */
2126
  function renderHTML() {
2129
 
2130
  /**
2131
  * Calculate the CSS rules required for the widget as is generated based on the settings passed at construction time
2132
+ *
2133
  * @return string
2134
+ *
2135
  * @since 4.7
2136
  */
2137
+ function getCSSRules($is_shortcode,&$ret) {
2138
  $settings = self::$collection[$this->id];
2139
  $widget_id = $this->id;
2140
  if (!$is_shortcode)
2141
  $widget_id .= '-internal';
2142
+
2143
  if (!(isset($settings['disable_css']) && $settings['disable_css'])) { // checks if css disable is not set
2144
+
2145
  $rules = array( // rules that should be applied to all widgets
2146
  '.cat-post-item img {max-width: initial; max-height: initial;}',
2147
  '.cat-post-current .cat-post-title {text-transform: uppercase;}',
2151
  '.cat-post-item:before {content: ""; display: table; clear: both;}',
2152
  '.cat-post-item img {margin: initial;}',
2153
  );
2154
+
2155
  if (!(isset($settings['disable_font_styles']) && $settings['disable_font_styles'])) { // checks if disable font styles is not set
2156
  // add general rules which apply to font styling
2157
  $rules[] = '.cat-post-title {font-size: 15px;}';
2159
  $rules[] = '.cat-post-date {font-size: 12px; line-height: 18px; font-style: italic; margin-bottom: 10px;}';
2160
  $rules[] = '.cat-post-comment-num {font-size: 12px; line-height: 18px;}';
2161
  } else {
2162
+ $rules[] = '.cat-post-date {margin-bottom: 10px;}';
2163
  }
2164
 
2165
  /*
2166
+ the twenty seventeen theme have a border between the LI elements of a widget,
2167
  so remove our border if we detect its use to avoid conflicting styling
2168
  */
2169
  if (!$is_shortcode && function_exists('twentyseventeen_setup')) {
2222
  bigger (add to the padding) use only top for now */
2223
  }
2224
  }
2225
+
2226
  if ((isset($settings['use_css_cropping']) && $settings['use_css_cropping']) || !(isset($settings['disable_css']) && $settings['disable_css'])) {
2227
  if (isset($settings['use_css_cropping']) && $settings['use_css_cropping'])
2228
  $ret[] = '#'.$widget_id.' .cat-post-crop {overflow: hidden; display:block}';
2233
  }
2234
 
2235
  /**
2236
+ * Output the widget CSS
2237
+ *
2238
  * Just a wrapper that output getCSSRules
2239
+ *
2240
  * @return void
2241
+ *
2242
  * @since 4.7
2243
  */
2244
  function outputCSS($is_shortcode) {
2250
  }
2251
  /**
2252
  * Get the id the virtual widget was registered with
2253
+ *
2254
  * @return string
2255
+ *
2256
  * @since 4.7
2257
  */
2258
  function id() {
2259
  return $this->id;
2260
  }
2261
+
2262
  /**
2263
  * Get all the setting of the virtual widgets in an array
2264
+ *
2265
  * @return array
2266
+ *
2267
  * @since 4.7
2268
  */
2269
  static function getAllSettings() {
2270
  return self::$collection;
2271
  }
2272
+
2273
  }
2274
 
2275
  /**
2276
  * Class that implement a simple repository for the virtual widgets representing
2277
  * actuall shortcode and widgets
2278
+ *
2279
  * @since 4.7
2280
  */
2281
  class virtualWidgetsRepository {
2282
  private static $shortcodeCollection = array();
2283
  private static $widgetCollection = array();
2284
+
2285
  /**
2286
  * Add a virtual widget representing a shortcode to the repository
2287
+ *
2288
  * @param string $index A name to identify the specific shortcode
2289
  * @param virtualWidget The virstual widget for it
2290
+ *
2291
  * @since 4.7
2292
  */
2293
  function addShortcode($index,$widget) {
2296
 
2297
  /**
2298
  * Get all the virtual widgets representing actual shortcodes
2299
+ *
2300
  * @return array
2301
+ *
2302
  * @since 4.7
2303
  */
2304
  function getShortcodes() {
2307
 
2308
  /**
2309
  * Add a virtual widget representing awidget to the repository
2310
+ *
2311
  * @param string $index A name to identify the specific widget
2312
  * @param virtualWidget The virstual widget for it
2313
+ *
2314
  * @since 4.7
2315
  */
2316
  function addWidget($index,$widget) {
2319
 
2320
  /**
2321
  * Get all the virtual widgets representing actual widgets
2322
+ *
2323
  * @return array
2324
+ *
2325
  * @since 4.7
2326
  */
2327
  function getWidgets() {
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: http://mkrdip.me/donate
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: 4.9
7
- Stable tag: 4.7.3
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -14,8 +14,8 @@ Adds a widget that shows the most recent posts from a single category.
14
  Category Posts Widget is a light widget designed to do one thing and do it well: display the most recent posts from a certain category.
15
 
16
  = Term and Category based Posts Widget =
17
- A premium version of this free widget here and available on <a href="http://tiptoppress.com/?utm_source=wordpress_org&utm_campaign=premium_widget_cpw&utm_medium=web">tiptoppress.com</a> created for big Wordpress sites.
18
- We've also started creating free widget extensions for the Premium Widget. The first extension is the <a href="https://wordpress.org/plugins/excerpt-extension/">Excerpt Extension</a>.
19
 
20
  = Premium features =
21
  * "Post List Alterations"
@@ -103,6 +103,10 @@ Automatic installation is the easiest option as WordPress handles the file trans
103
  * Version 3.0 or later version uses WordPress 2.9's built in post thumbnail functionality.
104
 
105
  == Frequently Asked Questions ==
 
 
 
 
106
  = Thumb and Title not able to float left =
107
  Check the option in the Thumbnails panels > "Show thumbnails above text".
108
  Then add this custom CSS:
@@ -135,6 +139,9 @@ We know there are peopel how use PHP 5.2 [wordpress.org/about/stats](https://wor
135
  == Changelog ==
136
  [Read more on our blog ...](http://tiptoppress.com/category/category-posts-widget?utm_source=wordpress_org&utm_campaign=changelog_cpw&utm_medium=web)
137
 
 
 
 
138
  = 4.7.3 - October 10th 2017 =
139
  * Add option to filter by post status
140
  * Fixed footer section do not change when switching to and from "all posts"
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: 4.9
7
+ Stable tag: 4.7.4
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
14
  Category Posts Widget is a light widget designed to do one thing and do it well: display the most recent posts from a certain category.
15
 
16
  = Term and Category based Posts Widget =
17
+ A premium version of this free widget here and available on [tiptoppress.com](http://tiptoppress.com/?utm_source=wordpress_org&utm_campaign=premium_widget_cpw&utm_medium=web) created for big Wordpress sites.
18
+ We've also started creating free widget Add-ons for the Premium Widget here: [Widget extensions](http://tiptoppress.com/extensions/?utm_source=wordpress_org&utm_campaign=premium_widget_cpw&utm_medium=web).
19
 
20
  = Premium features =
21
  * "Post List Alterations"
103
  * Version 3.0 or later version uses WordPress 2.9's built in post thumbnail functionality.
104
 
105
  == Frequently Asked Questions ==
106
+ = How Category Posts Widget work with SiteOrigin Page Builder =
107
+ Please add the widget with shortcode [catposts] inside a editor widget which is placed to a SiteOrigin Page Builder row.
108
+ We also create a YouTube video: [How Category Posts Widget work with SiteOrigin Page Builder](http://tiptoppress.com/how-category-posts-widget-work-with-siteorigin-page-builder/)
109
+
110
  = Thumb and Title not able to float left =
111
  Check the option in the Thumbnails panels > "Show thumbnails above text".
112
  Then add this custom CSS:
139
  == Changelog ==
140
  [Read more on our blog ...](http://tiptoppress.com/category/category-posts-widget?utm_source=wordpress_org&utm_campaign=changelog_cpw&utm_medium=web)
141
 
142
+ = 4.7.4 - October 21th 2017 =
143
+ * Bugfix for filter by post status (note private)
144
+
145
  = 4.7.3 - October 10th 2017 =
146
  * Add option to filter by post status
147
  * Fixed footer section do not change when switching to and from "all posts"