Category Posts Widget - Version 4.6.2

Version Description

  • August 28th 2016 =
  • Fixed only five widget instances can be costumized with shortcodes.
  • For editing shortcode adds a customizer link to the admin-bar if page/post is in edit mode.
Download this release

Release Info

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

Code changes from version 4.6.1 to 4.6.2

Files changed (3) hide show
  1. cat-posts.css +150 -150
  2. cat-posts.php +1449 -1370
  3. readme.txt +200 -186
cat-posts.css CHANGED
@@ -1,150 +1,150 @@
1
- /*
2
- Default CSS Styles for the Category Posts Widget plugin
3
- Version: 4.6.1
4
- */
5
-
6
- /*--------------------------------------------------------------
7
- >>> TABLE OF CONTENTS:
8
- ----------------------------------------------------------------
9
- 1.0 Normalise
10
- 2.0 General
11
- 3.0 CSS cropping
12
- 4.0 Thumbnail hover effects
13
- --------------------------------------------------------------*/
14
-
15
- /*--------------------------------------------------------------
16
- 1.0 Normalise
17
- --------------------------------------------------------------*/
18
- .cat-post-item span.cat-post-css-cropping img {
19
- max-width: initial;
20
- max-height: initial;
21
- }
22
- /*--------------------------------------------------------------
23
- 2.0 General
24
- --------------------------------------------------------------*/
25
- .cat-post-title {
26
- display: inline-block;
27
- font-size: 15px;
28
- }
29
- .cat-post-current .cat-post-title {
30
- font-weight: bold;
31
- text-transform: uppercase;
32
- }
33
- .cat-post-date,
34
- .cat-post-comment-num {
35
- font-size: 12px;
36
- line-height: 18px;
37
- margin-bottom: 0;
38
- }
39
- .cat-post-date {
40
- font-style: italic;
41
- }
42
- .cat-post-author {
43
- margin-bottom: 0;
44
- }
45
- .cat-post-thumbnail {
46
- display: block;
47
- }
48
- .cat-post-thumbnail img {
49
- margin: 5px 10px 5px 0;
50
- float: left;
51
- }
52
- .cat-post-item {
53
- border-bottom: 1px solid #ccc;
54
- list-style: none;
55
- list-style-type: none;
56
- margin: 3px 0;
57
- padding: 3px 0;
58
- }
59
- .cat-post-item:before,
60
- .cat-post-item:after {
61
- content: "";
62
- display: table;
63
- clear: both;
64
- }
65
- .cat-post-item:last-child {
66
- border-bottom: none;
67
- }
68
- /*--------------------------------------------------------------
69
- 3.0 CSS cropping
70
- --------------------------------------------------------------*/
71
- .cat-post-item .cat-post-css-cropping span {
72
- float: left;
73
- margin: 5px 10px 5px 0;
74
- }
75
- /*--------------------------------------------------------------
76
- 4.0 Thumbnail hover effects
77
- --------------------------------------------------------------*/
78
- /* For White, Dark, Scale */
79
- li a.cat-post-white,
80
- li a.cat-post-dark,
81
- li a.cat-post-scale,
82
- li a.cat-post-blur {
83
- display: inline-block;
84
- float: left;
85
- margin: 5px 10px 5px 0;
86
- }
87
- li.cat-post-item a.cat-post-white span,
88
- li.cat-post-item a.cat-post-dark span,
89
- li.cat-post-item a.cat-post-scale span,
90
- li.cat-post-item a.cat-post-blur span {
91
- margin: 0;
92
- }
93
- li a.cat-post-white img,
94
- li a.cat-post-dark img,
95
- li a.cat-post-scale img,
96
- li a.cat-post-blur img {
97
- margin: 0;
98
- padding-bottom: 0 !important;
99
- -webkit-transition: all 0.3s ease;
100
- -moz-transition: all 0.3s ease;
101
- -ms-transition: all 0.3s ease;
102
- -o-transition: all 0.3s ease;
103
- transition: all 0.3s ease;
104
- }
105
- /* Only for White */
106
- li a.cat-post-white {
107
- background-color: white;
108
- }
109
- li a.cat-post-white img:hover {
110
- opacity: 0.8;
111
- }
112
- /* Only for Dark */
113
- li a.cat-post-dark img:hover {
114
- -webkit-filter: brightness(75%);
115
- -moz-filter: brightness(75%);
116
- -ms-filter: brightness(75%);
117
- -o-filter: brightness(75%);
118
- filter: brightness(75%);
119
- }
120
- /* Only for Scale */
121
- li a.cat-post-scale {
122
- overflow: hidden;
123
- }
124
- li a.cat-post-scale.cat-post-css-cropping span {
125
- margin: 0;
126
- overflow: initial;
127
- }
128
- li a.cat-post-scale img {
129
- -webkit-transition: all 0.3s ease;
130
- -moz-transition: all 0.3s ease;
131
- -ms-transition: all 0.3s ease;
132
- -o-transition: all 0.3s ease;
133
- transition: all 0.3s ease;
134
- }
135
- li a.cat-post-scale img:hover {
136
- -webkit-transform: scale(1.1, 1.1);
137
- -ms-transform: scale(1.1, 1.1);
138
- transform: scale(1.1, 1.1);
139
- }
140
- /* Only for Blur */
141
- li a.cat-post-blur {
142
- overflow: hidden;
143
- }
144
- li a.cat-post-blur img:hover {
145
- -webkit-filter: blur(2px);
146
- -moz-filter: blur(2px);
147
- -o-filter: blur(2px);
148
- -ms-filter: blur(2px);
149
- filter: blur(2px);
150
- }
1
+ /*
2
+ Default CSS Styles for the Category Posts Widget plugin
3
+ Version: 4.6.2
4
+ */
5
+
6
+ /*--------------------------------------------------------------
7
+ >>> TABLE OF CONTENTS:
8
+ ----------------------------------------------------------------
9
+ 1.0 Normalise
10
+ 2.0 General
11
+ 3.0 CSS cropping
12
+ 4.0 Thumbnail hover effects
13
+ --------------------------------------------------------------*/
14
+
15
+ /*--------------------------------------------------------------
16
+ 1.0 Normalise
17
+ --------------------------------------------------------------*/
18
+ .cat-post-item span.cat-post-css-cropping img {
19
+ max-width: initial;
20
+ max-height: initial;
21
+ }
22
+ /*--------------------------------------------------------------
23
+ 2.0 General
24
+ --------------------------------------------------------------*/
25
+ .cat-post-title {
26
+ display: inline-block;
27
+ font-size: 15px;
28
+ }
29
+ .cat-post-current .cat-post-title {
30
+ font-weight: bold;
31
+ text-transform: uppercase;
32
+ }
33
+ .cat-post-date,
34
+ .cat-post-comment-num {
35
+ font-size: 12px;
36
+ line-height: 18px;
37
+ }
38
+ .cat-post-date {
39
+ font-style: italic;
40
+ margin-bottom: 10px;
41
+ }
42
+ .cat-post-author {
43
+ margin-bottom: 0;
44
+ }
45
+ .cat-post-thumbnail {
46
+ display: block;
47
+ }
48
+ .cat-post-thumbnail img {
49
+ margin: 5px 10px 5px 0;
50
+ float: left;
51
+ }
52
+ .cat-post-item {
53
+ border-bottom: 1px solid #ccc;
54
+ list-style: none;
55
+ list-style-type: none;
56
+ margin: 3px 0;
57
+ padding: 3px 0;
58
+ }
59
+ .cat-post-item:before,
60
+ .cat-post-item:after {
61
+ content: "";
62
+ display: table;
63
+ clear: both;
64
+ }
65
+ .cat-post-item:last-child {
66
+ border-bottom: none;
67
+ }
68
+ /*--------------------------------------------------------------
69
+ 3.0 CSS cropping
70
+ --------------------------------------------------------------*/
71
+ .cat-post-item .cat-post-css-cropping span {
72
+ float: left;
73
+ margin: 5px 10px 5px 0;
74
+ }
75
+ /*--------------------------------------------------------------
76
+ 4.0 Thumbnail hover effects
77
+ --------------------------------------------------------------*/
78
+ /* For White, Dark, Scale */
79
+ li a.cat-post-white,
80
+ li a.cat-post-dark,
81
+ li a.cat-post-scale,
82
+ li a.cat-post-blur {
83
+ display: inline-block;
84
+ float: left;
85
+ margin: 5px 10px 5px 0;
86
+ }
87
+ li.cat-post-item a.cat-post-white span,
88
+ li.cat-post-item a.cat-post-dark span,
89
+ li.cat-post-item a.cat-post-scale span,
90
+ li.cat-post-item a.cat-post-blur span {
91
+ margin: 0;
92
+ }
93
+ li a.cat-post-white img,
94
+ li a.cat-post-dark img,
95
+ li a.cat-post-scale img,
96
+ li a.cat-post-blur img {
97
+ margin: 0;
98
+ padding-bottom: 0 !important;
99
+ -webkit-transition: all 0.3s ease;
100
+ -moz-transition: all 0.3s ease;
101
+ -ms-transition: all 0.3s ease;
102
+ -o-transition: all 0.3s ease;
103
+ transition: all 0.3s ease;
104
+ }
105
+ /* Only for White */
106
+ li a.cat-post-white {
107
+ background-color: white;
108
+ }
109
+ li a.cat-post-white img:hover {
110
+ opacity: 0.8;
111
+ }
112
+ /* Only for Dark */
113
+ li a.cat-post-dark img:hover {
114
+ -webkit-filter: brightness(75%);
115
+ -moz-filter: brightness(75%);
116
+ -ms-filter: brightness(75%);
117
+ -o-filter: brightness(75%);
118
+ filter: brightness(75%);
119
+ }
120
+ /* Only for Scale */
121
+ li a.cat-post-scale {
122
+ overflow: hidden;
123
+ }
124
+ li a.cat-post-scale.cat-post-css-cropping span {
125
+ margin: 0;
126
+ overflow: initial;
127
+ }
128
+ li a.cat-post-scale img {
129
+ -webkit-transition: all 0.3s ease;
130
+ -moz-transition: all 0.3s ease;
131
+ -ms-transition: all 0.3s ease;
132
+ -o-transition: all 0.3s ease;
133
+ transition: all 0.3s ease;
134
+ }
135
+ li a.cat-post-scale img:hover {
136
+ -webkit-transform: scale(1.1, 1.1);
137
+ -ms-transform: scale(1.1, 1.1);
138
+ transform: scale(1.1, 1.1);
139
+ }
140
+ /* Only for Blur */
141
+ li a.cat-post-blur {
142
+ overflow: hidden;
143
+ }
144
+ li a.cat-post-blur img:hover {
145
+ -webkit-filter: blur(2px);
146
+ -moz-filter: blur(2px);
147
+ -o-filter: blur(2px);
148
+ -ms-filter: blur(2px);
149
+ filter: blur(2px);
150
+ }
cat-posts.php CHANGED
@@ -1,1371 +1,1450 @@
1
- <?php
2
- /*
3
- Plugin Name: Category Posts Widget
4
- Plugin URI: http://mkrdip.me/category-posts-widget
5
- Description: Adds a widget that shows the most recent posts from a single category.
6
- Author: Mrinal Kanti Roy
7
- Version: 4.6.1
8
- Author URI: http://mkrdip.me
9
- */
10
-
11
- namespace categoryPosts;
12
-
13
- // Don't call the file directly
14
- if ( !defined( 'ABSPATH' ) ) exit;
15
-
16
- define( 'CAT_POST_PLUGINURL', plugins_url(basename( dirname(__FILE__))) . "/");
17
- define( 'CAT_POST_PLUGINPATH', dirname(__FILE__) . "/");
18
- define( 'CAT_POST_VERSION', "4.6.1");
19
-
20
- const SHORTCODE_NAME = 'catposts';
21
- const SHORTCODE_META = 'categoryPosts-shorcode';
22
- const WIDGET_BASE_ID = 'category-posts';
23
-
24
- const TEXTDOMAIN = 'categoryposts';
25
- /*
26
- * Iterate over all the widgets active at the page and call the callback for them
27
- *
28
- * callback - accepts the widget settings, return true to continue iteration or false to stop
29
- */
30
- function iterator($id_base,$class,$callback) {
31
- global $wp_registered_widgets;
32
- $sidebars_widgets = wp_get_sidebars_widgets();
33
-
34
- if ( is_array($sidebars_widgets) ) {
35
- foreach ( $sidebars_widgets as $sidebar => $widgets ) {
36
- if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) {
37
- continue;
38
- }
39
-
40
- if ( is_array($widgets) ) {
41
- foreach ( $widgets as $widget ) {
42
- $widget_base = _get_widget_id_base($widget);
43
- if ( $widget_base == $id_base ) {
44
- $widgetclass = new $class();
45
- $allsettings = $widgetclass->get_settings();
46
- $settings = isset($allsettings[str_replace($widget_base.'-','',$widget)]) ? $allsettings[str_replace($widget_base.'-','',$widget)] : false;
47
- if (!$callback($settings))
48
- return;
49
- }
50
- }
51
- }
52
- }
53
- }
54
- }
55
-
56
- /*
57
- Check if CSS needs to be added to support cropping by traversing all active widgets on the page
58
- and checking if any has cropping enabled.
59
-
60
- Return: false if cropping is not active, false otherwise
61
- */
62
- function cropping_active($id_base,$class) {
63
- $ret = false;
64
-
65
- iterator($id_base, $class, function ($settings) use (&$ret) {
66
- if (isset($settings['use_css_cropping'])) { // checks if cropping is active
67
- $ret = true;
68
- return false; // stop iterator
69
- } else
70
- return true; // continue iteration to next widget
71
- });
72
-
73
- return $ret;
74
- }
75
-
76
- /*
77
- Check if CSS needs to be enqueued by traversing all active widgets on the page
78
- and checking if they all have disabled CSS.
79
-
80
- Return: false if CSS should not be enqueued, true if it should
81
- */
82
- function should_enqueue($id_base,$class) {
83
- $ret = false;
84
-
85
- iterator($id_base, $class, function ($settings) use (&$ret) {
86
- if (!(isset($settings['disable_css']) && $settings['disable_css'])) { // checks if css disable is not set
87
- $ret = true;
88
- return false; // stop iterator
89
- } else
90
- return true; // continue iteration to next widget
91
- });
92
-
93
- return $ret;
94
- }
95
-
96
- /**
97
- * Register our styles
98
- *
99
- * @return void
100
- */
101
- add_action( 'wp_enqueue_scripts', __NAMESPACE__.'\widget_styles' );
102
-
103
- function wp_head() {
104
- if (cropping_active(WIDGET_BASE_ID,__NAMESPACE__.'\Widget')) {
105
- ?>
106
- <style type="text/css">
107
- .cat-post-item .cat-post-css-cropping span {
108
- overflow: hidden;
109
- display:inline-block;
110
- }
111
- </style>
112
- <?php
113
- }
114
- }
115
-
116
- add_action('wp_head',__NAMESPACE__.'\wp_head');
117
-
118
- function widget_styles() {
119
-
120
- $enqueue = false;
121
- // check first for shortcode settings
122
- if (is_singular()) {
123
- $meta = shortcode_settings();
124
- if (is_array($meta) && !(isset($meta['disable_css']) && $meta['disable_css']))
125
- $enqueue = true;
126
- }
127
-
128
- if (!$enqueue)
129
- $enqueue = should_enqueue(WIDGET_BASE_ID,__NAMESPACE__.'\Widget');
130
-
131
- if ($enqueue) {
132
- wp_register_style( 'category-posts', CAT_POST_PLUGINURL . 'cat-posts.css',array(),CAT_POST_VERSION );
133
- wp_enqueue_style( 'category-posts' );
134
- }
135
- }
136
-
137
- /*
138
- Enqueue widget related scripts for the widget admin page and customizer
139
- */
140
- function admin_scripts($hook) {
141
-
142
- if ($hook == 'widgets.php') { // enqueue only for widget admin and customizer
143
-
144
- // control open and close the widget section
145
- wp_register_script( 'category-posts-widget-admin-js', CAT_POST_PLUGINURL.'/js/admin/category-posts-widget.js',array('jquery'),CAT_POST_VERSION,true );
146
- wp_enqueue_script( 'category-posts-widget-admin-js' );
147
- }
148
- }
149
-
150
- add_action('admin_enqueue_scripts', __NAMESPACE__.'\admin_scripts'); // "called on widgets.php and costumizer since 3.9
151
-
152
-
153
- /**
154
- * Load plugin textdomain.
155
- *
156
- */
157
- add_action( 'admin_init', __NAMESPACE__.'\load_textdomain' );
158
-
159
- function load_textdomain() {
160
- load_plugin_textdomain( TEXTDOMAIN, false, plugin_basename( dirname( __FILE__ ) ) . '/languages' );
161
- }
162
-
163
- /**
164
- * Add styles for widget sections
165
- *
166
- */
167
- add_action( 'admin_print_styles-widgets.php', __NAMESPACE__.'\admin_styles' );
168
-
169
- function admin_styles() {
170
- ?>
171
- <style>
172
- .category-widget-cont h4 {
173
- padding: 12px 15px;
174
- cursor: pointer;
175
- margin: 5px 0;
176
- border: 1px solid #E5E5E5;
177
- }
178
- .category-widget-cont h4:first-child {
179
- margin-top: 10px;
180
- }
181
- .category-widget-cont h4:last-of-type {
182
- margin-bottom: 10px;
183
- }
184
- .category-widget-cont h4:after {
185
- float:right;
186
- font-family: "dashicons";
187
- content: '\f140';
188
- -ms-transform: translate(-1px,1px);
189
- -webkit-transform: translate(-1px,1px);
190
- -moz-transform: translate(-1px,1px);
191
- transform: translate(-1px,1px);
192
- -ms-transition: all 600ms;
193
- -webkit-transition: all 600ms;
194
- -moz-transition: all 600ms;
195
- transition: all 600ms;
196
- }
197
- .category-widget-cont h4.open:after {
198
- -ms-transition: all 600ms;
199
- -webkit-transition: all 600ms;
200
- -moz-transition: all 600ms;
201
- transition: all 600ms;
202
- -ms-transform: rotate(180deg);
203
- -webkit-transform: rotate(180deg);
204
- -moz-transform: rotate(180deg);
205
- transform: rotate(180deg);
206
- }
207
- .category-widget-cont > div {
208
- display:none;
209
- overflow: hidden;
210
- }
211
- .category-widget-cont > div.open {
212
- display:block;
213
- }
214
- </style>
215
- <?php
216
- }
217
-
218
- /**
219
- * Get image size
220
- *
221
- * $thumb_w, $thumb_h - the width and height of the thumbnail in the widget settings
222
- * $image_w,$image_h - the width and height of the actual image being displayed
223
- *
224
- * return: an array with the width and height of the element containing the image
225
- */
226
- function get_image_size( $thumb_w,$thumb_h,$image_w,$image_h) {
227
-
228
- $image_size = array('image_h' => $thumb_h, 'image_w' => $thumb_w, 'marginAttr' => '', 'marginVal' => '');
229
- $relation_thumbnail = $thumb_w / $thumb_h;
230
- $relation_cropped = $image_w / $image_h;
231
-
232
- if ($relation_thumbnail < $relation_cropped) {
233
- // crop left and right site
234
- // thumbnail width/height ration is smaller, need to inflate the height of the image to thumb height
235
- // and adjust width to keep aspect ration of image
236
- $image_size['image_h'] = $thumb_h;
237
- $image_size['image_w'] = $thumb_h / $image_h * $image_w;
238
- $image_size['marginAttr'] = 'margin-left';
239
- $image_size['marginVal'] = ($image_size['image_w'] - $thumb_w) / 2;
240
- } else {
241
- // crop top and bottom
242
- // thumbnail width/height ration is bigger, need to inflate the width of the image to thumb width
243
- // and adjust height to keep aspect ration of image
244
- $image_size['image_w'] = $thumb_w;
245
- $image_size['image_h'] = $thumb_w / $image_w * $image_h;
246
- $image_size['marginAttr'] = 'margin-top';
247
- $image_size['marginVal'] = ($image_size['image_h'] - $thumb_h) / 2;
248
- }
249
-
250
- return $image_size;
251
- }
252
-
253
- /**
254
- * Category Posts Widget Class
255
- *
256
- * Shows the single category posts with some configurable options
257
- */
258
- class Widget extends \WP_Widget {
259
-
260
- function __construct() {
261
- $widget_ops = array('classname' => 'cat-post-widget', 'description' => __('List single category posts',TEXTDOMAIN));
262
- parent::__construct(WIDGET_BASE_ID, __('Category Posts',TEXTDOMAIN), $widget_ops);
263
- }
264
-
265
- /**
266
- * Calculate the HTML for showing the thumb of a post item.
267
- *
268
- * Used as a filter for the thumb wordpress API to add css based stretching and cropping
269
- * when the image is not at the requested dimensions
270
- *
271
- * @param string $html The original HTML generated by the core APIS
272
- * @param int $post_id the ID of the post of which the thumb is a featured image
273
- * @param int $post_thumbnail_id The id of the featured image attachment
274
- * @param string|array $size The requested size identified by name or (width, height) array
275
- * @param mixed $attr ignored in this context
276
- * @return string The HTML for the thumb related to the post
277
- *
278
- * @since 4.1
279
- */
280
- function post_thumbnail_html($html, $post_id, $post_thumbnail_id, $size, $attr){
281
- if ( empty($this->instance['thumb_w']) || empty($this->instance['thumb_h']))
282
- return $html; // bail out if no full dimensions defined
283
-
284
- $meta = image_get_intermediate_size($post_thumbnail_id,$size);
285
-
286
- if ( empty( $meta )) {
287
- $post_img = wp_get_attachment_metadata($post_thumbnail_id, $size);
288
- $meta['file'] = basename( $post_img['file'] );
289
- }
290
-
291
- $origfile = get_attached_file( $post_thumbnail_id, true); // the location of the full file
292
- $file = dirname($origfile) .'/'.$meta['file']; // the location of the file displayed as thumb
293
- list( $width, $height ) = getimagesize($file); // get actual size of the thumb file
294
-
295
- if ($width / $height == $this->instance['thumb_w'] / $this->instance['thumb_h']) {
296
- // image is same ratio as asked for, nothing to do here as the browser will handle it correctly
297
- ;
298
- } else if (isset($this->instance['use_css_cropping']) && $this->instance['use_css_cropping']) {
299
- $image = get_image_size($this->instance['thumb_w'],$this->instance['thumb_h'],$width,$height);
300
-
301
- // replace srcset
302
- $array = array();
303
- preg_match( '/width="([^"]*)"/i', $html, $array ) ;
304
- $pattern = "/".$array[1]."w/";
305
- $html = preg_replace($pattern, $image['image_w']."w", $html);
306
- // replace size
307
- $pattern = "/".$array[1]."px/";
308
- $html = preg_replace($pattern, $image['image_w']."px", $html);
309
- // replace width
310
- $pattern = "/width=\"[0-9]*\"/";
311
- $html = preg_replace($pattern, "width='".$image['image_w']."'", $html);
312
- // replace height
313
- $pattern = "/height=\"[0-9]*\"/";
314
- $html = preg_replace($pattern, "height='".$image['image_h']."'", $html);
315
- // set margin
316
- $html = str_replace('<img ','<img style="'.$image['marginAttr'].':-'.$image['marginVal'].'px;height:'.$image['image_h']
317
- .'px;clip:rect(auto,'.($this->instance['thumb_w']+$image['marginVal']).'px,auto,'.$image['marginVal']
318
- .'px);width:auto;max-width:initial;" ',$html);
319
- // wrap span
320
- $html = '<span style="width:'.$this->instance['thumb_w'].'px;height:'.$this->instance['thumb_h'].'px;">'
321
- .$html.'</span>';
322
- } else {
323
- // if use_css_cropping not used
324
- // no interface changes: leave without change
325
- }
326
- return $html;
327
- }
328
-
329
- /*
330
- wrapper to execute the the_post_thumbnail with filters
331
- */
332
- /**
333
- * Calculate the HTML for showing the thumb of a post item.
334
- *
335
- * It is a wrapper to execute the the_post_thumbnail with filters
336
- *
337
- * @param string|array $size The requested size identified by name or (width, height) array
338
- *
339
- * @return string The HTML for the thumb related to the post and empty string if it can not be calculated
340
- *
341
- * @since 4.1
342
- */
343
- function the_post_thumbnail($size= 'post-thumbnail') {
344
- if (empty($size)) // if junk value, make it a normal thumb
345
- $size= 'post-thumbnail';
346
- else if (is_array($size) && (count($size)==2)) { // good format at least
347
- // normalize to ints first
348
- $size[0] = (int) $size[0];
349
- $size[1] = (int) $size[1];
350
- if (($size[0] == 0) && ($size[1] == 0)) //both values zero then revert to thumbnail
351
- $size= 'post-thumbnail';
352
- // if one value is zero make a square using the other value
353
- else if (($size[0] == 0) && ($size[1] != 0))
354
- $size[0] = $size[1];
355
- else if (($size[0] != 0) && ($size[1] == 0))
356
- $size[1] = $size[0];
357
- } else $size= 'post-thumbnail'; // yet another form of junk
358
-
359
- add_filter('post_thumbnail_html',array($this,'post_thumbnail_html'),1,5);
360
- $ret = get_the_post_thumbnail( null,$size,'');
361
- remove_filter('post_thumbnail_html',array($this,'post_thumbnail_html'),1,5);
362
- return $ret;
363
- }
364
-
365
- /**
366
- * Excerpt more link filter
367
- */
368
- function excerpt_more_filter($more) {
369
- return ' <a class="cat-post-excerpt-more" href="'. get_permalink() . '">' . esc_html($this->instance["excerpt_more_text"]) . '</a>';
370
- }
371
-
372
- /**
373
- * Apply the_content filter for excerpt
374
- * This should show sharing buttons which comes with other widgets in the widget output in the same way as on the main content
375
- *
376
- * @param string The HTML with other applied excerpt filters
377
- *
378
- * @return string the result of applying the_content filter
379
- *
380
- * @since 4.6
381
- */
382
- function apply_the_excerpt($text) {
383
- $ret = apply_filters('the_content', $text);
384
- return $ret;
385
- }
386
-
387
- /**
388
- * Excerpt allow HTML
389
- */
390
- function allow_html_excerpt($text) {
391
- global $post, $wp_filter;
392
- $new_excerpt_length = ( isset($this->instance["excerpt_length"]) && $this->instance["excerpt_length"] > 0 ) ? $this->instance["excerpt_length"] : 55;
393
- if ( '' == $text ) {
394
- $text = get_the_content('');
395
- $text = strip_shortcodes( $text );
396
- $text = apply_filters('the_content', $text);
397
- $text = str_replace('\]\]\>', ']]&gt;', $text);
398
- $text = preg_replace('@<script[^>]*?>.*?</script>@si', '', $text);
399
- $cphtml = array(
400
- '&lt;a&gt;',
401
- '&lt;br&gt;',
402
- '&lt;em&gt;',
403
- '&lt;i&gt;',
404
- '&lt;ul&gt;',
405
- '&lt;ol&gt;',
406
- '&lt;li&gt;',
407
- '&lt;p&gt;',
408
- '&lt;img&gt;',
409
- '&lt;script&gt;',
410
- '&lt;style&gt;',
411
- '&lt;video&gt;',
412
- '&lt;audio&gt;'
413
- );
414
- $allowed_HTML = "";
415
- foreach ($cphtml as $index => $name) {
416
- if (in_array((string)($index),$this->instance['excerpt_allowed_elements'],true))
417
- $allowed_HTML .= $cphtml[$index];
418
- }
419
- $text = strip_tags($text, htmlspecialchars_decode($allowed_HTML));
420
- $excerpt_length = $new_excerpt_length;
421
-
422
- if( !empty($this->instance["excerpt_more_text"]) ) {
423
- $excerpt_more = $this->excerpt_more_filter($this->instance["excerpt_more_text"]);
424
- }else if($filterName = key($wp_filter['excerpt_more'][10])) {
425
- $excerpt_more = $wp_filter['excerpt_more'][10][$filterName]['function'](0);
426
- }else {
427
- $excerpt_more = '[...]';
428
- }
429
-
430
- $words = explode(' ', $text, $excerpt_length + 1);
431
- if (count($words)> $excerpt_length) {
432
- array_pop($words);
433
- array_push($words, $excerpt_more);
434
- $text = implode(' ', $words);
435
- }
436
- }
437
-
438
- return '<p>' . $text . '</p>';
439
- }
440
-
441
- /**
442
- * Calculate the HTML for showing the thumb of a post item.
443
- * Expected to be called from a loop with globals properly set
444
- *
445
- * @param array $instance Array which contains the various settings
446
- * @return string The HTML for the thumb related to the post
447
- *
448
- * @since 4.6
449
- */
450
- function show_thumb($instance) {
451
- $ret = '';
452
-
453
- if ( isset( $instance["thumb"] ) && $instance["thumb"] &&
454
- has_post_thumbnail() ) {
455
- $use_css_cropping = isset($this->instance['use_css_cropping']) ? "cat-post-css-cropping" : "";
456
- $class = '';
457
- if( !(isset( $this->instance['disable_css'] ) && $this->instance['disable_css'])) {
458
- if( isset($this->instance['thumb_hover'] )) {
459
- $class = "class=\"cat-post-thumbnail " . $use_css_cropping ." cat-post-" . $instance['thumb_hover'] . "\"";
460
- } else {
461
- $class = "class=\"cat-post-thumbnail " . $use_css_cropping . "\"";
462
- }
463
- }
464
- $title_args = array('echo'=>false);
465
- $ret .= '<a '.$class . ' href="'.get_the_permalink().'" title="'.the_title_attribute($title_args).'">';
466
- $ret .= $this->the_post_thumbnail( array($this->instance['thumb_w'],$this->instance['thumb_h']));
467
- $ret .= '</a>';
468
- }
469
-
470
- return $ret;
471
- }
472
-
473
- /**
474
- * Calculate the wp-query arguments matching the filter settings of the widget
475
- *
476
- * @param array $instance Array which contains the various settings
477
- * @return array The array that can be fed to wp_Query to get the relevant posts
478
- *
479
- * @since 4.6
480
- */
481
- function queryArgs($instance) {
482
- $valid_sort_orders = array('date', 'title', 'comment_count', 'rand');
483
- if ( isset($instance['sort_by']) && in_array($instance['sort_by'],$valid_sort_orders) ) {
484
- $sort_by = $instance['sort_by'];
485
- } else {
486
- $sort_by = 'date';
487
- }
488
- $sort_order = (isset( $instance['asc_sort_order'] ) && $instance['asc_sort_order']) ? 'ASC' : 'DESC';
489
-
490
- // Get array of post info.
491
- $args = array(
492
- 'orderby' => $sort_by,
493
- 'order' => $sort_order
494
- );
495
-
496
- if (isset($instance["num"]))
497
- $args['showposts'] = (int) $instance["num"];
498
-
499
- if (isset($instance["cat"]))
500
- $args['cat'] = (int) $instance["cat"];
501
-
502
- if (is_singular() && isset( $instance['exclude_current_post'] ) && $instance['exclude_current_post'])
503
- $args['post__not_in'] = array(get_the_ID());
504
-
505
- if( isset( $instance['hideNoThumb'] ) && $instance['hideNoThumb']) {
506
- $args = array_merge( $args, array( 'meta_query' => array(
507
- array(
508
- 'key' => '_thumbnail_id',
509
- 'compare' => 'EXISTS' )
510
- )
511
- )
512
- );
513
- }
514
-
515
- return $args;
516
- }
517
-
518
- /**
519
- * Calculate the HTML of the title based on the widget settings
520
- *
521
- * @param string $before_title The sidebar configured HTML that should come
522
- * before the title itself
523
- * @param string $after_title The sidebar configured HTML that should come
524
- * after the title itself
525
- * @param array $instance Array which contains the various settings
526
- * @return string The HTML for the title area
527
- *
528
- * @since 4.6
529
- */
530
- function titleHTML($before_title,$after_title,$instance) {
531
- $ret = '';
532
-
533
- // If not title, use the name of the category.
534
- if( !isset($instance["title"]) || !$instance["title"] ) {
535
- $instance["title"] = '';
536
- if (isset($instance["cat"])) {
537
- $category_info = get_category($instance["cat"]);
538
- if ($category_info && !is_wp_error($category_info))
539
- $instance["title"] = $category_info->name;
540
- }
541
- }
542
-
543
- if( !(isset ( $instance["hide_title"] ) && $instance["hide_title"])) {
544
- $ret = $before_title;
545
- if( isset ( $instance["title_link"]) && $instance["title_link"] && isset($instance["cat"]) && (get_category($instance["cat"]) != null)) {
546
- $ret .= '<a href="' . get_category_link($instance["cat"]) . '">' . esc_html(apply_filters( 'widget_title', $instance["title"] )) . '</a>';
547
- } else {
548
- $ret .= esc_html(apply_filters( 'widget_title', $instance["title"] ));
549
- }
550
- $ret .= $after_title;
551
- }
552
-
553
- return $ret;
554
- }
555
-
556
- /**
557
- * Calculate the HTML of the footer based on the widget settings
558
- *
559
- * @param array $instance Array which contains the various settings
560
- * @return string The HTML for the footer area
561
- *
562
- * @since 4.6
563
- */
564
- function footerHTML($instance) {
565
- $ret = '';
566
-
567
- if( isset ( $instance["footer_link"] ) && $instance["footer_link"] && isset($instance["cat"]) && (get_category($instance["cat"]) != null) ) {
568
- $ret = "<a";
569
- if( !(isset( $instance['disable_css'] ) && $instance['disable_css'])) { $ret.= " class=\"cat-post-footer-link\""; }
570
- $ret .= " href=\"" . get_category_link($instance["cat"]) . "\">" . esc_html($instance["footer_link"]) . "</a>";
571
- }
572
-
573
- return $ret;
574
- }
575
-
576
- /**
577
- * Calculate the HTML for a post item based on the widget settings and post.
578
- * Expected to be called in an active loop with all the globals set
579
- *
580
- * @param array $instance Array which contains the various settings
581
- * $param null|integer $current_post_id If on singular page specifies the id of
582
- * the post, otherwise null
583
- * @return string The HTML for item related to the post
584
- *
585
- * @since 4.6
586
- */
587
- function itemHTML($instance,$current_post_id) {
588
- global $post;
589
-
590
- $ret = '<li ';
591
-
592
- if ( $current_post_id == $post->ID ) {
593
- $ret .= "class='cat-post-item cat-post-current'";
594
- } else {
595
- $ret .= "class='cat-post-item'";
596
- }
597
- $ret.='>'; // close the li opening tag
598
-
599
- // Thumbnail position to top
600
- if( isset( $instance["thumbTop"] ) && $instance["thumbTop"]) {
601
- $ret .= $this->show_thumb($instance);
602
- }
603
-
604
- if( !(isset( $instance['hide_post_titles'] ) && $instance['hide_post_titles'])) {
605
- $ret .= '<a class="post-title';
606
- if( !isset( $instance['disable_css'] ) ) {
607
- $ret .= " cat-post-title";
608
- }
609
- $ret .= '" href="'.get_the_permalink().'" rel="bookmark">'.get_the_title();
610
- $ret .= '</a> ';
611
- }
612
-
613
- if ( isset( $instance['date']) && $instance['date']) {
614
- if ( isset( $instance['date_format'] ) && strlen( trim( $instance['date_format'] ) ) > 0 ) {
615
- $date_format = $instance['date_format'];
616
- } else {
617
- $date_format = "j M Y";
618
- }
619
- $ret .= '<p class="post-date ';
620
- if( !isset( $instance['disable_css'] ) ) {
621
- $ret .= "cat-post-date";
622
- }
623
- $ret .= '">';
624
- if ( isset ( $instance["date_link"] ) && $instance["date_link"]) {
625
- $ret .= '<a href="'.\get_the_permalink().'">';
626
- }
627
- $ret .= get_the_time($date_format);
628
- if ( isset ( $instance["date_link"] ) ) {
629
- $ret .= '</a>';
630
- }
631
- $ret .= '</p>';
632
- }
633
-
634
- // Thumbnail position normal
635
- if( !(isset( $instance["thumbTop"] ) && $instance["thumbTop"])) {
636
- $ret .= $this->show_thumb($instance);
637
- }
638
-
639
- if ( isset( $instance['excerpt'] ) && $instance['excerpt']) {
640
- // use the_excerpt filter to get the "normal" excerpt of the post
641
- // then apply our filter to let users customize excerpts in their own way
642
- if (isset($instance['excerpt_length']) && ($instance['excerpt_length'] > 0))
643
- $length = (int) $instance['excerpt_length'];
644
- else
645
- $length = 0; // indicate that invalid length is set
646
- $ret .= apply_filters('cpw_excerpt',apply_filters('the_excerpt',\get_the_excerpt()),$this,$length);
647
- }
648
-
649
- if ( isset( $instance['comment_num'] ) && $instance['comment_num']) {
650
- $ret .= '<p class="comment-num';
651
- if ( !isset( $instance['disable_css'] ) ) {
652
- $ret .= " cat-post-comment-num";
653
- }
654
- $ret .= '">';
655
- $ret .= '('.\get_comments_number().')';
656
- $ret .= '</p>';
657
- }
658
-
659
- if ( isset( $instance['author'] ) && $instance['author']) {
660
- $ret .= '<p class="post-author ';
661
- if( !isset( $instance['disable_css'] ) ) {
662
- $ret .= "cat-post-author";
663
- }
664
- $ret .= '">';
665
- global $authordata;
666
- $link = sprintf(
667
- '<a href="%1$s" title="%2$s" rel="author">%3$s</a>',
668
- esc_url( get_author_posts_url( $authordata->ID, $authordata->user_nicename ) ),
669
- esc_attr( sprintf( __( 'Posts by %s' ), get_the_author() ) ),
670
- get_the_author()
671
- );
672
- $ret .= $link;
673
- $ret .= '</p>';
674
- }
675
-
676
- $ret .= '</li>';
677
- return $ret;
678
- }
679
-
680
- /**
681
- * Filter to set the number of words in an excerpt
682
- *
683
- * @param int $length The number of words as configured by wordpress core or set by previous filters
684
- * @return int The number of words configured for the widget,
685
- * or the $length parameter if it is not configured or garbage value
686
- *
687
- * @since 4.6
688
- */
689
- function excerpt_length_filter($length) {
690
- if ( isset($this->instance["excerpt_length"]) && $this->instance["excerpt_length"] > 0 )
691
- $length = $this->instance["excerpt_length"];
692
-
693
- return $length;
694
- }
695
-
696
- /**
697
- * Set the proper excerpt filters based on the settings
698
- *
699
- * @param array $instance widget settings
700
- * @return void
701
- *
702
- * @since 4.6
703
- */
704
- function setExcerpFilters($instance) {
705
-
706
- if (isset($instance['excerpt']) && $instance['excerpt']) {
707
-
708
- // Excerpt length filter
709
- if ( isset($instance["excerpt_length"]) && ((int) $instance["excerpt_length"]) > 0 ) {
710
- add_filter('excerpt_length', array($this,'excerpt_length_filter'));
711
- }
712
-
713
- if( isset($instance["excerpt_more_text"]) && ltrim($instance["excerpt_more_text"]) != '' )
714
- {
715
- add_filter('excerpt_more', array($this,'excerpt_more_filter'));
716
- }
717
-
718
- if( isset( $instance['excerpt_allow_html'] ) ) {
719
- remove_filter('get_the_excerpt', 'wp_trim_excerpt');
720
- add_filter('the_excerpt', array($this,'allow_html_excerpt'));
721
- } else {
722
- add_filter('the_excerpt', array($this,'apply_the_excerpt'));
723
- }
724
- }
725
- }
726
-
727
- /**
728
- * Remove the excerpt filter
729
- *
730
- * @param array $instance widget settings
731
- * @return void
732
- *
733
- * @since 4.6
734
- */
735
- function removeExcerpFilters($instance) {
736
- remove_filter('excerpt_length', array($this,'excerpt_length_filter'));
737
- remove_filter('excerpt_more', array($this,'excerpt_more_filter'));
738
- add_filter('get_the_excerpt', 'wp_trim_excerpt');
739
- remove_filter('the_excerpt', array($this,'allow_html_excerpt'));
740
- remove_filter('the_excerpt', array($this,'apply_the_excerpt'));
741
- }
742
-
743
- /**
744
- * The main widget display controller
745
- *
746
- * Called by the sidebar processing core logic to display the widget
747
- *
748
- * @param array $args An array containing the "environment" setting for the widget,
749
- * namely, the enclosing tags for the widget and its title.
750
- * @param array $instance The settings associate with the widget
751
- *
752
- * @since 4.1
753
- */
754
- function widget($args, $instance) {
755
-
756
- extract( $args );
757
- $this->instance = $instance;
758
-
759
- $args = $this->queryArgs($instance);
760
- $cat_posts = new \WP_Query( $args );
761
-
762
- if ( !isset ( $instance["hide_if_empty"] ) || !$instance["hide_if_empty"] || $cat_posts->have_posts() ) {
763
- echo $before_widget;
764
- echo $this->titleHTML($before_title,$after_title,$instance);
765
-
766
- $current_post_id = null;
767
- if (is_singular())
768
- $current_post_id = get_the_ID();
769
-
770
- echo '<ul id="'.WIDGET_BASE_ID.'-'.$this->number."\">\n"; // use the internal number of the widget as a unique id
771
-
772
- $this->setExcerpFilters($instance);
773
- while ( $cat_posts->have_posts() )
774
- {
775
- $cat_posts->the_post();
776
- echo $this->itemHTML($instance,$current_post_id);
777
- }
778
- echo "</ul>\n";
779
-
780
- echo $this->footerHTML($instance);
781
- echo $after_widget;
782
-
783
- $this->removeExcerpFilters($instance);
784
-
785
- wp_reset_postdata();
786
-
787
- }
788
- }
789
-
790
- /**
791
- * Update the options
792
- *
793
- * @param array $new_instance
794
- * @param array $old_instance
795
- * @return array
796
- */
797
- function update($new_instance, $old_instance) {
798
-
799
- return $new_instance;
800
- }
801
-
802
- /**
803
- * Output the title panel of the widget configuration form.
804
- *
805
- * @param array $instance
806
- * @return void
807
- *
808
- * @since 4.6
809
- */
810
- function formTitlePanel($instance) {
811
- $instance = wp_parse_args( ( array ) $instance, array(
812
- 'title' => '',
813
- 'title_link' => '',
814
- 'hide_title' => ''
815
- ));
816
- $title = $instance['title'];
817
- $hide_title = $instance['hide_title'];
818
- $title_link = $instance['title_link'];
819
- ?>
820
- <h4 data-panel="title"><?php _e('Title',TEXTDOMAIN)?></h4>
821
- <div>
822
- <p>
823
- <label for="<?php echo $this->get_field_id("title"); ?>">
824
- <?php _e( 'Title',TEXTDOMAIN ); ?>:
825
- <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"]); ?>" />
826
- </label>
827
- </p>
828
- <p>
829
- <label for="<?php echo $this->get_field_id("title_link"); ?>">
830
- <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 ); ?> />
831
- <?php _e( 'Make widget title link',TEXTDOMAIN ); ?>
832
- </label>
833
- </p>
834
- <p>
835
- <label for="<?php echo $this->get_field_id("hide_title"); ?>">
836
- <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 ); ?> />
837
- <?php _e( 'Hide title',TEXTDOMAIN ); ?>
838
- </label>
839
- </p>
840
- </div>
841
- <?php
842
- }
843
-
844
- /**
845
- * Output the filter panel of the widget configuration form.
846
- *
847
- * @param array $instance
848
- * @return void
849
- *
850
- * @since 4.6
851
- */
852
- function formFilterPanel($instance) {
853
- $instance = wp_parse_args( ( array ) $instance, array(
854
- 'cat' => '',
855
- 'num' => get_option('posts_per_page'),
856
- 'sort_by' => '',
857
- 'asc_sort_order' => '',
858
- 'exclude_current_post' => '',
859
- 'hideNoThumb' => ''
860
- ));
861
- $cat = $instance['cat'];
862
- $num = $instance['num'];
863
- $sort_by = $instance['sort_by'];
864
- $asc_sort_order = $instance['asc_sort_order'];
865
- $exclude_current_post = $instance['exclude_current_post'];
866
- $hideNoThumb = $instance['hideNoThumb'];
867
- ?>
868
- <h4 data-panel="filter"><?php _e('Filter',TEXTDOMAIN);?></h4>
869
- <div>
870
- <p>
871
- <label>
872
- <?php _e( 'Category',TEXTDOMAIN ); ?>:
873
- <?php wp_dropdown_categories( array( 'hide_empty'=> 0, 'name' => $this->get_field_name("cat"), 'selected' => $instance["cat"] ) ); ?>
874
- </label>
875
- </p>
876
- <p>
877
- <label for="<?php echo $this->get_field_id("num"); ?>">
878
- <?php _e('Number of posts to show',TEXTDOMAIN); ?>:
879
- <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"]); ?>" />
880
- </label>
881
- </p>
882
- <p>
883
- <label for="<?php echo $this->get_field_id("sort_by"); ?>">
884
- <?php _e('Sort by',TEXTDOMAIN); ?>:
885
- <select id="<?php echo $this->get_field_id("sort_by"); ?>" name="<?php echo $this->get_field_name("sort_by"); ?>">
886
- <option value="date"<?php selected( $instance["sort_by"], "date" ); ?>><?php _e('Date',TEXTDOMAIN)?></option>
887
- <option value="title"<?php selected( $instance["sort_by"], "title" ); ?>><?php _e('Title',TEXTDOMAIN)?></option>
888
- <option value="comment_count"<?php selected( $instance["sort_by"], "comment_count" ); ?>><?php _e('Number of comments',TEXTDOMAIN)?></option>
889
- <option value="rand"<?php selected( $instance["sort_by"], "rand" ); ?>><?php _e('Random',TEXTDOMAIN)?></option>
890
- </select>
891
- </label>
892
- </p>
893
- <p>
894
- <label for="<?php echo $this->get_field_id("asc_sort_order"); ?>">
895
- <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 ); ?> />
896
- <?php _e( 'Reverse sort order (ascending)',TEXTDOMAIN ); ?>
897
- </label>
898
- </p>
899
- <p>
900
- <label for="<?php echo $this->get_field_id("exclude_current_post"); ?>">
901
- <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 ); ?> />
902
- <?php _e( 'Exclude current post',TEXTDOMAIN ); ?>
903
- </label>
904
- </p>
905
- <p>
906
- <label for="<?php echo $this->get_field_id("hideNoThumb"); ?>">
907
- <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 ); ?> />
908
- <?php _e( 'Exclude posts which have no thumbnail',TEXTDOMAIN ); ?>
909
- </label>
910
- </p>
911
- </div>
912
- <?php
913
- }
914
-
915
- /**
916
- * Output the filter panel of the widget configuration form.
917
- *
918
- * @param array $instance
919
- * @return void
920
- *
921
- * @since 4.6
922
- */
923
- function formThumbnailPanel($instance) {
924
- $instance = wp_parse_args( ( array ) $instance, array(
925
- 'thumb' => '',
926
- 'thumbTop' => '',
927
- 'thumb_w' => '',
928
- 'thumb_h' => '',
929
- 'use_css_cropping' => '',
930
- 'thumb_hover' => ''
931
- ));
932
- $thumb = $instance['thumb'];
933
- $thumbTop = $instance['thumbTop'];
934
- $thumb_w = $instance['thumb_w'];
935
- $thumb_h = $instance['thumb_h'];
936
- $use_css_cropping = $instance['use_css_cropping'];
937
- $thumb_hover = $instance['thumb_hover'];
938
- ?>
939
- <h4 data-panel="thumbnail"><?php _e('Thumbnails',TEXTDOMAIN)?></h4>
940
- <div>
941
- <p>
942
- <label for="<?php echo $this->get_field_id("thumb"); ?>">
943
- <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 ); ?> />
944
- <?php _e( 'Show post thumbnail',TEXTDOMAIN ); ?>
945
- </label>
946
- </p>
947
- <p>
948
- <label for="<?php echo $this->get_field_id("thumbTop"); ?>">
949
- <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 ); ?> />
950
- <?php _e( 'Show thumbnails above text',TEXTDOMAIN ); ?>
951
- </label>
952
- </p>
953
- <p>
954
- <label>
955
- <?php _e('Thumbnail dimensions (in pixels)',TEXTDOMAIN); ?>:<br />
956
- <label for="<?php echo $this->get_field_id("thumb_w"); ?>">
957
- <?php _e('Width:',TEXTDOMAIN)?> <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"]); ?>" />
958
- </label>
959
-
960
- <label for="<?php echo $this->get_field_id("thumb_h"); ?>">
961
- <?php _e('Height:',TEXTDOMAIN)?> <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"]); ?>" />
962
- </label>
963
- </label>
964
- </p>
965
- <p>
966
- <label for="<?php echo $this->get_field_id("use_css_cropping"); ?>">
967
- <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 ); ?> />
968
- <?php _e( 'CSS crop to requested size ',TEXTDOMAIN ); ?>
969
- </label>
970
- </p>
971
- <p>
972
- <label for="<?php echo $this->get_field_id("thumb_hover"); ?>">
973
- <?php _e( 'Animation on mouse hover:',TEXTDOMAIN ); ?>
974
- </label>
975
- <select id="<?php echo $this->get_field_id("thumb_hover"); ?>" name="<?php echo $this->get_field_name("thumb_hover"); ?>">
976
- <option value="none" <?php selected($thumb_hover, 'none')?>><?php _e( 'None', TEXTDOMAIN ); ?></option>
977
- <option value="dark" <?php selected($thumb_hover, 'dark')?>><?php _e( 'Darker', TEXTDOMAIN ); ?></option>
978
- <option value="white" <?php selected($thumb_hover, 'white')?>><?php _e( 'Brighter', TEXTDOMAIN ); ?></option>
979
- <option value="scale" <?php selected($thumb_hover, 'scale')?>><?php _e( 'Zoom in', TEXTDOMAIN ); ?></option>
980
- <option value="blur" <?php selected($thumb_hover, 'blur')?>><?php _e( 'Blur', TEXTDOMAIN ); ?></option>
981
- </select>
982
- </p>
983
- </div>
984
- <?php
985
- }
986
-
987
- /**
988
- * The widget configuration form back end.
989
- *
990
- * @param array $instance
991
- * @return void
992
- */
993
- function form($instance) {
994
- $instance = wp_parse_args( ( array ) $instance, array(
995
- 'footer_link' => '',
996
- 'hide_post_titles' => '',
997
- 'excerpt' => '',
998
- 'excerpt_length' => 55,
999
- 'excerpt_more_text' => '',
1000
- 'comment_num' => '',
1001
- 'author' => '',
1002
- 'date' => '',
1003
- 'date_link' => '',
1004
- 'date_format' => '',
1005
- 'disable_css' => '',
1006
- 'hide_if_empty' => '',
1007
- ) );
1008
-
1009
- $footer_link = $instance['footer_link'];
1010
- $hide_post_titles = $instance['hide_post_titles'];
1011
- $excerpt = $instance['excerpt'];
1012
- $excerpt_length = $instance['excerpt_length'];
1013
- $excerpt_more_text = $instance['excerpt_more_text'];
1014
- $comment_num = $instance['comment_num'];
1015
- $author = $instance['author'];
1016
- $date = $instance['date'];
1017
- $date_link = $instance['date_link'];
1018
- $date_format = $instance['date_format'];
1019
- $disable_css = $instance['disable_css'];
1020
- $hide_if_empty = $instance['hide_if_empty'];
1021
-
1022
- ?>
1023
- <div class="category-widget-cont">
1024
- <p><a target="_blank" href="http://tiptoppress.com/term-and-category-based-posts-widget/">Get the Pro Version</a></p>
1025
- <p><a target="_blank" href="http://tiptoppress.com/category-posts-widget/documentation/">Documentation</a></p>
1026
- <?php
1027
- $this->formTitlePanel($instance);
1028
- $this->formFilterPanel($instance);
1029
- $this->formThumbnailPanel($instance);
1030
- ?>
1031
- <h4 data-panel="details"><?php _e('Post details',TEXTDOMAIN)?></h4>
1032
- <div>
1033
- <p>
1034
- <label for="<?php echo $this->get_field_id("hide_post_titles"); ?>">
1035
- <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 ); ?> />
1036
- <?php _e( 'Hide post titles',TEXTDOMAIN ); ?>
1037
- </label>
1038
- </p>
1039
- <p>
1040
- <label for="<?php echo $this->get_field_id("excerpt"); ?>">
1041
- <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 ); ?> />
1042
- <?php _e( 'Show post excerpt',TEXTDOMAIN ); ?>
1043
- </label>
1044
- </p>
1045
- <p>
1046
- <label for="<?php echo $this->get_field_id("excerpt_length"); ?>">
1047
- <?php _e( 'Excerpt length (in words):',TEXTDOMAIN ); ?>
1048
- </label>
1049
- <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"]; ?>" />
1050
- </p>
1051
- <p>
1052
- <label for="<?php echo $this->get_field_id("excerpt_more_text"); ?>">
1053
- <?php _e( 'Excerpt \'more\' text:',TEXTDOMAIN ); ?>
1054
- </label>
1055
- <input class="widefat" style="width:50%;" placeholder="<?php _e('... more',TEXTDOMAIN)?>" 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"]); ?>" />
1056
- </p>
1057
- <p>
1058
- <label for="<?php echo $this->get_field_id("date"); ?>">
1059
- <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 ); ?> />
1060
- <?php _e( 'Show post date',TEXTDOMAIN ); ?>
1061
- </label>
1062
- </p>
1063
- <p>
1064
- <label for="<?php echo $this->get_field_id("date_format"); ?>">
1065
- <?php _e( 'Date format:',TEXTDOMAIN ); ?>
1066
- </label>
1067
- <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" />
1068
- </p>
1069
- <p>
1070
- <label for="<?php echo $this->get_field_id("date_link"); ?>">
1071
- <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 ); ?> />
1072
- <?php _e( 'Make widget date link',TEXTDOMAIN ); ?>
1073
- </label>
1074
- </p>
1075
- <p>
1076
- <label for="<?php echo $this->get_field_id("comment_num"); ?>">
1077
- <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 ); ?> />
1078
- <?php _e( 'Show number of comments',TEXTDOMAIN ); ?>
1079
- </label>
1080
- </p>
1081
- <p>
1082
- <label for="<?php echo $this->get_field_id("author"); ?>">
1083
- <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 ); ?> />
1084
- <?php _e( 'Show post author',TEXTDOMAIN ); ?>
1085
- </label>
1086
- </p>
1087
- </div>
1088
- <h4 data-panel="general"><?php _e('General',TEXTDOMAIN)?></h4>
1089
- <div>
1090
- <p>
1091
- <label for="<?php echo $this->get_field_id("disable_css"); ?>">
1092
- <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 ); ?> />
1093
- <?php _e( 'Disable the built-in CSS for this widget',TEXTDOMAIN ); ?>
1094
- </label>
1095
- </p>
1096
- <p>
1097
- <label for="<?php echo $this->get_field_id("hide_if_empty"); ?>">
1098
- <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 ); ?> />
1099
- <?php _e( 'Hide widget if there are no matching posts',TEXTDOMAIN ); ?>
1100
- </label>
1101
- </p>
1102
- </div>
1103
- <h4 data-panel="footer"><?php _e('Footer',TEXTDOMAIN)?></h4>
1104
- <div>
1105
- <p>
1106
- <label for="<?php echo $this->get_field_id("footer_link"); ?>">
1107
- <?php _e( 'Footer link text',TEXTDOMAIN ); ?>:
1108
- <input class="widefat" style="width:60%;" placeholder="<?php _e('... more by this topic',TEXTDOMAIN)?>" 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"]); ?>" />
1109
- </label>
1110
- </p>
1111
- </div>
1112
- <p style="text-align:right;">
1113
- Follow us on <a target="_blank" href="https://www.facebook.com/TipTopPress">Facebook</a> and
1114
- <a target="_blank" href="https://twitter.com/TipTopPress">Twitter</a></br></br>
1115
- </p>
1116
- </div>
1117
- <?php
1118
- }
1119
- }
1120
-
1121
- function register_widget() {
1122
- return \register_widget(__NAMESPACE__.'\Widget');
1123
- }
1124
-
1125
- add_action( 'widgets_init', __NAMESPACE__.'\register_widget' );
1126
-
1127
- // shortcode section
1128
-
1129
- /**
1130
- * Get shortcode settings taking into account if it is being customized
1131
- *
1132
- * When not customized returns the settings as stored in the meta, but when
1133
- * it is customized returns the setting stored in the virtual option used by the customizer
1134
- *
1135
- * @return array the shortcode settings if a short code exists or empty string
1136
- *
1137
- * @since 4.6
1138
- */
1139
- function shortcode_settings() {
1140
- $instance = get_post_meta(get_the_ID(),SHORTCODE_META,true);
1141
-
1142
- if (is_array($instance)) {
1143
- if (is_customize_preview()) {
1144
- $o=get_option('_virtual-'.WIDGET_BASE_ID);
1145
- if (is_array($o))
1146
- $instance=$o[get_the_ID()];
1147
- }
1148
- }
1149
-
1150
- return $instance;
1151
- }
1152
- /**
1153
- * Handle the shortcode
1154
- *
1155
- * @param array $attr Array of the attributes to the short code, none is expected
1156
- * @param string $content The content enclosed in the shortcode, none is expected
1157
- *
1158
- * @return string An HTML of the "widget" based on its settings, actual or customized
1159
- *
1160
- */
1161
- function shortcode($attr,$content=null) {
1162
- if (is_singular()) {
1163
- $instance = shortcode_settings();
1164
-
1165
- if (is_array($instance)) {
1166
- $widget=new Widget();
1167
- $widget->number = 'shortcode-'.get_the_ID(); // needed to make a unique id for the widget html element
1168
- ob_start();
1169
- $widget->widget(array(
1170
- 'before_widget' => '',
1171
- 'after_widget' => '',
1172
- 'before_title' => '',
1173
- 'after_title' => ''
1174
- ), $instance);
1175
- return ob_get_clean();
1176
- }
1177
- }
1178
-
1179
- return '';
1180
- }
1181
-
1182
- add_shortcode(SHORTCODE_NAME,__NAMESPACE__.'\shortcode');
1183
-
1184
- /**
1185
- * Find if a specific shortcode is used in a content
1186
- *
1187
- * @param string $shortcode_name The name of the shortcode
1188
- * #param string The content to look at
1189
- * @return boolean True if used, otherwise false
1190
- *
1191
- */
1192
- function shortcode_exist($shortcode_name,$content) {
1193
-
1194
- $regex_pattern = get_shortcode_regex();
1195
- if (preg_match_all ('/'.$regex_pattern.'/s', $content, $matches)) {
1196
- foreach ($matches[2] as $k=>$shortcode) {
1197
- if ($shortcode == SHORTCODE_NAME) {
1198
- return true;
1199
- }
1200
- }
1201
- }
1202
-
1203
- return false;
1204
- }
1205
-
1206
- /**
1207
- * Manipulate the relevant meta related to the short code when a post is save
1208
- *
1209
- * If A post has a short code, a meta holder is created, If it does not the meta holder is deleted
1210
- *
1211
- * @param integer $pid The post ID of the post being saved
1212
- * @param WP_Post $post The post being saved
1213
- * @return void
1214
- *
1215
- * @since 4.6
1216
- */
1217
- function save_post($pid,$post) {
1218
-
1219
- // ignore revisions and auto saves
1220
- if ( wp_is_post_revision( $pid ) || wp_is_post_autosave($pid))
1221
- return;
1222
-
1223
- $has_meta = get_post_meta($pid,SHORTCODE_META,true);
1224
- $exist = shortcode_exist(SHORTCODE_NAME,$post->post_content);
1225
-
1226
- if (!$exist)
1227
- delete_post_meta($pid,SHORTCODE_META);
1228
- else if (!is_array($has_meta)) // get_post_meta have strang return vaules when do not exist so just check it is expected structure
1229
- add_post_meta($pid,SHORTCODE_META,array(
1230
- 'title' => '',
1231
- 'title_link' => false,
1232
- 'hide_title' => false,
1233
- 'cat' => '',
1234
- 'num' => get_option('posts_per_page'),
1235
- 'sort_by' => 'date',
1236
- 'asc_sort_order' => false,
1237
- 'exclude_current_post' => false,
1238
- 'hideNoThumb' => false,
1239
- 'footer_link' => '',
1240
- 'thumb' => false,
1241
- 'thumbTop' => false,
1242
- 'thumb_w' => '',
1243
- 'thumb_h' => '',
1244
- 'use_css_cropping' => false,
1245
- 'thumb_hover' => 'none',
1246
- 'hide_post_titles' => false,
1247
- 'excerpt' => false,
1248
- 'excerpt_length' => 55,
1249
- 'excerpt_more_text' => '',
1250
- 'comment_num' => false,
1251
- 'author' => false,
1252
- 'date' => false,
1253
- 'date_link' => false,
1254
- 'date_format' => '',
1255
- 'disable_css' => false,
1256
- 'hide_if_empty' => false
1257
- ),
1258
- true);
1259
- }
1260
-
1261
- add_action('save_post',__NAMESPACE__.'\save_post',10,2);
1262
-
1263
- function customize_register($wp_customize) {
1264
-
1265
- class shortCodeControl extends \WP_Customize_Control {
1266
- public $form;
1267
-
1268
- public function render_content() {
1269
- $widget_title = 'Category Posts Shortcode';
1270
- ?>
1271
- <div class="widget-top">
1272
- <div class="widget-title"><h3><?php echo $widget_title; ?><span class="in-widget-title"></span></h3></div>
1273
- </div>
1274
- <div class="widget-inside" style="display: block;">
1275
- <div class="form">
1276
- <div class="widget-content">
1277
- <?php echo $this->form; ?>
1278
- </div>
1279
- </div>
1280
- </div>
1281
- <?php
1282
- }
1283
- }
1284
-
1285
- $args = array(
1286
- 'post_type' => 'any',
1287
- 'post_status' => 'any',
1288
- 'update_post_term_cache' => false,
1289
- 'meta_query' => array(
1290
- array(
1291
- 'key' => SHORTCODE_META,
1292
- 'compare' => 'EXISTS'
1293
- )
1294
- ),
1295
-
1296
- );
1297
- $posts = get_posts($args);
1298
-
1299
- if (count($posts) > 0) {
1300
- $wp_customize->add_section( __NAMESPACE__, array(
1301
- 'title' => __( 'Category Posts Shortcode', TEXTDOMAIN ),
1302
- 'priority' => 200
1303
- ) );
1304
-
1305
- foreach($posts as $p) {
1306
- $widget = new Widget();
1307
- $widget->number = $p->ID;
1308
- $meta = get_post_meta($p->ID,SHORTCODE_META,true);
1309
- if (!is_array($meta))
1310
- continue;
1311
-
1312
- ob_start();
1313
- $widget->form(array());
1314
- $form = ob_get_clean();
1315
- $form = preg_replace_callback('/<(input|select)\s+.*name=("|\').*\[\d*\]\[([^\]]*)\][^>]*>/',
1316
- function ($matches) use ($p, $wp_customize, $meta) {
1317
- $setting = '_virtual-'.WIDGET_BASE_ID.'['.$p->ID.']['.$matches[3].']';
1318
- if (!isset($meta[$matches[3]]))
1319
- $meta[$matches[3]] = null;
1320
- $wp_customize->add_setting( $setting, array(
1321
- 'default' => $meta[$matches[3]], // set default to current value
1322
- 'type' => 'option'
1323
- ) );
1324
-
1325
- return str_replace('<'.$matches[1],'<'.$matches[1].' data-customize-setting-link="'.$setting.'"',$matches[0]);
1326
- },
1327
- $form
1328
- );
1329
-
1330
- $wp_customize->add_control( new shortCodeControl(
1331
- $wp_customize,
1332
- '_virtual-'.WIDGET_BASE_ID.'['.$p->ID.'][title]',
1333
- array(
1334
- 'label' => __( 'Layout', 'twentyfourteen' ),
1335
- 'section' => __NAMESPACE__,
1336
- 'form' => $form,
1337
- 'settings' => '_virtual-'.WIDGET_BASE_ID.'['.$p->ID.'][title]',
1338
- 'active_callback' => function () use ($p) { return is_singular() && (get_the_ID()==$p->ID); }
1339
- )
1340
- ) );
1341
- }
1342
- }
1343
- }
1344
-
1345
- add_action( 'customize_register', __NAMESPACE__.'\customize_register' );
1346
-
1347
- /**
1348
- * Save the virtual option used by the customizer into the proper meta values.
1349
- *
1350
- * The customizer actually saves only the changed values, so a merge needs to be done.
1351
- * After everything is updated the virtual option is deleted to leave a clean slate
1352
- *
1353
- * @return void
1354
- *
1355
- * @since 4.6
1356
- */
1357
- function customize_save_after() {
1358
- $virtual = get_option('_virtual-'.WIDGET_BASE_ID);
1359
-
1360
- if (is_array($virtual)) {
1361
- foreach ($virtual as $pid => $instance) {
1362
- $meta = get_post_meta($pid,SHORTCODE_META,true);
1363
- $instance = array_merge($meta,$instance);
1364
- update_post_meta($pid,SHORTCODE_META, $instance);
1365
- }
1366
- }
1367
-
1368
- delete_option('_virtual-'.WIDGET_BASE_ID);
1369
- }
1370
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1371
  add_action('customize_save_after', __NAMESPACE__.'\customize_save_after', 100);
