Category Posts Widget - Version 4.8

Version Description

  • January 22th 2018 =
  • SVG icon support for post formats
  • Template to arrange the post details
  • Premade Templates
  • Date format: Time since plublished
  • Filter by post status: Published, scheduled, private
  • Hover effect: SVG icon
Download this release

Release Info

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

Code changes from version 4.7.4 to 4.8

cat-posts.php CHANGED
@@ -1,10 +1,18 @@
1
  <?php
 
 
 
 
 
 
 
 
2
  /*
3
  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.4
8
  Author URI: http://tiptoppress.com
9
  Text Domain: category-posts
10
  Domain Path: /languages
@@ -12,80 +20,93 @@ Domain Path: /languages
12
 
13
  namespace categoryPosts;
14
 
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';
22
  const SHORTCODE_META = 'categoryPosts-shorcode';
23
  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() {
31
  global $wp_admin_bar;
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' ),
52
- 'href' => $customize_url,
53
- 'meta' => array(
54
- 'class' => 'hide-if-no-customize',
55
- ),
56
  ) );
57
  add_action( 'wp_before_admin_bar_render', 'wp_customize_support_script' );
58
  }
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
  }
70
 
71
- foreach ($widgetRepository->getWidgets() as $widget) {
72
- $widget->getCSSRules(false,$rules);
73
  }
74
 
75
- if (!empty($rules)) {
76
- ?>
77
  <style type="text/css">
78
- <?php
79
- foreach ($rules as $rule) {
80
- echo "$rule\n";
81
- }
82
- ?>
 
 
83
  </style>
84
- <?php
85
- }
86
  }
87
 
88
- 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
@@ -98,41 +119,41 @@ function register_virtual_widgets() {
98
  global $post;
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) ) {
122
  foreach ( $sidebars_widgets as $sidebar => $widgets ) {
123
  if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) {
124
  continue;
125
  }
126
 
127
- if ( is_array($widgets) ) {
128
  foreach ( $widgets as $widget ) {
129
- $widget_base = _get_widget_id_base($widget);
130
- if ( $widget_base == WIDGET_BASE_ID ) {
131
- $class = __NAMESPACE__.'\Widget';
132
  $widgetclass = new $class();
133
  $allsettings = $widgetclass->get_settings();
134
- $settings = isset($allsettings[str_replace($widget_base.'-','',$widget)]) ? $allsettings[str_replace($widget_base.'-','',$widget)] : false;
135
- $repository->addWidget($widget, new virtualWidget($widget,$widget,$settings));
136
  }
137
  }
138
  }
@@ -140,38 +161,42 @@ function register_virtual_widgets() {
140
  }
141
  }
142
 
143
- 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(
164
- 'frame_title' => __( 'Select a default thumbnail', 'category-posts' ),
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
172
 
173
-
174
- add_action( 'admin_init', __NAMESPACE__.'\load_textdomain' );
175
 
176
  /**
177
  * Load plugin textdomain.
@@ -181,23 +206,28 @@ 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
- /**
188
  * Add styles for widget sections
189
- *
190
  */
191
- add_action( 'admin_print_styles-widgets.php', __NAMESPACE__.'\admin_styles' );
192
 
 
 
 
 
 
 
 
193
  function admin_styles() {
194
  ?>
195
  <style>
196
  .category-widget-cont h4 {
197
- padding: 12px 15px;
198
- cursor: pointer;
199
- margin: 5px 0;
200
- border: 1px solid #E5E5E5;
201
  }
202
  .category-widget-cont h4:first-child {
203
  margin-top: 10px;
@@ -216,15 +246,15 @@ 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
  }
@@ -234,6 +264,22 @@ function admin_styles() {
234
  .category-widget-cont > div.open {
235
  display:block;
236
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  </style>
238
  <?php
239
  }
@@ -241,38 +287,126 @@ function admin_styles() {
241
  /**
242
  * Get image size
243
  *
244
- * $thumb_w, $thumb_h - the width and height of the thumbnail in the widget settings
245
- * $image_w,$image_h - the width and height of the actual image being displayed
 
 
246
  *
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 {
264
  // crop top and bottom
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
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
276
  /**
277
  * Category Posts Widget Class
278
  *
@@ -280,158 +414,181 @@ function get_image_size( $thumb_w,$thumb_h,$image_w,$image_h) {
280
  */
281
  class Widget extends \WP_Widget {
282
 
283
- function __construct() {
284
- $widget_ops = array('classname' => 'cat-post-widget', 'description' => __('List single category posts','category-posts'));
285
- parent::__construct(WIDGET_BASE_ID, __('Category Posts','category-posts'), $widget_ops);
 
 
 
 
 
 
286
  }
287
 
288
  /**
289
  * Calculate the HTML for showing the thumb of a post item.
290
- *
291
- * Used as a filter for the thumb wordpress API to add css based stretching and cropping
292
- * when the image is not at the requested dimensions
293
- *
294
- * @param string $html The original HTML generated by the core APIS
295
- * @param int $post_id the ID of the post of which the thumb is a featured image
296
- * @param int $post_thumbnail_id The id of the featured image attachment
297
- * @param string|array $size The requested size identified by name or (width, height) array
298
- * @param mixed $attr ignored in this context
299
  * @return string The HTML for the thumb related to the post
300
- *
301
- * @since 4.1
302
  */
303
- function post_thumbnail_html($html, $post_id, $post_thumbnail_id, $size, $attr){
304
- if ( empty($this->instance['thumb_w']) || empty($this->instance['thumb_h']))
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
  }
313
 
314
- $origfile = get_attached_file( $post_thumbnail_id, true); // the location of the full file
315
- $file = dirname($origfile) .'/'.$meta['file']; // the location of the file displayed as thumb
316
- if (file_exists($file)) {
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']
339
- .'px);width:auto;max-width:initial;" ',$html);
340
- // wrap span
341
- $html = '<span class="cat-post-crop" style="width:'.$this->instance['thumb_w'].'px;height:'.$this->instance['thumb_h'].'px;">'
342
- .$html.'</span>';
 
 
 
 
 
343
  } else {
344
- // use_css_cropping is not used
345
- // wrap span
346
- $html = '<span>'.$html.'</span>';
347
  }
348
  }
349
  return $html;
350
  }
351
 
352
  /*
353
- wrapper to execute the the_post_thumbnail with filters
354
- */
355
  /**
356
  * Calculate the HTML for showing the thumb of a post item.
357
- *
358
- * It is a wrapper to execute the the_post_thumbnail with filters
359
- *
360
- * @param string|array $size The requested size identified by name or (width, height) array
361
- *
362
  * @return string The HTML for the thumb related to the post and empty string if it can not be calculated
363
- *
364
- * @since 4.1
365
  */
366
- function the_post_thumbnail($size= 'post-thumbnail') {
367
- if (empty($size)) // if junk value, make it a normal thumb
368
- $size= 'post-thumbnail';
369
- else if (is_array($size) && (count($size)==2)) { // good format at least
370
- // normalize to ints first
371
- $size[0] = (int) $size[0];
372
- $size[1] = (int) $size[1];
373
- if (($size[0] == 0) && ($size[1] == 0)) //both values zero then revert to thumbnail
374
- $size= array(get_option('thumbnail_size_w',150),get_option('thumbnail_size_h',150));
375
- // if one value is zero make a square using the other value
376
- else if (($size[0] == 0) && ($size[1] != 0))
377
- $size[0] = $size[1];
378
- else if (($size[0] != 0) && ($size[1] == 0))
379
- $size[1] = $size[0];
380
- } else $size= array(get_option('thumbnail_size_w',150),get_option('thumbnail_size_h',150)); // yet another form of junk
 
 
 
381
 
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 = '';
390
- else
391
- $ret = $this->post_thumbnail_html($html,get_the_ID(),$post_thumbnail_id,$size,'');
 
392
  do_action( 'end_fetch_post_thumbnail_html', get_the_ID(), $post_thumbnail_id, $size );
393
 
394
- return $ret;
395
  }
396
 
397
  /**
398
  * Excerpt more link filter
 
 
 
 
399
  */
400
- function excerpt_more_filter($more) {
401
- return ' <a class="cat-post-excerpt-more more-link" href="'. get_permalink() . '">' . esc_html($this->instance["excerpt_more_text"]) . '</a>';
402
  }
403
 
404
  /**
405
  * Apply the_content filter for excerpt
406
  * This should show sharing buttons which comes with other widgets in the widget output in the same way as on the main content
407
  *
408
- * @param string The HTML with other applied excerpt filters
409
- *
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"])
417
- $ret = $text;
418
- else
419
- $ret = apply_filters('the_content', $text);
 
420
  return $ret;
421
  }
422
 
423
  /**
424
  * Excerpt allow HTML
 
 
425
  */
426
- function allow_html_excerpt($text) {
427
  global $post, $wp_filter;
428
- $new_excerpt_length = ( isset($this->instance["excerpt_length"]) && $this->instance["excerpt_length"] > 0 ) ? $this->instance["excerpt_length"] : 55;
429
- if ( '' == $text ) {
430
- $text = get_the_content('');
431
  $text = strip_shortcodes( $text );
432
- $text = apply_filters('the_content', $text);
433
- $text = str_replace('\]\]\>', ']]&gt;', $text);
434
- $text = preg_replace('@<script[^>]*?>.*?</script>@si', '', $text);
435
  $cphtml = array(
436
  '&lt;a&gt;',
437
  '&lt;br&gt;',
@@ -445,194 +602,160 @@ class Widget extends \WP_Widget {
445
  '&lt;script&gt;',
446
  '&lt;style&gt;',
447
  '&lt;video&gt;',
448
- '&lt;audio&gt;'
449
  );
450
- $allowed_HTML = "";
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);
469
- array_push($words, $excerpt_more);
470
- $text = implode(' ', $words);
471
  }
472
  }
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
480
- *
481
- * @param array $instance Array which contains the various settings
482
- * @param bool $no_link indicates whether the thumb should be wrapped in a link or a span
483
- * @return string The HTML for the thumb related to the post
484
- *
485
- * @since 4.6
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
-
493
- $class = '';
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)
508
- $ret .= '<span '.$class.'>';
509
- else
510
- $ret .= '<a '.$class . ' href="'.get_the_permalink().'" title="'.the_title_attribute($title_args).'">';
511
-
512
- $ret .= $this->the_post_thumbnail( array($this->instance['thumb_w'],$this->instance['thumb_h']));
513
-
514
- if ($no_link)
515
- $ret .= '</span>';
516
- else
517
- $ret .= '</a>';
518
- }
519
-
520
- return $ret;
521
- }
522
-
523
  /**
524
  * Calculate the wp-query arguments matching the filter settings of the widget
525
  *
526
- * @param array $instance Array which contains the various settings
527
  * @return array The array that can be fed to wp_Query to get the relevant posts
528
- *
529
- * @since 4.6
530
  */