1
+ <?php
2
+ /*
3
+ Plugin Name: Category Posts Widget
4
+ Plugin URI: http://mkrdip.me/category-posts-widget
5
+ Description: Adds a widget that shows the most recent posts from a single category.
6
+ Author: Mrinal Kanti Roy
7
+ Version: 4.6.2
8
+ Author URI: http://mkrdip.me
9
+ Text Domain: category-posts
10
+ Domain Path: /languages
11
+ */
12
+
13
+ namespace categoryPosts;
14
+
15
+ // Don't call the file directly
16
+ if ( !defined( 'ABSPATH' ) ) exit;
17
+
18
+ define( 'CAT_POST_PLUGINURL', plugins_url(basename( dirname(__FILE__))) . "/");
19
+ define( 'CAT_POST_PLUGINPATH', dirname(__FILE__) . "/");
20
+ define( 'CAT_POST_VERSION', "4.6.1");
21
+
22
+ const SHORTCODE_NAME = 'catposts';
23
+ const SHORTCODE_META = 'categoryPosts-shorcode';
24
+ const WIDGET_BASE_ID = 'category-posts';
25
+
26
+ /*
27
+ * Iterate over all the widgets active at the page and call the callback for them
28
+ *
29
+ * callback - accepts the widget settings, return true to continue iteration or false to stop
30
+ */
31
+ function iterator($id_base,$class,$callback) {
32
+ global $wp_registered_widgets;
33
+ $sidebars_widgets = wp_get_sidebars_widgets();
34
+
35
+ if ( is_array($sidebars_widgets) ) {
36
+ foreach ( $sidebars_widgets as $sidebar => $widgets ) {
37
+ if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) {
38
+ continue;
39
+ }
40
+
41
+ if ( is_array($widgets) ) {
42
+ foreach ( $widgets as $widget ) {
43
+ $widget_base = _get_widget_id_base($widget);
44
+ if ( $widget_base == $id_base ) {
45
+ $widgetclass = new $class();
46
+ $allsettings = $widgetclass->get_settings();
47
+ $settings = isset($allsettings[str_replace($widget_base.'-','',$widget)]) ? $allsettings[str_replace($widget_base.'-','',$widget)] : false;
48
+ if (!$callback($settings))
49
+ return;
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
56
+
57
+ /*
58
+ Check if CSS needs to be added to support cropping by traversing all active widgets on the page
59
+ and checking if any has cropping enabled.
60
+
61
+ Return: false if cropping is not active, false otherwise
62
+ */
63
+ function cropping_active($id_base,$class) {
64
+ $ret = false;
65
+
66
+ iterator($id_base, $class, function ($settings) use (&$ret) {
67
+ if (isset($settings['use_css_cropping'])) { // checks if cropping is active
68
+ $ret = true;
69
+ return false; // stop iterator
70
+ } else
71
+ return true; // continue iteration to next widget
72
+ });
73
+
74
+ return $ret;
75
+ }
76
+
77
+ /*
78
+ Check if CSS needs to be enqueued by traversing all active widgets on the page
79
+ and checking if they all have disabled CSS.
80
+
81
+ Return: false if CSS should not be enqueued, true if it should
82
+ */
83
+ function should_enqueue($id_base,$class) {
84
+ $ret = false;
85
+
86
+ iterator($id_base, $class, function ($settings) use (&$ret) {
87
+ if (!(isset($settings['disable_css']) && $settings['disable_css'])) { // checks if css disable is not set
88
+ $ret = true;
89
+ return false; // stop iterator
90
+ } else
91
+ return true; // continue iteration to next widget
92
+ });
93
+
94
+ return $ret;
95
+ }
96
+
97
+ /***
98
+ * Adds the "Customize" link to the Toolbar on edit mode.
99
+ *
100
+ */
101
+ function wp_admin_bar_customize_menu() {
102
+ global $wp_admin_bar;
103
+
104
+ if ( ! isset($_GET['action']) || $_GET['action'] !== 'edit' )
105
+ return;
106
+
107
+ if ( !current_user_can( 'customize' ) || !is_admin() || !is_user_logged_in() || !is_admin_bar_showing() )
108
+ return;
109
+
110
+ $current_url = "";
111
+ if ( isset($_GET['post']) || $_GET['post'] !== '' )
112
+ $current_url = get_permalink( $_GET['post'] );
113
+ $customize_url = add_query_arg( 'url', urlencode( $current_url ), wp_customize_url() );
114
+
115
+ $wp_admin_bar->add_menu( array(
116
+ 'id' => 'customize',
117
+ 'title' => __( 'Customize' ),
118
+ 'href' => $customize_url,
119
+ 'meta' => array(
120
+ 'class' => 'hide-if-no-customize',
121
+ ),
122
+ ) );
123
+ add_action( 'wp_before_admin_bar_render', 'wp_customize_support_script' );
124
+ }
125
+ add_action('admin_bar_menu',__NAMESPACE__.'\wp_admin_bar_customize_menu', 35);
126
+
127
+ /**
128
+ * Register our styles
129
+ *
130
+ * @return void
131
+ */
132
+ add_action( 'wp_enqueue_scripts', __NAMESPACE__.'\widget_styles' );
133
+
134
+ function wp_head() {
135
+ if (cropping_active(WIDGET_BASE_ID,__NAMESPACE__.'\Widget')) {
136
+ ?>
137
+ <style type="text/css">
138
+ .cat-post-item .cat-post-css-cropping span {
139
+ overflow: hidden;
140
+ display:inline-block;
141
+ }
142
+ </style>
143
+ <?php
144
+ }
145
+ }
146
+
147
+ add_action('wp_head',__NAMESPACE__.'\wp_head');
148
+
149
+ function widget_styles() {
150
+
151
+ $enqueue = false;
152
+ // check first for shortcode settings
153
+ if (is_singular()) {
154
+ $meta = shortcode_settings();
155
+ if (is_array($meta) && !(isset($meta['disable_css']) && $meta['disable_css']))
156
+ $enqueue = true;
157
+ }
158
+
159
+ if (!$enqueue)
160
+ $enqueue = should_enqueue(WIDGET_BASE_ID,__NAMESPACE__.'\Widget');
161
+
162
+ if ($enqueue) {
163
+ wp_register_style( 'category-posts', CAT_POST_PLUGINURL . 'cat-posts.css',array(),CAT_POST_VERSION );
164
+ wp_enqueue_style( 'category-posts' );
165
+ }
166
+ }
167
+
168
+ /*
169
+ Enqueue widget related scripts for the widget admin page and customizer
170
+ */
171
+ function admin_scripts($hook) {
172
+
173
+ if ($hook == 'widgets.php') { // 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', CAT_POST_PLUGINURL.'/js/admin/category-posts-widget.js',array('jquery'),CAT_POST_VERSION,true );
177
+ wp_enqueue_script( 'category-posts-widget-admin-js' );
178
+ }
179
+ }
180
+
181
+ add_action('admin_enqueue_scripts', __NAMESPACE__.'\admin_scripts'); // "called on widgets.php and costumizer since 3.9
182
+
183
+
184
+ /**
185
+ * Load plugin textdomain.
186
+ *
187
+ */
188
+ add_action( 'admin_init', __NAMESPACE__.'\load_textdomain' );
189
+
190
+ function load_textdomain() {
191
+ load_plugin_textdomain( 'category-posts', false, plugin_basename( dirname( __FILE__ ) ) . '/languages' );
192
+ }
193
+
194
+ /**
195
+ * Add styles for widget sections
196
+ *
197
+ */
198
+ add_action( 'admin_print_styles-widgets.php', __NAMESPACE__.'\admin_styles' );
199
+
200
+ function admin_styles() {
201
+ ?>
202
+ <style>
203
+ .category-widget-cont h4 {
204
+ padding: 12px 15px;
205
+ cursor: pointer;
206
+ margin: 5px 0;
207
+ border: 1px solid #E5E5E5;
208
+ }
209
+ .category-widget-cont h4:first-child {
210
+ margin-top: 10px;
211
+ }
212
+ .category-widget-cont h4:last-of-type {
213
+ margin-bottom: 10px;
214
+ }
215
+ .category-widget-cont h4:after {
216
+ float:right;
217
+ font-family: "dashicons";
218
+ content: '\f140';
219
+ -ms-transform: translate(-1px,1px);
220
+ -webkit-transform: translate(-1px,1px);
221
+ -moz-transform: translate(-1px,1px);
222
+ transform: translate(-1px,1px);
223
+ -ms-transition: all 600ms;
224
+ -webkit-transition: all 600ms;
225
+ -moz-transition: all 600ms;
226
+ transition: all 600ms;
227
+ }
228
+ .category-widget-cont h4.open:after {
229
+ -ms-transition: all 600ms;
230
+ -webkit-transition: all 600ms;
231
+ -moz-transition: all 600ms;
232
+ transition: all 600ms;
233
+ -ms-transform: rotate(180deg);
234
+ -webkit-transform: rotate(180deg);
235
+ -moz-transform: rotate(180deg);
236
+ transform: rotate(180deg);
237
+ }
238
+ .category-widget-cont > div {
239
+ display:none;
240
+ overflow: hidden;
241
+ }
242
+ .category-widget-cont > div.open {
243
+ display:block;
244
+ }
245
+ </style>
246
+ <?php
247
+ }
248
+
249
+ /**
250
+ * Get image size
251
+ *
252
+ * $thumb_w, $thumb_h - the width and height of the thumbnail in the widget settings
253
+ * $image_w,$image_h - the width and height of the actual image being displayed
254
+ *
255
+ * return: an array with the width and height of the element containing the image
256
+ */
257
+ function get_image_size( $thumb_w,$thumb_h,$image_w,$image_h) {
258
+
259
+ $image_size = array('image_h' => $thumb_h, 'image_w' => $thumb_w, 'marginAttr' => '', 'marginVal' => '');
260
+ $relation_thumbnail = $thumb_w / $thumb_h;
261
+ $relation_cropped = $image_w / $image_h;
262
+
263
+ if ($relation_thumbnail < $relation_cropped) {
264
+ // crop left and right site
265
+ // thumbnail width/height ration is smaller, need to inflate the height of the image to thumb height
266
+ // and adjust width to keep aspect ration of image
267
+ $image_size['image_h'] = $thumb_h;
268
+ $image_size['image_w'] = $thumb_h / $image_h * $image_w;
269
+ $image_size['marginAttr'] = 'margin-left';
270
+ $image_size['marginVal'] = ($image_size['image_w'] - $thumb_w) / 2;
271
+ } else {
272
+ // crop top and bottom
273
+ // thumbnail width/height ration is bigger, need to inflate the width of the image to thumb width
274
+ // and adjust height to keep aspect ration of image
275
+ $image_size['image_w'] = $thumb_w;
276
+ $image_size['image_h'] = $thumb_w / $image_w * $image_h;
277
+ $image_size['marginAttr'] = 'margin-top';
278
+ $image_size['marginVal'] = ($image_size['image_h'] - $thumb_h) / 2;
279
+ }
280
+
281
+ return $image_size;
282
+ }
283
+
284
+ /**
285
+ * Category Posts Widget Class
286
+ *
287
+ * Shows the single category posts with some configurable options
288
+ */
289
+ class Widget extends \WP_Widget {
290
+
291
+ function __construct() {
292
+ $widget_ops = array('classname' => 'cat-post-widget', 'description' => __('List single category posts','category-posts'));
293
+ parent::__construct(WIDGET_BASE_ID, __('Category Posts','category-posts'), $widget_ops);
294
+ }
295
+
296
+ /**
297
+ * Calculate the HTML for showing the thumb of a post item.
298
+ *
299
+ * Used as a filter for the thumb wordpress API to add css based stretching and cropping
300
+ * when the image is not at the requested dimensions
301
+ *
302
+ * @param string $html The original HTML generated by the core APIS
303
+ * @param int $post_id the ID of the post of which the thumb is a featured image
304
+ * @param int $post_thumbnail_id The id of the featured image attachment
305
+ * @param string|array $size The requested size identified by name or (width, height) array
306
+ * @param mixed $attr ignored in this context
307
+ * @return string The HTML for the thumb related to the post
308
+ *
309
+ * @since 4.1
310
+ */
311
+ function post_thumbnail_html($html, $post_id, $post_thumbnail_id, $size, $attr){
312
+ if ( empty($this->instance['thumb_w']) || empty($this->instance['thumb_h']))
313
+ return $html; // bail out if no full dimensions defined
314
+
315
+ $meta = image_get_intermediate_size($post_thumbnail_id,$size);
316
+
317
+ if ( empty( $meta )) {
318
+ $post_img = wp_get_attachment_metadata($post_thumbnail_id, $size);
319
+ $meta['file'] = basename( $post_img['file'] );
320
+ }
321
+
322
+ $origfile = get_attached_file( $post_thumbnail_id, true); // the location of the full file
323
+ $file = dirname($origfile) .'/'.$meta['file']; // the location of the file displayed as thumb
324
+ list( $width, $height ) = getimagesize($file); // get actual size of the thumb file
325
+
326
+ if ($width / $height == $this->instance['thumb_w'] / $this->instance['thumb_h']) {
327
+ // image is same ratio as asked for, nothing to do here as the browser will handle it correctly
328
+ ;
329
+ } else if (isset($this->instance['use_css_cropping']) && $this->instance['use_css_cropping']) {
330
+ $image = get_image_size($this->instance['thumb_w'],$this->instance['thumb_h'],$width,$height);
331
+
332
+ // replace srcset
333
+ $array = array();
334
+ preg_match( '/width="([^"]*)"/i', $html, $array ) ;
335
+ $pattern = "/".$array[1]."w/";
336
+ $html = preg_replace($pattern, $image['image_w']."w", $html);
337
+ // replace size
338
+ $pattern = "/".$array[1]."px/";
339
+ $html = preg_replace($pattern, $image['image_w']."px", $html);
340
+ // replace width
341
+ $pattern = "/width=\"[0-9]*\"/";
342
+ $html = preg_replace($pattern, "width='".$image['image_w']."'", $html);
343
+ // replace height
344
+ $pattern = "/height=\"[0-9]*\"/";
345
+ $html = preg_replace($pattern, "height='".$image['image_h']."'", $html);
346
+ // set margin
347
+ $html = str_replace('<img ','<img style="'.$image['marginAttr'].':-'.$image['marginVal'].'px;height:'.$image['image_h']
348
+ .'px;clip:rect(auto,'.($this->instance['thumb_w']+$image['marginVal']).'px,auto,'.$image['marginVal']
349
+ .'px);width:auto;max-width:initial;" ',$html);
350
+ // wrap span
351
+ $html = '<span style="width:'.$this->instance['thumb_w'].'px;height:'.$this->instance['thumb_h'].'px;">'
352
+ .$html.'</span>';
353
+ } else {
354
+ // if use_css_cropping not used
355
+ // no interface changes: leave without change
356
+ }
357
+ return $html;
358
+ }
359
+
360
+ /*
361
+ wrapper to execute the the_post_thumbnail with filters
362
+ */
363
+ /**
364
+ * Calculate the HTML for showing the thumb of a post item.
365
+ *
366
+ * It is a wrapper to execute the the_post_thumbnail with filters
367
+ *
368
+ * @param string|array $size The requested size identified by name or (width, height) array
369
+ *
370
+ * @return string The HTML for the thumb related to the post and empty string if it can not be calculated
371
+ *
372
+ * @since 4.1
373
+ */
374
+ function the_post_thumbnail($size= 'post-thumbnail') {
375
+ if (empty($size)) // if junk value, make it a normal thumb
376
+ $size= 'post-thumbnail';
377
+ else if (is_array($size) && (count($size)==2)) { // good format at least
378
+ // normalize to ints first
379
+ $size[0] = (int) $size[0];
380
+ $size[1] = (int) $size[1];
381
+ if (($size[0] == 0) && ($size[1] == 0)) //both values zero then revert to thumbnail
382
+ $size= 'post-thumbnail';
383
+ // if one value is zero make a square using the other value
384
+ else if (($size[0] == 0) && ($size[1] != 0))
385
+ $size[0] = $size[1];
386
+ else if (($size[0] != 0) && ($size[1] == 0))
387
+ $size[1] = $size[0];
388
+ } else $size= 'post-thumbnail'; // yet another form of junk
389
+
390
+ add_filter('post_thumbnail_html',array($this,'post_thumbnail_html'),1,5);
391
+ $ret = get_the_post_thumbnail( null,$size,'');
392
+ remove_filter('post_thumbnail_html',array($this,'post_thumbnail_html'),1,5);
393
+ return $ret;
394
+ }
395
+
396
+ /**
397
+ * Excerpt more link filter
398
+ */
399
+ function excerpt_more_filter($more) {
400
+ return ' <a class="cat-post-excerpt-more" href="'. get_permalink() . '">' . esc_html($this->instance["excerpt_more_text"]) . '</a>';
401
+ }
402
+
403
+ /**
404
+ * Apply the_content filter for excerpt
405
+ * This should show sharing buttons which comes with other widgets in the widget output in the same way as on the main content
406
+ *
407
+ * @param string The HTML with other applied excerpt filters
408
+ *
409
+ * @return string If option hide_social_buttons is unchecked applay the_content filter
410
+ *
411
+ * @since 4.6
412
+ */
413
+ function apply_the_excerpt($text) {
414
+ $ret = "";
415
+ if (isset($this->instance["hide_social_buttons"]) && $this->instance["hide_social_buttons"])
416
+ $ret = $text;
417
+ else
418
+ $ret = apply_filters('the_content', $text);
419
+ return $ret;
420
+ }
421
+
422
+ /**
423
+ * Excerpt allow HTML
424
+ */
425
+ function allow_html_excerpt($text) {
426
+ global $post, $wp_filter;
427
+ $new_excerpt_length = ( isset($this->instance["excerpt_length"]) && $this->instance["excerpt_length"] > 0 ) ? $this->instance["excerpt_length"] : 55;
428
+ if ( '' == $text ) {
429
+ $text = get_the_content('');
430
+ $text = strip_shortcodes( $text );
431
+ $text = apply_filters('the_content', $text);
432
+ $text = str_replace('\]\]\>', ']]&gt;', $text);
433
+ $text = preg_replace('@<script[^>]*?>.*?</script>@si', '', $text);
434
+ $cphtml = array(
435
+ '&lt;a&gt;',
436
+ '&lt;br&gt;',
437
+ '&lt;em&gt;',
438
+ '&lt;i&gt;',
439
+ '&lt;ul&gt;',
440
+ '&lt;ol&gt;',
441
+ '&lt;li&gt;',
442
+ '&lt;p&gt;',
443
+ '&lt;img&gt;',
444
+ '&lt;script&gt;',
445
+ '&lt;style&gt;',
446
+ '&lt;video&gt;',
447
+ '&lt;audio&gt;'
448
+ );
449
+ $allowed_HTML = "";
450
+ foreach ($cphtml as $index => $name) {
451
+ if (in_array((string)($index),$this->instance['excerpt_allowed_elements'],true))
452
+ $allowed_HTML .= $cphtml[$index];
453
+ }
454
+ $text = strip_tags($text, htmlspecialchars_decode($allowed_HTML));
455
+ $excerpt_length = $new_excerpt_length;
456
+
457
+ if( !empty($this->instance["excerpt_more_text"]) ) {
458
+ $excerpt_more = $this->excerpt_more_filter($this->instance["excerpt_more_text"]);
459
+ }else if($filterName = key($wp_filter['excerpt_more'][10])) {
460
+ $excerpt_more = $wp_filter['excerpt_more'][10][$filterName]['function'](0);
461
+ }else {
462
+ $excerpt_more = '[...]';
463
+ }
464
+
465
+ $words = explode(' ', $text, $excerpt_length + 1);
466
+ if (count($words)> $excerpt_length) {
467
+ array_pop($words);
468
+ array_push($words, $excerpt_more);
469
+ $text = implode(' ', $words);
470
+ }
471
+ }
472
+
473
+ return '<p>' . $text . '</p>';
474
+ }
475
+
476
+ /**
477
+ * Calculate the HTML for showing the thumb of a post item.
478
+ * Expected to be called from a loop with globals properly set
479
+ *
480
+ * @param array $instance Array which contains the various settings
481
+ * @return string The HTML for the thumb related to the post
482
+ *
483
+ * @since 4.6
484
+ */
485
+ function show_thumb($instance) {
486
+ $ret = '';
487
+
488
+ if ( isset( $instance["thumb"] ) && $instance["thumb"] &&
489
+ has_post_thumbnail() ) {
490
+ $use_css_cropping = (isset($this->instance['use_css_cropping'])&&$this->instance['use_css_cropping']) ? "cat-post-css-cropping" : "";
491
+ $class = '';
492
+ if( !(isset( $this->instance['disable_css'] ) && $this->instance['disable_css'])) {
493
+ if( isset($this->instance['thumb_hover'] )) {
494
+ $class = "class=\"cat-post-thumbnail " . $use_css_cropping ." cat-post-" . $instance['thumb_hover'] . "\"";
495
+ } else {
496
+ $class = "class=\"cat-post-thumbnail " . $use_css_cropping . "\"";
497
+ }
498
+ }
499
+ $title_args = array('echo'=>false);
500
+ $ret .= '<a '.$class . ' href="'.get_the_permalink().'" title="'.the_title_attribute($title_args).'">';
501
+ $ret .= $this->the_post_thumbnail( array($this->instance['thumb_w'],$this->instance['thumb_h']));
502
+ $ret .= '</a>';
503
+ }
504
+
505
+ return $ret;
506
+ }
507
+
508
+ /**
509
+ * Calculate the wp-query arguments matching the filter settings of the widget
510
+ *
511
+ * @param array $instance Array which contains the various settings
512
+ * @return array The array that can be fed to wp_Query to get the relevant posts
513
+ *
514
+ * @since 4.6
515
+ */
516
+ function queryArgs($instance) {
517
+ $valid_sort_orders = array('date', 'title', 'comment_count', 'rand');
518
+ if ( isset($instance['sort_by']) && in_array($instance['sort_by'],$valid_sort_orders) ) {
519
+ $sort_by = $instance['sort_by'];
520
+ } else {
521
+ $sort_by = 'date';
522
+ }
523
+ $sort_order = (isset( $instance['asc_sort_order'] ) && $instance['asc_sort_order']) ? 'ASC' : 'DESC';
524
+
525
+ // Get array of post info.
526
+ $args = array(
527
+ 'orderby' => $sort_by,
528
+ 'order' => $sort_order
529
+ );
530
+
531
+ if (isset($instance["num"]))
532
+ $args['showposts'] = (int) $instance["num"];
533
+
534
+ if (isset($instance["cat"]))
535
+ $args['cat'] = (int) $instance["cat"];
536
+
537
+ if (is_singular() && isset( $instance['exclude_current_post'] ) && $instance['exclude_current_post'])
538
+ $args['post__not_in'] = array(get_the_ID());
539
+
540
+ if( isset( $instance['hideNoThumb'] ) && $instance['hideNoThumb']) {
541
+ $args = array_merge( $args, array( 'meta_query' => array(
542
+ array(
543
+ 'key' => '_thumbnail_id',
544
+ 'compare' => 'EXISTS' )
545
+ )
546
+ )
547
+ );
548
+ }
549
+
550
+ return $args;
551
+ }
552
+
553
+ /**
554
+ * Calculate the HTML of the title based on the widget settings
555
+ *
556
+ * @param string $before_title The sidebar configured HTML that should come
557
+ * before the title itself
558
+ * @param string $after_title The sidebar configured HTML that should come
559
+ * after the title itself
560
+ * @param array $instance Array which contains the various settings
561
+ * @return string The HTML for the title area
562
+ *
563
+ * @since 4.6
564
+ */
565
+ function titleHTML($before_title,$after_title,$instance) {
566
+ $ret = '';
567
+
568
+ // If not title, use the name of the category.
569
+ if( !isset($instance["title"]) || !$instance["title"] ) {
570
+ $instance["title"] = '';
571
+ if (isset($instance["cat"])) {
572
+ $category_info = get_category($instance["cat"]);
573
+ if ($category_info && !is_wp_error($category_info))
574
+ $instance["title"] = $category_info->name;
575
+ }
576
+ }
577
+
578
+ if( !(isset ( $instance["hide_title"] ) && $instance["hide_title"])) {
579
+ $ret = $before_title;
580
+ if( isset ( $instance["title_link"]) && $instance["title_link"] && isset($instance["cat"]) && (get_category($instance["cat"]) != null)) {
581
+ $ret .= '<a href="' . get_category_link($instance["cat"]) . '">' . esc_html(apply_filters( 'widget_title', $instance["title"] )) . '</a>';
582
+ } else {
583
+ $ret .= esc_html(apply_filters( 'widget_title', $instance["title"] ));
584
+ }
585
+ $ret .= $after_title;
586
+ }
587
+
588
+ return $ret;
589
+ }
590
+
591
+ /**
592
+ * Calculate the HTML of the footer based on the widget settings
593
+ *
594
+ * @param array $instance Array which contains the various settings
595
+ * @return string The HTML for the footer area
596
+ *
597
+ * @since 4.6
598
+ */
599
+ function footerHTML($instance) {
600
+ $ret = '';
601
+
602
+ if( isset ( $instance["footer_link"] ) && $instance["footer_link"] && isset($instance["cat"]) && (get_category($instance["cat"]) != null) ) {
603
+ $ret = "<a";
604
+ if( !(isset( $instance['disable_css'] ) && $instance['disable_css'])) { $ret.= " class=\"cat-post-footer-link\""; }
605
+ $ret .= " href=\"" . get_category_link($instance["cat"]) . "\">" . esc_html($instance["footer_link"]) . "</a>";
606
+ }
607
+
608
+ return $ret;
609
+ }
610
+
611
+ /**
612
+ * Calculate the HTML for a post item based on the widget settings and post.
613
+ * Expected to be called in an active loop with all the globals set
614
+ *
615
+ * @param array $instance Array which contains the various settings
616
+ * $param null|integer $current_post_id If on singular page specifies the id of
617
+ * the post, otherwise null
618
+ * @return string The HTML for item related to the post
619
+ *
620
+ * @since 4.6
621
+ */
622
+ function itemHTML($instance,$current_post_id) {
623
+ global $post;
624
+
625
+ $ret = '<li ';
626
+
627
+ if ( $current_post_id == $post->ID ) {
628
+ $ret .= "class='cat-post-item cat-post-current'";
629
+ } else {
630
+ $ret .= "class='cat-post-item'";
631
+ }
632
+ $ret.='>'; // close the li opening tag
633
+
634
+ // Thumbnail position to top
635
+ if( isset( $instance["thumbTop"] ) && $instance["thumbTop"]) {
636
+ $ret .= $this->show_thumb($instance);
637
+ }
638
+
639
+ if( !(isset( $instance['hide_post_titles'] ) && $instance['hide_post_titles'])) {
640
+ $ret .= '<a class="post-title';
641
+ if( !isset( $instance['disable_css'] ) ) {
642
+ $ret .= " cat-post-title";
643
+ }
644
+ $ret .= '" href="'.get_the_permalink().'" rel="bookmark">'.get_the_title();
645
+ $ret .= '</a> ';
646
+ }
647
+
648
+ if ( isset( $instance['date']) && $instance['date']) {
649
+ if ( isset( $instance['date_format'] ) && strlen( trim( $instance['date_format'] ) ) > 0 ) {
650
+ $date_format = $instance['date_format'];
651
+ } else {
652
+ $date_format = "j M Y";
653
+ }
654
+ $ret .= '<p class="post-date ';
655
+ if( !isset( $instance['disable_css'] ) ) {
656
+ $ret .= "cat-post-date";
657
+ }
658
+ $ret .= '">';
659
+ if ( isset ( $instance["date_link"] ) && $instance["date_link"]) {
660
+ $ret .= '<a href="'.\get_the_permalink().'">';
661
+ }
662
+ $ret .= get_the_time($date_format);
663
+ if ( isset ( $instance["date_link"] ) ) {
664
+ $ret .= '</a>';
665
+ }
666
+ $ret .= '</p>';
667
+ }
668
+
669
+ // Thumbnail position normal
670
+ if( !(isset( $instance["thumbTop"] ) && $instance["thumbTop"])) {
671
+ $ret .= $this->show_thumb($instance);
672
+ }
673
+
674
+ if ( isset( $instance['excerpt'] ) && $instance['excerpt']) {
675
+ // use the_excerpt filter to get the "normal" excerpt of the post
676
+ // then apply our filter to let users customize excerpts in their own way
677
+ if (isset($instance['excerpt_length']) && ($instance['excerpt_length'] > 0))
678
+ $length = (int) $instance['excerpt_length'];
679
+ else
680
+ $length = 0; // indicate that invalid length is set
681
+ $ret .= apply_filters('cpw_excerpt',apply_filters('the_excerpt',\get_the_excerpt()),$this,$length);
682
+ }
683
+
684
+ if ( isset( $instance['comment_num'] ) && $instance['comment_num']) {
685
+ $ret .= '<p class="comment-num';
686
+ if ( !isset( $instance['disable_css'] ) ) {
687
+ $ret .= " cat-post-comment-num";
688
+ }
689
+ $ret .= '">';
690
+ $ret .= '('.\get_comments_number().')';
691
+ $ret .= '</p>';
692
+ }
693
+
694
+ if ( isset( $instance['author'] ) && $instance['author']) {
695
+ $ret .= '<p class="post-author ';
696
+ if( !isset( $instance['disable_css'] ) ) {
697
+ $ret .= "cat-post-author";
698
+ }
699
+ $ret .= '">';
700
+ global $authordata;
701
+ $link = sprintf(
702
+ '<a href="%1$s" title="%2$s" rel="author">%3$s</a>',
703
+ esc_url( get_author_posts_url( $authordata->ID, $authordata->user_nicename ) ),
704
+ esc_attr( sprintf( __( 'Posts by %s' ), get_the_author() ) ),
705
+ get_the_author()
706
+ );
707
+ $ret .= $link;
708
+ $ret .= '</p>';
709
+ }
710
+
711
+ $ret .= '</li>';
712
+ return $ret;
713
+ }
714
+
715
+ /**
716
+ * Filter to set the number of words in an excerpt
717
+ *
718
+ * @param int $length The number of words as configured by wordpress core or set by previous filters
719
+ * @return int The number of words configured for the widget,
720
+ * or the $length parameter if it is not configured or garbage value
721
+ *
722
+ * @since 4.6
723
+ */
724
+ function excerpt_length_filter($length) {
725
+ if ( isset($this->instance["excerpt_length"]) && $this->instance["excerpt_length"] > 0 )
726
+ $length = $this->instance["excerpt_length"];
727
+
728
+ return $length;
729
+ }
730
+
731
+ /**
732
+ * Set the proper excerpt filters based on the settings
733
+ *
734
+ * @param array $instance widget settings
735
+ * @return void
736
+ *
737
+ * @since 4.6
738
+ */
739
+ function setExcerpFilters($instance) {
740
+
741
+ if (isset($instance['excerpt']) && $instance['excerpt']) {
742
+
743
+ // Excerpt length filter
744
+ if ( isset($instance["excerpt_length"]) && ((int) $instance["excerpt_length"]) > 0 ) {
745
+ add_filter('excerpt_length', array($this,'excerpt_length_filter'));
746
+ }
747
+
748
+ if( isset($instance["excerpt_more_text"]) && ltrim($instance["excerpt_more_text"]) != '' )
749
+ {
750
+ add_filter('excerpt_more', array($this,'excerpt_more_filter'));
751
+ }
752
+
753
+ if( isset( $instance['excerpt_allow_html'] ) ) {
754
+ remove_filter('get_the_excerpt', 'wp_trim_excerpt');
755
+ add_filter('the_excerpt', array($this,'allow_html_excerpt'));
756
+ } else {
757
+ add_filter('the_excerpt', array($this,'apply_the_excerpt'));
758
+ }
759
+ }
760
+ }
761
+
762
+ /**
763
+ * Remove the excerpt filter
764
+ *
765
+ * @param array $instance widget settings
766
+ * @return void
767
+ *
768
+ * @since 4.6
769
+ */
770
+ function removeExcerpFilters($instance) {
771
+ remove_filter('excerpt_length', array($this,'excerpt_length_filter'));
772
+ remove_filter('excerpt_more', array($this,'excerpt_more_filter'));
773
+ add_filter('get_the_excerpt', 'wp_trim_excerpt');
774
+ remove_filter('the_excerpt', array($this,'allow_html_excerpt'));
775
+ remove_filter('the_excerpt', array($this,'apply_the_excerpt'));
776
+ }
777
+
778
+ /**
779
+ * The main widget display controller
780
+ *
781
+ * Called by the sidebar processing core logic to display the widget
782
+ *
783
+ * @param array $args An array containing the "environment" setting for the widget,
784
+ * namely, the enclosing tags for the widget and its title.
785
+ * @param array $instance The settings associate with the widget
786
+ *
787
+ * @since 4.1
788
+ */
789
+ function widget($args, $instance) {
790
+
791
+ extract( $args );
792
+ $this->instance = $instance;
793
+
794
+ $args = $this->queryArgs($instance);
795
+ $cat_posts = new \WP_Query( $args );
796
+
797
+ if ( !isset ( $instance["hide_if_empty"] ) || !$instance["hide_if_empty"] || $cat_posts->have_posts() ) {
798
+ echo $before_widget;
799
+ echo $this->titleHTML($before_title,$after_title,$instance);
800
+
801
+ $current_post_id = null;
802
+ if (is_singular())
803
+ $current_post_id = get_the_ID();
804
+
805
+ echo "<ul>\n";
806
+
807
+ $this->setExcerpFilters($instance);
808
+ while ( $cat_posts->have_posts() )
809
+ {
810
+ $cat_posts->the_post();
811
+ echo $this->itemHTML($instance,$current_post_id);
812
+ }
813
+ echo "</ul>\n";
814
+
815
+ echo $this->footerHTML($instance);
816
+ echo $after_widget;
817
+
818
+ $this->removeExcerpFilters($instance);
819
+
820
+ wp_reset_postdata();
821
+
822
+ }
823
+ }
824
+
825
+ /**
826
+ * Update the options
827
+ *
828
+ * @param array $new_instance
829
+ * @param array $old_instance
830
+ * @return array
831
+ */
832
+ function update($new_instance, $old_instance) {
833
+
834
+ return $new_instance;
835
+ }
836
+
837
+ /**
838
+ * Output the title panel of the widget configuration form.
839
+ *
840
+ * @param array $instance
841
+ * @return void
842
+ *
843
+ * @since 4.6
844
+ */
845
+ function formTitlePanel($instance) {
846
+ $instance = wp_parse_args( ( array ) $instance, array(
847
+ 'title' => '',
848
+ 'title_link' => '',
849
+ 'hide_title' => ''
850
+ ));
851
+ $title = $instance['title'];
852
+ $hide_title = $instance['hide_title'];
853
+ $title_link = $instance['title_link'];
854
+ ?>
855
+ <h4 data-panel="title"><?php _e('Title','category-posts')?></h4>
856
+ <div>
857
+ <p>
858
+ <label for="<?php echo $this->get_field_id("title"); ?>">
859
+ <?php _e( 'Title','category-posts' ); ?>:
860
+ <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"]); ?>" />
861
+ </label>
862
+ </p>
863
+ <p>
864
+ <label for="<?php echo $this->get_field_id("title_link"); ?>">
865
+ <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 ); ?> />
866
+ <?php _e( 'Make widget title link','category-posts' ); ?>
867
+ </label>
868
+ </p>
869
+ <p>
870
+ <label for="<?php echo $this->get_field_id("hide_title"); ?>">
871
+ <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 ); ?> />
872
+ <?php _e( 'Hide title','category-posts' ); ?>
873
+ </label>
874
+ </p>
875
+ </div>
876
+ <?php
877
+ }
878
+
879
+ /**
880
+ * Output the filter panel of the widget configuration form.
881
+ *
882
+ * @param array $instance
883
+ * @return void
884
+ *
885
+ * @since 4.6
886
+ */
887
+ function formFilterPanel($instance) {
888
+ $instance = wp_parse_args( ( array ) $instance, array(
889
+ 'cat' => '',
890
+ 'num' => get_option('posts_per_page'),
891
+ 'sort_by' => '',
892
+ 'asc_sort_order' => '',
893
+ 'exclude_current_post' => '',
894
+ 'hideNoThumb' => ''
895
+ ));
896
+ $cat = $instance['cat'];
897
+ $num = $instance['num'];
898
+ $sort_by = $instance['sort_by'];
899
+ $asc_sort_order = $instance['asc_sort_order'];
900
+ $exclude_current_post = $instance['exclude_current_post'];
901
+ $hideNoThumb = $instance['hideNoThumb'];
902
+ ?>
903
+ <h4 data-panel="filter"><?php _e('Filter','category-posts');?></h4>
904
+ <div>
905
+ <p>
906
+ <label>
907
+ <?php _e( 'Category','category-posts' ); ?>:
908
+ <?php wp_dropdown_categories( array( 'hide_empty'=> 0, 'name' => $this->get_field_name("cat"), 'selected' => $instance["cat"] ) ); ?>
909
+ </label>
910
+ </p>
911
+ <p>
912
+ <label for="<?php echo $this->get_field_id("num"); ?>">
913
+ <?php _e('Number of posts to show','category-posts'); ?>:
914
+ <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"]); ?>" />
915
+ </label>
916
+ </p>
917
+ <p>
918
+ <label for="<?php echo $this->get_field_id("sort_by"); ?>">
919
+ <?php _e('Sort by','category-posts'); ?>:
920
+ <select id="<?php echo $this->get_field_id("sort_by"); ?>" name="<?php echo $this->get_field_name("sort_by"); ?>">
921
+ <option value="date"<?php selected( $instance["sort_by"], "date" ); ?>><?php _e('Date','category-posts')?></option>
922
+ <option value="title"<?php selected( $instance["sort_by"], "title" ); ?>><?php _e('Title','category-posts')?></option>
923
+ <option value="comment_count"<?php selected( $instance["sort_by"], "comment_count" ); ?>><?php _e('Number of comments','category-posts')?></option>
924
+ <option value="rand"<?php selected( $instance["sort_by"], "rand" ); ?>><?php _e('Random','category-posts')?></option>
925
+ </select>
926
+ </label>
927
+ </p>
928
+ <p>
929
+ <label for="<?php echo $this->get_field_id("asc_sort_order"); ?>">
930
+ <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 ); ?> />
931
+ <?php _e( 'Reverse sort order (ascending)','category-posts' ); ?>
932
+ </label>
933
+ </p>
934
+ <p>
935
+ <label for="<?php echo $this->get_field_id("exclude_current_post"); ?>">
936
+ <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 ); ?> />
937
+ <?php _e( 'Exclude current post','category-posts' ); ?>
938
+ </label>
939
+ </p>
940
+ <p>
941
+ <label for="<?php echo $this->get_field_id("hideNoThumb"); ?>">
942
+ <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 ); ?> />
943
+ <?php _e( 'Exclude posts which have no thumbnail','category-posts' ); ?>
944
+ </label>
945
+ </p>
946
+ </div>
947
+ <?php
948
+ }
949
+
950
+ /**
951
+ * Output the filter panel of the widget configuration form.
952
+ *
953
+ * @param array $instance
954
+ * @return void
955
+ *
956
+ * @since 4.6
957
+ */
958
+ function formThumbnailPanel($instance) {
959
+ $instance = wp_parse_args( ( array ) $instance, array(
960
+ 'thumb' => '',
961
+ 'thumbTop' => '',
962
+ 'thumb_w' => '',
963
+ 'thumb_h' => '',
964
+ 'use_css_cropping' => '',
965
+ 'thumb_hover' => ''
966
+ ));
967
+ $thumb = $instance['thumb'];
968
+ $thumbTop = $instance['thumbTop'];
969
+ $thumb_w = $instance['thumb_w'];
970
+ $thumb_h = $instance['thumb_h'];
971
+ $use_css_cropping = $instance['use_css_cropping'];
972
+ $thumb_hover = $instance['thumb_hover'];
973
+ ?>
974
+ <h4 data-panel="thumbnail"><?php _e('Thumbnails','category-posts')?></h4>
975
+ <div>
976
+ <p>
977
+ <label for="<?php echo $this->get_field_id("thumb"); ?>">
978
+ <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 ); ?> />
979
+ <?php _e( 'Show post thumbnail','category-posts' ); ?>
980
+ </label>
981
+ </p>
982
+ <p>
983
+ <label for="<?php echo $this->get_field_id("thumbTop"); ?>">
984
+ <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 ); ?> />
985
+ <?php _e( 'Show thumbnails above text','category-posts' ); ?>
986
+ </label>
987
+ </p>
988
+ <p>
989
+ <label>
990
+ <?php _e('Thumbnail dimensions (in pixels)','category-posts'); ?>:<br />
991
+ <label for="<?php echo $this->get_field_id("thumb_w"); ?>">
992
+ <?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"]); ?>" />
993
+ </label>
994
+
995
+ <label for="<?php echo $this->get_field_id("thumb_h"); ?>">
996
+ <?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"]); ?>" />
997
+ </label>
998
+ </label>
999
+ </p>
1000
+ <p>
1001
+ <label for="<?php echo $this->get_field_id("use_css_cropping"); ?>">
1002
+ <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 ); ?> />
1003
+ <?php _e( 'CSS crop to requested size ','category-posts' ); ?>
1004
+ </label>
1005
+ </p>
1006
+ <p>
1007
+ <label for="<?php echo $this->get_field_id("thumb_hover"); ?>">
1008
+ <?php _e( 'Animation on mouse hover:','category-posts' ); ?>
1009
+ </label>
1010
+ <select id="<?php echo $this->get_field_id("thumb_hover"); ?>" name="<?php echo $this->get_field_name("thumb_hover"); ?>">
1011
+ <option value="none" <?php selected($thumb_hover, 'none')?>><?php _e( 'None', 'category-posts' ); ?></option>
1012
+ <option value="dark" <?php selected($thumb_hover, 'dark')?>><?php _e( 'Darker', 'category-posts' ); ?></option>
1013
+ <option value="white" <?php selected($thumb_hover, 'white')?>><?php _e( 'Brighter', 'category-posts' ); ?></option>
1014
+ <option value="scale" <?php selected($thumb_hover, 'scale')?>><?php _e( 'Zoom in', 'category-posts' ); ?></option>
1015
+ <option value="blur" <?php selected($thumb_hover, 'blur')?>><?php _e( 'Blur', 'category-posts' ); ?></option>
1016
+ </select>
1017
+ </p>
1018
+ </div>
1019
+ <?php
1020
+ }
1021
+
1022
+ /**
1023
+ * The widget configuration form back end.
1024
+ *
1025
+ * @param array $instance
1026
+ * @return void
1027
+ */
1028
+ function form($instance) {
1029
+ $instance = wp_parse_args( ( array ) $instance, array(
1030
+ 'footer_link' => '',
1031
+ 'hide_post_titles' => '',
1032
+ 'excerpt' => '',
1033
+ 'excerpt_length' => 55,
1034
+ 'excerpt_more_text' => '',
1035
+ 'comment_num' => '',
1036
+ 'author' => '',
1037
+ 'date' => '',
1038
+ 'date_link' => '',
1039
+ 'date_format' => '',
1040
+ 'disable_css' => '',
1041
+ 'hide_if_empty' => '',
1042
+ 'hide_social_buttons' => '',
1043
+ 'auto_close_panels' => false,
1044
+ ) );
1045
+
1046
+ $footer_link = $instance['footer_link'];
1047
+ $hide_post_titles = $instance['hide_post_titles'];
1048
+ $excerpt = $instance['excerpt'];
1049
+ $excerpt_length = $instance['excerpt_length'];
1050
+ $excerpt_more_text = $instance['excerpt_more_text'];
1051
+ $comment_num = $instance['comment_num'];
1052
+ $author = $instance['author'];
1053
+ $date = $instance['date'];
1054
+ $date_link = $instance['date_link'];
1055
+ $date_format = $instance['date_format'];
1056
+ $disable_css = $instance['disable_css'];
1057
+ $hide_if_empty = $instance['hide_if_empty'];
1058
+ $auto_close_panels = $instance['auto_close_panels'];
1059
+
1060
+ ?>
1061
+ <div class="category-widget-cont">
1062
+ <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">Get the Pro Version</a></p>
1063
+ <p><a target="_blank" href="http://tiptoppress.com/category-posts-widget/4-6?utm_source=widget_cpw&utm_campaign=documentation_4_6_cpw&utm_medium=form">Documentation</a></p>
1064
+ <?php
1065
+ $this->formTitlePanel($instance);
1066
+ $this->formFilterPanel($instance);
1067
+ $this->formThumbnailPanel($instance);
1068
+ ?>
1069
+ <h4 data-panel="details"><?php _e('Post details','category-posts')?></h4>
1070
+ <div>
1071
+ <p>
1072
+ <label for="<?php echo $this->get_field_id("hide_post_titles"); ?>">
1073
+ <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 ); ?> />
1074
+ <?php _e( 'Hide post titles','category-posts' ); ?>
1075
+ </label>
1076
+ </p>
1077
+ <p>
1078
+ <label for="<?php echo $this->get_field_id("excerpt"); ?>">
1079
+ <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 ); ?> />
1080
+ <?php _e( 'Show post excerpt','category-posts' ); ?>
1081
+ </label>
1082
+ </p>
1083
+ <p>
1084
+ <label for="<?php echo $this->get_field_id("excerpt_length"); ?>">
1085
+ <?php _e( 'Excerpt length (in words):','category-posts' ); ?>
1086
+ </label>
1087
+ <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"]; ?>" />
1088
+ </p>
1089
+ <p>
1090
+ <label for="<?php echo $this->get_field_id("excerpt_more_text"); ?>">
1091
+ <?php _e( 'Excerpt \'more\' text:','category-posts' ); ?>
1092
+ </label>
1093
+ <input class="widefat" style="width:50%;" 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"]); ?>" />
1094
+ </p>
1095
+ <p>
1096
+ <label for="<?php echo $this->get_field_id("date"); ?>">
1097
+ <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 ); ?> />
1098
+ <?php _e( 'Show post date','category-posts' ); ?>
1099
+ </label>
1100
+ </p>
1101
+ <p>
1102
+ <label for="<?php echo $this->get_field_id("date_format"); ?>">
1103
+ <?php _e( 'Date format:','category-posts' ); ?>
1104
+ </label>
1105
+ <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" />
1106
+ </p>
1107
+ <p>
1108
+ <label for="<?php echo $this->get_field_id("date_link"); ?>">
1109
+ <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 ); ?> />
1110
+ <?php _e( 'Make widget date link','category-posts' ); ?>
1111
+ </label>
1112
+ </p>
1113
+ <p>
1114
+ <label for="<?php echo $this->get_field_id("comment_num"); ?>">
1115
+ <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 ); ?> />
1116
+ <?php _e( 'Show number of comments','category-posts' ); ?>
1117
+ </label>
1118
+ </p>
1119
+ <p>
1120
+ <label for="<?php echo $this->get_field_id("author"); ?>">
1121
+ <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 ); ?> />
1122
+ <?php _e( 'Show post author','category-posts' ); ?>
1123
+ </label>
1124
+ </p>
1125
+ </div>
1126
+ <h4 data-panel="general"><?php _e('General','category-posts')?></h4>
1127
+ <div>
1128
+ <p>
1129
+ <label for="<?php echo $this->get_field_id("disable_css"); ?>">
1130
+ <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 ); ?> />
1131
+ <?php _e( 'Disable the built-in CSS for this widget','category-posts' ); ?>
1132
+ </label>
1133
+ </p>
1134
+ <p>
1135
+ <label for="<?php echo $this->get_field_id("hide_if_empty"); ?>">
1136
+ <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 ); ?> />
1137
+ <?php _e( 'Hide widget if there are no matching posts','category-posts' ); ?>
1138
+ </label>
1139
+ </p>
1140
+ <p>
1141
+ <label for="<?php echo $this->get_field_id("hide_social_buttons"); ?>">
1142
+ <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("hide_social_buttons"); ?>" name="<?php echo $this->get_field_name("hide_social_buttons"); ?>"<?php checked( (bool) $instance["hide_social_buttons"], true ); ?> />
1143
+ <?php _e( 'Hide social buttons in widget output','category-posts' ); ?>
1144
+ </label>
1145
+ </p>
1146
+ </div>
1147
+ <h4 data-panel="footer"><?php _e('Footer','category-posts')?></h4>
1148
+ <div>
1149
+ <p>
1150
+ <label for="<?php echo $this->get_field_id("footer_link"); ?>">
1151
+ <?php _e( 'Footer link text','category-posts' ); ?>:
1152
+ <input class="widefat" style="width:60%;" placeholder="<?php _e('... more by this topic','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"]); ?>" />
1153
+ </label>
1154
+ </p>
1155
+ </div>
1156
+ <h4 data-panel="mysettings"><?php _e('My settings','category-posts')?></h4>
1157
+ <div class="categoryposts-mysettings-panel-auto-close-panels">
1158
+ <p>
1159
+ <label for="<?php echo $this->get_field_id("auto_close_panels"); ?>">
1160
+ <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("auto_close_panels"); ?>" name="<?php echo $this->get_field_name("auto_close_panels"); ?>"<?php checked( (bool) $instance["auto_close_panels"], true ); ?> />
1161
+ <?php _e( 'Auto close panels','category-posts' ); ?>
1162
+ </label>
1163
+ </p>
1164
+ </div>
1165
+ <p style="text-align:right;">
1166
+ Follow us on <a target="_blank" href="https://www.facebook.com/TipTopPress">Facebook</a> and
1167
+ <a target="_blank" href="https://twitter.com/TipTopPress">Twitter</a></br></br>
1168
+ </p>
1169
+ </div>
1170
+ <?php
1171
+ }
1172
+ }
1173
+
1174
+ // Plugin action links section
1175
+
1176
+ /**
1177
+ * Applied to the list of links to display on the plugins page (beside the activate/deactivate links).
1178
+ *
1179
+ * @return array of the widget links
1180
+ *
1181
+ * @since 4.6.3
1182
+ */
1183
+ add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), __NAMESPACE__.'\add_action_links' );
1184
+
1185
+ function add_action_links ( $links ) {
1186
+ $pro_link = array(
1187
+ '<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>',
1188
+ );
1189
+
1190
+ $links = array_merge($pro_link, $links);
1191
+
1192
+ return $links;
1193
+ }
1194
+
1195
+ function register_widget() {
1196
+ return \register_widget(__NAMESPACE__.'\Widget');
1197
+ }
1198
+
1199
+ add_action( 'widgets_init', __NAMESPACE__.'\register_widget' );
1200
+
1201
+ // shortcode section
1202
+
1203
+ /**
1204
+ * Get shortcode settings taking into account if it is being customized
1205
+ *
1206
+ * When not customized returns the settings as stored in the meta, but when
1207
+ * it is customized returns the setting stored in the virtual option used by the customizer
1208
+ *
1209
+ * @return array the shortcode settings if a short code exists or empty string
1210
+ *
1211
+ * @since 4.6
1212
+ */
1213
+ function shortcode_settings() {
1214
+ $instance = get_post_meta(get_the_ID(),SHORTCODE_META,true);
1215
+
1216
+ if (is_array($instance)) {
1217
+ if (is_customize_preview()) {
1218
+ $o=get_option('_virtual-'.WIDGET_BASE_ID);
1219
+ if (is_array($o))
1220
+ $instance=$o[get_the_ID()];
1221
+ }
1222
+ }
1223
+
1224
+ return $instance;
1225
+ }
1226
+ /**
1227
+ * Handle the shortcode
1228
+ *
1229
+ * @param array $attr Array of the attributes to the short code, none is expected
1230
+ * @param string $content The content enclosed in the shortcode, none is expected
1231
+ *
1232
+ * @return string An HTML of the "widget" based on its settings, actual or customized
1233
+ *
1234
+ */
1235
+ function shortcode($attr,$content=null) {
1236
+ if (is_singular()) {
1237
+ $instance = shortcode_settings();
1238
+
1239
+ if (is_array($instance)) {
1240
+ $widget=new Widget();
1241
+ $widget->number = 'shortcode-'.get_the_ID(); // needed to make a unique id for the widget html element
1242
+ ob_start();
1243
+ $widget->widget(array(
1244
+ 'before_widget' => '',
1245
+ 'after_widget' => '',
1246
+ 'before_title' => '',
1247
+ 'after_title' => ''
1248
+ ), $instance);
1249
+ $ret = ob_get_clean();
1250
+ $ret = '<div id="'.WIDGET_BASE_ID.'-'.$widget->number.'" class="'.WIDGET_BASE_ID.'-shortcode">'.$ret.'</div>';
1251
+ return $ret;
1252
+ }
1253
+ }
1254
+
1255
+ return '';
1256
+ }
1257
+
1258
+ add_shortcode(SHORTCODE_NAME,__NAMESPACE__.'\shortcode');
1259
+
1260
+ /**
1261
+ * Find if a specific shortcode is used in a content
1262
+ *
1263
+ * @param string $shortcode_name The name of the shortcode
1264
+ * #param string The content to look at
1265
+ * @return boolean True if used, otherwise false
1266
+ *
1267
+ */
1268
+ function shortcode_exist($shortcode_name,$content) {
1269
+
1270
+ $regex_pattern = get_shortcode_regex();
1271
+ if (preg_match_all ('/'.$regex_pattern.'/s', $content, $matches)) {
1272
+ foreach ($matches[2] as $k=>$shortcode) {
1273
+ if ($shortcode == SHORTCODE_NAME) {
1274
+ return true;
1275
+ }
1276
+ }
1277
+ }
1278
+
1279
+ return false;
1280
+ }
1281
+
1282
+ /**
1283
+ * Manipulate the relevant meta related to the short code when a post is save
1284
+ *
1285
+ * If A post has a short code, a meta holder is created, If it does not the meta holder is deleted
1286
+ *
1287
+ * @param integer $pid The post ID of the post being saved
1288
+ * @param WP_Post $post The post being saved
1289
+ * @return void
1290
+ *
1291
+ * @since 4.6
1292
+ */
1293
+ function save_post($pid,$post) {
1294
+
1295
+ // ignore revisions and auto saves
1296
+ if ( wp_is_post_revision( $pid ) || wp_is_post_autosave($pid))
1297
+ return;
1298
+
1299
+ $has_meta = get_post_meta($pid,SHORTCODE_META,true);
1300
+ $exist = shortcode_exist(SHORTCODE_NAME,$post->post_content);
1301
+
1302
+ if (!$exist)
1303
+ delete_post_meta($pid,SHORTCODE_META);
1304
+ else if (!is_array($has_meta)) // get_post_meta have strang return vaules when do not exist so just check it is expected structure
1305
+ add_post_meta($pid,SHORTCODE_META,array(
1306
+ 'title' => '',
1307
+ 'title_link' => false,
1308
+ 'hide_title' => false,
1309
+ 'cat' => '',
1310
+ 'num' => get_option('posts_per_page'),
1311
+ 'sort_by' => 'date',
1312
+ 'asc_sort_order' => false,
1313
+ 'exclude_current_post' => false,
1314
+ 'hideNoThumb' => false,
1315
+ 'footer_link' => '',
1316
+ 'thumb' => false,
1317
+ 'thumbTop' => false,
1318
+ 'thumb_w' => '',
1319
+ 'thumb_h' => '',
1320
+ 'use_css_cropping' => false,
1321
+ 'thumb_hover' => 'none',
1322
+ 'hide_post_titles' => false,
1323
+ 'excerpt' => false,
1324
+ 'excerpt_length' => 55,
1325
+ 'excerpt_more_text' => '',
1326
+ 'comment_num' => false,
1327
+ 'author' => false,
1328
+ 'date' => false,
1329
+ 'date_link' => false,
1330
+ 'date_format' => '',
1331
+ 'disable_css' => false,
1332
+ 'hide_if_empty' => false,
1333
+ 'hide_social_buttons' => '',
1334
+ 'auto_close_panels' => false,
1335
+ ),
1336
+ true);
1337
+ }
1338
+
1339
+ add_action('save_post',__NAMESPACE__.'\save_post',10,2);
1340
+
1341
+ function customize_register($wp_customize) {
1342
+
1343
+ class shortCodeControl extends \WP_Customize_Control {
1344
+ public $form;
1345
+
1346
+ public function render_content() {
1347
+ $widget_title = 'Category Posts Shortcode';
1348
+ ?>
1349
+ <div class="widget-top">
1350
+ <div class="widget-title"><h3><?php echo $widget_title; ?><span class="in-widget-title"></span></h3></div>
1351
+ </div>
1352
+ <div class="widget-inside" style="display: block;">
1353
+ <div class="form">
1354
+ <div class="widget-content">
1355
+ <?php echo $this->form; ?>
1356
+ </div>
1357
+ </div>
1358
+ </div>
1359
+ <?php
1360
+ }
1361
+ }
1362
+
1363
+ $args = array(
1364
+ 'post_type' => 'any',
1365
+ 'post_status' => 'any',
1366
+ 'posts_per_page' => -1,
1367
+ 'update_post_term_cache' => false,
1368
+ 'meta_query' => array(
1369
+ array(
1370
+ 'key' => SHORTCODE_META,
1371
+ 'compare' => 'EXISTS'
1372
+ )
1373
+ ),
1374
+
1375
+ );
1376
+ $posts = get_posts($args);
1377
+
1378
+ if (count($posts) > 0) {
1379
+ $wp_customize->add_section( __NAMESPACE__, array(
1380
+ 'title' => __( 'Category Posts Shortcode', 'category-posts' ),
1381
+ 'priority' => 200
1382
+ ) );
1383
+
1384
+ foreach($posts as $p) {
1385
+ $widget = new Widget();
1386
+ $widget->number = $p->ID;
1387
+ $meta = get_post_meta($p->ID,SHORTCODE_META,true);
1388
+ if (!is_array($meta))
1389
+ continue;
1390
+
1391
+ ob_start();
1392
+ $widget->form(array());
1393
+ $form = ob_get_clean();
1394
+ $form = preg_replace_callback('/<(input|select)\s+.*name=("|\').*\[\d*\]\[([^\]]*)\][^>]*>/',
1395
+ function ($matches) use ($p, $wp_customize, $meta) {
1396
+ $setting = '_virtual-'.WIDGET_BASE_ID.'['.$p->ID.']['.$matches[3].']';
1397
+ if (!isset($meta[$matches[3]]))
1398
+ $meta[$matches[3]] = null;
1399
+ $wp_customize->add_setting( $setting, array(
1400
+ 'default' => $meta[$matches[3]], // set default to current value
1401
+ 'type' => 'option'
1402
+ ) );
1403
+
1404
+ return str_replace('<'.$matches[1],'<'.$matches[1].' data-customize-setting-link="'.$setting.'"',$matches[0]);
1405
+ },
1406
+ $form
1407
+ );
1408
+
1409
+ $wp_customize->add_control( new shortCodeControl(
1410
+ $wp_customize,
1411
+ '_virtual-'.WIDGET_BASE_ID.'['.$p->ID.'][title]',
1412
+ array(
1413
+ 'label' => __( 'Layout', 'twentyfourteen' ),
1414
+ 'section' => __NAMESPACE__,
1415
+ 'form' => $form,
1416
+ 'settings' => '_virtual-'.WIDGET_BASE_ID.'['.$p->ID.'][title]',
1417
+ 'active_callback' => function () use ($p) { return is_singular() && (get_the_ID()==$p->ID); }
1418
+ )
1419
+ ) );
1420
+ }
1421
+ }
1422
+ }
1423
+
1424
+ add_action( 'customize_register', __NAMESPACE__.'\customize_register' );
1425
+
1426
+ /**
1427
+ * Save the virtual option used by the customizer into the proper meta values.
1428
+ *
1429
+ * The customizer actually saves only the changed values, so a merge needs to be done.
1430
+ * After everything is updated the virtual option is deleted to leave a clean slate
1431
+ *
1432
+ * @return void
1433
+ *
1434
+ * @since 4.6
1435
+ */
1436
+ function customize_save_after() {
1437
+ $virtual = get_option('_virtual-'.WIDGET_BASE_ID);
1438
+
1439
+ if (is_array($virtual)) {
1440
+ foreach ($virtual as $pid => $instance) {
1441
+ $meta = get_post_meta($pid,SHORTCODE_META,true);
1442
+ $instance = array_merge($meta,$instance);
1443
+ update_post_meta($pid,SHORTCODE_META, $instance);
1444
+ }
1445
+ }
1446
+
1447
+ delete_option('_virtual-'.WIDGET_BASE_ID);
1448
+ }
1449
+
1450
  add_action('customize_save_after', __NAMESPACE__.'\customize_save_after', 100);
readme.txt CHANGED
@@ -1,186 +1,200 @@
1
- === Category Posts Widget ===
2
- Contributors: mkrdip, mark-k, kometschuh
3
- Donate link: http://mkrdip.me/donate
4
- Tags: category, posts, widget, posts widget, recent posts, category recent posts
5
- Requires at least: 2.8
6
- Tested up to: 4.5.2
7
- Stable tag: 4.6.1
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.
12
-
13
- == Description ==
14
- Category Posts Widget is a light widget designed to do one thing and do it well: display the most recent posts from a certain category.
15
-
16
- = Term and Category based Posts Widget =
17
- It's the pro version and available on <a target="_blank" href="http://tiptoppress.com/">Tip Top Press</a> created for big Wordpress sites.
18
-
19
- = Pro features =
20
- * Custom Post Types, Terms and Custom Taxonomies
21
- * Multi selection
22
- * Vertical Scrolling News Ticker
23
- * More [examples on the demo page](http://demo.tiptoppress.com/)
24
-
25
- = Features =
26
- * 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).
27
- * Option to change ordering of posts.
28
- * Option to show post thumbnail & set dimension by width & height.
29
- * Option to crop thumbnails with CSS. <a target="_blank" href="http://tiptoppress.com/css-image-crop/">What is 'CSS Image Crop'?</a>
30
- * Option to set mouse hover effects for post thumbnail.
31
- * Jetpack 'Social buttons on posts' support
32
- * Option to hide social buttons on output
33
- * Option to put thumbnail on top
34
- * Option to hide posts which have no thumbnail.
35
- * Option to disable widget CSS.
36
- * Set how many posts to show.
37
- * Option exclude current post.
38
- * Option show post author.
39
- * Set which category the posts should come form.
40
- * Option to show the post excerpt, set the length and change 'more' text.
41
- * Option to show and <a target="_blank" href="https://codex.wordpress.org/Formatting_Date_and_Time">format</a> the post date and link to the category page.
42
- * Option to show the comment count.
43
- * Option to make the widget title link to the category page.
44
- * Option to link to the category page below posts list.
45
- * Option to hide the widget title and post titles.
46
- * Option to hide widget, if category have currently no posts.
47
- * Multiple widgets.
48
- * Multi sites support.
49
- * Localization support.
50
-
51
- = Documentation =
52
- * [Full documentation](http://tiptoppress.com/category-posts-widget/documentation/).
53
- * [Widget customizations, modifications and extensions](http://tiptoppress.com/category/widget-customizations-modifications-and-extensions/) for your WordPress site.
54
-
55
- = Contribute =
56
- While using this plugin if you find any bug or any conflict, please submit an issue at
57
- [Github](https://github.com/mkrdip/category-posts-widget) (If possible with a pull request).
58
-
59
- == Installation ==
60
- = Automatic installation =
61
- 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,
62
-
63
- 1. log in to your WordPress dashboard, navigate to the Plugins menu and click Add New.
64
- 2. In the search field type “Category Posts Widget” and click Search Plugins.
65
- 3. Once you’ve found plugin, you can install it by simply clicking “Install Now”.
66
- 4. Then, go to plugins page of WordPress admin activate the plugin.
67
- 5. Now, goto the Widgets page of the Appearance section and configure the Category Posts widget.
68
-
69
- = Manual installation =
70
- 1. Download the plugin.
71
- 2. Upload it to the plugins folder of your blog.
72
- 3. Activate the plugin through the 'Plugins' menu in WordPress
73
- 4. Now, goto the Widgets page of the Appearance section and configure the Category Posts widget.
74
-
75
- == Upgrade Notice ==
76
- * Please consider to re-configure the widget as the latest version has numerous changes from previous.
77
- * Version 4.0 uses CSS file for styling the widget in front end.
78
- * Version 3.0 or later version uses WordPress 2.9's built in post thumbnail functionality.
79
-
80
- == Frequently Asked Questions ==
81
- = The font-size is different from that of other widgets or Theme elements? =
82
- Please use the option: "Disable widget CSS".
83
-
84
- = I want the title as a link pointing to the selected Categorie page? =
85
- Enable the check box "Make widget title link".
86
-
87
- = Parse error: syntax error, unexpected T_FUNCTION in /home/www/blog/wp-content/plugins/category-posts/cat-posts.php on line 58 =
88
- Some of the features that were used in that version needs PHP 5.3+.
89
- We apologies for any headache this may cause you, but frankly it is better for you to check with your hosting company how can you upgrade the PHP version that you are using, and not only in order to use this plugin. PHP 5.2 should be considered insecure now, and for your own sake you should upgrade.
90
- 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).
91
- 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.
92
-
93
- == Screenshots ==
94
- 1. The widget configuration dialog.
95
- 2. Front end of the widget using a default WordPress Theme.
96
- 3. Use shortcode [catposts] in the content and edit options in the customizer.
97
-
98
- == Changelog ==
99
- [Read more on our blog ...](http://tiptoppress.com/category/category-posts-widget/)
100
-
101
- = 4.6.1 - June 5th 2016 =
102
- * Add shortcode [catposts] edit options only in the customizer
103
- * Keep panels open after save.
104
- * Option to hide social buttons on output.
105
-
106
- = 4.1.9 - May 5th 2016 =
107
- * Fixed undefined constant.
108
-
109
- = 4.1.8 - May 03th 2016 =
110
- * Add mouse hover effects: blur
111
- * Add option to choose allowed HTML in the excerpt
112
- * Add Jetpack 'Sharing - Show buttons on posts' support
113
- * Fixed division by zero bug (for small uploaded images)
114
-
115
- = 4.1.7 - April 14th 2016 =
116
- * Fixed division by zero bug.
117
-
118
- = 4.1.6 - April 13th 2016 =
119
- * Add option CSS cropping for thumbnails.
120
- * Add option to set mouse hover effects for post thumbnail.
121
- * Add option to change the excerpt more text.
122
- * Add option to allow links in the excerpt
123
- * Add filter 'widget_title' for the title
124
- * Add option to hide post titles.
125
-
126
- = 4.1.5 - February 4th 2016 =
127
- * Support for multi sites.
128
- * Support for localization.
129
- * Generate thumbs from existing images.
130
- * Area UI.
131
- * Meet new plugin author [mark-k](https://profiles.wordpress.org/mark-k/)
132
-
133
- = 4.1.4 =
134
- * Added option exclude current post.
135
- * Added option to hide posts which have no thumbnail.
136
- * Added option to make the widget date link to the category page.
137
- * Added option to link to the category page below posts list.
138
- * Added option show post author.
139
- * Added option to format the outputted date string.
140
-
141
- = 4.1.3 =
142
- * Added option to hide widget, if category have currently no posts.
143
-
144
- = 4.1.2 =
145
- * Fixed hide title bug.
146
-
147
- = 4.1.1 =
148
- * Added option to put thumbnail on top.
149
- * Added option to show/hide the title.
150
- * Fixed no background bug.
151
-
152
- = 4.1.0 =
153
- * Added PHP5 Constructor.
154
- * Added Option to allow/disallow widget CSS.
155
- * Now, compatible with WordPress 4.3.
156
- * Meet new plugin author [kometschuh](https://profiles.wordpress.org/kometschuh)
157
-
158
- = 4.0 =
159
- * Added CSS file for post styling .
160
- * Now compatible with latest versions of WordPress.
161
-
162
- = 3.3 =
163
- * Fixed random sort bug.
164
-
165
- = 3.2 =
166
- * Added option to change ordering of posts. Defaults to showing newest posts first.
167
-
168
- = 3.1 =
169
- * Fixed a bug in the thumbnail size registration routine.
170
-
171
- = 3.0 =
172
- * Added support for WP 2.9's post thumbnail feature.
173
- * Removed support for Simple Post Thumbnails plugin.
174
- * Added option to show the post date.
175
- * Added option to set the excerpt length.
176
- * Added option to show the number of comments.
177
-
178
- = 2.3 =
179
- * Really tried to fix bug where wp_query global was getting over written by manually instantiating a WP_Query object.
180
-
181
- = 2.1 =
182
- * Fixed bug where wp_query global was getting over written.
183
-
184
- = 2.0 =
185
- * Updated to use the WP 2.8 widget API.
186
- * Added support for [Simple Post Thumbnails plugin](http://wordpress.org/extend/plugins/simple-post-thumbnails/).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Category Posts Widget ===
2
+ Contributors: mkrdip, mark-k, kometschuh
3
+ Donate link: http://mkrdip.me/donate
4
+ Tags: category, posts, widget, posts widget, recent posts, category recent posts
5
+ Requires at least: 2.8
6
+ Tested up to: 4.7
7
+ Stable tag: 4.6.2
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.
12
+
13
+ == Description ==
14
+ Category Posts Widget is a light widget designed to do one thing and do it well: display the most recent posts from a certain category.
15
+
16
+ = Term and Category based Posts Widget =
17
+ It's the premium version and available on <a target="_blank" href="http://tiptoppress.com/?utm_source=wordpress_org&utm_campaign=premium_widget_cpw&utm_medium=web">Tip Top Press</a> created for big Wordpress sites.
18
+
19
+ = Premium features =
20
+ * "Post List Alterations"
21
+ * Masonry (Responsive grid layouts)
22
+ * Grid and Column full page layouts
23
+ * Slider (Vertical and horizontal)
24
+ * Categories, Custom Post Types, Taxonomies, Events, Products, ...
25
+ * Full background post images
26
+ * Mouse hover effects for post thumbnail
27
+ * E-Mail support
28
+ * All free features
29
+ * More [examples on the demo pages](http://demo.tiptoppress.com/?utm_source=wordpress_org&utm_campaign=demo_cpw&utm_medium=web)
30
+
31
+ = Features =
32
+ * Shortcode (Easily change all Shortcode options in the customizer.)
33
+ * For editing shortcode adds a Customizer link to the admin-bar ("With one click to the Customizer").
34
+ * Option to show post thumbnail & set dimensions by width & height.
35
+ * Option for <a target="_blank" href="http://tiptoppress.com/css-image-crop/?utm_source=wordpress_org&utm_campaign=features_crop_cpw&utm_medium=web">client-side cropped thumbnail dimensions</a> by width & height.
36
+ * Option to set mouse hover effects for post thumbnail.
37
+ * Jetpack 'Social buttons on posts' support.
38
+ * Option to hide social buttons on output.
39
+ * Option to change ordering of posts.
40
+ * Set which category the posts should come form.
41
+ * Set how many posts to show.
42
+ * Option to hide widget, if category have currently no posts.
43
+ * Option to put thumbnail on top.
44
+ * Option to hide posts which have no thumbnail.
45
+ * Option exclude current post.
46
+ * Option to hide the widget title and post titles.
47
+ * Option to make the widget title link to the category page.
48
+ * Option to show the post excerpt, set the length, allow HTML and change 'more' text.
49
+ * Option show post author.
50
+ * Option to show the comment count.
51
+ * Option to show the post date.
52
+ * Option to make the widget date link to the category page.
53
+ * Option to format the outputted date string.
54
+ * Option to link to the category page below posts list.
55
+ * Option to disable widget CSS.
56
+ * Multiple widgets.
57
+ * Multi sites support.
58
+ * Localization support.
59
+
60
+ = Documentation =
61
+ * Full documentation on [Tiptoppress](http://tiptoppress.com/category-posts-widget/4-6/?utm_source=wordpress_org&utm_campaign=documentation_4_6_cpw&utm_medium=web)
62
+ * 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)
63
+ * Formatting date and time: See <a target="_blank" href="https://codex.wordpress.org/Formatting_Date_and_Time">Formatting Date and Time</a>
64
+ * Widget <a target="_blank" href="http://tiptoppress.com/category/widget-customization-and-filter-extensions/?utm_source=wordpress_org&utm_campaign=documentation_filter_cpw&utm_medium=web">customization and filter extensions</a>
65
+
66
+ = Contribute =
67
+ While using this plugin if you find any bug or any conflict, please submit an issue at
68
+ [Github](https://github.com/mkrdip/category-posts-widget) (If possible with a pull request).
69
+
70
+ == Installation ==
71
+ = Automatic installation =
72
+ 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,
73
+
74
+ 1. log in to your WordPress dashboard, navigate to the Plugins menu and click Add New.
75
+ 2. In the search field type “Category Posts Widget” and click Search Plugins.
76
+ 3. Once you’ve found plugin, you can install it by simply clicking “Install Now”.
77
+ 4. Then, go to plugins page of WordPress admin activate the plugin.
78
+ 5. Now, goto the Widgets page of the Appearance section and configure the Category Posts widget.
79
+
80
+ = Manual installation =
81
+ 1. Download the plugin.
82
+ 2. Upload it to the plugins folder of your blog.
83
+ 3. Activate the plugin through the 'Plugins' menu in WordPress
84
+ 4. Now, goto the Widgets page of the Appearance section and configure the Category Posts widget.
85
+
86
+ == Upgrade Notice ==
87
+ * Please consider to re-configure the widget as the latest version has numerous changes from previous.
88
+ * Version 4.0 uses CSS file for styling the widget in front end.
89
+ * Version 3.0 or later version uses WordPress 2.9's built in post thumbnail functionality.
90
+
91
+ == Frequently Asked Questions ==
92
+ = The font-size is different from that of other widgets or Theme elements? =
93
+ Please use the option: "Disable widget CSS".
94
+
95
+ = I want the title as a link pointing to the selected Categorie page? =
96
+ Enable the check box "Make widget title link".
97
+
98
+ = Parse error: syntax error, unexpected T_FUNCTION in /home/www/blog/wp-content/plugins/category-posts/cat-posts.php on line 58 =
99
+ Some of the features that were used in that version needs PHP 5.3+.
100
+ We apologies for any headache this may cause you, but frankly it is better for you to check with your hosting company how can you upgrade the PHP version that you are using, and not only in order to use this plugin. PHP 5.2 should be considered insecure now, and for your own sake you should upgrade.
101
+ 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).
102
+ 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.
103
+
104
+ == Screenshots ==
105
+ 1. The widget configuration dialog.
106
+ 2. Front end of the widget using a default WordPress Theme.
107
+ 3. Use shortcode [catposts] in the content and edit options in the customizer.
108
+
109
+ == Changelog ==
110
+ [Read more on our blog ...](http://tiptoppress.com/category/category-posts-widget?utm_source=wordpress_org&utm_campaign=changelog_cpw&utm_medium=web)
111
+
112
+ = 4.6.2 - August 28th 2016 =
113
+ * Fixed only five widget instances can be costumized with shortcodes.
114
+ * For editing shortcode adds a customizer link to the admin-bar if page/post is in edit mode.
115
+
116
+ = 4.6.1 - June 5th 2016 =
117
+ * Add shortcode [catposts] edit options only in the customizer
118
+ * Keep panels open after save.
119
+ * Option to hide social buttons on output.
120
+
121
+ = 4.1.9 - May 5th 2016 =
122
+ * Fixed undefined constant.
123
+
124
+ = 4.1.8 - May 03th 2016 =
125
+ * Add mouse hover effects: blur
126
+ * Add option to choose allowed HTML in the excerpt
127
+ * Add Jetpack 'Sharing - Show buttons on posts' support
128
+ * Fixed division by zero bug (for small uploaded images)
129
+
130
+ = 4.1.7 - April 14th 2016 =
131
+ * Fixed division by zero bug.
132
+
133
+ = 4.1.6 - April 13th 2016 =
134
+ * Add option CSS cropping for thumbnails.
135
+ * Add option to set mouse hover effects for post thumbnail.
136
+ * Add option to change the excerpt more text.
137
+ * Add option to allow links in the excerpt
138
+ * Add filter 'widget_title' for the title
139
+ * Add option to hide post titles.
140
+
141
+ = 4.1.5 - February 4th 2016 =
142
+ * Support for multi sites.
143
+ * Support for localization.
144
+ * Area UI.
145
+ * Meet new plugin author [mark-k](https://profiles.wordpress.org/mark-k/)
146
+
147
+ = 4.1.4 =
148
+ * Added option exclude current post.
149
+ * Added option to hide posts which have no thumbnail.
150
+ * Added option to make the widget date link to the category page.
151
+ * Added option to link to the category page below posts list.
152
+ * Added option show post author.
153
+ * Added option to format the outputted date string.
154
+
155
+ = 4.1.3 =
156
+ * Added option to hide widget, if category have currently no posts.
157
+
158
+ = 4.1.2 =
159
+ * Fixed hide title bug.
160
+
161
+ = 4.1.1 =
162
+ * Added option to put thumbnail on top.
163
+ * Added option to show/hide the title.
164
+ * Fixed no background bug.
165
+
166
+ = 4.1.0 =
167
+ * Added PHP5 Constructor.
168
+ * Added Option to allow/disallow widget CSS.
169
+ * Now, compatible with WordPress 4.3.
170
+ * Meet new plugin author [kometschuh](https://profiles.wordpress.org/kometschuh)
171
+
172
+ = 4.0 =
173
+ * Added CSS file for post styling.
174
+ * Now compatible with latest versions of WordPress.
175
+
176
+ = 3.3 =
177
+ * Fixed random sort bug.
178
+
179
+ = 3.2 =
180
+ * Added option to change ordering of posts. Defaults to showing newest posts first.
181
+
182
+ = 3.1 =
183
+ * Fixed a bug in the thumbnail size registration routine.
184
+
185
+ = 3.0 =
186
+ * Added support for WP 2.9's post thumbnail feature.
187
+ * Removed support for Simple Post Thumbnails plugin.
188
+ * Added option to show the post date.
189
+ * Added option to set the excerpt length.
190
+ * Added option to show the number of comments.
191
+
192
+ = 2.3 =
193
+ * Really tried to fix bug where wp_query global was getting over written by manually instantiating a WP_Query object.
194
+
195
+ = 2.1 =
196
+ * Fixed bug where wp_query global was getting over written.
197
+
198
+ = 2.0 =
199
+ * Updated to use the WP 2.8 widget API.
200
+ * Added support for [Simple Post Thumbnails plugin](http://wordpress.org/extend/plugins/simple-post-thumbnails/).