531
- function queryArgs($instance) {
532
- $valid_sort_orders = array('date', 'title', 'comment_count', 'rand');
533
- if ( isset($instance['sort_by']) && in_array($instance['sort_by'],$valid_sort_orders) ) {
 
534
  $sort_by = $instance['sort_by'];
535
  } else {
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']) {
575
- $args = array_merge( $args, array( 'meta_query' => array(
 
576
  array(
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
  *
590
- * @param string $before_title The sidebar configured HTML that should come
591
- * before the title itself
592
- * @param string $after_title The sidebar configured HTML that should come
593
- * after the title itself
594
- * @param array $instance Array which contains the various settings
595
  * @return string The HTML for the title area
596
- *
597
- * @since 4.6
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"] = '';
605
- if (isset($instance["cat"])) {
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;
617
- if (isset($instance['is_shortcode']))
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)
630
- $ret .= '<a href="' . get_permalink($blog_page) . '">' . $title . '</a>';
631
- else
632
- $ret .= '<a href="' . home_url() . '">' . $title . '</a>';
633
  }
634
- } else
635
  $ret .= $title;
 
636
 
637
  $ret .= $after_title;
638
  }
@@ -640,801 +763,1171 @@ class Widget extends \WP_Widget {
640
  return $ret;
641
  }
642
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
643
  /**
644
  * Calculate the HTML of the footer based on the widget settings
645
  *
646
- * @param array $instance Array which contains the various settings
647
  * @return string The HTML for the footer area
648
- *
649
- * @since 4.6
650
  */
651
- function footerHTML($instance) {
652
 
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
670
- if (!empty($text) && empty($url)) {
671
- if (isset($instance["cat"]) && ($instance["cat"] != 0) && (get_category($instance["cat"]) != null) )
672
- $url = get_category_link($instance["cat"]);
673
- else {
674
- $blog_page = get_option('page_for_posts');
675
- if ($blog_page)
676
- $url = get_permalink($blog_page);
677
- else
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
691
  *
692
- * @param array $instance Array which contains the various settings
693
- * $param null|integer $current_post_id If on singular page specifies the id of
694
- * the post, otherwise null
695
- * @return string The HTML for item related to the post
696
- *
697
- * @since 4.6
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> ';
735
  }
736
- }
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);
763
- }
764
-
765
- // Excerpt
766
- if ( isset( $instance['excerpt'] ) && $instance['excerpt']) {
767
- // use the_excerpt filter to get the "normal" excerpt of the post
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
775
- $excerpt = apply_filters('the_excerpt', \get_the_excerpt() );
776
- } else { // if filters off replicate functionality of core generating excerpt
777
- if ($post->post_excerpt == '') {
778
- $text = get_the_content('');
779
- $text = strip_shortcodes( $text );
780
- $more_text = '[&hellip;]';
781
- if( isset($instance["excerpt_more_text"]) && $instance["excerpt_more_text"] )
782
- $more_text = ltrim($instance["excerpt_more_text"]);
783
-
784
- if ($everything_is_link)
785
- $excerpt_more_text = ' <span class="cat-post-excerpt-more">'.$more_text.'</span>';
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>';
808
- }
809
-
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) {
819
- $ret .= get_the_author();
820
  } else {
821
- $link = sprintf(
822
- '<a href="%1$s" title="%2$s" rel="author">%3$s</a>',
823
- esc_url( get_author_posts_url( $authordata->ID, $authordata->user_nicename ) ),
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
848
  */
849
- function excerpt_length_filter($length) {
850
- if ( isset($this->instance["excerpt_length"]) && $this->instance["excerpt_length"] > 0 )
851
- $length = $this->instance["excerpt_length"];
852
-
853
- return $length;
854
- }
855
 
856
  /**
857
  * Set the proper excerpt filters based on the settings
858
  *
859
- * @param array $instance widget settings
860
  * @return void
861
- *
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
- }
876
 
877
- if( isset( $instance['excerpt_allow_html'] ) ) {
878
- remove_filter('get_the_excerpt', 'wp_trim_excerpt');
879
- add_filter('the_excerpt', array($this,'allow_html_excerpt'));
880
- } else {
881
- add_filter('the_excerpt', array($this,'apply_the_excerpt'));
882
- }
883
- }
884
- }
885
 
886
  /**
887
  * Remove the excerpt filter
888
  *
889
- * @param array $instance widget settings
890
  * @return void
891
- *
892
- * @since 4.6
893
  */
894
- function removeExcerpFilters($instance) {
895
- remove_filter('excerpt_length', array($this,'excerpt_length_filter'));
896
- remove_filter('excerpt_more', array($this,'excerpt_more_filter'));
897
- add_filter('get_the_excerpt', 'wp_trim_excerpt');
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
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
912
  */
913
- function widget($args, $instance) {
 
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
 
925
- $current_post_id = null;
926
- if (is_singular())
927
- $current_post_id = get_the_ID();
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){
954
- // enque relevant scripts and parameters to perform cropping
955
- // once we support only 4.5+ it can be refactored to use wp_add_inline_script
956
- wp_enqueue_script( 'jquery'); // just in case the theme or other plugins didn't enqueue it
957
- add_action('wp_footer', __NAMESPACE__.'\change_cropped_image_dimensions', 100); // add to the footer the cropping script
958
- $number = $this->number;
959
- // a temporary hack to handle difference in the number in a true 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
977
  *
978
- * @param array $new_instance
979
- * @param array $old_instance
980
- * @return array
 
 
 
 
 
 
 
 
 
 
981
  */
982
- function update($new_instance, $old_instance) {
983
 
984
- $new_instance['title'] = sanitize_text_field( $new_instance['title'] ); // sanitize the title like core widgets do
985
- if (!isset($new_instance['excerpt_filters']))
986
- $new_instance['excerpt_filters'] = '';
987
- return $new_instance;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
988
  }
989
 
990
  /**
991
- * Output the title panel of the widget configuration form.
992
  *
993
- * @param array $instance
994
- * @return void
995
- *
996
- * @since 4.6
997
- */
998
- function formTitlePanel($instance) {
999
- $instance = wp_parse_args( ( array ) $instance, array(
1000
- 'title' => '',
1001
- 'title_link' => '',
1002
- 'hide_title' => ''
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>
1011
- <label for="<?php echo $this->get_field_id("title"); ?>">
1012
- <?php _e( 'Title','category-posts' ); ?>:
1013
- <input class="widefat" style="width:80%;" id="<?php echo $this->get_field_id("title"); ?>" name="<?php echo $this->get_field_name("title"); ?>" type="text" value="<?php echo esc_attr($instance["title"]); ?>" />
1014
- </label>
1015
- </p>
1016
- <p>
1017
- <label for="<?php echo $this->get_field_id("title_link"); ?>">
1018
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("title_link"); ?>" name="<?php echo $this->get_field_name("title_link"); ?>"<?php checked( (bool) $instance["title_link"], true ); ?> />
1019
- <?php _e( 'Make widget title link','category-posts' ); ?>
1020
- </label>
1021
- </p>
1022
- <p>
1023
- <label for="<?php echo $this->get_field_id("hide_title"); ?>">
1024
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("hide_title"); ?>" name="<?php echo $this->get_field_name("hide_title"); ?>"<?php checked( (bool) $instance["hide_title"], true ); ?> />
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
  *
1035
- * @param array $instance
1036
- * @return void
1037
- *
1038
- * @since 4.6
1039
  */
1040
- function formFilterPanel($instance) {
1041
- $instance = wp_parse_args( ( array ) $instance, array(
1042
- 'cat' => 0,
1043
- 'num' => get_option('posts_per_page'),
1044
- 'offset' => 1,
1045
- 'sort_by' => '',
1046
- 'status' => '',
1047
- 'asc_sort_order' => '',
1048
- 'exclude_current_post' => '',
1049
- 'hideNoThumb' => '',
1050
- 'no_cat_childs' => false,
1051
- ));
1052
- $cat = $instance['cat'];
1053
- $num = $instance['num'];
1054
- $offset = $instance['offset'];
1055
- $sort_by = $instance['sort_by'];
1056
- $status = $instance['status'];
1057
- $asc_sort_order = $instance['asc_sort_order'];
1058
- $exclude_current_post = $instance['exclude_current_post'];
1059
- $hideNoThumb = $instance['hideNoThumb'];
1060
- $noCatChilds = $instance['no_cat_childs'];
1061
- ?>
1062
- <h4 data-panel="filter"><?php _e('Filter','category-posts');?></h4>
1063
- <div>
1064
- <p>
1065
- <label>
1066
- <?php _e( 'Category','category-posts' ); ?>:
1067
- <?php wp_dropdown_categories( array( 'show_option_all' => __('All categories','category-posts'), 'hide_empty'=> 0, 'name' => $this->get_field_name("cat"), 'selected' => $instance["cat"], 'class' => 'categoryposts-data-panel-filter-cat' ) ); ?>
1068
- </label>
1069
- </p>
1070
- <p>
1071
- <label for="<?php echo $this->get_field_id("no_cat_childs"); ?>">
1072
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("no_cat_childs"); ?>" name="<?php echo $this->get_field_name("no_cat_childs"); ?>"<?php checked( (bool) $instance["no_cat_childs"], true ); ?> />
1073
- <?php _e( 'Exclude child categories','category-posts' ); ?>
1074
- </label>
1075
- </p>
1076
- <p>
1077
- <label for="<?php echo $this->get_field_id("num"); ?>">
1078
- <?php _e('Number of posts to show','category-posts'); ?>:
1079
- <input style="text-align: center; width: 30%;" id="<?php echo $this->get_field_id("num"); ?>" name="<?php echo $this->get_field_name("num"); ?>" type="number" min="0" value="<?php echo absint($instance["num"]); ?>" />
1080
- </label>
1081
- </p>
1082
- <p>
1083
- <label for="<?php echo $this->get_field_id("offset"); ?>">
1084
- <?php _e('Start with post','category-posts'); ?>:
1085
- <input style="text-align: center; width: 30%;" id="<?php echo $this->get_field_id("offset"); ?>" name="<?php echo $this->get_field_name("offset"); ?>" type="number" min="1" value="<?php echo absint($instance["offset"]); ?>" />
1086
- </label>
1087
- </p>
1088
- <p>
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>
1099
- <p>
1100
- <label for="<?php echo $this->get_field_id("sort_by"); ?>">
1101
- <?php _e('Sort by','category-posts'); ?>:
1102
- <select id="<?php echo $this->get_field_id("sort_by"); ?>" name="<?php echo $this->get_field_name("sort_by"); ?>">
1103
- <option value="date"<?php selected( $instance["sort_by"], "date" ); ?>><?php _e('Date','category-posts')?></option>
1104
- <option value="title"<?php selected( $instance["sort_by"], "title" ); ?>><?php _e('Title','category-posts')?></option>
1105
- <option value="comment_count"<?php selected( $instance["sort_by"], "comment_count" ); ?>><?php _e('Number of comments','category-posts')?></option>
1106
- <option value="rand"<?php selected( $instance["sort_by"], "rand" ); ?>><?php _e('Random','category-posts')?></option>
1107
- </select>
1108
- </label>
1109
- </p>
1110
- <p>
1111
- <label for="<?php echo $this->get_field_id("asc_sort_order"); ?>">
1112
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("asc_sort_order"); ?>" name="<?php echo $this->get_field_name("asc_sort_order"); ?>" <?php checked( (bool) $instance["asc_sort_order"], true ); ?> />
1113
- <?php _e( 'Reverse sort order (ascending)','category-posts' ); ?>
1114
- </label>
1115
- </p>
1116
- <p>
1117
- <label for="<?php echo $this->get_field_id("exclude_current_post"); ?>">
1118
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("exclude_current_post"); ?>" name="<?php echo $this->get_field_name("exclude_current_post"); ?>"<?php checked( (bool) $instance["exclude_current_post"], true ); ?> />
1119
- <?php _e( 'Exclude current post','category-posts' ); ?>
1120
- </label>
1121
- </p>
1122
- <p>
1123
- <label for="<?php echo $this->get_field_id("hideNoThumb"); ?>">
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
- *
1135
- * @param array $instance
1136
- * @return void
1137
- *
1138
- * @since 4.6
1139
- */
1140
- function formThumbnailPanel($instance) {
1141
- $instance = wp_parse_args( ( array ) $instance, array(
1142
- 'thumb' => '',
1143
- 'thumbTop' => '',
1144
- 'thumb_w' => get_option('thumbnail_size_w',150),
1145
- 'thumb_h' => get_option('thumbnail_size_h',150),
1146
- 'use_css_cropping' => '',
1147
- 'thumb_hover' => '',
1148
- 'default_thunmbnail' => 0,
1149
- ));
1150
- $thumb = $instance['thumb'];
1151
- $thumbTop = $instance['thumbTop'];
1152
- $thumb_w = $instance['thumb_w'];
1153
- $thumb_h = $instance['thumb_h'];
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>
1161
- <label for="<?php echo $this->get_field_id("thumb"); ?>">
1162
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("thumb"); ?>" name="<?php echo $this->get_field_name("thumb"); ?>"<?php checked( (bool) $instance["thumb"], true ); ?> />
1163
- <?php _e( 'Show post thumbnail','category-posts' ); ?>
1164
- </label>
1165
- </p>
1166
- <p>
1167
- <label for="<?php echo $this->get_field_id("thumbTop"); ?>">
1168
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("thumbTop"); ?>" name="<?php echo $this->get_field_name("thumbTop"); ?>"<?php checked( (bool) $instance["thumbTop"], true ); ?> />
1169
- <?php _e( 'Show thumbnails above text','category-posts' ); ?>
1170
- </label>
1171
- </p>
1172
- <p>
1173
- <label>
1174
- <?php _e('Thumbnail dimensions (in pixels)','category-posts'); ?><br />
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>
1182
- </label>
1183
- </p>
1184
- <p>
1185
- <label for="<?php echo $this->get_field_id("use_css_cropping"); ?>">
1186
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("use_css_cropping"); ?>" name="<?php echo $this->get_field_name("use_css_cropping"); ?>"<?php checked( (bool) $instance["use_css_cropping"], true ); ?> />
1187
- <?php _e( 'CSS crop to requested size ','category-posts' ); ?>
1188
- </label>
1189
- </p>
1190
- <p>
1191
- <label for="<?php echo $this->get_field_id("thumb_hover"); ?>">
1192
- <?php _e( 'Animation on mouse hover:','category-posts' ); ?>
1193
- </label>
1194
- <select id="<?php echo $this->get_field_id("thumb_hover"); ?>" name="<?php echo $this->get_field_name("thumb_hover"); ?>">
1195
- <option value="none" <?php selected($thumb_hover, 'none')?>><?php _e( 'None', 'category-posts' ); ?></option>
1196
- <option value="dark" <?php selected($thumb_hover, 'dark')?>><?php _e( 'Darker', 'category-posts' ); ?></option>
1197
- <option value="white" <?php selected($thumb_hover, 'white')?>><?php _e( 'Brighter', 'category-posts' ); ?></option>
1198
- <option value="scale" <?php selected($thumb_hover, 'scale')?>><?php _e( 'Zoom in', 'category-posts' ); ?></option>
1199
- <option value="blur" <?php selected($thumb_hover, 'blur')?>><?php _e( 'Blur', 'category-posts' ); ?></option>
1200
- </select>
1201
- </p>
1202
- <p>
1203
- <label style="display:block">
1204
- <?php _e( 'Default thumbnail: ','category-posts' ); ?>
1205
- </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);
1213
- echo '<img width="60" height="60" src="'.$img[0].'" />';
1214
- }
1215
- ?>
1216
- </span>
1217
- </p>
1218
- <p>
1219
- <button type="button" class="cwp_default_thumb_select button upload-button">
1220
- <?php _e('Select image','category-posts')?>
1221
- </button>
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
  *
1233
- * @param array $instance
1234
  * @return void
1235
  */
1236
- function form($instance) {
1237
- if (count($instance) == 0) { // new widget, use defaults
1238
- $instance = default_settings();
1239
- } else { // updated widgets come from =< 4.6 excerpt filter is on
1240
- if (!isset($instance['excerpt_filters']))
1241
- $instance['excerpt_filters'] = 'on';
1242
- }
1243
- $instance = wp_parse_args( ( array ) $instance, array(
1244
- 'everything_is_link' => false,
1245
- 'footer_link_text' => '',
1246
- 'footer_link' => '',
1247
- 'hide_post_titles' => '',
1248
- 'excerpt' => '',
1249
- 'excerpt_length' => 55,
1250
- 'excerpt_more_text' => '',
1251
- 'excerpt_filters' => '',
1252
- 'comment_num' => '',
1253
- 'author' => '',
1254
- 'date' => '',
1255
- 'date_link' => '',
1256
- 'date_format' => '',
1257
- 'disable_css' => '',
1258
- 'disable_font_styles' => '',
1259
- 'hide_if_empty' => '',
1260
- 'hide_social_buttons' => '',
 
 
1261
  ) );
1262
 
1263
- $everything_is_link = $instance['everything_is_link'];
1264
- $footer_link_text = $instance['footer_link_text'];
1265
- $footer_link = $instance['footer_link'];
1266
  $hide_post_titles = $instance['hide_post_titles'];
1267
  $excerpt = $instance['excerpt'];
1268
- $excerpt_length = $instance['excerpt_length'];
1269
  $excerpt_more_text = $instance['excerpt_more_text'];
1270
  $excerpt_filters = $instance['excerpt_filters'];
1271
- $comment_num = $instance['comment_num'];
1272
- $author = $instance['author'];
1273
  $date = $instance['date'];
1274
- $date_link = $instance['date_link'];
1275
  $date_format = $instance['date_format'];
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">
1286
- .cpwp_ident {
1287
  color: #6A6A6A;
1288
  background: #F1F1F1;
1289
- padding: 5px 10px;
1290
- }
1291
- .cpwp_ident > .cpwp_ident {
1292
- border-left:5px solid #B3B3B3;
1293
  padding: 0 10px;
1294
- }
1295
  .cpwp_ident > p {
1296
  margin: 5px 0;
1297
  }
1298
  .cpwp_ident > label {
1299
  line-height: 2.75;
1300
- display: inline-block;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1301
  }
1302
- .cpwp_ident_top {
1303
- margin-top:-1em;
1304
- padding-top:1em;
1305
- }
1306
- </style>
1307
 
1308
- <?php
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
1316
- $this->formTitlePanel($instance);
1317
- $this->formFilterPanel($instance);
1318
- $this->formThumbnailPanel($instance);
1319
- ?>
1320
- <h4 data-panel="details"><?php _e('Post details','category-posts')?></h4>
1321
  <div>
1322
- <p>
1323
- <label for="<?php echo $this->get_field_id("everything_is_link"); ?>">
1324
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("everything_is_link"); ?>" name="<?php echo $this->get_field_name("everything_is_link"); ?>"<?php checked( (bool) $everything_is_link, true ); ?> />
1325
- <?php _e( 'Everything is a link','category-posts' ); ?>
1326
- </label>
1327
- </p>
1328
- <p>
1329
- <label for="<?php echo $this->get_field_id("hide_post_titles"); ?>">
1330
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("hide_post_titles"); ?>" name="<?php echo $this->get_field_name("hide_post_titles"); ?>"<?php checked( (bool) $instance["hide_post_titles"], true ); ?> />
1331
- <?php _e( 'Hide post titles','category-posts' ); ?>
1332
- </label>
1333
- </p>
1334
- <p>
1335
- <label for="<?php echo $this->get_field_id("excerpt"); ?>" onchange="javascript:cwp_namespace.toggleExcerptPanel(this)">
1336
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("excerpt"); ?>" name="<?php echo $this->get_field_name("excerpt"); ?>"<?php checked( (bool) $instance["excerpt"], true ); ?> />
1337
- <?php _e( 'Show post excerpt','category-posts' ); ?>
1338
- </label>
1339
- </p>
1340
- <div class="cpwp_ident categoryposts-data-panel-excerpt" style="display:<?php echo ((bool) $excerpt) ? 'block' : 'none'?>">
1341
- <p>
1342
- <label for="<?php echo $this->get_field_id("excerpt_length"); ?>">
1343
- <?php _e( 'Excerpt length (in words):','category-posts' ); ?>
1344
- </label>
1345
- <input style="text-align: center; width:30%;" type="number" min="0" id="<?php echo $this->get_field_id("excerpt_length"); ?>" name="<?php echo $this->get_field_name("excerpt_length"); ?>" value="<?php echo $instance["excerpt_length"]; ?>" />
1346
- </p>
1347
- <p>
1348
- <label for="<?php echo $this->get_field_id("excerpt_more_text"); ?>">
1349
- <?php _e( 'Excerpt \'more\' text:','category-posts' ); ?>
1350
- </label>
1351
- <input class="widefat" style="width:45%;" placeholder="<?php _e('... more','category-posts')?>" id="<?php echo $this->get_field_id("excerpt_more_text"); ?>" name="<?php echo $this->get_field_name("excerpt_more_text"); ?>" type="text" value="<?php echo esc_attr($instance["excerpt_more_text"]); ?>" />
1352
- </p>
1353
- <p>
1354
- <label for="<?php echo $this->get_field_id("excerpt_filters"); ?>">
1355
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("excerpt_filters"); ?>" name="<?php echo $this->get_field_name("excerpt_filters"); ?>"<?php checked( !empty($excerpt_filters), true ); ?> />
1356
- <?php _e( 'Don\'t override Themes and plugin filters','category-posts' ); ?>
1357
- </label>
1358
- </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1359
  </div>
1360
- <p>
1361
- <label for="<?php echo $this->get_field_id("date"); ?>" onchange="javascript:cwp_namespace.toggleDatePanel(this)">
1362
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("date"); ?>" name="<?php echo $this->get_field_name("date"); ?>"<?php checked( (bool) $instance["date"], true ); ?> />
1363
- <?php _e( 'Show post date','category-posts' ); ?>
1364
- </label>
1365
- </p>
1366
- <div class="cpwp_ident categoryposts-data-panel-date" style="display:<?php echo ((bool) $date) ? 'block' : 'none'?>">
1367
- <p>
1368
- <label for="<?php echo $this->get_field_id("date_format"); ?>">
1369
- <?php _e( 'Date format:','category-posts' ); ?>
1370
- </label>
1371
- <input class="text" placeholder="j M Y" id="<?php echo $this->get_field_id("date_format"); ?>" name="<?php echo $this->get_field_name("date_format"); ?>" type="text" value="<?php echo esc_attr($instance["date_format"]); ?>" size="8" />
1372
- </p>
1373
- <p>
1374
- <label for="<?php echo $this->get_field_id("date_link"); ?>">
1375
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("date_link"); ?>" name="<?php echo $this->get_field_name("date_link"); ?>"<?php checked( (bool) $instance["date_link"], true ); ?> />
1376
- <?php _e( 'Make widget date link','category-posts' ); ?>
1377
- </label>
1378
- </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1379
  </div>
1380
- <p>
1381
- <label for="<?php echo $this->get_field_id("comment_num"); ?>">
1382
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("comment_num"); ?>" name="<?php echo $this->get_field_name("comment_num"); ?>"<?php checked( (bool) $instance["comment_num"], true ); ?> />
1383
- <?php _e( 'Show number of comments','category-posts' ); ?>
1384
- </label>
1385
- </p>
1386
- <p>
1387
- <label for="<?php echo $this->get_field_id("author"); ?>">
1388
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("author"); ?>" name="<?php echo $this->get_field_name("author"); ?>"<?php checked( (bool) $instance["author"], true ); ?> />
1389
- <?php _e( 'Show post author','category-posts' ); ?>
1390
- </label>
1391
- </p>
1392
  </div>
1393
- <h4 data-panel="general"><?php _e('General','category-posts')?></h4>
1394
  <div>
1395
- <p onchange="javascript:cwp_namespace.toggleDisableFontStyles(this)">
1396
- <label for="<?php echo $this->get_field_id("disable_css"); ?>">
1397
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("disable_css"); ?>" name="<?php echo $this->get_field_name("disable_css"); ?>"<?php checked( (bool) $instance["disable_css"], true ); ?> />
1398
- <?php _e( 'Disable the built-in CSS for this widget','category-posts' ); ?>
1399
- </label>
1400
- </p>
1401
- <p class="categoryposts-data-panel-general-disable-font-styles" style="display:<?php echo ((bool) $disable_css) ? 'none' : 'block'?>">
1402
- <label for="<?php echo $this->get_field_id("disable_font_styles"); ?>">
1403
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("disable_font_styles"); ?>" name="<?php echo $this->get_field_name("disable_font_styles"); ?>"<?php checked( (bool) $instance["disable_font_styles"], true ); ?> />
1404
- <?php _e( 'Disable only font styles for this widget','category-posts' ); ?>
1405
- </label>
1406
- </p>
1407
- <p>
1408
- <label for="<?php echo $this->get_field_id("hide_if_empty"); ?>">
1409
- <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("hide_if_empty"); ?>" name="<?php echo $this->get_field_name("hide_if_empty"); ?>"<?php checked( (bool) $instance["hide_if_empty"], true ); ?> />
1410
- <?php _e( 'Hide widget if there are no matching posts','category-posts' ); ?>
1411
- </label>
1412
- </p>
1413
  </div>
1414
- <h4 data-panel="footer"><?php _e('Footer','category-posts')?></h4>
1415
  <div>
1416
- <p>
1417
- <label for="<?php echo $this->get_field_id("footer_link_text"); ?>">
1418
- <?php _e( 'Footer link text','category-posts' ); ?>:
1419
- <input class="widefat" style="width:60%;" placeholder="<?php _e('... more by this topic','category-posts')?>" id="<?php echo $this->get_field_id("footer_link_text"); ?>" name="<?php echo $this->get_field_name("footer_link_text"); ?>" type="text" value="<?php echo esc_attr($instance["footer_link_text"]); ?>" />
1420
- </label>
1421
- </p>
1422
- <p class="categoryposts-data-panel-footer-footerLink">
1423
- <label for="<?php echo $this->get_field_id("footer_link"); ?>">
1424
- <?php _e( 'Footer link URL','category-posts' ); ?>:
1425
- <input class="widefat" style="width:60%;" placeholder="<?php _e('... URL of more link','category-posts')?>" id="<?php echo $this->get_field_id("footer_link"); ?>" name="<?php echo $this->get_field_name("footer_link"); ?>" type="text" value="<?php echo esc_attr($instance["footer_link"]); ?>" />
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>
1433
  <?php
1434
  }
1435
  }
1436
 
1437
- // Plugin action links section
 
 
1438
 
1439
  /**
1440
  * Applied to the list of links to display on the plugins page (beside the activate/deactivate links).
@@ -1443,23 +1936,32 @@ class Widget extends \WP_Widget {
1443
  *
1444
  * @since 4.6.3
1445
  */
1446
- add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), __NAMESPACE__.'\add_action_links' );
1447
 
1448
- function add_action_links ( $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
 
 
 
 
1458
  function register_widget() {
1459
- return \register_widget(__NAMESPACE__.'\Widget');
1460
  }
1461
 
1462
- add_action( 'widgets_init', __NAMESPACE__.'\register_widget' );
1463
 
1464
  /**
1465
  * Output js code to handle responsive thumbnails
@@ -1467,8 +1969,7 @@ add_action( 'widgets_init', __NAMESPACE__.'\register_widget' );
1467
  * @return void
1468
  *
1469
  * @since 4.7
1470
- *
1471
- **/
1472
  function change_cropped_image_dimensions() {
1473
  ?>
1474
  <script type="text/javascript">
@@ -1477,28 +1978,28 @@ function change_cropped_image_dimensions() {
1477
 
1478
  jQuery( document ).ready(function () {
1479
 
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
 
1493
- <?php /* variables */ ?>
1494
  this.self = _self;
1495
  this.imageRatio = _imageRatio;
1496
  },
1497
 
1498
- <?php /* class */ ?>
1499
  WidgetPosts : function (widget, ratio) {
1500
 
1501
- <?php /* variables */ ?>
1502
  this.Spans = {};
1503
  this.allSpans = widget.find( '.cat-post-crop' );
1504
  this.firstSpan = this.allSpans.first();
@@ -1511,14 +2012,14 @@ function change_cropped_image_dimensions() {
1511
  this.Spans[i] = new cwp_namespace.fluid_images.Span( jQuery(this.allSpans[i]), imageRatio );
1512
  }
1513
 
1514
- <?php /* functions */ ?>
1515
  this.changeImageSize = function changeImageSize() {
1516
 
1517
  this.listItemWidth = this.firstListItem.width();
1518
  this.SpanWidth = this.firstSpan.width();
1519
 
1520
- if(this.listItemWidth < this.SpanWidth || <?php /* if the layout-width have not enough space to show the regular source-width */ echo "\r\n" ?>
1521
- this.listItemWidth < this.maxSpanWidth) { <?php /* defined start and stop working width for the image: Accomplish only the image width will be get smaller as the source-width */ echo "\r\n" ?>
1522
  this.allSpans.width( this.listItemWidth );
1523
  var spanHeight = this.listItemWidth / this.ratio;
1524
  this.allSpans.height( spanHeight );
@@ -1535,22 +2036,22 @@ function change_cropped_image_dimensions() {
1535
  },
1536
  }
1537
 
1538
- <?php
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
  */
1546
- $widgets_ids = apply_filters('cpw_crop_widgets',array());
1547
- foreach ($widgets_ids as $number => $ratio) {
1548
- ?>
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();
@@ -1562,7 +2063,9 @@ function change_cropped_image_dimensions() {
1562
  <?php
1563
  }
1564
 
1565
- // shortcode section
 
 
1566
 
1567
  /**
1568
  * Get shortcode settings taking into account if it is being customized
@@ -1570,26 +2073,35 @@ function change_cropped_image_dimensions() {
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) {
1580
- $meta = get_post_meta(get_the_ID(),SHORTCODE_META,true);
1581
 
1582
- if (!empty($meta) && !is_array(reset($meta)))
1583
- $meta = array ('' => $meta); // the coversion
 
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;
@@ -1598,56 +2110,56 @@ function shortcode_settings($name) {
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
 
1625
- add_shortcode(SHORTCODE_NAME,__NAMESPACE__.'\shortcode');
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) {
1646
- if ($shortcode == SHORTCODE_NAME) {
1647
- $name ='';
1648
- $atts = shortcode_parse_atts( $matches[3][$k] );
1649
- if (! empty( $atts['name']))
1650
  $name = $atts['name'];
 
1651
  $names[] = $name;
1652
  }
1653
  }
@@ -1657,48 +2169,48 @@ function shortcode_names($shortcode_name,$content) {
1657
  }
1658
 
1659
  /**
1660
- * Organized way to have rhw default widget settings accessible
1661
  *
1662
  * @since 4.6
1663
  */
1664
- function default_settings() {
1665
- return array(
1666
- 'title' => '',
1667
- 'title_link' => false,
1668
- 'hide_title' => false,
1669
- 'cat' => 0,
1670
- 'num' => get_option('posts_per_page'),
1671
- 'offset' => 1,
1672
- 'sort_by' => 'date',
1673
- 'status' => 'publish',
1674
- 'asc_sort_order' => false,
1675
- 'exclude_current_post' => false,
1676
- 'hideNoThumb' => false,
1677
- 'footer_link_text' => '',
1678
- 'footer_link' => '',
1679
- 'thumb' => false,
1680
- 'thumbTop' => false,
1681
- 'thumb_w' => get_option('thumbnail_size_w',150),
1682
- 'thumb_h' => get_option('thumbnail_size_h',150),
1683
- 'use_css_cropping' => false,
1684
- 'thumb_hover' => 'none',
1685
- 'hide_post_titles' => false,
1686
- 'excerpt' => false,
1687
- 'excerpt_length' => 55,
1688
- 'excerpt_more_text' => '',
1689
- 'excerpt_filters' => false,
1690
- 'comment_num' => false,
1691
- 'author' => false,
1692
- 'date' => false,
1693
- 'date_link' => false,
1694
- 'date_format' => '',
1695
- 'disable_css' => false,
1696
- 'disable_font_styles' => false,
1697
- 'hide_if_empty' => false,
1698
- 'hide_social_buttons' => '',
1699
- 'no_cat_childs' => false,
1700
- 'everything_is_link' => false,
1701
- );
1702
  }
1703
 
1704
  /**
@@ -1706,168 +2218,202 @@ function default_settings() {
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) {
1716
 
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
 
1732
- // remove setting for unused names
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();
1740
  }
1741
  }
1742
 
1743
- delete_post_meta($pid,SHORTCODE_META);
1744
- if (!empty($meta))
1745
- add_post_meta($pid,SHORTCODE_META,$meta,true);
 
1746
  }
1747
 
1748
- add_action('save_post',__NAMESPACE__.'\save_post',10,2);
1749
 
1750
- function customize_register($wp_customize) {
 
 
 
 
 
1751
 
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
  ?>
1759
  <div class="widget-top">
1760
- <div class="widget-title"><h3><?php echo $widget_title; ?><span class="in-widget-title"></span></h3></div>
1761
  </div>
1762
  <div class="widget-inside" style="display: block;">
1763
  <div class="form">
1764
  <div class="widget-content">
1765
- <?php echo $this->form; ?>
1766
  </div>
1767
  </div>
1768
  </div>
1769
  <?php
1770
- }
1771
- }
1772
-
1773
- $args = array(
1774
- 'post_type' => 'any',
1775
- 'post_status' => 'any',
1776
- 'posts_per_page' => -1,
1777
- 'update_post_term_cache' => false,
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);
 
 
 
 
 
 
 
1828
  $form = ob_get_clean();
1829
- $form = preg_replace_callback('/<(input|select)\s+.*name=("|\').*\[\w*\]\[([^\]]*)\][^>]*>/',
1830
- function ($matches) use ($p, $wp_customize, $m, $k) {
1831
- $setting = '_virtual-'.WIDGET_BASE_ID.'['.$p->ID.']['.$k.']['.$matches[3].']';
1832
- if (!isset($m[$matches[3]]))
1833
- $m[$matches[3]] = null;
 
1834
  $wp_customize->add_setting( $setting, array(
1835
- 'default' => $m[$matches[3]], // set default to current value
1836
- 'type' => 'option'
1837
  ) );
1838
 
1839
- return str_replace('<'.$matches[1],'<'.$matches[1].' data-customize-setting-link="'.$setting.'"',$matches[0]);
1840
  },
1841
  $form
1842
  );
1843
 
1844
  $args = array(
1845
- 'label' => __( 'Layout', 'twentyfourteen' ),
1846
- 'section' => __NAMESPACE__.'-'.$p->id.'-'.$k,
1847
- 'form' => $form,
1848
- 'settings' => '_virtual-'.WIDGET_BASE_ID.'['.$p->ID.']['.$k.'][title]',
1849
- 'active_callback' => function () use ($p) { return is_singular() && (get_the_ID()==$p->ID); }
1850
- );
1851
-
1852
- if (get_option('page_on_front') == $p->ID) {
1853
- $args['active_callback'] = function () { return is_front_page(); };
 
 
 
 
1854
  }
1855
 
1856
  $sc = new shortCodeControl(
1857
  $wp_customize,
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);
 
1865
  }
1866
- }
1867
- }
1868
  }
1869
 
1870
- add_action( 'customize_register', __NAMESPACE__.'\customize_register' );
1871
 
1872
  /**
1873
  * Save the virtual option used by the customizer into the proper meta values.
@@ -1880,28 +2426,32 @@ add_action( 'customize_register', __NAMESPACE__.'\customize_register' );
1880
  * @since 4.6
1881
  */
1882
  function customize_save_after() {
1883
- $virtual = get_option('_virtual-'.WIDGET_BASE_ID);
1884
 
1885
- if (is_array($virtual)) {
1886
- foreach ($virtual as $pid => $instance) {
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);
 
1894
  }
1895
- }
1896
- update_post_meta($pid,SHORTCODE_META, $meta);
1897
- }
1898
 
1899
- delete_option('_virtual-'.WIDGET_BASE_ID);
1900
  }
1901
 
1902
- add_action('customize_save_after', __NAMESPACE__.'\customize_save_after', 100);
1903
 
1904
- // tinymce related functions
 
 
1905
 
1906
  /**
1907
  * Uninstall handler, cleanup DB from options and meta
@@ -1911,159 +2461,213 @@ add_action('customize_save_after', __NAMESPACE__.'\customize_save_after', 100);
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
 
1919
- register_uninstall_hook(__FILE__, __NAMESPACE__.'uninstall');
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
1929
  */
1930
- function mce_external_plugins($plugin_array)
1931
- {
1932
- if (current_user_can('edit_theme_options')) { // don't load the code if the user can not customize the shortcode
1933
- //enqueue TinyMCE plugin script with its ID.
1934
- $meta = get_user_meta(get_current_user_id(),__NAMESPACE__,true);
1935
- if (is_array($meta) && isset($meta['editor']))
1936
  ;
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
 
1944
- add_filter("mce_external_plugins", __NAMESPACE__."\mce_external_plugins");
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
1954
  */
1955
- function mce_buttons($buttons)
1956
- {
1957
- if (current_user_can('edit_theme_options')) { // don't load the code if the user can not customize the shortcode
1958
- //register buttons with their id.
1959
- $meta = get_user_meta(get_current_user_id(),__NAMESPACE__,true);
1960
- if (is_array($meta) && isset($meta['editor']))
1961
  ;
1962
- else
1963
- array_push($buttons, __NAMESPACE__);
 
1964
  }
1965
- return $buttons;
 
1966
  }
1967
 
1968
- add_filter("mce_buttons", __NAMESPACE__."\mce_buttons");
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) {
1980
- if (current_user_can('edit_theme_options')) // don't load the code if the user can not customize the shortcode
1981
- $meta = get_user_meta(get_current_user_id(),__NAMESPACE__,true);
1982
- if (is_array($meta) && isset($meta['editor']))
1983
  ;
1984
- else
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
 
 
1992
 
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;
 
2000
 
2001
- if ( !current_user_can( 'edit_theme_options', $user->ID ) )
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;
 
2016
  ?>
2017
- <h3 id="<?php echo __NAMESPACE__ ?>"><?php _e('Category Posts Widget behaviour settings','category-posts')?></h3>
2018
 
2019
  <table class="form-table">
2020
  <tr>
2021
- <th><label for="<?php echo __NAMESPACE__?>[panels]"><?php _e('Open panels behavior','category-posts')?></label></th>
2022
  <td>
2023
- <input type="checkbox" name="<?php echo __NAMESPACE__?>[panels]" id="<?php echo __NAMESPACE__?>[panels]" <?php checked($accordion); ?>>
2024
- <label for=<?php echo __NAMESPACE__?>[panels]><?php _e('Close the curremtly open panel when opening a new one','category-posts')?></label>
2025
  </td>
2026
  </tr>
2027
  <tr>
2028
- <th><label for="<?php echo __NAMESPACE__?>[editor]"><?php _e('Visual editor button','category-posts')?></label></th>
2029
  <td>
2030
- <input type="checkbox" name="<?php echo __NAMESPACE__?>[editor]" id="<?php echo __NAMESPACE__?>[editor]" <?php checked($editor); ?>>
2031
- <label for="<?php echo __NAMESPACE__?>[editor]"><?php _e('Hide the "insert shortcode" button from the editor','category-posts')?></label>
2032
  </td>
2033
  </tr>
2034
  </table>
2035
  <?php
2036
  }
2037
 
2038
- add_action( 'personal_options_update', __NAMESPACE__.'\personal_options_update' );
2039
- add_action( 'edit_user_profile_update', __NAMESPACE__.'\personal_options_update' );
2040
 
 
 
 
 
 
 
 
2041
  function personal_options_update( $user_id ) {
2042
 
2043
- if ( !current_user_can( 'edit_user', $user_id ) )
2044
  return false;
 
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
  /**
@@ -2071,46 +2675,51 @@ class virtualWidget {
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) {
2083
  $this->id = $id;
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();
2104
- $args = self::$collection[$this->id];
2105
- $args['is_shortcode'] = true; // indicate that we are doing shortcode processing to outputting funtions
2106
  $widget->widget(array(
2107
- 'before_widget' => '',
2108
- 'after_widget' => '',
2109
- 'before_title' => '',
2110
- 'after_title' => ''
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
 
@@ -2123,113 +2732,207 @@ class virtualWidget {
2123
  *
2124
  * @since 4.7
2125
  */
2126
- function renderHTML() {
2127
  echo $this->getHTML();
2128
  }
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;}',
2148
- '.cat-post-date {margin-bottom: 10px;}',
2149
- '.cat-post-author {margin-bottom: 0;}',
2150
- '.cat-post-thumbnail {margin: 5px 10px 5px 0; display: block;}',
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;}';
2158
- $rules[] = '.cat-post-current .cat-post-title {font-weight: bold; text-transform: uppercase;}';
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')) {
2170
- $rules[] = '.cat-post-item {list-style: none; list-style-type: none; margin: 3px 0; padding: 3px 0;}';
2171
  } else {
2172
- $rules[] = '.cat-post-item {border-bottom: 1px solid #ccc; list-style: none; list-style-type: none; margin: 3px 0; padding: 3px 0;}';
2173
- $rules[] = '.cat-post-item:last-child {border-bottom: none;}';
2174
  }
2175
 
2176
- if (!(isset($settings['thumbTop']) && $settings['thumbTop'])) {
2177
- $rules[] = '.cat-post-thumbnail {float:left;}';
 
 
 
 
2178
  }
2179
 
2180
- if (isset($settings['thumb_hover'])) {
2181
- switch ($settings['thumb_hover']) {
2182
- case 'white':
2183
- $rules[] = '.cat-post-white img {padding-bottom: 0 !important; -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -ms-transition: all 0.3s ease; -o-transition: all 0.3s ease; transition: all 0.3s ease;}';
2184
- $rules[] = '.cat-post-white {background-color: white;}';
2185
- $rules[] = '.cat-post-white img:hover {opacity: 0.8;}';
2186
- break;
2187
- case 'dark':
2188
- $rules[] = '.cat-post-dark img {padding-bottom: 0 !important; -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -ms-transition: all 0.3s ease; -o-transition: all 0.3s ease; transition: all 0.3s ease;}';
2189
- $rules[] = '.cat-post-dark img:hover {-webkit-filter: brightness(75%); -moz-filter: brightness(75%); -ms-filter: brightness(75%); -o-filter: brightness(75%); filter: brightness(75%);}';
2190
- break;
2191
- case 'scale':
2192
- $rules[] = '.cat-post-scale img {margin: initial; padding-bottom: 0 !important; -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -ms-transition: all 0.3s ease; -o-transition: all 0.3s ease; transition: all 0.3s ease;}';
2193
- $rules[] = '.cat-post-scale img:hover {-webkit-transform: scale(1.1, 1.1); -ms-transform: scale(1.1, 1.1); transform: scale(1.1, 1.1);}';
2194
- break;
2195
- case 'blur':
2196
- $rules[] = '.cat-post-blur img {padding-bottom: 0 !important; -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -ms-transition: all 0.3s ease; -o-transition: all 0.3s ease; transition: all 0.3s ease;}';
2197
- $rules[] = '.cat-post-blur img:hover {-webkit-filter: blur(2px); -moz-filter: blur(2px); -o-filter: blur(2px); -ms-filter: blur(2px); filter: blur(2px);}';
2198
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2199
  }
2200
  }
2201
 
2202
- // everything link related styling
2203
- // if we are dealing with "everything is a link" option, we need to add the clear:both to the a element, not the div
2204
- if (isset( $settings['everything_is_link'] ) && $settings['everything_is_link']) {
2205
- $rules[] = '.cat-post-everything-is-link { }';
2206
- $rules[] = '.cat-post-item a:after {content: ""; display: table; clear: both;}';
2207
- } else {
2208
- $rules[] = '.cat-post-item:after {content: ""; display: table; clear: both;}';
2209
- }
2210
-
2211
- foreach ($rules as $rule) {
2212
- $ret[] = '#'.$widget_id.' '.$rule;
2213
  }
2214
 
2215
- if ($is_shortcode) {
2216
  // Twenty Sixteen Theme adds underlines to links with box whadow wtf ...
2217
- $ret[] = '#'.$widget_id.' .cat-post-thumbnail {box-shadow:none}'; // this for the thumb link
 
 
 
 
2218
  // Twenty Fifteen Theme adds border ...
2219
- $ret[] = '#'.$widget_id.' .cat-post-thumbnail {border:0}'; // this for the thumb link
2220
- // probably all Themes have too much margin on their p element when used in the shortcode
2221
- $ret[] = '#'.$widget_id.' p {margin:5px 0 0 0}'; /* since on bottom it will make the spacing on cover
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}';
2229
- else
2230
- $ret[] = '#'.$widget_id.' .cat-post-thumbnail span {overflow: hidden; display:block}';
2231
- $ret[] = '#'.$widget_id.' .cat-post-item img {margin: initial;}';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2232
  }
 
2233
  }
2234
 
2235
  /**
@@ -2237,17 +2940,18 @@ class virtualWidget {
2237
  *
2238
  * Just a wrapper that output getCSSRules
2239
  *
2240
- * @return void
2241
  *
2242
  * @since 4.7
2243
  */
2244
- function outputCSS($is_shortcode) {
2245
  $rules = array();
2246
- getCSSRules($is_shortcode, $rules);
2247
- foreach ($rules as $rule) {
2248
  echo "$rule\n";
2249
  }
2250
  }
 
2251
  /**
2252
  * Get the id the virtual widget was registered with
2253
  *
@@ -2255,7 +2959,7 @@ class virtualWidget {
2255
  *
2256
  * @since 4.7
2257
  */
2258
- function id() {
2259
  return $this->id;
2260
  }
2261
 
@@ -2266,7 +2970,7 @@ class virtualWidget {
2266
  *
2267
  * @since 4.7
2268
  */
2269
- static function getAllSettings() {
2270
  return self::$collection;
2271
  }
2272
 
@@ -2279,19 +2983,35 @@ class virtualWidget {
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) {
2294
- self::$shortcodeCollection[$index] = $widget;
2295
  }
2296
 
2297
  /**
@@ -2301,20 +3021,20 @@ class virtualWidgetsRepository {
2301
  *
2302
  * @since 4.7
2303
  */
2304
- function getShortcodes() {
2305
  return self::$shortcodeCollection;
2306
  }
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) {
2317
- self::$widgetCollection[$index] = $widget;
2318
  }
2319
 
2320
  /**
@@ -2324,19 +3044,19 @@ class virtualWidgetsRepository {
2324
  *
2325
  * @since 4.7
2326
  */
2327
- function getWidgets() {
2328
  return self::$widgetCollection;
2329
  }
2330
 
2331
  }
2332
 
2333
- add_action('wp_loaded',__NAMESPACE__.'\wp_loaded');
2334
 
2335
  /**
2336
- * Run after wordpress finished bootstrapping, do whatever is needed at this stage
2337
- * like registering the meta
2338
  */
2339
  function wp_loaded() {
2340
- register_meta('post', SHORTCODE_META,null,'__return_false'); // do not allow access to the shortcode meta
2341
- // use the pre 4.6 format for backward compatibility
2342
  }
1
  <?php
2
+ /**
3
+ * Main file of the plugin
4
+ *
5
+ * @package categoryposts.
6
+ *
7
+ * @since 1.0
8
+ */
9
+
10
  /*
11
  Plugin Name: Category Posts Widget
12
  Plugin URI: https://wordpress.org/plugins/category-posts/
13
  Description: Adds a widget that shows the most recent posts from a single category.
14
  Author: TipTopPress
15
+ Version: 4.8
16
  Author URI: http://tiptoppress.com
17
  Text Domain: category-posts
18
  Domain Path: /languages
20
 
21
  namespace categoryPosts;
22
 
23
+ // Don't call the file directly.
24
+ if ( ! defined( 'ABSPATH' ) ) {
25
+ exit;
26
+ }
 
27
 
28
+ const VERSION = '4.8.beta2';
29
+ const DOC_URL = 'http://tiptoppress.com/category-posts-widget/documentation-4-8?utm_source=widget_cpw&utm_campaign=documentation_4_8_cpw&utm_medium=form';
30
+ const PRO_URL = 'http://tiptoppress.com/term-and-category-based-posts-widget/?utm_source=widget_cpw&utm_campaign=get_pro_cpw&utm_medium=action_link';
31
+ const SUPPORT_URL = 'https://wordpress.org/support/plugin/category-posts';
32
  const SHORTCODE_NAME = 'catposts';
33
  const SHORTCODE_META = 'categoryPosts-shorcode';
34
  const WIDGET_BASE_ID = 'category-posts';
35
 
36
+ /**
37
  * Adds the "Customize" link to the Toolbar on edit mode.
38
  *
39
  * @since 4.6
40
+ */
41
  function wp_admin_bar_customize_menu() {
42
  global $wp_admin_bar;
43
 
44
+ if ( ! isset( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) ) {
45
  return;
46
+ }
47
 
48
+ if ( ! current_user_can( 'customize' ) || ! is_admin() || ! is_user_logged_in() || ! is_admin_bar_showing() ) {
49
  return;
50
+ }
51
 
52
+ $current_url = '';
53
+ if ( isset( $_GET['post'] ) && ( '' !== $_GET['post'] ) ) {
54
+ $current_url = get_permalink( absint( $_GET['post'] ) );
55
+ }
56
+ $customize_url = add_query_arg( 'url', rawurlencode( $current_url ), wp_customize_url() );
57
 
58
+ $p = isset( $_GET['post'] ) && ! empty( $_GET['post'] ) ? get_post( absint( $_GET['post'] ) ) : false;
59
  $names = $p ? shortcode_names( SHORTCODE_NAME, $p->post_content ) : array();
60
+ if ( empty( $names ) ) {
61
  return;
62
+ }
63
 
64
  $wp_admin_bar->add_menu( array(
65
+ 'id' => 'customize',
66
+ 'title' => __( 'Customize' ),
67
+ 'href' => $customize_url,
68
+ 'meta' => array(
69
+ 'class' => 'hide-if-no-customize',
70
+ ),
71
  ) );
72
  add_action( 'wp_before_admin_bar_render', 'wp_customize_support_script' );
73
  }
 
74
 
75
+ add_action( 'admin_bar_menu', __NAMESPACE__ . '\wp_admin_bar_customize_menu', 35 );
76
+
77
+ /**
78
+ * Print out required CSS, hooked on the wp_head hook.
79
+ */
80
  function wp_head() {
81
 
82
+ $widget_repository = new virtualWidgetsRepository();
83
 
84
+ $styles = array();
85
 
86
+ foreach ( $widget_repository->getShortcodes() as $widget ) {
87
+ $widget->getCSSRules( true, $styles );
88
  }
89
 
90
+ foreach ( $widget_repository->getWidgets() as $widget ) {
91
+ $widget->getCSSRules( false, $styles );
92
  }
93
 
94
+ if ( ! empty( $styles ) ) {
95
+ ?>
96
  <style type="text/css">
97
+ <?php
98
+ foreach ( $styles as $rules ) {
99
+ foreach ( $rules as $rule ) {
100
+ echo "$rule\n"; // Xss ok. raw css output, can not be html escaped.
101
+ }
102
+ }
103
+ ?>
104
  </style>
105
+ <?php
106
+ }
107
  }
108
 
109
+ add_action( 'wp_head', __NAMESPACE__ . '\register_virtual_widgets', 0 );
110
 
111
  /**
112
  * Register virtual widgets for all widgets and shortcodes that are going to be displayed on the page
119
  global $post;
120
  global $wp_registered_widgets;
121
 
122
+ $repository = new virtualWidgetsRepository();
 
 
 
 
123
 
124
+ // check first for shortcode settings.
125
+ if ( is_singular() ) {
126
+ $names = shortcode_names( SHORTCODE_NAME, $post->post_content );
 
 
 
127
 
128
+ foreach ( $names as $name ) {
129
+ $meta = shortcode_settings( $name );
130
+ if ( is_array( $meta ) ) {
131
+ $id = WIDGET_BASE_ID . '-shortcode-' . get_the_ID(); // needed to make a unique id for the widget html element.
132
+ if ( '' !== $name ) { // if not default name append to the id.
133
+ $id .= '-' . sanitize_title( $name ); // sanitize to be on the safe side, not sure where when and how this will be used.
134
+ }
135
+ $repository->addShortcode( $name, new virtualWidget( $id, WIDGET_BASE_ID . '-shortcode', $meta ) );
136
  }
137
  }
138
+ }
139
 
140
  $sidebars_widgets = wp_get_sidebars_widgets();
141
 
142
+ if ( is_array( $sidebars_widgets ) ) {
143
  foreach ( $sidebars_widgets as $sidebar => $widgets ) {
144
  if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) {
145
  continue;
146
  }
147
 
148
+ if ( is_array( $widgets ) ) {
149
  foreach ( $widgets as $widget ) {
150
+ $widget_base = _get_widget_id_base( $widget );
151
+ if ( WIDGET_BASE_ID === $widget_base ) {
152
+ $class = __NAMESPACE__ . '\Widget';
153
  $widgetclass = new $class();
154
  $allsettings = $widgetclass->get_settings();
155
+ $settings = isset( $allsettings[ str_replace( $widget_base . '-', '', $widget ) ] ) ? $allsettings[ str_replace( $widget_base . '-', '', $widget ) ] : false;
156
+ $repository->addWidget( $widget, new virtualWidget( $widget, $widget, $settings ) );
157
  }
158
  }
159
  }
161
  }
162
  }
163
 
164
+ add_action( 'wp_head', __NAMESPACE__ . '\wp_head' );
165
 
166
+ /**
167
+ * Enqueue widget related scripts for the widget admin page and customizer.
168
+ *
169
+ * @param string $hook the name of the admin hook for which the function was triggered.
170
+ */
171
+ function admin_scripts( $hook ) {
172
 
173
+ if ( 'widgets.php' === $hook ) { // enqueue only for widget admin and customizer.
174
 
175
+ // control open and close the widget section.
176
+ wp_register_script( 'category-posts-widget-admin-js', plugins_url( 'js/admin/category-posts-widget.js', __FILE__ ), array( 'jquery' ), VERSION, true );
177
+ wp_enqueue_script( 'category-posts-widget-admin-js' );
178
 
179
+ $js_data = array( 'accordion' => false );
180
+ $meta = get_user_meta( get_current_user_id(), __NAMESPACE__, true );
181
+ if ( is_array( $meta ) && isset( $meta['panels'] ) ) {
182
+ $js_data['accordion'] = true;
183
+ }
184
+ $js_data['template_tags'] = get_template_tags();
185
+ $js_data[ __NAMESPACE__ ] = $js_data; // To make accessing the data in JS easier to understand.
186
 
187
+ wp_localize_script( 'category-posts-widget-admin-js', 'tiptoppress', $js_data );
188
  wp_enqueue_media();
189
  wp_localize_script( 'category-posts-widget-admin-js', 'cwp_default_thumb_selection', array(
190
+ 'frame_title' => __( 'Select a default thumbnail', 'category-posts' ),
191
  'button_title' => __( 'Select', 'category-posts' ),
192
+ 'none' => __( 'None', 'category-posts' ),
193
  ) );
194
  }
195
  }
196
 
197
+ add_action( 'admin_enqueue_scripts', __NAMESPACE__ . '\admin_scripts' ); // "called on widgets.php and costumizer since 3.9.
198
 
199
+ add_action( 'admin_init', __NAMESPACE__ . '\load_textdomain' );
 
200
 
201
  /**
202
  * Load plugin textdomain.
206
  * @since 4.1
207
  **/
208
  function load_textdomain() {
209
+ load_plugin_textdomain( 'category-posts', false, plugin_basename( dirname( __FILE__ ) ) . '/languages' );
210
  }
211
 
212
+ /*
213
  * Add styles for widget sections
 
214
  */
 
215
 
216
+ add_action( 'admin_print_styles-widgets.php', __NAMESPACE__ . '\admin_styles' );
217
+
218
+ /**
219
+ * Add required admin styles.
220
+ *
221
+ * @since 4.1
222
+ **/
223
  function admin_styles() {
224
  ?>
225
  <style>
226
  .category-widget-cont h4 {
227
+ padding: 12px 15px;
228
+ cursor: pointer;
229
+ margin: 5px 0;
230
+ border: 1px solid #E5E5E5;
231
  }
232
  .category-widget-cont h4:first-child {
233
  margin-top: 10px;
246
  -ms-transition: all 600ms;
247
  -webkit-transition: all 600ms;
248
  -moz-transition: all 600ms;
249
+ transition: all 600ms;
250
  }
251
  .category-widget-cont h4.open:after {
252
  -ms-transition: all 600ms;
253
  -webkit-transition: all 600ms;
254
  -moz-transition: all 600ms;
255
+ transition: all 600ms;
256
  -ms-transform: rotate(180deg);
257
+ -webkit-transform: rotate(180deg);
258
  -moz-transform: rotate(180deg);
259
  transform: rotate(180deg);
260
  }
264
  .category-widget-cont > div.open {
265
  display:block;
266
  }
267
+ .category-widget-cont th,
268
+ .category-widget-cont tr {
269
+ vertical-align: baseline;
270
+ text-align:start;
271
+ }
272
+
273
+ .cat-post-template-help {display:none;}
274
+
275
+ .categoryPosts-template textarea {width:100%}
276
+
277
+ .category-widget-cont .open-template-help {
278
+ border:0;
279
+ padding:0;
280
+ cursor: pointer;
281
+ }
282
+
283
  </style>
284
  <?php
285
  }
287
  /**
288
  * Get image size
289
  *
290
+ * @param int $thumb_w The width of the thumbnail in the widget settings.
291
+ * @param int $thumb_h The height of the thumbnail in the widget settings.
292
+ * @param int $image_w The width of the actual image being displayed.
293
+ * @param int $image_h The height of the actual image being displayed.
294
  *
295
+ * @return array An array with the width and height of the element containing the image
296
  */
297
+ function get_image_size( $thumb_w, $thumb_h, $image_w, $image_h ) {
298
+
299
+ $image_size = array(
300
+ 'image_h' => $thumb_h,
301
+ 'image_w' => $thumb_w,
302
+ 'marginAttr' => '',
303
+ 'marginVal' => '',
304
+ );
305
  $relation_thumbnail = $thumb_w / $thumb_h;
306
  $relation_cropped = $image_w / $image_h;
307
 
308
+ if ( $relation_thumbnail < $relation_cropped ) {
309
  // crop left and right site
310
  // thumbnail width/height ration is smaller, need to inflate the height of the image to thumb height
311
+ // and adjust width to keep aspect ration of image.
312
  $image_size['image_h'] = $thumb_h;
313
  $image_size['image_w'] = $thumb_h / $image_h * $image_w;
314
  $image_size['marginAttr'] = 'margin-left';
315
+ $image_size['marginVal'] = ( $image_size['image_w'] - $thumb_w ) / 2;
316
  } else {
317
  // crop top and bottom
318
  // thumbnail width/height ration is bigger, need to inflate the width of the image to thumb width
319
+ // and adjust height to keep aspect ration of image.
320
  $image_size['image_w'] = $thumb_w;
321
  $image_size['image_h'] = $thumb_w / $image_w * $image_h;
322
  $image_size['marginAttr'] = 'margin-top';
323
+ $image_size['marginVal'] = ( $image_size['image_h'] - $thumb_h ) / 2;
324
  }
325
 
326
  return $image_size;
327
  }
328
 
329
+ /**
330
+ * Get the tags which might be used in the template.
331
+ *
332
+ * @since 4.8
333
+ *
334
+ * @return array Array of strings of the tags.
335
+ */
336
+ function get_template_tags() {
337
+ return array( 'author', 'title', 'date', 'thumb', 'excerpt', 'commentnum', 'post_tag', 'category' );
338
+ }
339
+
340
+ /**
341
+ * Get a regex to parse the template in order to find the tags used in it.
342
+ *
343
+ * @since 4.8
344
+ *
345
+ * @return string The template parsing regex.
346
+ */
347
+ function get_template_regex() {
348
+ $tags = get_template_tags();
349
+
350
+ $regexp = '';
351
+ foreach ( $tags as $t ) {
352
+ if ( ! empty( $regexp ) ) {
353
+ $regexp .= '|';
354
+ }
355
+ $regexp .= '%' . $t . '%';
356
+ }
357
+
358
+ $regexp = '@(' . $regexp . ')@i';
359
+
360
+ return $regexp;
361
+ }
362
+
363
+ /**
364
+ * Convert pre 4.8 settings into template
365
+ *
366
+ * @param array $instance Array which contains the various settings.
367
+ *
368
+ * @since 4.8
369
+ */
370
+ function convert_settings_to_template( $instance ) {
371
+
372
+ $thumbtop = false;
373
+
374
+ $template = '';
375
+
376
+ if ( isset( $instance['thumb'] ) && $instance['thumb'] ) {
377
+ if ( isset( $instance['thumbTop'] ) && $instance['thumbTop'] ) {
378
+ $template .= "%thumb%";
379
+ $thumbtop = true;
380
+ } elseif ( isset( $instance['date'] ) && $instance['date'] ) {
381
+ if ( ! ( isset( $instance['hide_post_titles'] ) && $instance['hide_post_titles'] ) ) {
382
+ $template .= "%title%";
383
+ }
384
+ $template .= "%date%";
385
+ $template .= "%thumb%";
386
+ } elseif ( ! ( isset( $instance['hide_post_titles'] ) && $instance['hide_post_titles'] ) ) {
387
+ $template .= "%thumb%%title%";
388
+ }
389
+ } else {
390
+ if ( ! ( isset( $instance['hide_post_titles'] ) && $instance['hide_post_titles'] ) ) {
391
+ $template .= "%title%";
392
+ }
393
+ if ( isset( $instance['date'] ) && $instance['date'] ) {
394
+ $template .= "%date%";
395
+ }
396
+ }
397
+ if ( isset( $instance['excerpt'] ) && $instance['excerpt'] ) {
398
+ $template .= '%excerpt%';
399
+ }
400
+ if ( isset( $instance['comment_num'] ) && $instance['comment_num'] ) {
401
+ $template .= "%commentnum%";
402
+ }
403
+ if ( isset( $instance['author'] ) && $instance['author'] ) {
404
+ $template .= "%author%";
405
+ }
406
+
407
+ return $template;
408
+ }
409
+
410
  /**
411
  * Category Posts Widget Class
412
  *
414
  */
415
  class Widget extends \WP_Widget {
416
 
417
+ /**
418
+ * Widget constructor.
419
+ */
420
+ public function __construct() {
421
+ $widget_ops = array(
422
+ 'classname' => 'cat-post-widget',
423
+ 'description' => __( 'List single category posts', 'category-posts' ),
424
+ );
425
+ parent::__construct( WIDGET_BASE_ID, __( 'Category Posts', 'category-posts' ), $widget_ops );
426
  }
427
 
428
  /**
429
  * Calculate the HTML for showing the thumb of a post item.
430
+ *
431
+ * Used as a filter for the thumb wordpress API to add css based stretching and cropping
432
+ * when the image is not at the requested dimensions
433
+ *
434
+ * @param string $html The original HTML generated by the core APIS.
435
+ * @param int $post_id the ID of the post of which the thumb is a featured image.
436
+ * @param int $post_thumbnail_id The id of the featured image attachment.
437
+ * @param string|array $size The requested size identified by name or (width, height) array.
438
+ * @param mixed $attr ignored in this context.
439
  * @return string The HTML for the thumb related to the post
440
+ *
441
+ * @since 4.1
442
  */
443
+ public function post_thumbnail_html( $html, $post_id, $post_thumbnail_id, $size, $attr ) {
444
+ if ( empty( $this->instance['thumb_w'] ) || empty( $this->instance['thumb_h'] ) ) {
445
+ return $html; // bail out if no full dimensions defined.
446
+ }
447
+ $meta = image_get_intermediate_size( $post_thumbnail_id, $size );
448
 
449
+ if ( empty( $meta ) ) {
450
+ $post_img = wp_get_attachment_metadata( $post_thumbnail_id, $size );
451
  $meta['file'] = basename( $post_img['file'] );
452
  }
453
 
454
+ $origfile = get_attached_file( $post_thumbnail_id, true ); // the location of the full file.
455
+ $file = dirname( $origfile ) . '/' . $meta['file']; // the location of the file displayed as thumb.
456
+ if ( file_exists( $file ) ) {
457
+ list( $width, $height ) = getimagesize( $file ); // get actual size of the thumb file.
458
 
459
+ if ( isset( $this->instance['use_css_cropping'] ) && $this->instance['use_css_cropping'] ) {
460
+ $image = get_image_size( $this->instance['thumb_w'], $this->instance['thumb_h'], $width, $height );
461
 
462
+ // replace srcset.
463
  $array = array();
464
+ preg_match( '/width="([^"]*)"/i', $html, $array );
465
+ $pattern = '/' . $array[1] . 'w/';
466
+ $html = preg_replace( $pattern, $image['image_w'] . 'w', $html );
467
+ // replace size.
468
+ $pattern = '/' . $array[1] . 'px/';
469
+ $html = preg_replace( $pattern, $image['image_w'] . 'px', $html );
470
+ // replace width.
471
+ $pattern = '/width="[0-9]*"/';
472
+ $html = preg_replace( $pattern, "width='" . $image['image_w'] . "'", $html );
473
+ // replace height.
474
+ $pattern = '/height="[0-9]*"/';
475
+ $html = preg_replace( $pattern, "height='" . $image['image_h'] . "'", $html );
476
+ // set margin.
477
+ $html = str_replace( '<img ', '<img style="' . $image['marginAttr'] . ':-' . $image['marginVal'] . 'px;height:' . $image['image_h']
478
+ . 'px;clip:rect(auto,' . ( $this->instance['thumb_w'] + $image['marginVal'] ) . 'px,auto,' . $image['marginVal']
479
+ . 'px);width:auto;max-width:initial;" ', $html );
480
+ // wrap span with post format.
481
+ $show_post_format = isset( $this->instance['show_post_format'] ) && ( 'none' !== $this->instance['show_post_format'] );
482
+ if ( $show_post_format || $this->instance['thumb_hover'] ) {
483
+ $format = get_post_format() ? : 'standard';
484
+ $post_format_class = 'cat-post-format cat-post-format-' . $format;
485
+ }
486
+ $html = '<span class="cat-post-crop ' . $post_format_class . '" style="width:' . $this->instance['thumb_w'] . 'px;height:' . $this->instance['thumb_h'] . 'px;">'
487
+ . $html . '</span>';
488
  } else {
489
+ // use_css_cropping is not used.
490
+ // wrap span.
491
+ $html = '<span>' . $html . '</span>';
492
  }
493
  }
494
  return $html;
495
  }
496
 
497
  /*
498
+ * wrapper to execute the the_post_thumbnail with filters.
499
+ */
500
  /**
501
  * Calculate the HTML for showing the thumb of a post item.
502
+ *
503
+ * It is a wrapper to execute the the_post_thumbnail with filters
504
+ *
505
+ * @param string|array $size The requested size identified by name or (width, height) array.
506
+ *
507
  * @return string The HTML for the thumb related to the post and empty string if it can not be calculated
508
+ *
509
+ * @since 4.1
510
  */
511
+ public function the_post_thumbnail( $size = 'post-thumbnail' ) {
512
+ if ( empty( $size ) ) { // if junk value, make it a normal thumb.
513
+ $size = 'post-thumbnail';
514
+ } elseif ( is_array( $size ) && ( 2 === count( $size ) ) ) { // good format at least.
515
+ // normalize to ints first.
516
+ $size[0] = (int) $size[0];
517
+ $size[1] = (int) $size[1];
518
+ if ( ( 0 === $size[0] ) && ( 0 === $size[1] ) ) { // Both values zero then revert to thumbnail.
519
+ $size = array( get_option( 'thumbnail_size_w', 150 ), get_option( 'thumbnail_size_h', 150 ) );
520
+ } elseif ( ( 0 === $size[0] ) && ( 0 !== $size[1] ) ) {
521
+ // if one value is zero make a square using the other value.
522
+ $size[0] = $size[1];
523
+ } elseif ( ( 0 !== $size[0] ) && ( 0 === $size[1] ) ) {
524
+ $size[1] = $size[0];
525
+ }
526
+ } else {
527
+ $size = array( get_option( 'thumbnail_size_w', 150 ), get_option( 'thumbnail_size_h', 150 ) ); // yet another form of junk.
528
+ }
529
 
530
  $post_thumbnail_id = get_post_thumbnail_id( get_the_ID() );
531
+ if ( ! $post_thumbnail_id && $this->instance['default_thunmbnail'] ) {
532
  $post_thumbnail_id = $this->instance['default_thunmbnail'];
533
+ }
534
 
535
  do_action( 'begin_fetch_post_thumbnail_html', get_the_ID(), $post_thumbnail_id, $size );
536
  $html = wp_get_attachment_image( $post_thumbnail_id, $size, false, '' );
537
+ if ( ! $html ) {
538
  $ret = '';
539
+ } else {
540
+ $ret = $this->post_thumbnail_html( $html, get_the_ID(), $post_thumbnail_id, $size, '' );
541
+ }
542
  do_action( 'end_fetch_post_thumbnail_html', get_the_ID(), $post_thumbnail_id, $size );
543
 
544
+ return $ret;
545
  }
546
 
547
  /**
548
  * Excerpt more link filter
549
+ *
550
+ * @param string $more The "more" text passed by the filter.
551
+ *
552
+ * @return string The link to the post with the "more" text configured in the widget.
553
  */
554
+ public function excerpt_more_filter( $more ) {
555
+ return ' <a class="cat-post-excerpt-more more-link" href="' . get_permalink() . '">' . esc_html( $this->instance['excerpt_more_text'] ) . '</a>';
556
  }
557
 
558
  /**
559
  * Apply the_content filter for excerpt
560
  * This should show sharing buttons which comes with other widgets in the widget output in the same way as on the main content
561
  *
562
+ * @param string $text The HTML with other applied excerpt filters.
563
+ *
564
+ * @return string If option hide_social_buttons is unchecked applay the_content filter.
565
+ *
566
+ * @since 4.6
567
  */
568
+ public function apply_the_excerpt( $text ) {
569
+ $ret = '';
570
+ if ( isset( $this->instance['hide_social_buttons'] ) && $this->instance['hide_social_buttons'] ) {
571
+ $ret = $text;
572
+ } else {
573
+ $ret = apply_filters( 'the_content', $text );
574
+ }
575
  return $ret;
576
  }
577
 
578
  /**
579
  * Excerpt allow HTML
580
+ *
581
+ * @param string $text The HTML with other applied excerpt filters.
582
  */
583
+ public function allow_html_excerpt( $text ) {
584
  global $post, $wp_filter;
585
+ $new_excerpt_length = ( isset( $this->instance['excerpt_length'] ) && $this->instance['excerpt_length'] > 0 ) ? $this->instance['excerpt_length'] : 55;
586
+ if ( '' === $text ) {
587
+ $text = get_the_content( '' );
588
  $text = strip_shortcodes( $text );
589
+ $text = apply_filters( 'the_content', $text );
590
+ $text = str_replace( '\]\]\>', ']]&gt;', $text );
591
+ $text = preg_replace( '@<script[^>]*?>.*?</script>@si', '', $text );
592
  $cphtml = array(
593
  '&lt;a&gt;',
594
  '&lt;br&gt;',
602
  '&lt;script&gt;',
603
  '&lt;style&gt;',
604
  '&lt;video&gt;',
605
+ '&lt;audio&gt;',
606
  );
607
+ $allowed_HTML = '';
608
+ foreach ( $cphtml as $index => $name ) {
609
+ if ( in_array( (string) ( $index ), $this->instance['excerpt_allowed_elements'], true ) ) {
610
+ $allowed_HTML .= $cphtml[ $index ];
611
+ }
612
  }
613
+ $text = strip_tags( $text, htmlspecialchars_decode( $allowed_HTML ) );
614
  $excerpt_length = $new_excerpt_length;
615
 
616
+ if ( ! empty( $this->instance['excerpt_more_text'] ) ) {
617
+ $excerpt_more = $this->excerpt_more_filter( $this->instance['excerpt_more_text'] );
618
+ } elseif ( $filterName = key( $wp_filter['excerpt_more'][10] ) ) {
619
+ $excerpt_more = $wp_filter['excerpt_more'][10][ $filterName ]['function']( 0 );
620
+ } else {
621
  $excerpt_more = '[...]';
622
  }
623
 
624
+ $words = explode( ' ', $text, $excerpt_length + 1 );
625
+ if ( count( $words ) > $excerpt_length ) {
626
+ array_pop( $words );
627
+ array_push( $words, $excerpt_more );
628
+ $text = implode( ' ', $words );
629
  }
630
  }
631
 
632
  return '<p>' . $text . '</p>';
633
  }
634
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
635
  /**
636
  * Calculate the wp-query arguments matching the filter settings of the widget
637
  *
638
+ * @param array $instance Array which contains the various settings.
639
  * @return array The array that can be fed to wp_Query to get the relevant posts
640
+ *
641
+ * @since 4.6
642
  */
643
+ public function queryArgs( $instance ) {
644
+
645
+ $valid_sort_orders = array( 'date', 'title', 'comment_count', 'rand' );
646
+ if ( isset( $instance['sort_by'] ) && in_array( $instance['sort_by'], $valid_sort_orders, true ) ) {
647
  $sort_by = $instance['sort_by'];
648
  } else {
649
  $sort_by = 'date';
650
  }
651
+ $sort_order = ( isset( $instance['asc_sort_order'] ) && $instance['asc_sort_order'] ) ? 'ASC' : 'DESC';
652
 
653
  // Get array of post info.
654
  $args = array(
655
+ 'orderby' => $sort_by,
656
+ 'order' => $sort_order,
657
+ 'ignore_sticky_posts' => 1, // Make sure we do not get stickies out of order.
658
  );
659
 
660
  $non_default_valid_status = array(
661
+ 'publish',
662
+ 'future',
663
+ 'publish,future',
664
+ 'private',
665
+ 'private,publish',
666
+ 'private,publish,future',
667
+ );
668
  if ( isset( $instance['status'] ) && in_array( $instance['status'], $non_default_valid_status, true ) ) {
669
+ $args['post_status'] = $instance['status'];
670
  }
671
 
672
+ if ( isset( $instance['num'] ) ) {
673
+ $args['showposts'] = (int) $instance['num'];
674
+ }
 
 
675
 
676
+ if ( isset( $instance['offset'] ) && ( (int) $instance['offset'] > 1 ) ) {
677
+ $args['offset'] = (int) $instance['offset'] - 1;
678
+ }
679
+ if ( isset( $instance['cat'] ) ) {
680
+ if ( isset( $instance['no_cat_childs'] ) && $instance['no_cat_childs'] ) {
681
+ $args['category__in'] = (int) $instance['cat'];
682
+ } else {
683
+ $args['cat'] = (int) $instance['cat'];
684
+ }
685
  }
686
 
687
+ if ( is_singular() && isset( $instance['exclude_current_post'] ) && $instance['exclude_current_post'] ) {
688
+ $args['post__not_in'] = array( get_the_ID() );
689
+ }
690
 
691
+ if ( isset( $instance['hideNoThumb'] ) && $instance['hideNoThumb'] ) {
692
+ $args = array_merge( $args, array(
693
+ 'meta_query' => array(
694
  array(
695
+ 'key' => '_thumbnail_id',
696
+ 'compare' => 'EXISTS',
697
+ ),
698
+ ),
699
+ ) );
700
  }
701
 
702
+ return $args;
703
+ }
704
 
705
  /**
706
  * Calculate the HTML of the title based on the widget settings
707
  *
708
+ * @param string $before_title The sidebar configured HTML that should come
709
+ * before the title itself.
710
+ * @param string $after_title The sidebar configured HTML that should come
711
+ * after the title itself.
712
+ * @param array $instance Array which contains the various settings.
713
  * @return string The HTML for the title area
714
+ *
715
+ * @since 4.6
716
  */
717
+ public function titleHTML( $before_title, $after_title, $instance ) {
718
+ $ret = '';
719
+
720
+ if ( ! isset( $instance['cat'] ) ) {
721
+ $instance['cat'] = 0;
722
+ }
723
+
724
+ // If no title, use the name of the category.
725
+ if ( ! isset( $instance['title'] ) || ! $instance['title'] ) {
726
+ $instance['title'] = '';
727
+ if ( 0 !== $instance['cat'] ) {
728
+ $category_info = get_category( $instance['cat'] );
729
+ if ( $category_info && ! is_wp_error( $category_info ) ) {
730
+ $instance['title'] = $category_info->name;
731
+ } else {
732
+ $instance['cat'] = 0; // For further processing treat it like "all categories".
733
+ $instance['title'] = __( 'Recent Posts', 'category-posts' );
734
+ }
735
+ } else {
736
+ $instance['title'] = __( 'Recent Posts', 'category-posts' );
737
+ }
738
+ }
739
+
740
+ if ( ! ( isset( $instance['hide_title'] ) && $instance['hide_title'] ) ) {
741
+ $ret = $before_title;
742
+ if ( isset( $instance['is_shortcode'] ) ) {
743
+ $title = esc_html( $instance['title'] );
744
+ } else {
745
+ $title = apply_filters( 'widget_title', $instance['title'] );
746
+ }
747
+
748
+ if ( isset( $instance['title_link'] ) && $instance['title_link'] ) {
749
+ if ( 0 !== $instance['cat'] ) {
750
+ $ret .= '<a href="' . get_category_link( $instance['cat'] ) . '">' . $title . '</a>';
751
+ } elseif ( isset( $instance['title_link_url'] ) && $instance['title_link_url'] ) {
752
+ $ret .= '<a href="' . esc_url( $instance['title_link_url'] ) . '">' . $title . '</a>';
753
  } else {
754
+ $ret .= '<a href="' . esc_url( $this->blog_page_url() ) . '">' . $title . '</a>';
 
 
 
 
 
 
755
  }
756
+ } else {
757
  $ret .= $title;
758
+ }
759
 
760
  $ret .= $after_title;
761
  }
763
  return $ret;
764
  }
765
 
766
+ /**
767
+ * Get the URL of the blog page or home page if no explicit blog page is defined.
768
+ *
769
+ * @return string The URL of the blog page
770
+ *
771
+ * @since 4.8
772
+ */
773
+ private function blog_page_url() {
774
+
775
+ $blog_page = get_option( 'page_for_posts' );
776
+ if ( $blog_page ) {
777
+ $url = get_permalink( $blog_page );
778
+ } else {
779
+ $url = home_url();
780
+ }
781
+
782
+ return $url;
783
+ }
784
+
785
  /**
786
  * Calculate the HTML of the footer based on the widget settings
787
  *
788
+ * @param array $instance Array which contains the various settings.
789
  * @return string The HTML for the footer area
790
+ *
791
+ * @since 4.6
792
  */
793
+ public function footerHTML( $instance ) {
794
 
795
+ $ret = '';
796
  $url = '';
797
  $text = '';
798
 
799
+ if ( isset( $instance['footer_link'] ) ) {
800
+ $url = $instance['footer_link'];
801
+ }
802
 
803
+ if ( isset( $instance['footer_link_text'] ) ) {
804
+ $text = $instance['footer_link_text'];
805
+ }
806
 
807
+ // if url is set, but no text, just use the url as text.
808
+ if ( empty( $text ) && ! empty( $url ) ) {
809
  $text = $url;
810
+ }
811
 
812
  // if no url is set but just text, assume the url should be to the relevant archive page
813
  // category archive for categories filter and home page or blog page when "all categories"
814
+ // is used.
815
+ if ( ! empty( $text ) && empty( $url ) ) {
816
+ if ( isset( $instance['cat'] ) && ( 0 !== $instance['cat'] ) && ( null !== get_category( $instance['cat'] ) ) ) {
817
+ $url = get_category_link( $instance['cat'] );
818
+ } else {
819
+ $url = $this->blog_page_url();
 
 
 
 
820
  }
821
  }
822
 
823
+ if ( ! empty( $url ) ) {
824
+ $ret .= '<a class="cat-post-footer-link" href="' . esc_url( $url ) . '">' . esc_html( $text ) . '</a>';
825
+ }
826
 
827
  return $ret;
828
  }
829
 
830
  /**
831
+ * Current post item date string based on the format requested in the settings
 
832
  *
833
+ * @param array $instance Array which contains the various settings.
834
+ * @param bool $everything_is_link Indicates whether the return string should avoid links.
835
+ *
836
+ * @since 4.8
 
 
837
  */
838
+ public function itemDate( $instance, $everything_is_link ) {
839
+ $ret = '';
840
 
841
+ if ( ! isset( $instance['preset_date_format'] ) ) {
842
+ $preset_date_format = 'other';
843
+ } else {
844
+ $preset_date_format = $instance['preset_date_format'];
845
+ }
846
+
847
+ switch ( $preset_date_format ) {
848
+ case 'sitedateandtime':
849
+ $date = get_the_time( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) );
850
+ break;
851
+ case 'sitedate':
852
+ $date = get_the_time( get_option( 'date_format' ) );
853
+ break;
854
+ case 'sincepublished':
855
+ $date = human_time_diff( get_the_time( 'U' ), current_time( 'timestamp' ) );
856
+ break;
857
+ default:
858
+ if ( isset( $instance['date_format'] ) && strlen( trim( $instance['date_format'] ) ) > 0 ) {
859
+ $date_format = $instance['date_format'];
860
+ } else {
861
+ $date_format = 'j M Y';
862
+ }
863
+ $date = get_the_time( $date_format );
864
+ break;
865
+ }
866
+ $ret .= '<span class="cat-post-date">';
867
+ if ( isset( $instance['date_link'] ) && $instance['date_link'] && ! $everything_is_link ) {
868
+ $ret .= '<a href="' . \get_the_permalink() . '">';
869
+ }
870
+ $ret .= $date;
871
+
872
+ if ( isset( $instance['date_link'] ) && $instance['date_link'] && ! $everything_is_link ) {
873
+ $ret .= '</a>';
874
+ }
875
+ $ret .= '</span>';
876
+ return $ret;
877
+ }
878
+
879
+
880
+ /**
881
+ * Calculate the HTML for showing the thumb of a post item.
882
+ * Expected to be called from a loop with globals properly set.
883
+ *
884
+ * @param array $instance Array which contains the various settings.
885
+ * @param bool $no_link indicates whether the thumb should be wrapped in a link or a span.
886
+ * @return string The HTML for the thumb related to the post
887
+ *
888
+ * @since 4.6
889
+ */
890
+ public function itemThumb( $instance, $no_link ) {
891
+ $ret = '';
892
+
893
+ if ( ( isset( $instance['default_thunmbnail'] ) && ( 0 !== $instance['default_thunmbnail'] ) ) || has_post_thumbnail() ) {
894
+ $class = '';
895
+ $use_css_cropping = isset( $this->instance['use_css_cropping'] ) && $this->instance['use_css_cropping'];
896
+ $disable_css = isset( $instance['disable_css'] ) && $instance['disable_css'];
897
+
898
+ if ( isset( $this->instance['thumb_hover'] ) && ! $disable_css ) {
899
+ $class = 'class="cat-post-thumbnail cat-post-' . $instance['thumb_hover'] . '"';
900
+ } else {
901
+ $class = 'class="cat-post-thumbnail"';
902
+ }
903
+
904
+ $title_args = array( 'echo' => false );
905
+
906
+ if ( $no_link ) {
907
+ $ret .= '<span ' . $class . '>';
908
+ } else {
909
+ $ret .= '<a ' . $class . ' href="' . get_the_permalink() . '" title="' . the_title_attribute( $title_args ) . '">';
910
+ }
911
+
912
+ $ret .= $this->the_post_thumbnail( array( $this->instance['thumb_w'], $this->instance['thumb_h'] ) );
913
+
914
+ if ( $no_link ) {
915
+ $ret .= '</span>';
916
+ } else {
917
+ $ret .= '</a>';
918
+ }
919
+ }
920
 
921
+ return $ret;
922
+ }
923
 
924
+ /**
925
+ * Current post item categories string
926
+ *
927
+ * @param array $instance Array which contains the various settings.
928
+ * @param bool $everything_is_link Indicates whether the return string should avoid links.
929
+ *
930
+ * @since 4.8
931
+ */
932
+ public function itemCategories( $instance, $everything_is_link ) {
933
 
934
+ $ret = '<span class="cat-post-tax-category">';
935
+ $cat_ids = wp_get_post_categories( get_the_ID(), array( 'number' => 0 ) );
936
+ foreach ( $cat_ids as $cat_id ) {
937
+ if ( $everything_is_link ) {
938
+ $ret .= ' ' . get_cat_name( $cat_id );
939
+ } else {
940
+ $ret .= " <a href='" . get_category_link( $cat_id ) . "'>" . get_cat_name( $cat_id ) . '</a>';
941
+ }
942
  }
943
+ $ret .= '</span>';
944
+ return $ret;
945
+ }
946
 
947
+ /**
948
+ * Current post item tags string
949
+ *
950
+ * @param array $instance Array which contains the various settings.
951
+ * @param bool $everything_is_link Indicates whether the return string should avoid links.
952
+ *
953
+ * @since 4.8
954
+ */
955
+ public function itemTags( $instance, $everything_is_link ) {
956
 
957
+ $ret = '<span class="cat-post-tax-post_tag">';
958
+ $tag_ids = wp_get_post_tags( get_the_ID(), array( 'number' => 0 ) );
959
+ foreach ( $tag_ids as $tag_id ) {
960
+ if ( $everything_is_link ) {
961
+ $ret .= ' ' . $tag_id->name;
962
  } else {
963
+ $ret .= " <a href='" . get_tag_link( $tag_id->term_id ) . "'>" . $tag_id->name . '</a>';
 
 
 
 
 
964
  }
965
+ }
966
+ $ret .= '</span>';
967
+ return $ret;
968
+ }
969
+
970
+ /**
971
+ * Current post item comment number string
972
+ *
973
+ * @param array $instance Array which contains the various settings.
974
+ * @param bool $everything_is_link Indicates whether the return string should avoid links.
975
+ *
976
+ * @since 4.8
977
+ */
978
+ public function itemCommentNum( $instance, $everything_is_link ) {
979
+ global $post;
980
+
981
+ $ret = '<span class="cat-post-comment-num">';
982
+
983
+ if ( $everything_is_link ) {
984
+ $ret .= '(' . \get_comments_number() . ')';
985
+ } else {
986
+ $link = sprintf(
987
+ '<a href="%1$s" title="%2$s">(%3$d)</a>',
988
+ esc_url( get_comments_link( $post->ID ) ),
989
+ esc_attr( sprintf( __( '(%d) comments to this post' ), get_comments_number() ) ),
990
+ get_comments_number()
991
+ );
992
+ $ret .= $link;
993
+ }
994
+
995
+ $ret .= '</span>';
996
+ return $ret;
997
+ }
998
+
999
+ /**
1000
+ * Current post item author string
1001
+ *
1002
+ * @param array $instance Array which contains the various settings.
1003
+ * @param bool $everything_is_link Indicates whether the return string should avoid links.
1004
+ *
1005
+ * @since 4.8
1006
+ */
1007
+ public function itemAuthor( $instance, $everything_is_link ) {
1008
+
1009
+ $ret = '<span class="cat-post-author">';
1010
+
1011
+ if ( $everything_is_link ) {
1012
+ $ret .= get_the_author();
1013
+ } else {
1014
+ $link = get_the_author_posts_link();
1015
+ $ret .= $link;
1016
+ }
1017
+ $ret .= '</span>';
1018
+ return $ret;
1019
+ }
1020
+
1021
+ /**
1022
+ * Current post item excerpt string
1023
+ *
1024
+ * @param array $instance Array which contains the various settings.
1025
+ * @param bool $everything_is_link Indicates whether the return string should avoid links.
1026
+ *
1027
+ * @since 4.8
1028
+ */
1029
+ public function itemExcerpt( $instance, $everything_is_link ) {
1030
+ global $post;
1031
+
1032
+ // use the_excerpt filter to get the "normal" excerpt of the post
1033
+ // then apply our filter to let users customize excerpts in their own way.
1034
+ if ( isset( $instance['excerpt_length'] ) && ( $instance['excerpt_length'] > 0 ) ) {
1035
+ $length = (int) $instance['excerpt_length'];
1036
+ } else {
1037
+ $length = 55; // Use the wordpress default.
1038
+ }
1039
+
1040
+ if ( ! isset( $instance['excerpt_filters'] ) || $instance['excerpt_filters'] ) { // pre 4.7 widgets has filters on.
1041
+ $excerpt = apply_filters( 'the_excerpt', \get_the_excerpt() );
1042
+ } else { // if filters off replicate functionality of core generating excerpt.
1043
+ $more_text = '[&hellip;]';
1044
+ if ( isset( $instance['excerpt_more_text'] ) && $instance['excerpt_more_text'] ) {
1045
+ $more_text = ltrim( $instance['excerpt_more_text'] );
1046
  }
1047
+
1048
+ if ( $everything_is_link ) {
1049
+ $excerpt_more_text = ' <span class="cat-post-excerpt-more">' . $more_text . '</span>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1050
  } else {
1051
+ $excerpt_more_text = ' <a class="cat-post-excerpt-more" href="' . get_permalink() . '" title="' . sprintf( __( 'Continue reading %s' ), get_the_title() ) . '">' . $more_text . '</a>';
1052
+ }
1053
+ if ( '' === $post->post_excerpt ) {
1054
+ $text = get_the_content( '' );
1055
+ $text = strip_shortcodes( $text );
1056
+ $excerpt = \wp_trim_words( $text, $length, $excerpt_more_text );
1057
+ // adjust html output same way as for the normal excerpt,
1058
+ // just force all functions depending on the_excerpt hook.
1059
+ $excerpt = shortcode_unautop( wpautop( convert_chars( convert_smilies( wptexturize( $excerpt ) ) ) ) );
1060
+ } else {
1061
+ $excerpt = $post->post_excerpt . $excerpt_more_text;
1062
+ $excerpt = shortcode_unautop( wpautop( convert_chars( convert_smilies( wptexturize( $excerpt ) ) ) ) );
1063
  }
1064
+ }
1065
+ $ret = apply_filters( 'cpw_excerpt', $excerpt, $this );
1066
+ return $ret;
1067
+ }
1068
 
1069
+ /**
1070
+ * Current post item title string
1071
+ *
1072
+ * @param array $instance Array which contains the various settings.
1073
+ * @param bool $everything_is_link Indicates whether the return string should avoid links.
1074
+ *
1075
+ * @since 4.8
1076
+ */
1077
+ public function itemTitle( $instance, $everything_is_link ) {
1078
+
1079
+ $ret = '';
1080
+
1081
+ if ( $everything_is_link ) {
1082
+ $ret .= '<span class="cat-post-title">' . get_the_title() . '</span>';
1083
+ } else {
1084
+ $ret .= '<a class="cat-post-title"';
1085
+ $ret .= ' href="' . get_the_permalink() . '" rel="bookmark">' . get_the_title();
1086
  $ret .= '</a>';
1087
  }
1088
+ return $ret;
1089
+ }
1090
 
1091
+ /**
1092
+ * Calculate the HTML for a post item based on the widget settings and post.
1093
+ * Expected to be called in an active loop with all the globals set.
1094
+ *
1095
+ * @param array $instance Array which contains the various settings.
1096
+ * @param null|integer $current_post_id If on singular page specifies the id of
1097
+ * the post, otherwise null.
1098
+ * @return string The HTML for item related to the post
1099
+ *
1100
+ * @since 4.6
1101
+ */
1102
+ public function itemHTML( $instance, $current_post_id ) {
1103
+ global $post;
1104
+
1105
+ $everything_is_link = isset( $instance['everything_is_link'] ) && $instance['everything_is_link'];
1106
+ $wrap = isset( $instance['text_do_not_wrap_thumb'] ) && $instance['text_do_not_wrap_thumb'];
1107
+
1108
+ $template = '';
1109
+ if ( isset( $instance['template'] ) ) {
1110
+ $template = $instance['template'];
1111
+ } else {
1112
+ $template = convert_settings_to_template( $instance );
1113
+ }
1114
+ $ret = '<li ';
1115
+
1116
+ // Current post.
1117
+ if ( $current_post_id === $post->ID ) {
1118
+ $ret .= "class='cat-post-item cat-post-current'";
1119
+ } else {
1120
+ $ret .= "class='cat-post-item'";
1121
+ }
1122
+ $ret .= '>'; // close the li opening tag.
1123
+
1124
+ if ( $everything_is_link ) {
1125
+ $ret .= '<a class="cat-post-everything-is-link" href="' . get_the_permalink() . '" title="">';
1126
+ }
1127
+
1128
+ // Try to do smart formatting for floating thumb based on its location.
1129
+ if ( $wrap ) {
1130
+ if( preg_match( '#(\%thumb\%)#', $template ) && ! preg_match( '#(\%thumb\%$)#', $template ) ) {
1131
+ $thumb_flex = explode( '%thumb%', $template );
1132
+ if( count( $thumb_flex ) == 1) {
1133
+ $template = '<div class="cat-post-do-not-wrap-thumbnail">%thumb%<div>' . $thumb_flex[0] . '</div></div>';
1134
+ }
1135
+ if( count( $thumb_flex ) == 2) {
1136
+ $template = $thumb_flex[0] . '<div class="cat-post-do-not-wrap-thumbnail">%thumb%<div>' . $thumb_flex[1] . '</div></div>';
1137
+ }
1138
+ }
1139
+ }
1140
+
1141
+ // Post details (Template).
1142
+ $widget = $this;
1143
+ $template_res = preg_replace_callback( get_template_regex(), function ( $matches ) use ( $widget, $instance, $everything_is_link ) {
1144
+ switch ( $matches[0] ) {
1145
+ case '%title%':
1146
+ return $widget->itemTitle( $instance, $everything_is_link );
1147
+ case '%author%':
1148
+ return $widget->itemAuthor( $instance, $everything_is_link );
1149
+ case '%commentnum%':
1150
+ return $widget->itemCommentNum( $instance, $everything_is_link );
1151
+ case '%date%':
1152
+ return $widget->itemDate( $instance, $everything_is_link );
1153
+ case '%thumb%':
1154
+ return $widget->itemThumb( $instance, $everything_is_link );
1155
+ case '%post_tag%':
1156
+ return $widget->itemTags( $instance, $everything_is_link );
1157
+ case '%category%':
1158
+ return $widget->itemCategories( $instance, $everything_is_link );
1159
+ case '%excerpt%':
1160
+ return $widget->itemExcerpt( $instance, $everything_is_link );
1161
+ default:
1162
+ return $matches[0];
1163
+ }
1164
+ }, $template );
1165
+
1166
+ // Replace empty line with closing and opening DIV.
1167
+ $template_res = trim( $template_res );
1168
+ $template_res = str_replace( "\r\n\r\n", '</div><div>', $template_res );
1169
+ $template_res = '<div>' . $template_res . '</div>';
1170
+
1171
+ // replace new lines with spaces.
1172
+ $template_res = str_replace( "\r\n", ' ', $template_res );
1173
+
1174
+ $ret .= $template_res;
1175
+
1176
+ if ( $everything_is_link ) {
1177
+ $ret .= '</a>';
1178
+ }
1179
+
1180
+ $ret .= '</li>';
1181
+ return $ret;
1182
+ }
1183
 
1184
  /**
1185
  * Filter to set the number of words in an excerpt
1186
  *
1187
+ * @param int $length The number of words as configured by wordpress core or set by previous filters.
1188
  * @return int The number of words configured for the widget,
1189
+ * or the $length parameter if it is not configured or garbage value.
1190
+ *
1191
+ * @since 4.6
1192
  */
1193
+ public function excerpt_length_filter( $length ) {
1194
+ if ( isset( $this->instance['excerpt_length'] ) && $this->instance['excerpt_length'] > 0 ) {
1195
+ $length = $this->instance['excerpt_length'];
1196
+ }
1197
+ return $length;
1198
+ }
1199
 
1200
  /**
1201
  * Set the proper excerpt filters based on the settings
1202
  *
1203
+ * @param array $instance widget settings.
1204
  * @return void
1205
+ *
1206
+ * @since 4.6
1207
  */
1208
+ public function setExcerpFilters( $instance ) {
1209
 
1210
+ if ( isset( $instance['excerpt'] ) && $instance['excerpt'] ) {
1211
 
1212
+ // Excerpt length filter.
1213
+ if ( isset( $instance['excerpt_length'] ) && ( (int) $instance['excerpt_length'] ) > 0 ) {
1214
+ add_filter( 'excerpt_length', array( $this, 'excerpt_length_filter' ) );
1215
+ }
1216
 
1217
+ if ( isset( $instance['excerpt_more_text'] ) && ( '' !== ltrim( $instance['excerpt_more_text'] ) ) ) {
1218
+ add_filter( 'excerpt_more', array( $this, 'excerpt_more_filter' ) );
1219
+ }
1220
 
1221
+ if ( isset( $instance['excerpt_allow_html'] ) ) {
1222
+ remove_filter( 'get_the_excerpt', 'wp_trim_excerpt' );
1223
+ add_filter( 'the_excerpt', array( $this, 'allow_html_excerpt' ) );
1224
+ } else {
1225
+ add_filter( 'the_excerpt', array( $this, 'apply_the_excerpt' ) );
1226
+ }
1227
+ }
1228
+ }
1229
 
1230
  /**
1231
  * Remove the excerpt filter
1232
  *
1233
+ * @param array $instance widget settings.
1234
  * @return void
1235
+ *
1236
+ * @since 4.6
1237
  */
1238
+ public function removeExcerpFilters( $instance ) {
1239
+ remove_filter( 'excerpt_length', array( $this, 'excerpt_length_filter' ) );
1240
+ remove_filter( 'excerpt_more', array( $this, 'excerpt_more_filter' ) );
1241
+ add_filter( 'get_the_excerpt', 'wp_trim_excerpt' );
1242
+ remove_filter( 'the_excerpt', array( $this, 'allow_html_excerpt' ) );
1243
+ remove_filter( 'the_excerpt', array( $this, 'apply_the_excerpt' ) );
1244
+ }
1245
 
1246
  /**
1247
  * The main widget display controller
 
 
1248
  *
1249
+ * Called by the sidebar processing core logic to display the widget.
1250
+ *
1251
+ * @param array $args An array containing the "environment" setting for the widget,
1252
+ * namely, the enclosing tags for the widget and its title.
1253
+ * @param array $instance The settings associate with the widget.
1254
+ *
1255
+ * @since 4.1
1256
+ */
1257
+ public function widget( $args, $instance ) {
1258
+
1259
+ extract( $args );
1260
+ $this->instance = $instance;
1261
+
1262
+ $args = $this->queryArgs( $instance );
1263
+ $cat_posts = new \WP_Query( $args );
1264
+
1265
+ if ( ! isset( $instance['hide_if_empty'] ) || ! $instance['hide_if_empty'] || $cat_posts->have_posts() ) {
1266
+ echo $before_widget; // Xss ok. This is how widget actually expected to behave.
1267
+ echo $this->titleHTML( $before_title, $after_title, $instance );
1268
+
1269
+ $current_post_id = null;
1270
+ if ( is_singular() ) {
1271
+ $current_post_id = get_the_ID();
1272
+ }
1273
+
1274
+ if ( ! ( isset( $instance['is_shortcode'] ) && $instance['is_shortcode'] ) ) { // the internal id is needed only for widgets.
1275
+ echo '<ul id="' . esc_attr( WIDGET_BASE_ID ) . '-' . esc_attr( $this->number ) . '-internal" class="' . esc_attr( WIDGET_BASE_ID ) . '-internal' . "\">\n";
1276
+ } else {
1277
+ echo '<ul>';
1278
+ }
1279
+
1280
+ // set widget filters.
1281
+ if ( ! isset( $instance['excerpt_filters'] ) || $instance['excerpt_filters'] ) { // pre 4.7 widgets has filters on.
1282
+ $this->setExcerpFilters( $instance );
1283
+ }
1284
+
1285
+ while ( $cat_posts->have_posts() ) {
1286
+ $cat_posts->the_post();
1287
+ echo $this->itemHTML( $instance, $current_post_id );
1288
+ }
1289
+ echo "</ul>\n";
1290
+
1291
+ echo $this->footerHTML( $instance );
1292
+ echo $after_widget; // Xss ok. This is how widget actually expected to behave.
1293
+
1294
+ // remove widget filters.
1295
+ if ( ! isset( $instance['excerpt_filters'] ) || $instance['excerpt_filters'] ) { // pre 4.7 widgets has filters on.
1296
+ $this->removeExcerpFilters( $instance );
1297
+ }
1298
+
1299
+ wp_reset_postdata();
1300
+
1301
+ $use_css_cropping = isset( $this->instance['use_css_cropping'] ) && $this->instance['use_css_cropping'];
1302
+
1303
+ if ( $use_css_cropping ) {
1304
+ // enqueue relevant scripts and parameters to perform cropping
1305
+ // once we support only 4.5+ it can be refactored to use wp_add_inline_script.
1306
+ wp_enqueue_script( 'jquery' ); // just in case the theme or other plugins didn't enqueue it.
1307
+ add_action( 'wp_footer', __NAMESPACE__ . '\change_cropped_image_dimensions', 100 ); // add to the footer the cropping script.
1308
+ $number = $this->number;
1309
+ // a temporary hack to handle difference in the number in a true widget
1310
+ // and the number format expected at the rest of the places.
1311
+ if ( is_numeric( $number ) ) {
1312
+ $number = WIDGET_BASE_ID . '-' . $number;
1313
+ }
1314
+
1315
+ // add Javascript to change change cropped image dimensions on load and window resize.
1316
+ $thumb_w = $this->instance['thumb_w'];
1317
+ $thumb_h = $this->instance['thumb_h'];
1318
+ add_filter( 'cpw_crop_widgets',
1319
+ function ( $a ) use ( $number, $thumb_w, $thumb_h ) {
1320
+ $a[ $number ] = $thumb_w / $thumb_h;
1321
+ return $a;
1322
+ }
1323
+ );
1324
+ }
1325
+ }
1326
+ }
1327
+
1328
+ /**
1329
+ * Update the options.
1330
+ *
1331
+ * @param array $new_instance The new settings of the widget.
1332
+ * @param array $old_instance The current settings of the widget.
1333
+ * @return array
1334
+ */
1335
+ public function update( $new_instance, $old_instance ) {
1336
+
1337
+ $new_instance['title'] = sanitize_text_field( $new_instance['title'] ); // sanitize the title like core widgets do.
1338
+ if ( ! isset( $new_instance['excerpt_filters'] ) ) {
1339
+ $new_instance['excerpt_filters'] = '';
1340
+ }
1341
+ if ( current_user_can( 'unfiltered_html' ) ) {
1342
+ $instance['text'] = $new_instance['template'];
1343
+ } else {
1344
+ $instance['text'] = wp_kses_post( $new_instance['template'] );
1345
+ }
1346
+ return $new_instance;
1347
+ }
1348
+
1349
+ /**
1350
+ * Output the title panel of the widget configuration form.
1351
+ *
1352
+ * @param array $instance The widget's settings.
1353
+ * @return void
1354
+ *
1355
+ * @since 4.6
1356
+ */
1357
+ public function formTitlePanel( $instance ) {
1358
+ if ( isset( $instance['cat'] ) ) {
1359
+ $cat = $instance['cat'];
1360
+ } else {
1361
+ $cat = 0;
1362
+ }
1363
+
1364
+ $hide_title = false;
1365
+ if ( isset( $instance['hide_title'] ) && $instance['hide_title'] ) {
1366
+ $hide_title = true;
1367
+ }
1368
+ ?>
1369
+ <h4 data-panel="title"><?php esc_html_e( 'Title', 'category-posts' ); ?></h4>
1370
+ <div>
1371
+ <?php echo $this->get_checkbox_block_html( $instance, 'hide_title', esc_html__( 'Hide title', 'category-posts' ), false, true ); ?>
1372
+ <div class="cpwp_ident categoryposts-data-panel-title-settings" <?php if ( $hide_title ) { echo 'style="display:none"'; } ?>>
1373
+ <?php echo $this->get_text_input_block_html( $instance, 'title', esc_html__( 'Title', 'category-posts' ), '', __( 'Recent Posts', 'category-posts' ), true ); ?>
1374
+ <?php echo $this->get_checkbox_block_html( $instance, 'title_link', esc_html__( 'Make widget title link', 'category-posts' ), false, 0 !== $cat ); ?>
1375
+ <?php echo $this->get_text_input_block_html( $instance, 'title_link_url', esc_html__( 'Title link URL', 'category-posts' ), '', '', 0 === $cat ); ?>
1376
+ </div>
1377
+ </div>
1378
+ <?php
1379
+ }
1380
+
1381
+ /**
1382
+ * Output the filter panel of the widget configuration form.
1383
+ *
1384
+ * @param array $instance The parameters configured for the widget.
1385
+ * @return void
1386
+ *
1387
+ * @since 4.6
1388
+ */
1389
+ public function formFilterPanel( $instance ) {
1390
+ $instance = wp_parse_args( (array) $instance, array( 'cat' => 0 ) );
1391
+ $cat = $instance['cat'];
1392
+ ?>
1393
+ <h4 data-panel="filter"><?php esc_html_e( 'Filter', 'category-posts' ); ?></h4>
1394
+ <div>
1395
+ <p>
1396
+ <label>
1397
+ <?php esc_html_e( 'Category', 'category-posts' ); ?>:
1398
+ <?php
1399
+ wp_dropdown_categories( array(
1400
+ 'show_option_all' => __( 'All categories', 'category-posts' ),
1401
+ 'hide_empty' => 0,
1402
+ 'name' => $this->get_field_name( 'cat' ),
1403
+ 'selected' => $instance['cat'],
1404
+ 'class' => 'categoryposts-data-panel-filter-cat',
1405
+ ) );
1406
+ ?>
1407
+ </label>
1408
+ </p>
1409
+ <?php
1410
+ echo $this->get_checkbox_block_html( $instance, 'no_cat_childs', esc_html__( 'Exclude child categories', 'category-posts' ), false, ! empty( $instance['cat'] ) );
1411
+ echo $this->get_select_block_html( $instance, 'status', esc_html__( 'Status', 'category-posts' ), array(
1412
+ 'default' => esc_html__( 'WordPress Default', 'category-posts' ),
1413
+ 'publish' => esc_html__( 'Published', 'category-posts' ),
1414
+ 'future' => esc_html__( 'Scheduled', 'category-posts' ),
1415
+ 'private' => esc_html__( 'Private', 'category-posts' ),
1416
+ 'publish,future' => esc_html__( 'Published or Scheduled', 'category-posts' ),
1417
+ 'private,publish' => esc_html__( 'Published or Private', 'category-posts' ),
1418
+ 'private,future' => esc_html__( 'Private or Scheduled', 'category-posts' ),
1419
+ 'private,publish,future' => esc_html__( 'Published, Private or Scheduled', 'category-posts' ),
1420
+ ), 'default', true );
1421
+ echo $this->get_number_input_block_html( $instance, 'num', esc_html__( 'Number of posts to show', 'category-posts' ), get_option( 'posts_per_page' ), 1, '', '', true );
1422
+ echo $this->get_number_input_block_html( $instance, 'offset', esc_html__( 'Start with post', 'category-posts' ), 1, 1, '', '', true );
1423
+ echo $this->get_select_block_html( $instance, 'sort_by', esc_html__( 'Sort by', 'category-posts' ), array(
1424
+ 'date' => esc_html__( 'Date', 'category-posts' ),
1425
+ 'title' => esc_html__( 'Title', 'category-posts' ),
1426
+ 'comment_count' => esc_html__( 'Number of comments', 'category-posts' ),
1427
+ 'rand' => esc_html__( 'Random', 'category-posts' ),
1428
+ ), 'date', true );
1429
+ echo $this->get_checkbox_block_html( $instance, 'asc_sort_order', esc_html__( 'Reverse sort order (ascending)', 'category-posts' ), false, true );
1430
+ echo $this->get_checkbox_block_html( $instance, 'exclude_current_post', esc_html__( 'Exclude current post', 'category-posts' ), false, true );
1431
+ echo $this->get_checkbox_block_html( $instance, 'hideNoThumb', esc_html__( 'Exclude posts which have no thumbnail', 'category-posts' ), false, true );
1432
+ ?>
1433
+ </div>
1434
+ <?php
1435
+ }
1436
+
1437
+ /**
1438
+ * Generate the wrapper P around a form input element
1439
+ *
1440
+ * @since 4.8
1441
+ * @param string $html The HTML to wrap.
1442
+ * @param string $key The key to use as the prefix to the class.
1443
+ * @param bool $visible Indicates if the element should be visible when rendered.
1444
+ *
1445
+ * @return string HTML with P element contaning the html being passed with class based on the key
1446
+ * and style set to display:none if visibility is off.
1447
+ */
1448
+ private function get_wrap_block_html( $html, $key, $visible ) {
1449
+
1450
+ $cl = ' class="' . __NAMESPACE__ . '-' . esc_attr( $key ) . '"';
1451
+
1452
+ $style = '';
1453
+ if ( ! $visible ) {
1454
+ $style = ' style="display:none"';
1455
+ }
1456
+ $ret = '<p' . $cl . $style . ">\n" . $html . "</p>\n";
1457
+
1458
+ return $ret;
1459
+ }
1460
+
1461
+ /**
1462
+ * Generate a form P element containing a select element
1463
+ *
1464
+ * @since 4.8
1465
+ * @param array $instance The instance.
1466
+ * @param string $key The key in the instance array.
1467
+ * @param string $label The label to display and associate with the input.
1468
+ * @param array $list An array of pairs value (index) => label to be used for the options.
1469
+ * The labels are expected to be html escaped.
1470
+ * @param int $default The value to use if the key is not set in the instance.
1471
+ * @param bool $visible Indicates if the element should be visible when rendered.
1472
+ *
1473
+ * @return string HTML a P element contaning the select, its label, class based on the key
1474
+ * and style set to display:none if visibility is off.
1475
  */
1476
+ private function get_select_block_html( $instance, $key, $label, $list, $default, $visible ) {
1477
+ $value = $default;
1478
 
1479
+ if ( isset( $instance[ $key ] ) ) {
1480
+ $value = $instance[ $key ];
1481
+ }
1482
 
1483
+ if ( ! array_key_exists( $value, $list ) ) {
1484
+ $value = $default;
1485
+ }
1486
 
1487
+ $ret = '<label for="' . $this->get_field_id( $key ) . "\">\n" .
1488
+ $label .
1489
+ "</label>\n" .
1490
+ '<select id="' . $this->get_field_id( $key ) . '" name="' . $this->get_field_name( $key ) . '" autocomplete="off">' . "\n";
1491
+ foreach ( $list as $v => $l ) {
1492
+ $ret .= '<option value="' . esc_attr( $v ) . '" ' . selected( $v, $value, false ) . '>' . $l . "</option>\n";
1493
+ }
1494
+ $ret .= "</select>\n";
1495
 
1496
+ return $this->get_wrap_block_html( $ret, $key, $visible );
1497
+ }
 
1498
 
1499
+ /**
1500
+ * Generate a form P element containing a textarea input
1501
+ *
1502
+ * @since 4.8
1503
+ * @param array $instance The instance.
1504
+ * @param string $key The key in the instance array.
1505
+ * @param string $label The label to display and associate with the input (should be html escaped).
1506
+ * @param int $default The value to use if the key is not set in the instance.
1507
+ * @param string $placeholder The placeholder to use in the input (should be attribute escaped).
1508
+ * @param bool $visible Indicates if the element should be visible when rendered.
1509
+ * @param int $num_rows Number of rows.
1510
+ *
1511
+ * @return string HTML a P element containing the input, its label, class based on the key
1512
+ * and style set to display:none if visibility is off.
1513
+ */
1514
+ private function get_textarea_html( $instance, $key, $label, $default, $placeholder, $visible, $num_rows ) {
1515
 
1516
+ $value = $default;
 
 
 
 
 
 
 
1517
 
1518
+ if ( isset( $instance[ $key ] ) ) {
1519
+ $value = $instance[ $key ];
1520
+ }
1521
 
1522
+ $ret = '<label for="' . esc_attr( $this->get_field_id( $key ) ) . '">' . $label . '</label>' .
1523
+ '<textarea rows="' . esc_attr( $num_rows ) . '" placeholder="' . $placeholder . '" id="' . esc_attr( $this->get_field_id( $key ) ) . '" name="' . esc_attr( $this->get_field_name( $key ) ) . '" autocomplete="off">' . esc_textarea( $value ) . '</textarea>';
1524
 
1525
+ return $this->get_wrap_block_html( $ret, $key, $visible );
1526
+ }
1527
 
1528
+ /**
1529
+ * Generate a form P element containing a text input
1530
+ *
1531
+ * @since 4.8
1532
+ * @param array $instance The instance.
1533
+ * @param string $key The key in the instance array.
1534
+ * @param string $label The label to display and associate with the input.
1535
+ * Should be html escaped.
1536
+ * @param int $default The value to use if the key is not set in the instance.
1537
+ * @param string $placeholder The placeholder to use in the input. should be attribute escaped.
1538
+ * @param bool $visible Indicates if the element should be visible when rendered.
1539
+ *
1540
+ * @return string HTML a P element contaning the input, its label, class based on the key
1541
+ * and style set to display:none if visibility is off.
1542
+ */
1543
+ private function get_text_input_block_html( $instance, $key, $label, $default, $placeholder, $visible ) {
1544
 
1545
+ $value = $default;
 
 
 
 
 
 
 
 
 
1546
 
1547
+ if ( isset( $instance[ $key ] ) ) {
1548
+ $value = $instance[ $key ];
 
 
 
 
 
 
1549
  }
1550
+
1551
+ $ret = '<label for="' . $this->get_field_id( $key ) . "\">\n" .
1552
+ $label .
1553
+ '<input placeholder="' . $placeholder . '" id="' . $this->get_field_id( $key ) . '" name="' . $this->get_field_name( $key ) . '" type="text" value="' . esc_attr( $value ) . '" autocomplete="off"/>' . "\n" .
1554
+ "</label>\n";
1555
+
1556
+ return $this->get_wrap_block_html( $ret, $key, $visible );
1557
  }
1558
 
1559
  /**
1560
+ * Generate a form P element containing a number input
1561
  *
1562
+ * @since 4.8
1563
+ * @param array $instance The instance.
1564
+ * @param string $key The key in the instance array.
1565
+ * @param string $label The label to display and associate with the input.
1566
+ * expected to be escaped.
1567
+ * @param int $default The value to use if the key is not set in the instance.
1568
+ * @param int $min The minimum value allowed to be input.
1569
+ * @param int $max The maximum value allowed to be input.
1570
+ * @param string $placeholder The placeholder string to be used. expected to be escaped.
1571
+ * @param bool $visible Indicates if the element should be visible when rendered.
1572
+ *
1573
+ * @return string HTML a P element contaning the input, its label, class based on the key
1574
+ * and style set to display:none if visibility is off.
1575
  */
1576
+ private function get_number_input_block_html( $instance, $key, $label, $default, $min, $max, $placeholder, $visible ) {
1577
 
1578
+ $value = $default;
1579
+
1580
+ if ( isset( $instance[ $key ] ) ) {
1581
+ $value = $instance[ $key ];
1582
+ }
1583
+
1584
+ $minmax = '';
1585
+ if ( '' !== $min ) {
1586
+ $minmax .= ' min="' . $min . '"';
1587
+ }
1588
+ if ( '' !== $max ) {
1589
+ $minmax .= ' max="' . $max . '"';
1590
+ }
1591
+
1592
+ $ret = '<label for="' . $this->get_field_id( $key ) . "\">\n" .
1593
+ esc_html( $label ) . "\n" .
1594
+ '<input placeholder="' . $placeholder . '" id="' . esc_attr( $this->get_field_id( $key ) ) . '" name="' . esc_attr( $this->get_field_name( $key ) ) . '" class="' . esc_attr( $key ) . '" type="number"' . $minmax . ' value="' . esc_attr( $value ) . '" autocomplete="off" />' . "\n" .
1595
+ "</label>\n";
1596
+
1597
+ return $this->get_wrap_block_html( $ret, $key, $visible );
1598
  }
1599
 
1600
  /**
1601
+ * Generate a form P element containing a checkbox input
1602
  *
1603
+ * @since 4.8
1604
+ * @param array $instance The instance.
1605
+ * @param string $key The key in the instance array.
1606
+ * @param string $label The label to display and associate with the checkbox.
1607
+ * should be escaped string.
1608
+ * @param bool $default The value to use if the key is not set in the instance.
1609
+ * @param bool $visible Indicates if the element should be visible when rendered.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1610
  *
1611
+ * @return string HTML a P element contaning the checkbox, its label, class based on the key
1612
+ * and style set to display:none if visibility is off.
 
 
1613
  */
1614
+ private function get_checkbox_block_html( $instance, $key, $label, $default, $visible ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1615
 
1616
+ $value = $default;
1617
+
1618
+ if ( array_key_exists( $key, $instance ) ) {
1619
+ if ( $instance[ $key ] ) {
1620
+ $value = true;
1621
+ } else {
1622
+ $value = false;
1623
+ }
1624
+ }
1625
+ $ret = '<label for="' . esc_attr( $this->get_field_id( $key ) ) . "\">\n" .
1626
+ '<input id="' . esc_attr( $this->get_field_id( $key ) ) . '" name="' . esc_attr( $this->get_field_name( $key ) ) . '" type="checkbox" ' . checked( $value, true, false ) . '/>' . "\n" .
1627
+ $label .
1628
+ "</label>\n";
1629
+
1630
+ return $this->get_wrap_block_html( $ret, $key, $visible );
1631
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1632
 
1633
  /**
1634
  * The widget configuration form back end.
1635
  *
1636
+ * @param array $instance The parameters associated with the widget.
1637
  * @return void
1638
  */
1639
+ public function form( $instance ) {
1640
+ if ( 0 === count( $instance ) ) { // new widget, use defaults.
1641
+ $instance = default_settings();
1642
+ } else { // updated widgets come from =< 4.6 excerpt filter is on.
1643
+ if ( ! isset( $instance['excerpt_filters'] ) ) {
1644
+ $instance['excerpt_filters'] = 'on';
1645
+ }
1646
+ }
1647
+
1648
+ $instance = wp_parse_args( (array) $instance, array(
1649
+ 'hide_post_titles' => '',
1650
+ 'excerpt' => '',
1651
+ 'excerpt_more_text' => '',
1652
+ 'excerpt_filters' => '',
1653
+ 'date' => '',
1654
+ 'date_format' => '',
1655
+ 'disable_css' => '',
1656
+ 'disable_font_styles' => '',
1657
+ 'hide_if_empty' => '',
1658
+ 'hide_social_buttons' => '',
1659
+ 'preset_date_format' => 'other',
1660
+ 'thumb' => false,
1661
+ 'thumb_w' => get_option( 'thumbnail_size_w', 150 ),
1662
+ 'thumb_h' => get_option( 'thumbnail_size_h', 150 ),
1663
+ 'default_thunmbnail' => 0,
1664
+ 'use_css_cropping' => true,
1665
+ 'text_do_not_wrap_thumb' => false,
1666
  ) );
1667
 
 
 
 
1668
  $hide_post_titles = $instance['hide_post_titles'];
1669
  $excerpt = $instance['excerpt'];
 
1670
  $excerpt_more_text = $instance['excerpt_more_text'];
1671
  $excerpt_filters = $instance['excerpt_filters'];
 
 
1672
  $date = $instance['date'];
 
1673
  $date_format = $instance['date_format'];
1674
  $disable_css = $instance['disable_css'];
1675
  $disable_font_styles = $instance['disable_font_styles'];
1676
  $hide_if_empty = $instance['hide_if_empty'];
1677
+ $preset_date_format = $instance['preset_date_format'];
1678
+ $thumb = ! empty( $instance['thumb'] );
1679
+ $thumb_w = $instance['thumb_w'];
1680
+ $thumb_h = $instance['thumb_h'];
1681
+ $default_thunmbnail = $instance['default_thunmbnail'];
1682
+ $use_css_cropping = $instance['use_css_cropping'];
1683
+ $text_do_not_wrap_thumb = $instance['text_do_not_wrap_thumb'];
1684
 
1685
  $cat = $instance['cat'];
1686
 
1687
+ if ( ! isset( $style_done ) ) { // what an ugly hack, but can't figure out how to do it nicer on 4.3.
 
1688
  ?>
1689
+ <style type="text/css">
1690
+ .cpwp_ident {
1691
  color: #6A6A6A;
1692
  background: #F1F1F1;
1693
+ padding: 5px;
1694
+ }
1695
+ .cpwp_ident > .cpwp_ident {
1696
+ border-left:5px solid #B3B3B3;
1697
  padding: 0 10px;
1698
+ }
1699
  .cpwp_ident > p {
1700
  margin: 5px 0;
1701
  }
1702
  .cpwp_ident > label {
1703
  line-height: 2.75;
1704
+ display: inline-block;
1705
+ }
1706
+ .cpwp_ident_top {
1707
+ margin-top:-1em;
1708
+ padding-top:1em;
1709
+ }
1710
+
1711
+ .category-widget-cont input[type="number"] {
1712
+ width:5em;
1713
+ text-align:center;
1714
+ }
1715
+
1716
+ .categoryposts-template-help th {
1717
+ text-align:start;
1718
+ font-weight:bold;
1719
+ }
1720
+
1721
+ .categoryposts-template-help td {
1722
+ padding:2px;
1723
+ }
1724
+
1725
+ .categoryPosts-template textarea {
1726
+ font-size:16px;
1727
+ line-height:20px;
1728
  }
1729
+ </style>
 
 
 
 
1730
 
1731
+ <?php
1732
+ $style_done = true;
1733
+ }
1734
+ ?>
1735
 
1736
  <div class="category-widget-cont">
1737
+ <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 esc_html_e( 'Get the Pro version', 'category-posts' ); ?></a></p>
1738
+ <?php
1739
+ $this->formTitlePanel( $instance );
1740
+ $this->formFilterPanel( $instance );
1741
+ ?>
1742
+ <h4 data-panel="details"><?php esc_html_e( 'Post details', 'category-posts' ); ?></h4>
 
1743
  <div>
1744
+ <?php
1745
+ $template = '';
1746
+ if ( ! isset( $instance['template'] ) ) {
1747
+ $template = convert_settings_to_template( $instance );
1748
+ } else {
1749
+ $template = $instance['template'];
1750
+ }
1751
+ ?>
1752
+ <p><?php esc_html_e( 'Displayed parts', 'category-posts' ); ?></p>
1753
+ <div class="cpwp_ident">
1754
+ <?php
1755
+ echo $this->get_textarea_html( $instance, 'template', esc_html__( 'Template', 'category-posts' ) . ' <a href="#" class="dashicons toggle-template-help dashicons-editor-help imgedit-help-toggle"><span class="screen-reader-text">' . esc_html__( 'Show template help', 'category-posts' ) . '</span></a>', $template, '', true, 5 );
1756
+ preg_match_all( get_template_regex(), $template, $matches );
1757
+ $tags = array();
1758
+ if ( ! empty( $matches[0] ) ) {
1759
+ $tags = array_flip( $matches[0] );
1760
+ }
1761
+ ?>
1762
+ <div class="cat-post-template-help">
1763
+ <p><?php esc_html_e( 'The following text will be replaced with the relevant information. In addition you can use any text and html (if you have the permisions) anywhere you want', 'category-posts' ); ?>
1764
+ </p>
1765
+ <table>
1766
+ <tr>
1767
+ <th><?php esc_html_e( 'New line', 'category-posts' ); ?></th>
1768
+ <td><?php esc_html_e( 'Space', 'category-posts' ); ?></td>
1769
+ </tr>
1770
+ <tr>
1771
+ <th><?php esc_html_e( 'Empty line', 'category-posts' ); ?></th>
1772
+ <td><?php esc_html_e( 'Next line is a paragraph', 'category-posts' ); ?></td>
1773
+ </tr>
1774
+ <tr>
1775
+ <th>%title%</th>
1776
+ <td><?php esc_html_e( 'Post title', 'category-posts' ); ?></td>
1777
+ </tr>
1778
+ <tr>
1779
+ <th>%thumb%</th>
1780
+ <td><?php esc_html_e( 'Post thumbnail possibly wrapped by text', 'category-posts' ); ?></td>
1781
+ </tr>
1782
+ <tr>
1783
+ <th>%date%</th>
1784
+ <td><?php esc_html_e( 'Post publish date', 'category-posts' ); ?></td>
1785
+ </tr>
1786
+ <tr>
1787
+ <th>%excerpt%</th>
1788
+ <td><?php esc_html_e( 'Post excerpt', 'category-posts' ); ?></td>
1789
+ </tr>
1790
+ <tr>
1791
+ <th>%author%</th>
1792
+ <td><?php esc_html_e( 'Post author', 'category-posts' ); ?></td>
1793
+ </tr>
1794
+ <tr>
1795
+ <th>%commentnum%</th>
1796
+ <td><?php esc_html_e( 'The number of comments to the post', 'category-posts' ); ?></td>
1797
+ </tr>
1798
+ <tr>
1799
+ <th>%post_tag%</th>
1800
+ <td><?php esc_html_e( 'Post tags', 'category-posts' ); ?></td>
1801
+ </tr>
1802
+ <tr>
1803
+ <th>%category%</th>
1804
+ <td><?php esc_html_e( 'Post categories', 'category-posts' ); ?></td>
1805
+ </tr>
1806
+ </table>
1807
+ </div>
1808
+ <div class="cat-post-premade_templates">
1809
+ <p><label><?php esc_html_e( 'Select premade Template', 'category-posts' ); ?></label></p>
1810
+ <select>
1811
+ <option value="title"><?php esc_html_e( 'Only the title', 'category-posts' ); ?></option>
1812
+ <option value="title_excerpt"><?php esc_html_e( 'Title and Excerpt', 'category-posts' ); ?></option>
1813
+ <option value="title_thumb"><?php esc_html_e( 'Title and Thumbnail', 'category-posts' ); ?></option>
1814
+ <option value="title_thum_excerpt"><?php esc_html_e( 'Title, Thumbnail and Excerpt', 'category-posts' ); ?></option>
1815
+ <option value="everything"><?php esc_html_e( 'All with icons', 'category-posts' ); ?></option>
1816
+ </select>
1817
+ <p><button type="button" class="button"><?php esc_html_e( 'Select this template', 'category-posts' ); ?></button></p>
1818
+ </div>
1819
+ </div>
1820
+
1821
+ <?php // Excerpt settings. ?>
1822
+ <div class="categoryposts-data-panel-excerpt" style="display:<?php echo ( isset( $tags['%excerpt%'] ) ) ? 'block' : 'none'; ?>">
1823
+ <p><?php esc_html_e( 'Excerpt settings', 'category-posts' ); ?></p>
1824
+ <div class="cpwp_ident">
1825
+ <?php
1826
+ echo $this->get_number_input_block_html( $instance, 'excerpt_length', esc_html__( 'Excerpt length (words):', 'category-posts' ), get_option( 'posts_per_page' ), 1, 55, '', true );
1827
+ echo $this->get_text_input_block_html( $instance, 'excerpt_more_text', esc_html__( 'Excerpt \'more\' text:', 'category-posts' ), '', esc_attr__( '...', 'category-posts' ), true );
1828
+ echo $this->get_checkbox_block_html( $instance, 'excerpt_filters', esc_html__( 'Don\'t override Themes and plugin filters', 'category-posts' ), false, true );
1829
+ ?>
1830
+ </div>
1831
  </div>
1832
+ <div class="categoryposts-data-panel-date" style="display:<?php echo ( isset( $tags['%date%'] ) ) ? 'block' : 'none'; ?>">
1833
+ <p><?php esc_html_e( 'Date format settings', 'category-posts' ); ?></p>
1834
+ <div class="cpwp_ident">
1835
+ <?php
1836
+ echo $this->get_select_block_html( $instance, 'preset_date_format', esc_html__( 'Date format', 'category-posts' ), array(
1837
+ 'sitedateandtime' => esc_html__( 'Site date and time', 'category-posts' ),
1838
+ 'sitedate' => esc_html__( 'Site date', 'category-posts' ),
1839
+ 'sincepublished' => esc_html__( 'Time since published', 'category-posts' ),
1840
+ 'other' => esc_html__( 'PHP style format', 'category-posts' ),
1841
+ ), 'sitedateandtime', true );
1842
+ echo $this->get_text_input_block_html( $instance, 'date_format', esc_html__( 'PHP Style Date format', 'category-posts' ), '', 'j M Y', 'other' === $preset_date_format );
1843
+ ?>
1844
+ </div>
1845
+ </div>
1846
+
1847
+ <?php // Thumbnail settings. ?>
1848
+ <div class="categoryposts-data-panel-thumb" style="display:<?php echo ( isset( $tags['%thumb%'] ) ) ? 'block' : 'none'; ?>">
1849
+ <p><?php esc_html_e( 'Thumbnail settings', 'category-posts' ); ?></p>
1850
+ <div class="cpwp_ident">
1851
+ <p><?php esc_html_e( 'Thumbnail dimensions (pixel)', 'category-posts' ); ?></p>
1852
+ <?php
1853
+ echo $this->get_number_input_block_html( $instance, 'thumb_w', esc_html__( 'Width:', 'category-posts' ), get_option( 'thumbnail_size_w', 150 ), 1, '', '', true );
1854
+ echo $this->get_number_input_block_html( $instance, 'thumb_h', esc_html__( 'Height:', 'category-posts' ), get_option( 'thumbnail_size_h', 150 ), 1, '', '', true );
1855
+
1856
+ echo $this->get_checkbox_block_html( $instance, 'text_do_not_wrap_thumb', esc_html__( 'Do not wrap thumbnail with overflowing text', 'category-posts' ), false, true );
1857
+ echo $this->get_checkbox_block_html( $instance, 'use_css_cropping', esc_html__( 'CSS crop to requested size', 'category-posts' ), false, false );
1858
+ echo $this->get_select_block_html( $instance, 'thumb_hover', esc_html__( 'Animation on mouse hover:', 'category-posts' ), array(
1859
+ 'none' => esc_html__( 'None', 'category-posts' ),
1860
+ 'dark' => esc_html__( 'Darker', 'category-posts' ),
1861
+ 'white' => esc_html__( 'Brighter', 'category-posts' ),
1862
+ 'scale' => esc_html__( 'Zoom in', 'category-posts' ),
1863
+ 'blur' => esc_html__( 'Blur', 'category-posts' ),
1864
+ 'icon' => esc_html__( 'Icon', 'category-posts' ),
1865
+ ), 'none', true);
1866
+ echo $this->get_select_block_html( $instance, 'show_post_format', esc_html__( 'Indicate post format and position', 'category-posts' ), array(
1867
+ 'none' => esc_html__( 'None', 'category-posts' ),
1868
+ 'topleft' => esc_html__( 'Top left', 'category-posts' ),
1869
+ 'bottomleft' => esc_html__( 'Bottom left', 'category-posts' ),
1870
+ 'ceter' => esc_html__( 'Center', 'category-posts' ),
1871
+ 'topright' => esc_html__( 'Top right', 'category-posts' ),
1872
+ 'bottomright' => esc_html__( 'Bottom right', 'category-posts' ),
1873
+ 'nocss' => esc_html__( 'HTML without styling', 'category-posts' ),
1874
+ ), 'none', true );
1875
+ ?>
1876
+ <p>
1877
+ <label style="display:block">
1878
+ <?php esc_html_e( 'Default thumbnail: ', 'category-posts' ); ?>
1879
+ </label>
1880
+ <input type="hidden" class="default_thumb_id" id="<?php echo esc_attr( $this->get_field_id( 'default_thunmbnail' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'default_thunmbnail' ) ); ?>" value="<?php echo esc_attr( $default_thunmbnail ); ?>"/>
1881
+ <span class="default_thumb_img">
1882
+ <?php
1883
+ if ( ! $default_thunmbnail ) {
1884
+ esc_html_e( 'None', 'category-posts' );
1885
+ } else {
1886
+ $img = wp_get_attachment_image_src( $default_thunmbnail );
1887
+ echo '<img width="60" height="60" src="' . esc_url( $img[0] ) . '" />';
1888
+ }
1889
+ ?>
1890
+ </span>
1891
+ </p>
1892
+ <p>
1893
+ <button type="button" class="cwp_default_thumb_select button upload-button">
1894
+ <?php esc_html_e( 'Select image', 'category-posts' ); ?>
1895
+ </button>
1896
+ <button type="button" class="cwp_default_thumb_remove button upload-button" <?php if ( ! $default_thunmbnail ) { echo 'style="display:none"'; } ?> >
1897
+ <?php esc_html_e( 'No default', 'category-posts' ); ?>
1898
+ </button>
1899
+ </p>
1900
+ </div>
1901
  </div>
1902
+ <?php
1903
+ echo $this->get_checkbox_block_html( $instance, 'everything_is_link', esc_html__( 'Everything is a link', 'category-posts' ), false, true );
1904
+ ?>
 
 
 
 
 
 
 
 
 
1905
  </div>
1906
+ <h4 data-panel="general"><?php esc_html_e( 'General', 'category-posts' ); ?></h4>
1907
  <div>
1908
+ <div class="cpwp_ident">
1909
+ <?php echo $this->get_checkbox_block_html( $instance, 'disable_css', esc_html__( 'Disable the built-in CSS', 'category-posts' ), false, true ); ?>
1910
+ <?php echo $this->get_checkbox_block_html( $instance, 'disable_font_styles', esc_html__( 'Disable only font styles', 'category-posts' ), false, true ); ?>
1911
+ </div>
1912
+ <?php echo $this->get_checkbox_block_html( $instance, 'hide_if_empty', esc_html__( 'Hide if there are no matching posts', 'category-posts' ), false, true ); ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
1913
  </div>
1914
+ <h4 data-panel="footer"><?php esc_html_e( 'Footer', 'category-posts' ); ?></h4>
1915
  <div>
1916
+ <?php echo $this->get_text_input_block_html( $instance, 'footer_link_text', esc_html__( 'Footer link text', 'category-posts' ), '', '', true ); ?>
1917
+ <?php echo $this->get_text_input_block_html( $instance, 'footer_link', esc_html__( 'Footer link URL', 'category-posts' ), '', '', true ); ?>
 
 
 
 
 
 
 
 
 
 
1918
  </div>
1919
+ <p><a href="<?php echo esc_url( get_edit_user_link() ) . '#' . __NAMESPACE__; ?>"><?php esc_html_e( 'Widget admin behaviour settings', 'category-posts' ); ?></a></p>
1920
+ <p><a target="_blank" href="<?php echo esc_url( DOC_URL ); ?>"><?php esc_html_e( 'Documentation', 'category-posts' ); ?></a></p>
1921
+ <p><a target="_blank" href="<?php echo esc_url( SUPPORT_URL ); ?>"><?php esc_html_e( 'Support', 'category-posts' ); ?></a></p>
1922
+ <p><?php echo sprintf( wp_kses( __( 'We are on <a href="%1$s">Facebook</a> and <a href="%2$s">Twitter</a>.', 'category-posts' ), array( 'a' => array( 'href' => array() ) ) ), esc_url( 'https://www.facebook.com/TipTopPress' ), esc_url( 'https://twitter.com/TipTopPress' ) ); ?></p>
1923
  </div>
1924
  <?php
1925
  }
1926
  }
1927
 
1928
+ /*
1929
+ * Plugin action links section
1930
+ */
1931
 
1932
  /**
1933
  * Applied to the list of links to display on the plugins page (beside the activate/deactivate links).
1936
  *
1937
  * @since 4.6.3
1938
  */
1939
+ add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), __NAMESPACE__ . '\add_action_links' );
1940
 
1941
+ /**
1942
+ * Handle the add links filter, add our links to the links displayed under the plugin_basename
1943
+ * in the plugin admin screen.
1944
+ *
1945
+ * @param array $links The current links about to be displayed.
1946
+ */
1947
+ function add_action_links( $links ) {
1948
+ $pro_link = array(
1949
+ '<a target="_blank" href="' . esc_url( PRO_URL ) . '">' . esc_html__( 'Get the Pro version', 'category-posts' ) . '</a>',
1950
+ );
1951
 
1952
+ $links = array_merge( $pro_link, $links );
1953
 
1954
+ return $links;
1955
  }
1956
 
1957
+ /**
1958
+ * Register the widget.
1959
+ */
1960
  function register_widget() {
1961
+ return \register_widget( __NAMESPACE__ . '\Widget' );
1962
  }
1963
 
1964
+ add_action( 'widgets_init', __NAMESPACE__ . '\register_widget' );
1965
 
1966
  /**
1967
  * Output js code to handle responsive thumbnails
1969
  * @return void
1970
  *
1971
  * @since 4.7
1972
+ */
 
1973
  function change_cropped_image_dimensions() {
1974
  ?>
1975
  <script type="text/javascript">
1978
 
1979
  jQuery( document ).ready(function () {
1980
 
1981
+ <?php // namespace. ?>
1982
  var cwp_namespace = window.cwp_namespace || {};
1983
  cwp_namespace.fluid_images = cwp_namespace.fluid_images || {};
1984
 
1985
  cwp_namespace.fluid_images = {
1986
 
1987
+ <?php // variables. ?>
1988
  Widgets : {},
1989
  widget : null,
1990
 
1991
+ <?php // class. ?>
1992
  Span : function (_self, _imageRatio) {
1993
 
1994
+ <?php // variables. ?>
1995
  this.self = _self;
1996
  this.imageRatio = _imageRatio;
1997
  },
1998
 
1999
+ <?php // class. ?>
2000
  WidgetPosts : function (widget, ratio) {
2001
 
2002
+ <?php // variables. ?>
2003
  this.Spans = {};
2004
  this.allSpans = widget.find( '.cat-post-crop' );
2005
  this.firstSpan = this.allSpans.first();
2012
  this.Spans[i] = new cwp_namespace.fluid_images.Span( jQuery(this.allSpans[i]), imageRatio );
2013
  }
2014
 
2015
+ <?php // functions. ?>
2016
  this.changeImageSize = function changeImageSize() {
2017
 
2018
  this.listItemWidth = this.firstListItem.width();
2019
  this.SpanWidth = this.firstSpan.width();
2020
 
2021
+ if(this.listItemWidth < this.SpanWidth || <?php /* if the layout-width have not enough space to show the regular source-width */ echo "\r\n"; ?>
2022
+ this.listItemWidth < this.maxSpanWidth) { <?php /* defined start and stop working width for the image: Accomplish only the image width will be get smaller as the source-width */ echo "\r\n"; ?>
2023
  this.allSpans.width( this.listItemWidth );
2024
  var spanHeight = this.listItemWidth / this.ratio;
2025
  this.allSpans.height( spanHeight );
2036
  },
2037
  }
2038
 
2039
+ <?php
2040
+ /**
2041
+ * The cpw_crop_widgets is an internal filter that is used
2042
  * to gather the ids of the widgets to which apply cropping
2043
  *
2044
+ * For easier prevention of duplication, the widget id number should be an index
2045
  * in the array while the ratio of width/height be the value
2046
  */
2047
+ $widgets_ids = apply_filters( 'cpw_crop_widgets', array() );
2048
+ foreach ( $widgets_ids as $number => $ratio ) {
2049
+ ?>
2050
+ cwp_namespace.fluid_images.widget = jQuery('#<?php echo esc_attr( $number ); ?>');
2051
+ cwp_namespace.fluid_images.Widgets['<?php echo esc_attr( $number ); ?>'] = new cwp_namespace.fluid_images.WidgetPosts(cwp_namespace.fluid_images.widget,<?php echo esc_attr( $ratio ); ?>);
2052
+ <?php } ?>
2053
+
2054
+ <?php /* do on page load or on resize the browser window */ echo "\r\n"; ?>
2055
  jQuery(window).on('load resize', function() {
2056
  for (var widget in cwp_namespace.fluid_images.Widgets) {
2057
  cwp_namespace.fluid_images.Widgets[widget].changeImageSize();
2063
  <?php
2064
  }
2065
 
2066
+ /*
2067
+ * shortcode section.
2068
+ */
2069
 
2070
  /**
2071
  * Get shortcode settings taking into account if it is being customized
2073
  * When not customized returns the settings as stored in the meta, but when
2074
  * it is customized returns the setting stored in the virtual option used by the customizer
2075
  *
2076
+ * @param string $name The name of the shortcode to retun, empty string indicates the nameless.
2077
  *
2078
  * @return array the shortcode settings if a short code exists or empty string, empty array if name not found
2079
  *
2080
  * @since 4.6
2081
  */
2082
+ function shortcode_settings( $name ) {
2083
+ $meta = get_post_meta( get_the_ID(), SHORTCODE_META, true );
2084
 
2085
+ if ( ! empty( $meta ) && ! is_array( reset( $meta ) ) ) {
2086
+ $meta = array( '' => $meta ); // the conversion.
2087
+ }
2088
 
2089
+ if ( ! isset( $meta[ $name ] ) ) { // name do not exists? return empty array.
2090
  return array();
2091
+ }
2092
 
2093
+ $instance = $meta[ $name ];
2094
+ if ( is_customize_preview() ) {
2095
+ $o = get_option( '_virtual-' . WIDGET_BASE_ID );
2096
+ if ( is_array( $o ) ) {
2097
+ $instance = $o[ get_the_ID() ][ $name ];
2098
+ }
2099
+ }
2100
+
2101
+ if ( isset( $instance['template'] ) && $instance['template'] ) {
2102
+ ;
2103
+ } else {
2104
+ $instance['template'] = convert_settings_to_template( $instance );
2105
  }
2106
 
2107
  return $instance;
2110
  /**
2111
  * Handle the shortcode
2112
  *
2113
+ * @param array $attr Array of the attributes to the short code, none is expected.
2114
+ * @param string $content The content enclosed in the shortcode, none is expected.
2115
  *
2116
  * @return string An HTML of the "widget" based on its settings, actual or customized
 
2117
  */
2118
+ function shortcode( $attr, $content = null ) {
2119
+ $repository = new virtualWidgetsRepository();
2120
 
2121
  $shortcodes = $repository->getShortcodes();
2122
 
2123
  $name = '';
2124
+ if ( isset( $attr['name'] ) ) {
2125
  $name = $attr['name'];
2126
+ }
2127
 
2128
+ if ( is_singular() ) {
2129
+ if ( isset( $shortcodes[ $name ] ) ) {
2130
+ return $shortcodes[ $name ]->getHTML();
2131
+ }
2132
+ }
2133
 
2134
+ return '';
2135
  }
2136
 
2137
+ add_shortcode( SHORTCODE_NAME, __NAMESPACE__ . '\shortcode' );
2138
 
2139
  /**
2140
  * Find if a specific shortcode is used in a content
2141
  *
2142
+ * @param string $shortcode_name The name of the shortcode.
2143
+ * @param string $content The content to look at.
2144
  *
2145
  * @return array An array containing the name attributes of the shortcodes. Empty array is
2146
  * an indication there were no shourcodes
2147
  *
2148
  * @since 4.7
 
2149
  */
2150
+ function shortcode_names( $shortcode_name, $content ) {
2151
 
2152
  $names = array();
2153
 
2154
  $regex_pattern = get_shortcode_regex();
2155
+ if ( preg_match_all( '/' . $regex_pattern . '/s', $content, $matches ) ) {
2156
+ foreach ( $matches[2] as $k => $shortcode ) {
2157
+ if ( SHORTCODE_NAME === $shortcode ) {
2158
+ $name = '';
2159
+ $atts = shortcode_parse_atts( $matches[3][ $k ] );
2160
+ if ( ! empty( $atts['name'] ) ) {
2161
  $name = $atts['name'];
2162
+ }
2163
  $names[] = $name;
2164
  }
2165
  }
2169
  }
2170
 
2171
  /**
2172
+ * Organized way to have the default widget settings accessible
2173
  *
2174
  * @since 4.6
2175
  */
2176
+ function default_settings() {
2177
+ return array(
2178
+ 'title' => __( 'Recent Posts', 'category-posts' ),
2179
+ 'title_link' => false,
2180
+ 'title_link_url' => '',
2181
+ 'hide_title' => false,
2182
+ 'cat' => 0,
2183
+ 'num' => get_option( 'posts_per_page' ),
2184
+ 'offset' => 1,
2185
+ 'sort_by' => 'date',
2186
+ 'status' => 'publish',
2187
+ 'asc_sort_order' => false,
2188
+ 'exclude_current_post' => false,
2189
+ 'hideNoThumb' => false,
2190
+ 'footer_link_text' => '',
2191
+ 'footer_link' => '',
2192
+ 'thumb_w' => get_option( 'thumbnail_size_w', 150 ),
2193
+ 'thumb_h' => get_option( 'thumbnail_size_h', 150 ),
2194
+ 'use_css_cropping' => true,
2195
+ 'thumb_hover' => 'none',
2196
+ 'hide_post_titles' => false,
2197
+ 'excerpt_length' => 55,
2198
+ 'excerpt_more_text' => __( '...', 'category-posts' ),
2199
+ 'excerpt_filters' => false,
2200
+ 'comment_num' => false,
2201
+ 'date_link' => false,
2202
+ 'date_format' => '',
2203
+ 'disable_css' => false,
2204
+ 'disable_font_styles' => false,
2205
+ 'hide_if_empty' => false,
2206
+ 'show_post_format' => 'none',
2207
+ 'hide_social_buttons' => '',
2208
+ 'no_cat_childs' => false,
2209
+ 'everything_is_link' => false,
2210
+ 'preset_date_format' => 'sitedateandtime',
2211
+ 'template' => "%title%\n%thumb%",
2212
+ 'text_do_not_wrap_thumb' => false,
2213
+ );
2214
  }
2215
 
2216
  /**
2218
  *
2219
  * If A post has a short code, a meta holder is created, If it does not the meta holder is deleted
2220
  *
2221
+ * @param integer $pid The post ID of the post being saved.
2222
+ * @param WP_Post $post The post being saved.
2223
  * @return void
2224
  *
2225
  * @since 4.6
2226
  */
2227
+ function save_post( $pid, $post ) {
2228
 
2229
+ // ignore revisions and auto saves.
2230
+ if ( wp_is_post_revision( $pid ) || wp_is_post_autosave( $pid ) ) {
2231
  return;
2232
+ }
2233
 
2234
+ $meta = get_post_meta( $pid, SHORTCODE_META, true );
2235
+ if ( empty( $meta ) ) {
2236
  $meta = array();
2237
+ }
2238
 
2239
+ // check if only one shortcode format - non array of arrays, and convert it.
2240
+ if ( ! empty( $meta ) && ! is_array( reset( $meta ) ) ) {
2241
+ $meta = array( '' => $meta ); // the conversion.
2242
+ }
2243
 
2244
+ $old_names = array_keys( $meta ); // keep list of current shortcode names to delete lter whatever was deleted.
2245
+ $names = shortcode_names( SHORTCODE_NAME, $post->post_content );
2246
 
2247
+ // remove setting for unused names.
2248
+ $to_delete = array_diff( $old_names, $names );
2249
+ foreach ( $to_delete as $k ) {
2250
+ unset( $meta[ $k ] );
2251
+ }
2252
 
2253
+ foreach ( $names as $name ) {
2254
+ if ( ! isset( $meta[ $name ] ) ) {
2255
+ $meta[ $name ] = default_settings();
2256
  }
2257
  }
2258
 
2259
+ delete_post_meta( $pid, SHORTCODE_META );
2260
+ if ( ! empty( $meta ) ) {
2261
+ add_post_meta( $pid, SHORTCODE_META, $meta, true );
2262
+ }
2263
  }
2264
 
2265
+ add_action( 'save_post', __NAMESPACE__ . '\save_post', 10, 2 );
2266
 
2267
+ /**
2268
+ * Called on Customizer init to do related registrations.
2269
+ *
2270
+ * @param mixed $wp_customize The customizer object.
2271
+ */
2272
+ function customize_register( $wp_customize ) {
2273
 
2274
+ class shortCodeControl extends \WP_Customize_Control {
2275
+ public $form;
2276
  public $title_postfix;
2277
 
2278
+ public function render_content() {
2279
+ $widget_title = 'Category Posts Shortcode' . $this->title_postfix;
2280
  ?>
2281
  <div class="widget-top">
2282
+ <div class="widget-title"><h3><?php echo esc_html( $widget_title ); ?><span class="in-widget-title"></span></h3></div>
2283
  </div>
2284
  <div class="widget-inside" style="display: block;">
2285
  <div class="form">
2286
  <div class="widget-content">
2287
+ <?php echo $this->form; ?>
2288
  </div>
2289
  </div>
2290
  </div>
2291
  <?php
2292
+ }
2293
+ }
 
 
 
 
 
 
 
 
 
 
 
 
2294
 
2295
+ $args = array(
2296
+ 'post_type' => 'any',
2297
+ 'post_status' => 'any',
2298
+ 'posts_per_page' => -1,
2299
+ 'update_post_term_cache' => false,
2300
+ 'meta_query' => array(
2301
+ array(
2302
+ 'key' => SHORTCODE_META,
2303
+ 'compare' => 'EXISTS',
2304
+ ),
2305
+ ),
2306
+
2307
+ );
2308
+ $posts = get_posts( $args );
2309
 
2310
+ if ( count( $posts ) > 0 ) {
2311
+ $wp_customize->add_panel( __NAMESPACE__, array(
2312
+ 'title' => __( 'Category Posts Shortcode', 'category-posts' ),
2313
+ 'priority' => 300,
2314
  'capability' => 'edit_theme_options',
2315
+ ) );
2316
 
2317
+ foreach ( $posts as $p ) {
2318
+ $widget = new Widget();
2319
+ $meta = get_post_meta( $p->ID, SHORTCODE_META, true );
2320
+ if ( ! is_array( $meta ) ) {
2321
+ continue;
2322
+ }
2323
 
2324
+ if ( ! is_array( reset( $meta ) ) ) { // 4.6 format.
2325
+ $meta = array( '' => $meta );
2326
+ }
2327
 
2328
+ foreach ( $meta as $k => $m ) {
2329
+
2330
+ if ( isset( $m['template'] ) && $m['template'] ) {
2331
+ ;
2332
+ } else {
2333
+ $m['template'] = convert_settings_to_template( $m );
2334
+ }
2335
+
2336
+ $m = wp_parse_args( $m, default_settings() );
2337
 
2338
+ if ( 0 === count( $meta ) ) { // new widget, use defaults.
2339
  ;
2340
+ } else { // updated widgets come from =< 4.6 excerpt filter is on.
2341
+ if ( ! isset( $m['excerpt_filters'] ) ) {
2342
  $m['excerpt_filters'] = 'on';
2343
+ }
2344
  }
2345
 
2346
  $section_title = $k;
2347
+ if ( '' === $section_title ) {
2348
+ $section_title = __( '[shortcode]', 'category-posts' );
2349
+ }
2350
 
2351
+ $wp_customize->add_section( __NAMESPACE__ . '-' . $p->id . '-' . $k, array(
2352
+ 'title' => $section_title,
2353
+ 'priority' => 10,
2354
  'capability' => 'edit_theme_options',
2355
+ 'panel' => __NAMESPACE__,
2356
  ) );
2357
 
2358
  ob_start();
2359
+
2360
+ // For the form method to handle generation gracefully, the number needs to be a simple string, and the name might include other chars as well, so for simplisity md5 it.
2361
+ if ( '' !== $k ) {
2362
+ $widget->number = $p->ID . '_' . md5( $k );
2363
+ } else {
2364
+ $widget->number = $p->ID . '_';
2365
+ }
2366
+
2367
+ $widget->form( $m );
2368
  $form = ob_get_clean();
2369
+ $form = preg_replace_callback('/<(input|select|textarea)\s+.*name=("|\').*\[\w*\]\[([^\]]*)\][^>]*>/',
2370
+ function ( $matches ) use ( $p, $wp_customize, $m, $k ) {
2371
+ $setting = '_virtual-' . WIDGET_BASE_ID . '[' . $p->ID . '][' . $k . '][' . $matches[3] . ']';
2372
+ if ( ! isset( $m[ $matches[3] ] ) ) {
2373
+ $m[ $matches[3] ] = null;
2374
+ }
2375
  $wp_customize->add_setting( $setting, array(
2376
+ 'default' => $m[ $matches[3] ], // set default to current value.
2377
+ 'type' => 'option',
2378
  ) );
2379
 
2380
+ return str_replace( '<' . $matches[1], '<' . $matches[1] . ' data-customize-setting-link="' . $setting . '"', $matches[0] );
2381
  },
2382
  $form
2383
  );
2384
 
2385
  $args = array(
2386
+ 'label' => __( 'Layout', 'twentyfourteen' ),
2387
+ 'section' => __NAMESPACE__ . '-' . $p->id . '-' . $k,
2388
+ 'form' => $form,
2389
+ 'settings' => '_virtual-' . WIDGET_BASE_ID . '[' . $p->ID . '][' . $k . '][title]',
2390
+ 'active_callback' => function () use ( $p ) {
2391
+ return is_singular() && ( get_the_ID() === $p->ID );
2392
+ },
2393
+ );
2394
+
2395
+ if ( get_option( 'page_on_front' ) === $p->ID ) {
2396
+ $args['active_callback'] = function () {
2397
+ return is_front_page();
2398
+ };
2399
  }
2400
 
2401
  $sc = new shortCodeControl(
2402
  $wp_customize,
2403
+ '_virtual-' . WIDGET_BASE_ID . '[' . $p->ID . '][' . $k . '][title]',
2404
  $args
2405
+ );
2406
 
2407
+ if ( '' !== $k ) {
2408
+ $sc->title_postfix = ' ' . $k;
2409
+ }
2410
+ $wp_customize->add_control( $sc );
2411
  }
2412
+ }
2413
+ }
2414
  }
2415
 
2416
+ add_action( 'customize_register', __NAMESPACE__ . '\customize_register' );
2417
 
2418
  /**
2419
  * Save the virtual option used by the customizer into the proper meta values.
2426
  * @since 4.6
2427
  */
2428
  function customize_save_after() {
2429
+ $virtual = get_option( '_virtual-' . WIDGET_BASE_ID );
2430
 
2431
+ if ( is_array( $virtual ) ) {
2432
+ foreach ( $virtual as $pid => $instance ) {
2433
+ $meta = get_post_meta( $pid, SHORTCODE_META, true );
2434
+ if ( ! empty( $meta ) && ! is_array( reset( $meta ) ) ) {
2435
+ $meta = array( '' => $meta ); // the conversion.
2436
+ }
2437
 
2438
+ foreach ( $instance as $name => $new ) {
2439
+ if ( isset( $meta[ $name ] ) ) { // unlikely but maybe that short code was deleted by other session.
2440
+ $meta[ $name ] = array_merge( $meta[ $name ], $new );
2441
+ }
2442
  }
2443
+ }
2444
+ update_post_meta( $pid, SHORTCODE_META, $meta );
2445
+ }
2446
 
2447
+ delete_option( '_virtual-' . WIDGET_BASE_ID );
2448
  }
2449
 
2450
+ add_action( 'customize_save_after', __NAMESPACE__ . '\customize_save_after', 100 );
2451
 
2452
+ /*
2453
+ * tinymce related functions.
2454
+ */
2455
 
2456
  /**
2457
  * Uninstall handler, cleanup DB from options and meta
2461
  * @since 4.7
2462
  */
2463
  function uninstall() {
2464
+ delete_option( 'widget-' . WIDGET_BASE_ID ); // delete the option storing the widget options.
2465
+ delete_post_meta_by_key( SHORTCODE_META ); // delete the meta storing the shortcode.
2466
+ delete_metadata( 'user', 0, __NAMESPACE__, '', true ); // delete all user metadata.
2467
  }
2468
 
2469
+ register_uninstall_hook( __FILE__, __NAMESPACE__ . 'uninstall' );
2470
 
2471
  /**
2472
  * Register the tinymce shortcode plugin
2473
  *
2474
+ * @param array $plugin_array An array containing the current plugins to be used by tinymce.
2475
  *
2476
  * @return array An array containing the plugins to be used by tinymce, our plugin added to the $plugin_array parameter
2477
  *
2478
  * @since 4.7
2479
  */
2480
+ function mce_external_plugins( $plugin_array ) {
2481
+ if ( current_user_can( 'edit_theme_options' ) ) { // don't load the code if the user can not customize the shortcode.
2482
+ // enqueue TinyMCE plugin script with its ID.
2483
+ $meta = get_user_meta( get_current_user_id(), __NAMESPACE__, true );
2484
+ if ( is_array( $meta ) && isset( $meta['editor'] ) ) {
 
2485
  ;
2486
+ } else {
2487
+ $plugin_array[ __NAMESPACE__ ] = plugins_url( 'js/admin/tinymce.js?ver=' . VERSION, __FILE__ );
2488
+ }
2489
  }
2490
 
2491
+ return $plugin_array;
2492
  }
2493
 
2494
+ add_filter( 'mce_external_plugins', __NAMESPACE__ . '\mce_external_plugins' );
2495
 
2496
  /**
2497
  * Register the tinymce buttons for the add shortcode
2498
  *
2499
+ * @param array $buttons An array containing the current buttons to be used by tinymce.
2500
  *
2501
  * @return array An array containing the buttons to be used by tinymce, our button added to the $buttons parameter
2502
  *
2503
  * @since 4.7
2504
  */
2505
+ function mce_buttons( $buttons ) {
2506
+ if ( current_user_can( 'edit_theme_options' ) ) { // don't load the code if the user can not customize the shortcode
2507
+ // register buttons with their id.
2508
+ $meta = get_user_meta( get_current_user_id(), __NAMESPACE__, true );
2509
+ if ( is_array( $meta ) && isset( $meta['editor'] ) ) {
 
2510
  ;
2511
+ } else {
2512
+ array_push( $buttons, __NAMESPACE__ );
2513
+ }
2514
  }
2515
+
2516
+ return $buttons;
2517
  }
2518
 
2519
+ add_filter( 'mce_buttons', __NAMESPACE__ . '\mce_buttons' );
2520
 
2521
  /**
2522
  * Register the tinymcetranslation file
2523
  *
2524
+ * @param array $locales An array containing the current translations to be used by tinymce.
2525
  *
2526
  * @return array An array containing the translations to be used by tinymce, our localization added to the $locale parameter
2527
  *
2528
  * @since 4.7
2529
  */
2530
+ function mce_external_languages( $locales ) {
2531
+ if ( current_user_can( 'edit_theme_options' ) ) { // don't load the code if the user can not customize the shortcode.
2532
+ $meta = get_user_meta( get_current_user_id(), __NAMESPACE__, true );
2533
+ if ( is_array( $meta ) && isset( $meta['editor'] ) ) {
2534
  ;
2535
+ } else {
2536
+ $locales['cat-posts'] = plugin_dir_path( __FILE__ ) . 'tinymce_translations.php';
2537
+ }
2538
+ }
2539
+
2540
+ return $locales;
2541
  }
2542
 
2543
+ add_filter( 'mce_external_languages', __NAMESPACE__ . '\mce_external_languages' );
2544
 
2545
+ /*
2546
+ * user profile related functions.
2547
+ */
2548
 
2549
+ add_action( 'show_user_profile', __NAMESPACE__ . '\show_user_profile' );
2550
+ add_action( 'edit_user_profile', __NAMESPACE__ . '\show_user_profile' );
2551
 
2552
+ /**
2553
+ * Display the user specific setting on its profile page
2554
+ *
2555
+ * @param WP_user $user The user for which the profile page displays information.
2556
+ *
2557
+ * @since 4.7
2558
+ */
2559
  function show_user_profile( $user ) {
2560
 
2561
+ if ( ! current_user_can( 'edit_user', $user->ID ) ) {
2562
  return;
2563
+ }
2564
 
2565
+ if ( ! current_user_can( 'edit_theme_options', $user->ID ) ) {
2566
  return;
2567
+ }
2568
 
2569
  $meta = get_the_author_meta( __NAMESPACE__, $user->ID );
2570
 
2571
+ if ( empty( $meta ) ) {
2572
  $meta = array();
2573
+ }
2574
 
2575
  $accordion = false;
2576
+ if ( isset( $meta['panels'] ) ) {
2577
  $accordion = true;
2578
+ }
2579
 
2580
  $editor = false;
2581
+ if ( isset( $meta['editor'] ) ) {
2582
  $editor = true;
2583
+ }
2584
  ?>
2585
+ <h3 id="<?php echo __NAMESPACE__; ?>"><?php esc_html_e( 'Category Posts Widget behaviour settings', 'category-posts' ); ?></h3>
2586
 
2587
  <table class="form-table">
2588
  <tr>
2589
+ <th><label for="<?php echo __NAMESPACE__; ?>[panels]"><?php esc_html_e( 'Open panels behavior', 'category-posts' ); ?></label></th>
2590
  <td>
2591
+ <input type="checkbox" name="<?php echo __NAMESPACE__; ?>[panels]" id="<?php echo __NAMESPACE__; ?>[panels]" <?php checked( $accordion ); ?>>
2592
+ <label for=<?php echo __NAMESPACE__; ?>[panels]><?php esc_html_e( 'Close the curremtly open panel when opening a new one', 'category-posts' ); ?></label>
2593
  </td>
2594
  </tr>
2595
  <tr>
2596
+ <th><label for="<?php echo __NAMESPACE__; ?>[editor]"><?php esc_html_e( 'Visual editor button', 'category-posts' ); ?></label></th>
2597
  <td>
2598
+ <input type="checkbox" name="<?php echo __NAMESPACE__; ?>[editor]" id="<?php echo __NAMESPACE__; ?>[editor]" <?php checked( $editor ); ?>>
2599
+ <label for="<?php echo __NAMESPACE__; ?>[editor]"><?php esc_html_e( 'Hide the "insert shortcode" button from the editor', 'category-posts' ); ?></label>
2600
  </td>
2601
  </tr>
2602
  </table>
2603
  <?php
2604
  }
2605
 
2606
+ add_action( 'personal_options_update', __NAMESPACE__ . '\personal_options_update' );
2607
+ add_action( 'edit_user_profile_update', __NAMESPACE__ . '\personal_options_update' );
2608
 
2609
+ /**
2610
+ * Handles saving user related settings as was set in the profile page.
2611
+ *
2612
+ * @param int $user_id the ID of the user for which the data is saved..
2613
+ *
2614
+ * @since 4.7
2615
+ */
2616
  function personal_options_update( $user_id ) {
2617
 
2618
+ if ( ! current_user_can( 'edit_user', $user_id ) ) {
2619
  return false;
2620
+ }
2621
 
2622
+ if ( ! current_user_can( 'edit_theme_options', $user_id ) ) {
2623
  return;
2624
+ }
2625
 
2626
+ if ( isset( $_POST[ __NAMESPACE__ ] ) ) {
2627
+ update_user_meta( $user_id, __NAMESPACE__, wp_unslash( $_POST[ __NAMESPACE__ ] ) );
2628
+ } else {
2629
+ delete_user_meta( $user_id, __NAMESPACE__ );
2630
+ }
2631
  }
2632
 
2633
+ /*
2634
+ * external API.
2635
+ */
2636
 
2637
  /**
2638
  * Class that represent a virtual widget. Each widget being created will have relevant
2639
+ * CSS output in the header, but still requires a call for getHTML method or renderHTML
2640
  * to get or output the HTML
2641
  *
2642
  * @since 4.7
2643
  */
2644
  class virtualWidget {
2645
+
2646
+ /**
2647
+ * A container for all the "active" objects
2648
+ *
2649
+ * @var Array
2650
+ *
2651
+ * @since 4.7
2652
+ */
2653
  private static $collection = array();
2654
+
2655
+ /**
2656
+ * The identifier use as the id of the root html element when the HTML is generated.
2657
+ *
2658
+ * @var string
2659
+ *
2660
+ * @since 4.7
2661
+ */
2662
  private $id;
2663
+
2664
+ /**
2665
+ * A container for all the "active" objects
2666
+ *
2667
+ * @var string The class name to be use us the class attribute on the root html element.
2668
+ *
2669
+ * @since 4.7
2670
+ */
2671
  private $class;
2672
 
2673
  /**
2675
  * 10 is executed if any CSS output should be generated.
2676
  *
2677
  * @param string $id The identifier use as the id of the root html element when the HTML
2678
+ * is generated.
2679
  *
2680
+ * @param string $class The class name to be use us the class attribute on the root html element.
2681
  *
2682
+ * @param array $args The setting to be applied to the widget.
2683
  *
2684
  * @since 4.7
2685
  */
2686
+ public function __construct( $id, $class, $args ) {
2687
  $this->id = $id;
2688
  $this->class = $class;
2689
+ self::$collection[ $id ] = wp_parse_args( $args, default_settings() );
2690
  }
2691
 
2692
+ /**
2693
+ * Do what ever cleanup needed when the object is destroyed.
2694
+ *
2695
+ * @since 4.7
2696
+ */
2697
+ public function __destruct() {
2698
+ unset( self::$collection[ $this->id ] );
2699
  }
2700
 
2701
  /**
2702
+ * Return the HTML of the widget as is generated based on the settings passed at construction time
2703
  *
2704
  * @return string
2705
  *
2706
  * @since 4.7
2707
  */
2708
+ public function getHTML() {
2709
 
2710
+ $widget = new Widget();
2711
+ $widget->number = $this->id; // needed to make a unique id for the widget html element.
2712
  ob_start();
2713
+ $args = self::$collection[ $this->id ];
2714
+ $args['is_shortcode'] = true; // indicate that we are doing shortcode processing to outputting funtions.
2715
  $widget->widget(array(
2716
+ 'before_widget' => '',
2717
+ 'after_widget' => '',
2718
+ 'before_title' => '',
2719
+ 'after_title' => '',
2720
+ ), $args);
2721
  $ret = ob_get_clean();
2722
+ $ret = '<div id="' . esc_attr( $this->id ) . '" class="' . esc_attr( $this->class ) . '">' . $ret . '</div>';
2723
  return $ret;
2724
  }
2725
 
2732
  *
2733
  * @since 4.7
2734
  */
2735
+ public function renderHTML() {
2736
  echo $this->getHTML();
2737
  }
2738
 
2739
  /**
2740
  * Calculate the CSS rules required for the widget as is generated based on the settings passed at construction time
2741
  *
2742
+ * @param bool $is_shortcode Indicated if rules are generated for a shortcode.
2743
+ * @param array $ret "returned" Collection of CSS rules.
2744
  *
2745
  * @since 4.7
2746
  */
2747
+ public function getCSSRules( $is_shortcode, &$rules ) {
2748
+ $ret = array();
2749
+ $settings = self::$collection[ $this->id ];
2750
  $widget_id = $this->id;
2751
+ if ( ! $is_shortcode ) {
2752
  $widget_id .= '-internal';
2753
+ }
2754
+ $disable_css = isset( $settings['disable_css'] ) && $settings['disable_css'];
2755
 
2756
+ if ( ! $disable_css ) { // checks if css disable is not set.
2757
 
2758
+ $styles = array( // styles that should be applied to all widgets.
2759
+ 'thumb_clenup' => '.cat-post-item img {max-width: initial; max-height: initial; margin: initial;}',
2760
+ 'author_clenup' => '.cat-post-author {margin-bottom: 0;}',
2761
+ 'thumb' => '.cat-post-thumbnail {margin: 5px 10px 5px 0;}',
2762
+ 'item_clenup' => '.cat-post-item:before {content: ""; clear: both;}',
 
 
 
2763
  );
2764
 
2765
+ if ( ! ( isset( $settings['disable_font_styles'] ) && $settings['disable_font_styles'] ) ) { // checks if disable font styles is not set.
2766
+ // add general styles which apply to font styling.
2767
+ $styles['title_font'] = '.cat-post-title {font-size: 15px;}';
2768
+ $styles['current_title_font'] = '.cat-post-current .cat-post-title {font-weight: bold; text-transform: uppercase;}';
2769
+ $styles['date_font'] = '.cat-post-date {font-size: 14px; line-height: 18px; font-style: italic; margin-bottom: 5px;}';
2770
+ $styles['comment_num_font'] = '.cat-post-comment-num {font-size: 14px; line-height: 18px;}';
 
 
2771
  }
2772
 
2773
  /*
2774
+ * The twenty seventeen theme have a border between the LI elements of a widget,
2775
+ * so remove our border if we detect its use to avoid conflicting styling.
2776
+ */
2777
+ if ( ! $is_shortcode && function_exists( 'twentyseventeen_setup' ) ) {
2778
+ $styles['item_style'] = '.cat-post-item {list-style: none; list-style-type: none; margin: 0; padding: 3px 0;}';
2779
  } else {
2780
+ $styles['item_style'] = '.cat-post-item {border-bottom: 1px solid #ccc; list-style: none; list-style-type: none; margin: 3px 0; padding: 3px 0;}';
2781
+ $styles['last_item_style'] = '.cat-post-item:last-child {border-bottom: none;}';
2782
  }
2783
 
2784
+ // everything link related styling
2785
+ // if we are dealing with "everything is a link" option, we need to add the clear:both to the a element, not the div.
2786
+ if ( isset( $settings['everything_is_link'] ) && $settings['everything_is_link'] ) {
2787
+ $styles['after_item'] = '.cat-post-item a:after {content: ""; display: table; clear: both;}';
2788
+ } else {
2789
+ $styles['after_item'] = '.cat-post-item:after {content: ""; display: table; clear: both;}';
2790
  }
2791
 
2792
+ // add post format css if needed.
2793
+ if ( isset( $settings['template'] ) && preg_match( '/%thumb%/', $settings['template'] ) ) {
2794
+ if ( ! isset( $settings['show_post_format'] ) || ( ( 'none' !== $settings['show_post_format'] ) && ( 'nocss' !== $settings['show_post_format'] ) ) ) {
2795
+ static $fonts_added = false;
2796
+ if ( ! $fonts_added ) {
2797
+ $fonturl = esc_url( plugins_url( 'icons/font', __FILE__ ) );
2798
+ $ret['post_format_font'] = "@font-face {\n" .
2799
+ "font-family: 'cat_post';\n" .
2800
+ "src: url('$fonturl/cat_post.eot?58348147');\n" .
2801
+ "src: url('$fonturl/cat_post.eot?58348147#iefix') format('embedded-opentype'),\n" .
2802
+ " url('$fonturl/cat_post.woff2?58348147') format('woff2'),\n" .
2803
+ " url('$fonturl/cat_post.woff?58348147') format('woff'),\n" .
2804
+ " url('$fonturl/cat_post.ttf?58348147') format('truetype');\n" .
2805
+ " font-weight: normal;\n" .
2806
+ " font-style: normal;\n" .
2807
+ "}\n";
2808
+ }
2809
+ $fonts_added = true;
2810
+
2811
+ $placement = '';
2812
+ switch ( $settings['show_post_format'] ) {
2813
+ case 'topleft':
2814
+ $placement = 'top:10%; left:10%;';
2815
+ break;
2816
+ case 'bottomleft':
2817
+ $placement = 'bottom:10%; left:10%;';
2818
+ break;
2819
+ case 'ceter':
2820
+ $placement = 'top:calc(50% - 34px); left:calc(50% - 34px);';
2821
+ break;
2822
+ case 'topright':
2823
+ $placement = 'top:10%; right:10%;';
2824
+ break;
2825
+ case 'bottomright':
2826
+ $placement = 'bottom:10%; right:10%;';
2827
+ break;
2828
+ }
2829
+ $styles['post_format_thumb'] = '.cat-post-thumbnail span {position:relative}';
2830
+ $styles['post_format_icon_styling'] = '.cat-post-format:before {font-family: "cat_post"; position:absolute; color:#FFFFFF; font-size:64px; line-height: 1; ' . $placement . '}';
2831
+
2832
+ $styles['post_format_icon_aside'] = ".cat-post-format-aside:before { content: '\\f0f6'; }";
2833
+ $styles['post_format_icon_chat'] = ".cat-post-format-chat:before { content: '\\e802'; }";
2834
+ $styles['post_format_icon_gallery'] = ".cat-post-format-gallery:before { content: '\\e805'; }";
2835
+ $styles['post_format_icon_link'] = ".cat-post-format-link:before { content: '\\e809'; }";
2836
+ $styles['post_format_icon_image'] = ".cat-post-format-image:before { content: '\\e800'; }";
2837
+ $styles['post_format_icon_quote'] = ".cat-post-format-quote:before { content: '\\f10d'; }";
2838
+ $styles['post_format_icon_status'] = ".cat-post-format-status:before { content: '\\e80a'; }";
2839
+ $styles['post_format_icon_video'] = ".cat-post-format-video:before { content: '\\e801'; }";
2840
+ $styles['post_format_icon_audio'] = ".cat-post-format-audio:before { content: '\\e803'; }";
2841
+
2842
  }
2843
  }
2844
 
2845
+ foreach ( $styles as $key => $style ) {
2846
+ $ret[ $key ] = '#' . $widget_id . ' ' . $style;
 
 
 
 
 
 
 
 
 
2847
  }
2848
 
2849
+ if ( $is_shortcode ) {
2850
  // Twenty Sixteen Theme adds underlines to links with box whadow wtf ...
2851
+ $ret['twentysixteen_thumb'] = '#' . $widget_id . ' .cat-post-thumbnail {box-shadow:none}'; // this for the thumb link.
2852
+ if ( ! ( isset( $settings['disable_font_styles'] ) && $settings['disable_font_styles'] ) ) { // checks if disable font styles is not set.
2853
+ $ret['twentysixteen_tag_link'] = '#' . $widget_id . ' .cat-post-tax-post_tag a {box-shadow:none}'; // this for the tag link.
2854
+ $ret['twentysixteen_tag_span'] = '#' . $widget_id . ' .cat-post-tax-post_tag span {box-shadow:none}'; // this for the tag link.
2855
+ }
2856
  // Twenty Fifteen Theme adds border ...
2857
+ $ret['twentyfifteen_thumb'] = '#' . $widget_id . ' .cat-post-thumbnail {border:0}'; // this for the thumb link.
2858
+ if ( ! ( isset( $settings['disable_font_styles'] ) && $settings['disable_font_styles'] ) ) { // checks if disable font styles is not set.
2859
+ $ret['twentysixteen_tag_link'] = '#' . $widget_id . ' .cat-post-tax-post_tag a {border:0}'; // this for the tag link.
2860
+ $ret['twentysixteen_tag_span'] = '#' . $widget_id . ' .cat-post-tax-post_tag span {border:0}'; // this for the tag link.
2861
+ }
2862
+ }
2863
+
2864
+ // probably all Themes have too much margin on their p element when used in the shortcode or widget.
2865
+ $ret['p_styling'] = '#' . $widget_id . ' p {margin:5px 0 0 0}'; // since on bottom it will make the spacing on cover
2866
+ // bigger (add to the padding) use only top for now.
2867
+ $ret['div_styling'] = '#' . $widget_id . ' li > div {margin:5px 0 0 0; clear:both;}'; // Add margin between the rows.
2868
+
2869
+ // use WP dashicons in the template (e.g. for premade Template 'All and icons')
2870
+ $ret['dashicons'] = '#' . $widget_id . ' .dashicons {vertical-align:middle;}';
2871
+ }
2872
+
2873
+ // Regardless if css is disabled we need some styling for the thumbnail
2874
+ // to make sure cropping is properly done, and they fit the allocated space.
2875
+ if ( isset( $settings['template'] ) && preg_match( '/%thumb%/', $settings['template'], $m, PREG_OFFSET_CAPTURE ) ) {
2876
+ if ( isset( $settings['use_css_cropping'] ) && $settings['use_css_cropping'] ) {
2877
+ $ret['thumb_crop'] = '#' . $widget_id . ' .cat-post-crop {overflow: hidden; display:inline-block}';
2878
+ } else {
2879
+ $ret['thumb_overflow'] = '#' . $widget_id . ' .cat-post-thumbnail span {overflow: hidden; display:inline-block}';
2880
  }
2881
+ $ret['thumb_styling'] = '#' . $widget_id . ' .cat-post-item img {margin: initial;}';
2882
+
2883
+ // Thumbnail related positioning rules.
2884
+ $wrap = isset( $settings['text_do_not_wrap_thumb'] ) && $settings['text_do_not_wrap_thumb'];
2885
+ if ( $wrap ) {
2886
+ $ret['thumb_flex'] = '#' . $widget_id . ' .cat-post-do-not-wrap-thumbnail {display:flex;}'; // Thumbnail container should flex.
2887
+ }
2888
+ $ret['text_do_not_wrap_thumb'] = '#' . $widget_id . ' .cat-post-thumbnail {float:left;}';
2889
  }
2890
 
2891
+ // Some hover effect require css to work, add it even if CSS is disabled.
2892
+ if ( isset( $settings['thumb_hover'] ) ) {
2893
+ switch ( $settings['thumb_hover'] ) {
2894
+ case 'white':
2895
+ $ret['white_hover_background'] = '#' . $widget_id . ' .cat-post-white {background-color: white;}';
2896
+ $ret['white_hover_thumb'] = '#' . $widget_id . ' .cat-post-white img {padding-bottom: 0 !important; -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -ms-transition: all 0.3s ease; -o-transition: all 0.3s ease; transition: all 0.3s ease;}';
2897
+ $ret['white_hover_transform'] = '#' . $widget_id . ' .cat-post-white:hover img {opacity: 0.8;}';
2898
+ break;
2899
+ case 'dark':
2900
+ $ret['dark_hover_thumb'] = '#' . $widget_id . ' .cat-post-dark img {padding-bottom: 0 !important; -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -ms-transition: all 0.3s ease; -o-transition: all 0.3s ease; transition: all 0.3s ease;}';
2901
+ $ret['dark_hover_transform'] = '#' . $widget_id . ' .cat-post-dark:hover img {-webkit-filter: brightness(75%); -moz-filter: brightness(75%); -ms-filter: brightness(75%); -o-filter: brightness(75%); filter: brightness(75%);}';
2902
+ break;
2903
+ case 'scale':
2904
+ $ret['scale_hover_thumb'] = '#' . $widget_id . ' .cat-post-scale img {margin: initial; padding-bottom: 0 !important; -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -ms-transition: all 0.3s ease; -o-transition: all 0.3s ease; transition: all 0.3s ease;}';
2905
+ $ret['scale_hover_transform'] = '#' . $widget_id . ' .cat-post-scale:hover img {-webkit-transform: scale(1.1, 1.1); -ms-transform: scale(1.1, 1.1); transform: scale(1.1, 1.1);}';
2906
+ break;
2907
+ case 'blur':
2908
+ $ret['blur_hover_thumb'] = '#' . $widget_id . ' .cat-post-blur img {padding-bottom: 0 !important; -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -ms-transition: all 0.3s ease; -o-transition: all 0.3s ease; transition: all 0.3s ease;}';
2909
+ $ret['blur_hover_transform'] = '#' . $widget_id . ' .cat-post-blur:hover img {-webkit-filter: blur(2px); -moz-filter: blur(2px); -o-filter: blur(2px); -ms-filter: blur(2px); filter: blur(2px);}';
2910
+ break;
2911
+ case 'icon':
2912
+ $fonturl = esc_url( plugins_url( 'icons/font', __FILE__ ) );
2913
+ $ret['icon_hover_font'] = "@font-face {\n" .
2914
+ "font-family: 'cat_post';\n" .
2915
+ "src: url('$fonturl/cat_post.eot?58348147');\n" .
2916
+ "src: url('$fonturl/cat_post.eot?58348147#iefix') format('embedded-opentype'),\n" .
2917
+ " url('$fonturl/cat_post.woff2?58348147') format('woff2'),\n" .
2918
+ " url('$fonturl/cat_post.woff?58348147') format('woff'),\n" .
2919
+ " url('$fonturl/cat_post.ttf?58348147') format('truetype');\n" .
2920
+ " font-weight: normal;\n" .
2921
+ " font-style: normal;\n" .
2922
+ "}\n";
2923
+
2924
+ $ret['icon_hover_thumb'] = '#' . $widget_id . ' .cat-post-format-standard:before {opacity:0; -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -ms-transition: all 0.3s ease; -o-transition: all 0.3s ease; transition: all 0.3s ease;}';
2925
+ $ret['icon_hover_transform'] = '#' . $widget_id . ' .cat-post-thumbnail:hover .cat-post-format-standard:before {opacity:1;}';
2926
+ if ( isset( $settings['show_post_format'] ) && ( 'none' === $settings['show_post_format'] ) ) {
2927
+ $ret[] = '#' . $widget_id . ' .cat-post-thumbnail {position:relative}';
2928
+ $ret[] = '#' . $widget_id . ' .cat-post-icon .cat-post-format:before {font-family: "cat_post"; position:absolute; color:#FFFFFF; font-size:64px; line-height: 1; ' .
2929
+ 'top:calc(50% - 34px); left:calc(50% - 34px);}';
2930
+ }
2931
+ $ret[] = '#' . $widget_id . " .cat-post-format-standard:before {padding-left:12px; content: '\\e806'; }";
2932
+ break;
2933
+ }
2934
  }
2935
+ $rules[] = $ret;
2936
  }
2937
 
2938
  /**
2940
  *
2941
  * Just a wrapper that output getCSSRules
2942
  *
2943
+ * @param bool $is_shortcode Indicates if we are in the context os a shortcode.
2944
  *
2945
  * @since 4.7
2946
  */
2947
+ public function outputCSS( $is_shortcode ) {
2948
  $rules = array();
2949
+ getCSSRules( $is_shortcode, $rules );
2950
+ foreach ( $rules as $rule ) {
2951
  echo "$rule\n";
2952
  }
2953
  }
2954
+
2955
  /**
2956
  * Get the id the virtual widget was registered with
2957
  *
2959
  *
2960
  * @since 4.7
2961
  */
2962
+ public function id() {
2963
  return $this->id;
2964
  }
2965
 
2970
  *
2971
  * @since 4.7
2972
  */
2973
+ public static function getAllSettings() {
2974
  return self::$collection;
2975
  }
2976
 
2983
  * @since 4.7
2984
  */
2985
  class virtualWidgetsRepository {
2986
+
2987
+ /**
2988
+ * Collection of objects representing shortcodes.
2989
+ *
2990
+ * @var array
2991
+ *
2992
+ * @since 4.7
2993
+ */
2994
  private static $shortcodeCollection = array();
2995
+
2996
+ /**
2997
+ * Collection of objects representing widgets.
2998
+ *
2999
+ * @var array
3000
+ *
3001
+ * @since 4.7
3002
+ */
3003
  private static $widgetCollection = array();
3004
 
3005
  /**
3006
  * Add a virtual widget representing a shortcode to the repository
3007
  *
3008
+ * @param string $index A name to identify the specific shortcode.
3009
+ * @param virtualWidget $widget The virtual widget for it.
3010
  *
3011
  * @since 4.7
3012
  */
3013
+ public function addShortcode( $index, $widget ) {
3014
+ self::$shortcodeCollection[ $index ] = $widget;
3015
  }
3016
 
3017
  /**
3021
  *
3022
  * @since 4.7
3023
  */
3024
+ public function getShortcodes() {
3025
  return self::$shortcodeCollection;
3026
  }
3027
 
3028
  /**
3029
  * Add a virtual widget representing awidget to the repository
3030
  *
3031
+ * @param string $index A name to identify the specific widget.
3032
+ * @param virtualWidget $widget The virstual widget for it.
3033
  *
3034
  * @since 4.7
3035
  */
3036
+ public function addWidget( $index, $widget ) {
3037
+ self::$widgetCollection[ $index ] = $widget;
3038
  }
3039
 
3040
  /**
3044
  *
3045
  * @since 4.7
3046
  */
3047
+ public function getWidgets() {
3048
  return self::$widgetCollection;
3049
  }
3050
 
3051
  }
3052
 
3053
+ add_action( 'wp_loaded', __NAMESPACE__ . '\wp_loaded' );
3054
 
3055
  /**
3056
+ * Run after WordPress finished bootstrapping, do whatever is needed at this stage
3057
+ * like registering the meta.
3058
  */
3059
  function wp_loaded() {
3060
+ register_meta( 'post', SHORTCODE_META, null, '__return_false' ); // do not allow access to the shortcode meta
3061
+ // use the pre 4.6 format for backward compatibility.
3062
  }
icons/LICENSE.txt ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Font license info
2
+
3
+
4
+ ## Font Awesome
5
+
6
+ Copyright (C) 2016 by Dave Gandy
7
+
8
+ Author: Dave Gandy
9
+ License: SIL ()
10
+ Homepage: http://fortawesome.github.com/Font-Awesome/
11
+
12
+
13
+ ## Typicons
14
+
15
+ (c) Stephen Hutchings 2012
16
+
17
+ Author: Stephen Hutchings
18
+ License: SIL (http://scripts.sil.org/OFL)
19
+ Homepage: http://typicons.com/
20
+
21
+
22
+ ## Entypo
23
+
24
+ Copyright (C) 2012 by Daniel Bruce
25
+
26
+ Author: Daniel Bruce
27
+ License: SIL (http://scripts.sil.org/OFL)
28
+ Homepage: http://www.entypo.com
29
+
30
+
31
+ ## Web Symbols
32
+
33
+ Copyright (c) 2011 by Just Be Nice studio. All rights reserved.
34
+
35
+ Author: Just Be Nice studio
36
+ License: SIL (http://scripts.sil.org/OFL)
37
+ Homepage: http://www.justbenicestudio.com/
38
+
39
+
icons/README.txt ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ This webfont is generated by http://fontello.com open source project.
2
+
3
+
4
+ ================================================================================
5
+ Please, note, that you should obey original font licenses, used to make this
6
+ webfont pack. Details available in LICENSE.txt file.
7
+
8
+ - Usually, it's enough to publish content of LICENSE.txt file somewhere on your
9
+ site in "About" section.
10
+
11
+ - If your project is open-source, usually, it will be ok to make LICENSE.txt
12
+ file publicly available in your repository.
13
+
14
+ - Fonts, used in Fontello, don't require a clickable link on your site.
15
+ But any kind of additional authors crediting is welcome.
16
+ ================================================================================
17
+
18
+
19
+ Comments on archive content
20
+ ---------------------------
21
+
22
+ - /font/* - fonts in different formats
23
+
24
+ - /css/* - different kinds of css, for all situations. Should be ok with
25
+ twitter bootstrap. Also, you can skip <i> style and assign icon classes
26
+ directly to text elements, if you don't mind about IE7.
27
+
28
+ - demo.html - demo file, to show your webfont content
29
+
30
+ - LICENSE.txt - license info about source fonts, used to build your one.
31
+
32
+ - config.json - keeps your settings. You can import it back into fontello
33
+ anytime, to continue your work
34
+
35
+
36
+ Why so many CSS files ?
37
+ -----------------------
38
+
39
+ Because we like to fit all your needs :)
40
+
41
+ - basic file, <your_font_name>.css - is usually enough, it contains @font-face
42
+ and character code definitions
43
+
44
+ - *-ie7.css - if you need IE7 support, but still don't wish to put char codes
45
+ directly into html
46
+
47
+ - *-codes.css and *-ie7-codes.css - if you like to use your own @font-face
48
+ rules, but still wish to benefit from css generation. That can be very
49
+ convenient for automated asset build systems. When you need to update font -
50
+ no need to manually edit files, just override old version with archive
51
+ content. See fontello source code for examples.
52
+
53
+ - *-embedded.css - basic css file, but with embedded WOFF font, to avoid
54
+ CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain.
55
+ We strongly recommend to resolve this issue by `Access-Control-Allow-Origin`
56
+ server headers. But if you ok with dirty hack - this file is for you. Note,
57
+ that data url moved to separate @font-face to avoid problems with <IE9, when
58
+ string is too long.
59
+
60
+ - animate.css - use it to get ideas about spinner rotation animation.
61
+
62
+
63
+ Attention for server setup
64
+ --------------------------
65
+
66
+ You MUST setup server to reply with proper `mime-types` for font files -
67
+ otherwise some browsers will fail to show fonts.
68
+
69
+ Usually, `apache` already has necessary settings, but `nginx` and other
70
+ webservers should be tuned. Here is list of mime types for our file extensions:
71
+
72
+ - `application/vnd.ms-fontobject` - eot
73
+ - `application/x-font-woff` - woff
74
+ - `application/x-font-ttf` - ttf
75
+ - `image/svg+xml` - svg
icons/config.json ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "cat_post",
3
+ "css_prefix_text": "cat-post-icon-",
4
+ "css_use_suffix": false,
5
+ "hinting": true,
6
+ "units_per_em": 1000,
7
+ "ascent": 850,
8
+ "glyphs": [
9
+ {
10
+ "uid": "381da2c2f7fd51f8de877c044d7f439d",
11
+ "css": "image",
12
+ "code": 59392,
13
+ "src": "fontawesome"
14
+ },
15
+ {
16
+ "uid": "872d9516df93eb6b776cc4d94bd97dac",
17
+ "css": "video",
18
+ "code": 59393,
19
+ "src": "fontawesome"
20
+ },
21
+ {
22
+ "uid": "dcedf50ab1ede3283d7a6c70e2fe32f3",
23
+ "css": "chat",
24
+ "code": 59394,
25
+ "src": "fontawesome"
26
+ },
27
+ {
28
+ "uid": "ab95e1351ebaec5850101097cbf7097f",
29
+ "css": "quote",
30
+ "code": 61709,
31
+ "src": "fontawesome"
32
+ },
33
+ {
34
+ "uid": "9ea0a737ccc45d6c510dcbae56058849",
35
+ "css": "audio",
36
+ "code": 59395,
37
+ "src": "fontawesome"
38
+ },
39
+ {
40
+ "uid": "3def559c3c39b8500882e02892b7daa8",
41
+ "css": "gallery",
42
+ "code": 59397,
43
+ "src": "entypo"
44
+ },
45
+ {
46
+ "uid": "7p5gflyid3o4gtesy94a6erq94e4pz7u",
47
+ "css": "standard",
48
+ "code": 59398,
49
+ "src": "typicons"
50
+ },
51
+ {
52
+ "uid": "0ddd3e8201ccc7d41f7b7c9d27eca6c1",
53
+ "css": "link",
54
+ "code": 59401,
55
+ "src": "fontawesome"
56
+ },
57
+ {
58
+ "uid": "5408be43f7c42bccee419c6be53fdef5",
59
+ "css": "aside",
60
+ "code": 61686,
61
+ "src": "fontawesome"
62
+ },
63
+ {
64
+ "uid": "p57wgnf4glngbchbucdi029iptu8oxb8",
65
+ "css": "pin",
66
+ "code": 59399,
67
+ "src": "typicons"
68
+ },
69
+ {
70
+ "uid": "21f6a88daf13c62e5a70f5ef6ad9e23f",
71
+ "css": "status",
72
+ "code": 59402,
73
+ "src": "websymbols"
74
+ }
75
+ ]
76
+ }
icons/css/animation.css ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ Animation example, for spinners
3
+ */
4
+ .animate-spin {
5
+ -moz-animation: spin 2s infinite linear;
6
+ -o-animation: spin 2s infinite linear;
7
+ -webkit-animation: spin 2s infinite linear;
8
+ animation: spin 2s infinite linear;
9
+ display: inline-block;
10
+ }
11
+ @-moz-keyframes spin {
12
+ 0% {
13
+ -moz-transform: rotate(0deg);
14
+ -o-transform: rotate(0deg);
15
+ -webkit-transform: rotate(0deg);
16
+ transform: rotate(0deg);
17
+ }
18
+
19
+ 100% {
20
+ -moz-transform: rotate(359deg);
21
+ -o-transform: rotate(359deg);
22
+ -webkit-transform: rotate(359deg);
23
+ transform: rotate(359deg);
24
+ }
25
+ }
26
+ @-webkit-keyframes spin {
27
+ 0% {
28
+ -moz-transform: rotate(0deg);
29
+ -o-transform: rotate(0deg);
30
+ -webkit-transform: rotate(0deg);
31
+ transform: rotate(0deg);
32
+ }
33
+
34
+ 100% {
35
+ -moz-transform: rotate(359deg);
36
+ -o-transform: rotate(359deg);
37
+ -webkit-transform: rotate(359deg);
38
+ transform: rotate(359deg);
39
+ }
40
+ }
41
+ @-o-keyframes spin {
42
+ 0% {
43
+ -moz-transform: rotate(0deg);
44
+ -o-transform: rotate(0deg);
45
+ -webkit-transform: rotate(0deg);
46
+ transform: rotate(0deg);
47
+ }
48
+
49
+ 100% {
50
+ -moz-transform: rotate(359deg);
51
+ -o-transform: rotate(359deg);
52
+ -webkit-transform: rotate(359deg);
53
+ transform: rotate(359deg);
54
+ }
55
+ }
56
+ @-ms-keyframes spin {
57
+ 0% {
58
+ -moz-transform: rotate(0deg);
59
+ -o-transform: rotate(0deg);
60
+ -webkit-transform: rotate(0deg);
61
+ transform: rotate(0deg);
62
+ }
63
+
64
+ 100% {
65
+ -moz-transform: rotate(359deg);
66
+ -o-transform: rotate(359deg);
67
+ -webkit-transform: rotate(359deg);
68
+ transform: rotate(359deg);
69
+ }
70
+ }
71
+ @keyframes spin {
72
+ 0% {
73
+ -moz-transform: rotate(0deg);
74
+ -o-transform: rotate(0deg);
75
+ -webkit-transform: rotate(0deg);
76
+ transform: rotate(0deg);
77
+ }
78
+
79
+ 100% {
80
+ -moz-transform: rotate(359deg);
81
+ -o-transform: rotate(359deg);
82
+ -webkit-transform: rotate(359deg);
83
+ transform: rotate(359deg);
84
+ }
85
+ }
icons/css/cat_post-codes.css ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ .cat-post-icon-image:before { content: '\e800'; } /* '' */
3
+ .cat-post-icon-video:before { content: '\e801'; } /* '' */
4
+ .cat-post-icon-chat:before { content: '\e802'; } /* '' */
5
+ .cat-post-icon-audio:before { content: '\e803'; } /* '' */
6
+ .cat-post-icon-gallery:before { content: '\e805'; } /* '' */
7
+ .cat-post-icon-standard:before { content: '\e806'; } /* '' */
8
+ .cat-post-icon-pin:before { content: '\e807'; } /* '' */
9
+ .cat-post-icon-link:before { content: '\e809'; } /* '' */
10
+ .cat-post-icon-status:before { content: '\e80a'; } /* '' */
11
+ .cat-post-icon-aside:before { content: '\f0f6'; } /* '' */
12
+ .cat-post-icon-quote:before { content: '\f10d'; } /* '' */
icons/css/cat_post-embedded.css ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @font-face {
2
+ font-family: 'cat_post';
3
+ src: url('../font/cat_post.eot?33448716');
4
+ src: url('../font/cat_post.eot?33448716#iefix') format('embedded-opentype'),
5
+ url('../font/cat_post.svg?33448716#cat_post') format('svg');
6
+ font-weight: normal;
7
+ font-style: normal;
8
+ }
9
+ @font-face {
10
+ font-family: 'cat_post';
11
+ src: url('data:application/octet-stream;base64,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') format('woff'),
12
+ url('data:application/octet-stream;base64,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') format('truetype');
13
+ }
14
+ /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
15
+ /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
16
+ /*
17
+ @media screen and (-webkit-min-device-pixel-ratio:0) {
18
+ @font-face {
19
+ font-family: 'cat_post';
20
+ src: url('../font/cat_post.svg?33448716#cat_post') format('svg');
21
+ }
22
+ }
23
+ */
24
+
25
+ [class^="cat-post-icon-"]:before, [class*=" cat-post-icon-"]:before {
26
+ font-family: "cat_post";
27
+ font-style: normal;
28
+ font-weight: normal;
29
+ speak: none;
30
+
31
+ display: inline-block;
32
+ text-decoration: inherit;
33
+ width: 1em;
34
+ margin-right: .2em;
35
+ text-align: center;
36
+ /* opacity: .8; */
37
+
38
+ /* For safety - reset parent styles, that can break glyph codes*/
39
+ font-variant: normal;
40
+ text-transform: none;
41
+
42
+ /* fix buttons height, for twitter bootstrap */
43
+ line-height: 1em;
44
+
45
+ /* Animation center compensation - margins should be symmetric */
46
+ /* remove if not needed */
47
+ margin-left: .2em;
48
+
49
+ /* you can be more comfortable with increased icons size */
50
+ /* font-size: 120%; */
51
+
52
+ /* Uncomment for 3D effect */
53
+ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
54
+ }
55
+ .cat-post-icon-image:before { content: '\e800'; } /* '' */
56
+ .cat-post-icon-video:before { content: '\e801'; } /* '' */
57
+ .cat-post-icon-chat:before { content: '\e802'; } /* '' */
58
+ .cat-post-icon-audio:before { content: '\e803'; } /* '' */
59
+ .cat-post-icon-gallery:before { content: '\e805'; } /* '' */
60
+ .cat-post-icon-standard:before { content: '\e806'; } /* '' */
61
+ .cat-post-icon-pin:before { content: '\e807'; } /* '' */
62
+ .cat-post-icon-link:before { content: '\e809'; } /* '' */
63
+ .cat-post-icon-status:before { content: '\e80a'; } /* '' */
64
+ .cat-post-icon-aside:before { content: '\f0f6'; } /* '' */
65
+ .cat-post-icon-quote:before { content: '\f10d'; } /* '' */
icons/css/cat_post-ie7-codes.css ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ .cat-post-icon-image { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe800;&nbsp;'); }
3
+ .cat-post-icon-video { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe801;&nbsp;'); }
4
+ .cat-post-icon-chat { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe802;&nbsp;'); }
5
+ .cat-post-icon-audio { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe803;&nbsp;'); }
6
+ .cat-post-icon-gallery { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe805;&nbsp;'); }
7
+ .cat-post-icon-standard { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe806;&nbsp;'); }
8
+ .cat-post-icon-pin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe807;&nbsp;'); }
9
+ .cat-post-icon-link { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe809;&nbsp;'); }
10
+ .cat-post-icon-status { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe80a;&nbsp;'); }
11
+ .cat-post-icon-aside { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f6;&nbsp;'); }
12
+ .cat-post-icon-quote { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf10d;&nbsp;'); }
icons/css/cat_post-ie7.css ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [class^="cat-post-icon-"], [class*=" cat-post-icon-"] {
2
+ font-family: 'cat_post';
3
+ font-style: normal;
4
+ font-weight: normal;
5
+
6
+ /* fix buttons height */
7
+ line-height: 1em;
8
+
9
+ /* you can be more comfortable with increased icons size */
10
+ /* font-size: 120%; */
11
+ }
12
+
13
+ .cat-post-icon-image { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe800;&nbsp;'); }
14
+ .cat-post-icon-video { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe801;&nbsp;'); }
15
+ .cat-post-icon-chat { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe802;&nbsp;'); }
16
+ .cat-post-icon-audio { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe803;&nbsp;'); }
17
+ .cat-post-icon-gallery { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe805;&nbsp;'); }
18
+ .cat-post-icon-standard { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe806;&nbsp;'); }
19
+ .cat-post-icon-pin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe807;&nbsp;'); }
20
+ .cat-post-icon-link { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe809;&nbsp;'); }
21
+ .cat-post-icon-status { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe80a;&nbsp;'); }
22
+ .cat-post-icon-aside { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f6;&nbsp;'); }
23
+ .cat-post-icon-quote { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf10d;&nbsp;'); }
icons/css/cat_post.css ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @font-face {
2
+ font-family: 'cat_post';
3
+ src: url('../font/cat_post.eot?21642608');
4
+ src: url('../font/cat_post.eot?21642608#iefix') format('embedded-opentype'),
5
+ url('../font/cat_post.woff2?21642608') format('woff2'),
6
+ url('../font/cat_post.woff?21642608') format('woff'),
7
+ url('../font/cat_post.ttf?21642608') format('truetype'),
8
+ url('../font/cat_post.svg?21642608#cat_post') format('svg');
9
+ font-weight: normal;
10
+ font-style: normal;
11
+ }
12
+ /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
13
+ /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
14
+ /*
15
+ @media screen and (-webkit-min-device-pixel-ratio:0) {
16
+ @font-face {
17
+ font-family: 'cat_post';
18
+ src: url('../font/cat_post.svg?21642608#cat_post') format('svg');
19
+ }
20
+ }
21
+ */
22
+
23
+ [class^="cat-post-icon-"]:before, [class*=" cat-post-icon-"]:before {
24
+ font-family: "cat_post";
25
+ font-style: normal;
26
+ font-weight: normal;
27
+ speak: none;
28
+
29
+ display: inline-block;
30
+ text-decoration: inherit;
31
+ width: 1em;
32
+ margin-right: .2em;
33
+ text-align: center;
34
+ /* opacity: .8; */
35
+
36
+ /* For safety - reset parent styles, that can break glyph codes*/
37
+ font-variant: normal;
38
+ text-transform: none;
39
+
40
+ /* fix buttons height, for twitter bootstrap */
41
+ line-height: 1em;
42
+
43
+ /* Animation center compensation - margins should be symmetric */
44
+ /* remove if not needed */
45
+ margin-left: .2em;
46
+
47
+ /* you can be more comfortable with increased icons size */
48
+ /* font-size: 120%; */
49
+
50
+ /* Font smoothing. That was taken from TWBS */
51
+ -webkit-font-smoothing: antialiased;
52
+ -moz-osx-font-smoothing: grayscale;
53
+
54
+ /* Uncomment for 3D effect */
55
+ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
56
+ }
57
+
58
+ .cat-post-icon-image:before { content: '\e800'; } /* '' */
59
+ .cat-post-icon-video:before { content: '\e801'; } /* '' */
60
+ .cat-post-icon-chat:before { content: '\e802'; } /* '' */
61
+ .cat-post-icon-audio:before { content: '\e803'; } /* '' */
62
+ .cat-post-icon-gallery:before { content: '\e805'; } /* '' */
63
+ .cat-post-icon-standard:before { content: '\e806'; } /* '' */
64
+ .cat-post-icon-pin:before { content: '\e807'; } /* '' */
65
+ .cat-post-icon-link:before { content: '\e809'; } /* '' */
66
+ .cat-post-icon-status:before { content: '\e80a'; } /* '' */
67
+ .cat-post-icon-aside:before { content: '\f0f6'; } /* '' */
68
+ .cat-post-icon-quote:before { content: '\f10d'; } /* '' */
icons/demo.html ADDED
@@ -0,0 +1,323 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head><!--[if lt IE 9]><script language="javascript" type="text/javascript" src="//html5shim.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
4
+ <meta charset="UTF-8"><style>/*
5
+ * Bootstrap v2.2.1
6
+ *
7
+ * Copyright 2012 Twitter, Inc
8
+ * Licensed under the Apache License v2.0
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
12
+ */
13
+ .clearfix {
14
+ *zoom: 1;
15
+ }
16
+ .clearfix:before,
17
+ .clearfix:after {
18
+ display: table;
19
+ content: "";
20
+ line-height: 0;
21
+ }
22
+ .clearfix:after {
23
+ clear: both;
24
+ }
25
+ html {
26
+ font-size: 100%;
27
+ -webkit-text-size-adjust: 100%;
28
+ -ms-text-size-adjust: 100%;
29
+ }
30
+ a:focus {
31
+ outline: thin dotted #333;
32
+ outline: 5px auto -webkit-focus-ring-color;
33
+ outline-offset: -2px;
34
+ }
35
+ a:hover,
36
+ a:active {
37
+ outline: 0;
38
+ }
39
+ button,
40
+ input,
41
+ select,
42
+ textarea {
43
+ margin: 0;
44
+ font-size: 100%;
45
+ vertical-align: middle;
46
+ }
47
+ button,
48
+ input {
49
+ *overflow: visible;
50
+ line-height: normal;
51
+ }
52
+ button::-moz-focus-inner,
53
+ input::-moz-focus-inner {
54
+ padding: 0;
55
+ border: 0;
56
+ }
57
+ body {
58
+ margin: 0;
59
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
60
+ font-size: 14px;
61
+ line-height: 20px;
62
+ color: #333;
63
+ background-color: #fff;
64
+ }
65
+ a {
66
+ color: #08c;
67
+ text-decoration: none;
68
+ }
69
+ a:hover {
70
+ color: #005580;
71
+ text-decoration: underline;
72
+ }
73
+ .row {
74
+ margin-left: -20px;
75
+ *zoom: 1;
76
+ }
77
+ .row:before,
78
+ .row:after {
79
+ display: table;
80
+ content: "";
81
+ line-height: 0;
82
+ }
83
+ .row:after {
84
+ clear: both;
85
+ }
86
+ [class*="span"] {
87
+ float: left;
88
+ min-height: 1px;
89
+ margin-left: 20px;
90
+ }
91
+ .container,
92
+ .navbar-static-top .container,
93
+ .navbar-fixed-top .container,
94
+ .navbar-fixed-bottom .container {
95
+ width: 940px;
96
+ }
97
+ .span12 {
98
+ width: 940px;
99
+ }
100
+ .span11 {
101
+ width: 860px;
102
+ }
103
+ .span10 {
104
+ width: 780px;
105
+ }
106
+ .span9 {
107
+ width: 700px;
108
+ }
109
+ .span8 {
110
+ width: 620px;
111
+ }
112
+ .span7 {
113
+ width: 540px;
114
+ }
115
+ .span6 {
116
+ width: 460px;
117
+ }
118
+ .span5 {
119
+ width: 380px;
120
+ }
121
+ .span4 {
122
+ width: 300px;
123
+ }
124
+ .span3 {
125
+ width: 220px;
126
+ }
127
+ .span2 {
128
+ width: 140px;
129
+ }
130
+ .span1 {
131
+ width: 60px;
132
+ }
133
+ [class*="span"].pull-right,
134
+ .row-fluid [class*="span"].pull-right {
135
+ float: right;
136
+ }
137
+ .container {
138
+ margin-right: auto;
139
+ margin-left: auto;
140
+ *zoom: 1;
141
+ }
142
+ .container:before,
143
+ .container:after {
144
+ display: table;
145
+ content: "";
146
+ line-height: 0;
147
+ }
148
+ .container:after {
149
+ clear: both;
150
+ }
151
+ p {
152
+ margin: 0 0 10px;
153
+ }
154
+ .lead {
155
+ margin-bottom: 20px;
156
+ font-size: 21px;
157
+ font-weight: 200;
158
+ line-height: 30px;
159
+ }
160
+ small {
161
+ font-size: 85%;
162
+ }
163
+ h1 {
164
+ margin: 10px 0;
165
+ font-family: inherit;
166
+ font-weight: bold;
167
+ line-height: 20px;
168
+ color: inherit;
169
+ text-rendering: optimizelegibility;
170
+ }
171
+ h1 small {
172
+ font-weight: normal;
173
+ line-height: 1;
174
+ color: #999;
175
+ }
176
+ h1 {
177
+ line-height: 40px;
178
+ }
179
+ h1 {
180
+ font-size: 38.5px;
181
+ }
182
+ h1 small {
183
+ font-size: 24.5px;
184
+ }
185
+ body {
186
+ margin-top: 90px;
187
+ }
188
+ .header {
189
+ position: fixed;
190
+ top: 0;
191
+ left: 50%;
192
+ margin-left: -480px;
193
+ background-color: #fff;
194
+ border-bottom: 1px solid #ddd;
195
+ padding-top: 10px;
196
+ z-index: 10;
197
+ }
198
+ .footer {
199
+ color: #ddd;
200
+ font-size: 12px;
201
+ text-align: center;
202
+ margin-top: 20px;
203
+ }
204
+ .footer a {
205
+ color: #ccc;
206
+ text-decoration: underline;
207
+ }
208
+ .the-icons {
209
+ font-size: 14px;
210
+ line-height: 24px;
211
+ }
212
+ .switch {
213
+ position: absolute;
214
+ right: 0;
215
+ bottom: 10px;
216
+ color: #666;
217
+ }
218
+ .switch input {
219
+ margin-right: 0.3em;
220
+ }
221
+ .codesOn .i-name {
222
+ display: none;
223
+ }
224
+ .codesOn .i-code {
225
+ display: inline;
226
+ }
227
+ .i-code {
228
+ display: none;
229
+ }
230
+ @font-face {
231
+ font-family: 'cat_post';
232
+ src: url('./font/cat_post.eot?58348147');
233
+ src: url('./font/cat_post.eot?58348147#iefix') format('embedded-opentype'),
234
+ url('./font/cat_post.woff?58348147') format('woff'),
235
+ url('./font/cat_post.ttf?58348147') format('truetype'),
236
+ url('./font/cat_post.svg?58348147#cat_post') format('svg');
237
+ font-weight: normal;
238
+ font-style: normal;
239
+ }
240
+
241
+
242
+ .demo-icon
243
+ {
244
+ font-family: "cat_post";
245
+ font-style: normal;
246
+ font-weight: normal;
247
+ speak: none;
248
+
249
+ display: inline-block;
250
+ text-decoration: inherit;
251
+ width: 1em;
252
+ margin-right: .2em;
253
+ text-align: center;
254
+ /* opacity: .8; */
255
+
256
+ /* For safety - reset parent styles, that can break glyph codes*/
257
+ font-variant: normal;
258
+ text-transform: none;
259
+
260
+ /* fix buttons height, for twitter bootstrap */
261
+ line-height: 1em;
262
+
263
+ /* Animation center compensation - margins should be symmetric */
264
+ /* remove if not needed */
265
+ margin-left: .2em;
266
+
267
+ /* You can be more comfortable with increased icons size */
268
+ /* font-size: 120%; */
269
+
270
+ /* Font smoothing. That was taken from TWBS */
271
+ -webkit-font-smoothing: antialiased;
272
+ -moz-osx-font-smoothing: grayscale;
273
+
274
+ /* Uncomment for 3D effect */
275
+ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
276
+ }
277
+ </style>
278
+ <link rel="stylesheet" href="css/animation.css"><!--[if IE 7]><link rel="stylesheet" href="css/cat_post-ie7.css"><![endif]-->
279
+ <script>
280
+ function toggleCodes(on) {
281
+ var obj = document.getElementById('icons');
282
+
283
+ if (on) {
284
+ obj.className += ' codesOn';
285
+ } else {
286
+ obj.className = obj.className.replace(' codesOn', '');
287
+ }
288
+ }
289
+
290
+ </script>
291
+ </head>
292
+ <body>
293
+ <div class="container header">
294
+ <h1>
295
+ cat_post
296
+ <small>font demo</small>
297
+ </h1>
298
+ <label class="switch">
299
+ <input type="checkbox" onclick="toggleCodes(this.checked)">show codes
300
+ </label>
301
+ </div>
302
+ <div id="icons" class="container">
303
+ <div class="row">
304
+ <div title="Code: 0xe800" class="the-icons span3"><i class="demo-icon cat-post-icon-image">&#xe800;</i> <span class="i-name">cat-post-icon-image</span><span class="i-code">0xe800</span></div>
305
+ <div title="Code: 0xe801" class="the-icons span3"><i class="demo-icon cat-post-icon-video">&#xe801;</i> <span class="i-name">cat-post-icon-video</span><span class="i-code">0xe801</span></div>
306
+ <div title="Code: 0xe802" class="the-icons span3"><i class="demo-icon cat-post-icon-chat">&#xe802;</i> <span class="i-name">cat-post-icon-chat</span><span class="i-code">0xe802</span></div>
307
+ <div title="Code: 0xe803" class="the-icons span3"><i class="demo-icon cat-post-icon-audio">&#xe803;</i> <span class="i-name">cat-post-icon-audio</span><span class="i-code">0xe803</span></div>
308
+ </div>
309
+ <div class="row">
310
+ <div title="Code: 0xe805" class="the-icons span3"><i class="demo-icon cat-post-icon-gallery">&#xe805;</i> <span class="i-name">cat-post-icon-gallery</span><span class="i-code">0xe805</span></div>
311
+ <div title="Code: 0xe806" class="the-icons span3"><i class="demo-icon cat-post-icon-standard">&#xe806;</i> <span class="i-name">cat-post-icon-standard</span><span class="i-code">0xe806</span></div>
312
+ <div title="Code: 0xe807" class="the-icons span3"><i class="demo-icon cat-post-icon-pin">&#xe807;</i> <span class="i-name">cat-post-icon-pin</span><span class="i-code">0xe807</span></div>
313
+ <div title="Code: 0xe809" class="the-icons span3"><i class="demo-icon cat-post-icon-link">&#xe809;</i> <span class="i-name">cat-post-icon-link</span><span class="i-code">0xe809</span></div>
314
+ </div>
315
+ <div class="row">
316
+ <div title="Code: 0xe80a" class="the-icons span3"><i class="demo-icon cat-post-icon-status">&#xe80a;</i> <span class="i-name">cat-post-icon-status</span><span class="i-code">0xe80a</span></div>
317
+ <div title="Code: 0xf0f6" class="the-icons span3"><i class="demo-icon cat-post-icon-aside">&#xf0f6;</i> <span class="i-name">cat-post-icon-aside</span><span class="i-code">0xf0f6</span></div>
318
+ <div title="Code: 0xf10d" class="the-icons span3"><i class="demo-icon cat-post-icon-quote">&#xf10d;</i> <span class="i-name">cat-post-icon-quote</span><span class="i-code">0xf10d</span></div>
319
+ </div>
320
+ </div>
321
+ <div class="container footer">Generated by <a href="http://fontello.com">fontello.com</a></div>
322
+ </body>
323
+ </html>
icons/font/cat_post.eot ADDED
Binary file
icons/font/cat_post.svg ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
+ <svg xmlns="http://www.w3.org/2000/svg">
4
+ <metadata>Copyright (C) 2018 by original authors @ fontello.com</metadata>
5
+ <defs>
6
+ <font id="cat_post" horiz-adv-x="1000" >
7
+ <font-face font-family="cat_post" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
8
+ <missing-glyph horiz-adv-x="1000" />
9
+ <glyph glyph-name="image" unicode="&#xe800;" d="M357 529q0-45-31-76t-76-32-76 32-31 76 31 76 76 31 76-31 31-76z m572-215v-250h-786v107l178 179 90-89 285 285z m53 393h-893q-7 0-12-5t-6-13v-678q0-7 6-13t12-5h893q7 0 13 5t5 13v678q0 8-5 13t-13 5z m89-18v-678q0-37-26-63t-63-27h-893q-36 0-63 27t-26 63v678q0 37 26 63t63 27h893q37 0 63-27t26-63z" horiz-adv-x="1071.4" />
10
+
11
+ <glyph glyph-name="video" unicode="&#xe801;" d="M214-43v72q0 14-10 25t-25 10h-72q-14 0-25-10t-11-25v-72q0-14 11-25t25-11h72q14 0 25 11t10 25z m0 214v72q0 14-10 25t-25 11h-72q-14 0-25-11t-11-25v-72q0-14 11-25t25-10h72q14 0 25 10t10 25z m0 215v71q0 15-10 25t-25 11h-72q-14 0-25-11t-11-25v-71q0-15 11-25t25-11h72q14 0 25 11t10 25z m572-429v286q0 14-11 25t-25 11h-429q-14 0-25-11t-10-25v-286q0-14 10-25t25-11h429q15 0 25 11t11 25z m-572 643v71q0 15-10 26t-25 10h-72q-14 0-25-10t-11-26v-71q0-14 11-25t25-11h72q14 0 25 11t10 25z m786-643v72q0 14-11 25t-25 10h-71q-15 0-25-10t-11-25v-72q0-14 11-25t25-11h71q15 0 25 11t11 25z m-214 429v285q0 15-11 26t-25 10h-429q-14 0-25-10t-10-26v-285q0-15 10-25t25-11h429q15 0 25 11t11 25z m214-215v72q0 14-11 25t-25 11h-71q-15 0-25-11t-11-25v-72q0-14 11-25t25-10h71q15 0 25 10t11 25z m0 215v71q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-71q0-15 11-25t25-11h71q15 0 25 11t11 25z m0 214v71q0 15-11 26t-25 10h-71q-15 0-25-10t-11-26v-71q0-14 11-25t25-11h71q15 0 25 11t11 25z m71 89v-750q0-37-26-63t-63-26h-893q-36 0-63 26t-26 63v750q0 37 26 63t63 27h893q37 0 63-27t26-63z" horiz-adv-x="1071.4" />
12
+
13
+ <glyph glyph-name="chat" unicode="&#xe802;" d="M786 421q0-77-53-143t-143-104-197-38q-48 0-98 9-70-49-155-72-21-5-48-9h-2q-6 0-12 5t-6 12q-1 1-1 3t1 4 1 3l1 3t2 3 2 3 3 3 2 2q3 3 13 14t15 16 12 17 14 21 11 25q-69 40-108 98t-40 125q0 78 53 144t143 104 197 38 197-38 143-104 53-144z m214-142q0-67-40-126t-108-98q5-14 11-25t14-21 13-16 14-17 13-14q0 0 2-2t3-3 2-3 2-3l1-3t1-3 1-4-1-3q-2-8-7-13t-12-4q-28 4-48 9-86 23-156 72-50-9-98-9-151 0-263 74 32-3 49-3 90 0 172 25t148 72q69 52 107 119t37 141q0 43-13 85 72-39 114-99t42-128z" horiz-adv-x="1000" />
14
+
15
+ <glyph glyph-name="audio" unicode="&#xe803;" d="M857 725v-625q0-28-19-50t-48-33-58-18-53-6-54 6-58 18-48 33-19 50 19 50 48 33 58 18 54 6q58 0 107-22v300l-429-132v-396q0-28-19-50t-48-33-58-18-53-6-54 6-58 18-48 33-19 50 19 50 48 34 58 17 54 6q58 0 107-21v539q0 17 10 32t28 20l464 142q7 3 16 3 22 0 38-16t15-38z" horiz-adv-x="857.1" />
16
+
17
+ <glyph glyph-name="gallery" unicode="&#xe805;" d="M856 518l-100 0-124 150-214-150-180 0q-52 0-90-39t-38-91l0-160-108 296q-10 38 22 52l680 248q36 10 50-24z m106-90q16 0 27-12t11-28l0-472q0-16-11-28t-27-12l-724 0q-16 0-27 12t-11 28l0 472q0 16 11 28t27 12l724 0z m-56-452l0 162-72 160-166-60-130-132-138 170-92-214 0-86 598 0z" horiz-adv-x="1000" />
18
+
19
+ <glyph glyph-name="standard" unicode="&#xe806;" d="M416 650q0 21 16 36t37 16 36-15l329-324-329-323q-15-15-36-15t-37 15-16 37l0 130q-132-4-234-46t-182-163l0 53q0 180 119 313t297 153l0 133z" horiz-adv-x="834" />
20
+
21
+ <glyph glyph-name="pin" unicode="&#xe807;" d="M573 37q0-23-15-38t-37-15q-21 0-37 16l-169 169-315-236 236 315-168 169q-24 23-12 56 14 32 48 32 157 0 270 57 90 45 151 171 9 24 36 32t50-13l208-209q21-23 14-50t-32-36q-127-63-172-152-56-110-56-268z" horiz-adv-x="834" />
22
+
23
+ <glyph glyph-name="link" unicode="&#xe809;" d="M813 171q0 23-16 38l-116 116q-16 16-38 16-24 0-40-18 1-1 10-10t12-12 9-11 7-14 2-15q0-23-16-38t-38-16q-8 0-15 2t-14 7-11 9-12 12-10 10q-19-17-19-40 0-23 16-38l115-116q15-15 38-15 22 0 38 15l82 81q16 16 16 37z m-393 394q0 22-15 38l-115 115q-16 16-38 16-22 0-38-15l-82-82q-16-15-16-37 0-22 16-38l116-116q15-15 38-15 23 0 40 17-2 2-11 11t-12 12-8 10-7 14-2 16q0 22 15 38t38 15q9 0 16-2t14-7 11-8 12-12 10-11q18 17 18 41z m500-394q0-66-48-113l-82-81q-46-47-113-47-68 0-114 48l-115 115q-46 47-46 114 0 68 49 116l-49 49q-48-49-116-49-67 0-114 47l-116 116q-47 47-47 114t47 113l82 82q47 46 114 46 67 0 114-47l115-116q46-46 46-113 0-69-49-117l49-49q48 49 116 49 67 0 114-47l116-116q47-47 47-114z" horiz-adv-x="928.6" />
24
+
25
+ <glyph glyph-name="status" unicode="&#xe80a;" d="M1179 385q0-126-79-233t-215-170-296-62q-122 0-234 39l2-3-357-107q44 59 71 126t31 106l4 38q-106 120-106 266 0 126 79 233t215 169 295 62 296-62 215-169 79-233z m-250 0q0 29-21 50t-51 21q-29 0-50-21t-21-50q0-30 21-51t50-21q30 0 51 21t21 51z m-250 0q0 29-21 50t-51 21q-29 0-50-21t-21-50q0-30 21-51t50-21q30 0 51 21t21 51z m-250 0q0 29-21 50t-51 21q-29 0-50-21t-21-50q0-30 21-51t50-21q30 0 51 21t21 51z" horiz-adv-x="1179" />
26
+
27
+ <glyph glyph-name="aside" unicode="&#xf0f6;" d="M819 638q16-16 27-42t11-50v-642q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38v892q0 23 16 38t38 16h500q22 0 49-11t42-27z m-248 136v-210h210q-5 17-12 23l-175 175q-6 7-23 12z m215-853v572h-232q-23 0-38 16t-16 37v233h-429v-858h715z m-572 483q0 7 5 12t13 5h393q8 0 13-5t5-12v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13v36z m411-125q8 0 13-5t5-13v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13v36q0 8 5 13t13 5h393z m0-143q8 0 13-5t5-13v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13v36q0 8 5 13t13 5h393z" horiz-adv-x="857.1" />
28
+
29
+ <glyph glyph-name="quote" unicode="&#xf10d;" d="M429 314v-214q0-45-32-76t-76-31h-214q-44 0-76 31t-31 76v393q0 58 23 111t61 91 91 61 111 23h35q15 0 26-11t10-25v-72q0-14-10-25t-26-10h-35q-59 0-101-42t-42-101v-18q0-22 16-38t37-16h125q45 0 76-31t32-76z m500 0v-214q0-45-32-76t-76-31h-214q-44 0-76 31t-31 76v393q0 58 23 111t61 91 91 61 111 23h35q15 0 26-11t10-25v-72q0-14-10-25t-26-10h-35q-59 0-101-42t-42-101v-18q0-22 16-38t37-16h125q45 0 76-31t32-76z" horiz-adv-x="928.6" />
30
+ </font>
31
+ </defs>
32
+ </svg>
icons/font/cat_post.ttf ADDED
Binary file
icons/font/cat_post.woff ADDED
Binary file
icons/font/cat_post.woff2 ADDED
Binary file
js/admin/category-posts-widget.js CHANGED
@@ -7,12 +7,16 @@
7
  * Released under the GPLv2 license or later - http://www.gnu.org/licenses/gpl-2.0.html
8
  */
9
 
10
- // namespace
11
-
12
  var cwp_namespace = {
13
 
 
 
 
14
  open_panels : {}, // holds an array of open panels per wiget id
15
-
 
16
  // generic click handler on the panel title
17
  clickHandler: function(element) {
18
  // open the div "below" the h4 title
@@ -26,49 +30,25 @@
26
  o = this.open_panels[id];
27
  if (o.hasOwnProperty(panel))
28
  delete o[panel];
29
- else
30
  o[panel] = true;
31
  this.open_panels[id] = o;
32
  },
33
 
34
- // Show hide excerpt options on excerpt option check box change
35
- toggleExcerptPanel: function(item) {
36
- var value = jQuery(item).find("input").attr('checked');
37
- var panel = item.parentElement.parentElement;
38
- var layout = jQuery(panel).find(".layout_select option:selected").attr('value');
39
- if(value == 'checked') {
40
- jQuery(panel).find('.categoryposts-data-panel-excerpt').show();
41
- }
42
- else {
43
- jQuery(panel).find('.categoryposts-data-panel-excerpt').hide();
44
- }
45
- },
46
-
47
- // Show hide date options on date option check box change
48
- toggleDatePanel: function(item) {
49
- var value = jQuery(item).find("input").attr('checked');
50
- var panel = item.parentElement.parentElement;
51
- var layout = jQuery(panel).find(".layout_select option:selected").attr('value');
52
- if(value == 'checked') {
53
- jQuery(panel).find('.categoryposts-data-panel-date').show();
54
- }
55
- else {
56
- jQuery(panel).find('.categoryposts-data-panel-date').hide();
57
- }
58
- },
59
-
60
  // Show hide foote link URL
61
  toggleCatSelection: function(item) {
62
  var cat = jQuery(item).find("option:selected").attr('value');
63
  var panel = item.parentElement.parentElement.parentElement.parentElement;
64
  if(cat == '0') {
65
- jQuery(panel).find('.categoryPosts-title_link').hide();
66
- jQuery(panel).find('.categoryPosts-title_link_url').show();
 
67
  }
68
  else {
69
- jQuery(panel).find('.categoryPosts-title_link').show();
70
- jQuery(panel).find('.categoryPosts-title_link_url').hide();
71
- }
 
72
  },
73
 
74
  // Show hide disable font styles
@@ -80,19 +60,92 @@
80
  }
81
  else {
82
  jQuery(panel).find('.categoryposts-data-panel-general-disable-font-styles').show();
83
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  },
85
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  // Close all open panels if open
87
  autoCloseOpenPanels: function(_this) {
88
- if( categoryPosts.accordion ) {
89
  if(!jQuery(_this).hasClass('open')) {
90
  var jCloseElement = jQuery(_this).parent().find('.open');
91
  this.clickHandler(jCloseElement);
92
  }
93
  }
94
  },
95
-
96
  defaultThumbnailSelection: function (elem, title, button_title) {
97
 
98
  var frame = wp.media({
@@ -120,7 +173,7 @@
120
  frame.open();
121
  return false;
122
  },
123
-
124
  removeDefaultThumbnailSelection : function (elem) {
125
  jQuery(elem).parent().prev().find('.default_thumb_img').html(cwp_default_thumb_selection.none);
126
  jQuery(elem).hide();
@@ -128,11 +181,35 @@
128
 
129
  return false;
130
  },
131
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  }
133
-
134
  jQuery(document).ready( function () {
135
-
 
 
136
  jQuery('.category-widget-cont h4').click(function () { // for widgets page
137
  cwp_namespace.autoCloseOpenPanels(this);
138
  // toggle panel open/close
@@ -141,6 +218,7 @@ jQuery(document).ready( function () {
141
 
142
  // needed to reassign click handlers after widget refresh
143
  jQuery(document).on('widget-added widget-updated', function(root,element){ // for customize and after save on widgets page
 
144
  jQuery('.category-widget-cont h4').off('click').on('click', function () {
145
  cwp_namespace.autoCloseOpenPanels(this);
146
  // toggle panel open/close
@@ -153,6 +231,7 @@ jQuery(document).ready( function () {
153
  jQuery('.cwp_default_thumb_remove').off('click').on('click', function () { // remove default thumb
154
  cwp_namespace.removeDefaultThumbnailSelection(this);
155
  });
 
156
  // refresh panels to state before the refresh
157
  var id = jQuery(element).attr('id');
158
  if (cwp_namespace.open_panels.hasOwnProperty(id)) {
@@ -162,18 +241,52 @@ jQuery(document).ready( function () {
162
  .next().stop().show();
163
  }
164
  }
165
- });
166
 
167
- jQuery('.cwp_default_thumb_select').off('click').on('click', function () { // select default thumb
168
- cwp_namespace.defaultThumbnailSelection(this, cwp_default_thumb_selection.frame_title,cwp_default_thumb_selection.button_title);
169
  });
170
 
171
- jQuery('.cwp_default_thumb_remove').off('click').on('click', function () { // remove default thumb
172
- cwp_namespace.removeDefaultThumbnailSelection(this);
173
- });
 
174
 
175
- jQuery('.categoryposts-data-panel-filter-cat').on('change', function () { // change category filter
176
- cwp_namespace.toggleCatSelection(this);
177
- });
178
- });
179
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  * Released under the GPLv2 license or later - http://www.gnu.org/licenses/gpl-2.0.html
8
  */
9
 
10
+ // namespace
11
+
12
  var cwp_namespace = {
13
 
14
+ php_settings_var : 'categoryPosts',
15
+ widget_class : '.category-widget-cont',
16
+ template_panel_prefix : '.categoryposts-data-panel-',
17
  open_panels : {}, // holds an array of open panels per wiget id
18
+ template_change_timer : null, // Used for debouncing change events generate when template changes.
19
+
20
  // generic click handler on the panel title
21
  clickHandler: function(element) {
22
  // open the div "below" the h4 title
30
  o = this.open_panels[id];
31
  if (o.hasOwnProperty(panel))
32
  delete o[panel];
33
+ else
34
  o[panel] = true;
35
  this.open_panels[id] = o;
36
  },
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  // Show hide foote link URL
39
  toggleCatSelection: function(item) {
40
  var cat = jQuery(item).find("option:selected").attr('value');
41
  var panel = item.parentElement.parentElement.parentElement.parentElement;
42
  if(cat == '0') {
43
+ jQuery(panel).find( '.categoryPosts-title_link' ).hide();
44
+ jQuery(panel).find( '.categoryPosts-title_link_url' ).show();
45
+ jQuery(panel).find( '.categoryPosts-no_cat_childs' ).hide();
46
  }
47
  else {
48
+ jQuery(panel).find('.categoryPosts-title_link' ).show();
49
+ jQuery(panel).find('.categoryPosts-title_link_url' ).hide();
50
+ jQuery(panel).find( '.categoryPosts-no_cat_childs' ).show();
51
+ }
52
  },
53
 
54
  // Show hide disable font styles
60
  }
61
  else {
62
  jQuery(panel).find('.categoryposts-data-panel-general-disable-font-styles').show();
63
+ }
64
+ },
65
+
66
+ // Show hide other date format
67
+ toggleDateFormat: function(item) {
68
+ var value = jQuery(item).val();
69
+ var panel = item.parentElement.parentElement;
70
+ if( value != 'other') {
71
+ jQuery(panel).find('.categoryPosts-date_format').hide();
72
+ } else {
73
+ jQuery(panel).find('.categoryPosts-date_format').show();
74
+ }
75
+ },
76
+
77
+ // Show template help
78
+ toggleTemplateHelp: function(item,event) {
79
+ event.preventDefault();
80
+ var panel = item.parentElement.parentElement.parentElement.parentElement;
81
+ jQuery(panel).find('.cat-post-template-help').toggle('slow');
82
  },
83
+
84
+ toggleAssignedCategoriesTop: function(item) {
85
+ var value = jQuery(item).find("input").attr('checked');
86
+ var panel = item.parentElement.parentElement;
87
+ if(value == 'checked') {
88
+ jQuery(panel).find('.categoryposts-details-panel-assigned-cat-top').show();
89
+ }
90
+ else {
91
+ jQuery(panel).find('.categoryposts-details-panel-assigned-cat-top').hide();
92
+ }
93
+ },
94
+
95
+ toggleHideTitle: function(item) {
96
+ var value = jQuery(item).attr('checked');
97
+ var panel = item.parentElement.parentElement.parentElement;
98
+ if (value != 'checked') {
99
+ jQuery(panel).find('.categoryposts-data-panel-title-settings').show();
100
+ } else {
101
+ jQuery(panel).find('.categoryposts-data-panel-title-settings').hide();
102
+ }
103
+ },
104
+
105
+ selectPremadeTemplate: function(item) {
106
+ var panel = item.parentElement.parentElement.parentElement;
107
+ var div = item.parentElement.parentElement;
108
+ var select = jQuery(div).find('select');
109
+ var template = '%title%';
110
+ value = select.val();
111
+ switch (value) {
112
+ case 'title':
113
+ template = '%title%';
114
+ break;
115
+ case 'title_excerpt':
116
+ template = '%title%\n%excerpt%';
117
+ break;
118
+ case 'title_thumb':
119
+ template = '%title%\n%thumb%';
120
+ break;
121
+ case 'title_thum_excerpt':
122
+ template = '%title%\n%thumb%\n%excerpt%';
123
+ break;
124
+ case 'everything':
125
+ template = '%thumb%\n\n';
126
+ template += '%title%\n\n';
127
+ template += '%date% // <span class="dashicons dashicons-admin-comments"></span> %commentnum%\n\n';
128
+ template += '<span class="dashicons dashicons-admin-users"></span> %author%\n\n';
129
+ template += '%excerpt%\n\n';
130
+ template += 'Categories: %category%\n\n';
131
+ template += '<span class="dashicons dashicons-tag"></span> %post_tag%';
132
+ }
133
+ var textarea = jQuery(panel).find('textarea');
134
+ textarea.val(template);
135
+ textarea.trigger('input');
136
+ textarea.trigger('change');
137
+ },
138
+
139
  // Close all open panels if open
140
  autoCloseOpenPanels: function(_this) {
141
+ if( tiptoppress[ this.php_settings_var ].accordion ) {
142
  if(!jQuery(_this).hasClass('open')) {
143
  var jCloseElement = jQuery(_this).parent().find('.open');
144
  this.clickHandler(jCloseElement);
145
  }
146
  }
147
  },
148
+
149
  defaultThumbnailSelection: function (elem, title, button_title) {
150
 
151
  var frame = wp.media({
173
  frame.open();
174
  return false;
175
  },
176
+
177
  removeDefaultThumbnailSelection : function (elem) {
178
  jQuery(elem).parent().prev().find('.default_thumb_img').html(cwp_default_thumb_selection.none);
179
  jQuery(elem).hide();
181
 
182
  return false;
183
  },
184
+
185
+ templateChange : function (elem) {
186
+
187
+ function adjustUiToTemplate() {
188
+ var template = jQuery(elem).val();
189
+ var tags = tiptoppress[ this.php_settings_var ].template_tags;
190
+ var widget_cont = jQuery(elem.parentElement.parentElement.parentElement.parentElement);
191
+ for (var i = 0; i < tags.length; i++) {
192
+ if ( -1 !== template.indexOf( tags[i] ) ) {
193
+ widget_cont.find(this.template_panel_prefix + tags[i] ).show();
194
+ } else {
195
+ widget_cont.find(this.template_panel_prefix + tags[i] ).hide();
196
+ }
197
+ }
198
+ }
199
+
200
+ if (null != this.template_change_timer) {
201
+ clearTimeout( this.template_change_timer );
202
+ }
203
+ this.template_change_timer = setTimeout(adjustUiToTemplate.bind(this), 250);
204
+
205
+ },
206
+
207
  }
208
+
209
  jQuery(document).ready( function () {
210
+
211
+ var class_namespace = '.category-widget-cont';
212
+
213
  jQuery('.category-widget-cont h4').click(function () { // for widgets page
214
  cwp_namespace.autoCloseOpenPanels(this);
215
  // toggle panel open/close
218
 
219
  // needed to reassign click handlers after widget refresh
220
  jQuery(document).on('widget-added widget-updated', function(root,element){ // for customize and after save on widgets page
221
+
222
  jQuery('.category-widget-cont h4').off('click').on('click', function () {
223
  cwp_namespace.autoCloseOpenPanels(this);
224
  // toggle panel open/close
231
  jQuery('.cwp_default_thumb_remove').off('click').on('click', function () { // remove default thumb
232
  cwp_namespace.removeDefaultThumbnailSelection(this);
233
  });
234
+
235
  // refresh panels to state before the refresh
236
  var id = jQuery(element).attr('id');
237
  if (cwp_namespace.open_panels.hasOwnProperty(id)) {
241
  .next().stop().show();
242
  }
243
  }
 
244
 
245
+ setChangeHandlers();
 
246
  });
247
 
248
+ function setChangeHandlers() {
249
+ jQuery('.cwp_default_thumb_select').off('click').on('click', function () { // select default thumb
250
+ cwp_namespace.defaultThumbnailSelection(this, cwp_default_thumb_selection.frame_title,cwp_default_thumb_selection.button_title);
251
+ });
252
 
253
+ jQuery(document).on('change', class_namespace+' .categoryposts-data-panel-filter-cat', function () { // change category filter
254
+ cwp_namespace.toggleCatSelection(this);
255
+ });
 
256
 
257
+ jQuery('.cwp_default_thumb_remove').off('click').on('click', function () { // remove default thumb
258
+ cwp_namespace.removeDefaultThumbnailSelection(this);
259
+ });
260
+
261
+ jQuery(class_namespace+'-assigned_categories').off('click').on('click', function () {
262
+ cwp_namespace.toggleAssignedCategoriesTop(this);
263
+ });
264
+
265
+ jQuery(document).on('click', class_namespace+' .hide_title', function () {
266
+ cwp_namespace.toggleHideTitle(this);
267
+ });
268
+
269
+ jQuery(document).on('change', class_namespace+' .categoryPosts-preset_date_format select', function () { // change date format
270
+ cwp_namespace.toggleDateFormat(this);
271
+ });
272
+
273
+ jQuery(document).off('click').on('click', class_namespace+' a.toggle-template-help', function (event) { // show template help
274
+ cwp_namespace.toggleTemplateHelp(this, event);
275
+ });
276
+
277
+ jQuery(document).on('click', class_namespace+' .cat-post-premade_templates button', function () { // select a pre made template
278
+ cwp_namespace.selectPremadeTemplate(this);
279
+ });
280
+
281
+ jQuery(document).on('change', class_namespace+' .cat-post-premade_templates select', function (event) { // prevent refresh ontemplate selection
282
+ event.preventDefault();
283
+ event.stopPropagation();
284
+ });
285
+
286
+ jQuery(document).on('input', class_namespace+' .categoryPosts-template textarea', function () { // prevent refresh ontemplate selection
287
+ cwp_namespace.templateChange(this);
288
+ });
289
+ }
290
+
291
+ setChangeHandlers();
292
+ });
phpcs.xml ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <ruleset name="CategoryPostsWidget Plugin">
3
+ <description>A custom set of rules to check for a WPized WordPress project</description>
4
+
5
+ <rule ref="WordPress">
6
+ <exclude name="WordPress.Files.FileName.InvalidClassFileName" />
7
+ <exclude name="WordPress.NamingConventions" />
8
+ <exclude name="WordPress.VIP.RestrictedFunctions" />
9
+ <exclude name="WordPress.VIP.SlowDBQuery.slow_db_query_meta_query" />
10
+ <exclude name="WordPress.WP.CapitalPDangit" />
11
+ <exclude name="WordPress.WP.I18n.Missing.Translators.Comment" />
12
+ <exclude name="Generic.Formatting.MultipleStatementAlignment.NotSameWarning" />
13
+ </rule>
14
+
15
+ <rule ref="WordPress.WP.DeprecatedClasses">
16
+ <properties>
17
+ <property name="minimum_supported_version" value="4.4"/>
18
+ </properties>
19
+ </rule>
20
+
21
+ <rule ref="WordPress.WP.DeprecatedFunctions">
22
+ <properties>
23
+ <property name="minimum_supported_version" value="4.4"/>
24
+ </properties>
25
+ </rule>
26
+
27
+ <rule ref="WordPress.WP.DeprecatedParameters">
28
+ <properties>
29
+ <property name="minimum_supported_version" value="4.4"/>
30
+ </properties>
31
+ </rule>
32
+
33
+ </ruleset>
readme.txt CHANGED
@@ -4,8 +4,8 @@ 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.4
8
- License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
11
  Adds a widget that shows the most recent posts from a single category.
@@ -26,13 +26,21 @@ We've also started creating free widget Add-ons for the Premium Widget here: [Wi
26
  * Categories, Custom Post Types, Taxonomies, Events, Products, ...
27
  * Full background post images
28
  * Mouse hover effects for post thumbnail
29
- * <a target="_blank" href="http://tiptoppress.com/category/extensions/?utm_source=wordpress_org&utm_campaign=premium_features_extensions&utm_medium=web">Extensions</a>
30
  * E-Mail support
31
- * All free features
32
  * Free trail on localhost
33
- * More [examples on the demo pages](http://demo.tiptoppress.com/?utm_source=wordpress_org&utm_campaign=premium_features_demo&utm_medium=web)
 
 
34
 
35
  = Features =
 
 
 
 
 
 
 
36
  * Shortcode (Easily change all Shortcode options in the customizer).
37
  * Support multiple shortcodes at the same post.
38
  * Add option for post offset (use two or more widgets after another).
@@ -73,22 +81,22 @@ We've also started creating free widget Add-ons for the Premium Widget here: [Wi
73
  * Use WP user profile for settings ('auto close' and if the shortcode button appears in the editor toolbar).
74
 
75
  = Documentation =
76
- * Full documentation on [tiptoppress.com](http://tiptoppress.com/category-posts-widget/documentation-4-7/?utm_source=wordpress_org&utm_campaign=documentation_4_7_cpw&utm_medium=web)
77
  * Shortcode: Use [catposts] [in the content and edit options in the customizer](http://tiptoppress.com/use-shortcode-to-add-category-posts-widget-to-the-content/?utm_source=wordpress_org&utm_campaign=documentation_shortcode_cpw&utm_medium=web)
78
  * Formatting date and time: See <a target="_blank" href="https://codex.wordpress.org/Formatting_Date_and_Time">Formatting Date and Time</a>
79
 
80
  = Contribute =
81
- While using this plugin if you find any bug or any conflict, please submit an issue at
82
- [Github](https://github.com/tiptoppress/category-posts-widget) (If possible with a pull request).
83
 
84
  == Installation ==
85
  = Automatic installation =
86
- Automatic installation is the easiest option as WordPress handles the file transfers itself and you don’t need to leave your web browser. To do an automatic install of Category Posts Widget,
87
 
88
- 1. log in to your WordPress dashboard, navigate to the Plugins menu and click Add New.
89
- 2. In the search field type “Category Posts Widget” and click Search Plugins.
90
- 3. Once you’ve found plugin, you can install it by simply clicking “Install Now”.
91
- 4. Then, go to plugins page of WordPress admin activate the plugin.
92
  5. Now, goto the Widgets page of the Appearance section and configure the Category Posts widget.
93
 
94
  = Manual installation =
@@ -103,6 +111,12 @@ 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
  = 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/)
@@ -131,14 +145,27 @@ We apologies for any headache this may cause you, but frankly it is better for y
131
  PHP 5.2 is very old and any support for it from the php developers had ended more then 5 years ago [php.net/eol.php](http://php.net/eol.php).
132
  We know there are peopel how use PHP 5.2 [wordpress.org/about/stats](https://wordpress.org/about/stats/) and we can't imagine this people will have no other problems, if they don't update.
133
 
 
 
 
134
  == Screenshots ==
135
- 1. The widget configuration dialog.
136
- 2. Front end of the widget using a default WordPress Theme.
137
  3. Use shortcode [catposts] in the content and edit options in the customizer.
 
 
138
 
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
 
@@ -260,4 +287,4 @@ We know there are peopel how use PHP 5.2 [wordpress.org/about/stats](https://wor
260
 
261
  = 2.0 =
262
  * Updated to use the WP 2.8 widget API.
263
- * Added support for [Simple Post Thumbnails plugin](http://wordpress.org/extend/plugins/simple-post-thumbnails/).
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.8
8
+ License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
11
  Adds a widget that shows the most recent posts from a single category.
26
  * Categories, Custom Post Types, Taxonomies, Events, Products, ...
27
  * Full background post images
28
  * Mouse hover effects for post thumbnail
29
+ * All Category Posts Widget features
30
  * E-Mail support
 
31
  * Free trail on localhost
32
+ * E-Mail support
33
+ * All free features
34
+ * More examples on the [demo pages](http://demo.tiptoppress.com/?utm_source=wordpress_org&utm_campaign=demo_cpw&utm_medium=web)
35
 
36
  = Features =
37
+ * SVG icon support for post formats
38
+ * Template to arrange the post details
39
+ * Premade Templates
40
+ * The Template text can a placeholder, text, HTML or HTML for icons
41
+ * New date format: Time since plublished
42
+ * Filter by post status: Published, scheduled, private
43
+ * New hover effect: SVG icon
44
  * Shortcode (Easily change all Shortcode options in the customizer).
45
  * Support multiple shortcodes at the same post.
46
  * Add option for post offset (use two or more widgets after another).
81
  * Use WP user profile for settings ('auto close' and if the shortcode button appears in the editor toolbar).
82
 
83
  = Documentation =
84
+ * Full [documentation](http://tiptoppress.com/category-posts-widget/documentation-4-8/?utm_source=wordpress_org&utm_campaign=documentation_4_8_cpw&utm_medium=web)
85
  * Shortcode: Use [catposts] [in the content and edit options in the customizer](http://tiptoppress.com/use-shortcode-to-add-category-posts-widget-to-the-content/?utm_source=wordpress_org&utm_campaign=documentation_shortcode_cpw&utm_medium=web)
86
  * Formatting date and time: See <a target="_blank" href="https://codex.wordpress.org/Formatting_Date_and_Time">Formatting Date and Time</a>
87
 
88
  = Contribute =
89
+ While using this plugin if you find any bug or any conflict, please submit an issue at
90
+ [Github](https://github.com/tiptoppress/category-posts-widget) (If possible with a pull request).
91
 
92
  == Installation ==
93
  = Automatic installation =
94
+ Automatic installation is the easiest option as WordPress handles the file transfers itself and you don’t need to leave your web browser. To do an automatic install of Category Posts Widget,
95
 
96
+ 1. log in to your WordPress dashboard, navigate to the Plugins menu and click Add New.
97
+ 2. In the search field type “Category Posts Widget” and click Search Plugins.
98
+ 3. Once you’ve found plugin, you can install it by simply clicking “Install Now”.
99
+ 4. Then, go to plugins page of WordPress admin activate the plugin.
100
  5. Now, goto the Widgets page of the Appearance section and configure the Category Posts widget.
101
 
102
  = Manual installation =
111
  * Version 3.0 or later version uses WordPress 2.9's built in post thumbnail functionality.
112
 
113
  == Frequently Asked Questions ==
114
+ = Template and post detail =
115
+ Here You can control the [Post Detail parts](http://tiptoppress.com/category-posts-widget/documentation-4-8/#Post_details), which appears as part of the post item. All post detail will placed as placeholder. The text in the Template area can be a placeholder, text, HTML code or HTML code for icons.
116
+
117
+ = SVG icons =
118
+ For SVG icon HTML we recommend the WordPress Dashicons, which are included as default and can be used without any icon-font including [Dashicons](https://developer.wordpress.org/resource/dashicons/).
119
+
120
  = How Category Posts Widget work with SiteOrigin Page Builder =
121
  Please add the widget with shortcode [catposts] inside a editor widget which is placed to a SiteOrigin Page Builder row.
122
  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/)
145
  PHP 5.2 is very old and any support for it from the php developers had ended more then 5 years ago [php.net/eol.php](http://php.net/eol.php).
146
  We know there are peopel how use PHP 5.2 [wordpress.org/about/stats](https://wordpress.org/about/stats/) and we can't imagine this people will have no other problems, if they don't update.
147
 
148
+ = You check the PHP version with phpversion(), but the widget don't work =
149
+ Check also the .htaccess file, if there is an entry for an older PHP version.
150
+
151
  == Screenshots ==
152
+ 1. SVG icons support and hover effects
153
+ 2. Template to arrange the post details
154
  3. Use shortcode [catposts] in the content and edit options in the customizer.
155
+ 4. The widget configuration dialog.
156
+ 5. Front end of the widget using a default WordPress Theme.
157
 
158
  == Changelog ==
159
  [Read more on our blog ...](http://tiptoppress.com/category/category-posts-widget?utm_source=wordpress_org&utm_campaign=changelog_cpw&utm_medium=web)
160
 
161
+ = 4.8 - January 22th 2018 =
162
+ * SVG icon support for post formats
163
+ * Template to arrange the post details
164
+ * Premade Templates
165
+ * Date format: Time since plublished
166
+ * Filter by post status: Published, scheduled, private
167
+ * Hover effect: SVG icon
168
+
169
  = 4.7.4 - October 21th 2017 =
170
  * Bugfix for filter by post status (note private)
171
 
287
 
288
  = 2.0 =
289
  * Updated to use the WP 2.8 widget API.
290
+ * Added support for [Simple Post Thumbnails plugin](http://wordpress.org/extend/plugins/simple-post-thumbnails/).