';
126 | $output .= paginate_links( $args_pagi);
127 | $output .= '
';
128 | return $output;
129 | }
130 |
131 |
132 | /**
133 | * Build additional arguments for the WP_Query object.
134 | *
135 | * @param array $atts Attributes for building the $args array.
136 | */
137 | protected function set_args( $atts ) {
138 | global $wp_query;
139 | $this->args['posts_per_page'] = get_option( 'posts_per_page' );
140 | // Parse the arguments using the defaults.
141 | $this->args = wp_parse_args( $atts, $this->args );
142 | // Multiple post types are indicated, pass as an array.
143 | if ( strpos( $this->args['post_type'], ',' ) ) {
144 | $post_types = explode( ',', $this->args['post_type'] );
145 | $this->args['post_type'] = $post_types;
146 | }
147 |
148 | // Show specific posts by ID.
149 | if ( isset( $atts['ids'] ) ) {
150 | $post_ids = explode( ',', $atts['ids'] );
151 | $this->args['post__in'] = $post_ids;
152 | $this->args['posts_per_page'] = count( $post_ids );
153 | }
154 |
155 | // Use a specified template.
156 | if ( isset( $atts['template'] ) ) {
157 | $this->args['template'] = $atts['template'];
158 | }
159 |
160 | // Get posts in a certain category by name (slug).
161 | if ( isset( $atts['category'] ) ) {
162 | $this->args['category_name'] = $atts['category'];
163 | } elseif ( isset( $atts['cats'] ) ) {
164 | // Get posts in a certain category by id.
165 | $this->args['cat'] = $atts['cats'];
166 | }
167 |
168 | // Do a tax query, tax and term a required.
169 | if ( isset( $atts['tax'] ) ) {
170 | if ( isset( $atts['term'] ) ) {
171 | $terms = explode( ',', $atts['term'] );
172 | $this->args['tax_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
173 | array(
174 | 'taxonomy' => $atts['tax'],
175 | 'field' => 'slug',
176 | 'terms' => ( count( $terms ) > 1 ) ? $terms : $atts['term'],
177 | ),
178 | );
179 | }
180 | }
181 |
182 | // Get posts with a certain tag.
183 | if ( isset( $atts['tag'] ) ) {
184 | $this->args['tag'] = $atts['tag'];
185 | }
186 |
187 | // Override default post_type argument ('publish').
188 | if ( isset( $atts['post_status'] ) ) {
189 | $this->args['post_status'] = $atts['post_status'];
190 | }
191 |
192 | // Exclude posts with certain category by name (slug).
193 | if ( isset( $atts['exclude_category'] ) ) {
194 | $category = $atts['exclude_category'];
195 | if ( strpos( $category, ',' ) ) {
196 | // Multiple.
197 | $category = explode( ',', $category );
198 | foreach ( $category as $cat ) {
199 | $term = get_category_by_slug( $cat );
200 | $exclude[] = '-' . $term->term_id;
201 | }
202 | $category = implode( ',', $exclude );
203 | } else {
204 | // Single.
205 | $term = get_category_by_slug( $category );
206 | $category = '-' . $term->term_id;
207 | }
208 | if ( isset( $this->args['cat'] ) && ! is_null( $this->args['cat'] ) ) {
209 | // Merge lists.
210 | $this->args['cat'] .= ',' . $category;
211 | }
212 | $this->args['cat'] = $category;
213 | // Unset our unneeded variables.
214 | unset( $category, $term, $exclude );
215 | }
216 |
217 | // Show number of posts (default is 10, showposts or posts_per_page are both valid, only one is needed).
218 | if ( isset( $atts['showposts'] ) ) {
219 | $this->args['posts_per_page'] = $atts['showposts'];
220 | }
221 |
222 | // Handle pagination (for code, template pagination is in the template).
223 | if ( isset( $wp_query->query_vars['page'] ) && $wp_query->query_vars['page'] > 1 ) {
224 | $this->args['paged'] = $wp_query->query_vars['page'];
225 | }
226 |
227 | if (
228 | ! ( isset( $this->args['ignore_sticky_posts'] ) &&
229 | ( 'no' === strtolower( $this->args['ignore_sticky_posts'] ) ||
230 | 'false' === strtolower( $this->args['ignore_sticky_posts'] ) ) )
231 | ) {
232 |
233 | $this->args['post__not_in'] = get_option( 'sticky_posts' );
234 | }
235 |
236 | $this->args['ignore_sticky_posts'] = isset( $this->args['ignore_sticky_posts'] ) ? $this->shortcode_bool( $this->args['ignore_sticky_posts'] ) : true;
237 |
238 | if ( isset( $this->args['more_tag'] ) ) {
239 | add_filter( 'excerpt_more', array( $this, 'custom_excerpt_more' ), 11 );
240 | }
241 |
242 | if ( isset( $atts['exclude_ids'] ) ) {
243 | $exclude_posts = explode( ',', $atts['exclude_ids'] );
244 | if ( isset( $this->args['post__not_in'] ) ) {
245 | $this->args['post__not_in'] = array_merge( $this->args['post__not_in'], $exclude_posts );
246 | } else {
247 | $this->args['post__not_in'] = $exclude_posts;
248 | }
249 | }
250 |
251 | if ( isset( $atts['from_date'] ) && isset( $atts['to_date'] ) ) {
252 | $r_from = explode( '-', $atts['from_date'] );
253 | $r_to = explode( '-', $atts['to_date'] );
254 | $this->args['date_query'] = array(
255 | array(
256 | 'after' => array(
257 | 'year' => $r_from[2],
258 | 'month' => $r_from[1],
259 | 'day' => $r_from[0],
260 | ),
261 | 'before' => array(
262 | 'year' => $r_to[2],
263 | 'month' => $r_to[1],
264 | 'day' => $r_to[0],
265 | ),
266 | 'inclusive' => true,
267 | ),
268 | );
269 | } elseif ( isset( $atts['from_date'] ) ) {
270 | $r_from = explode( '-', $atts['from_date'] );
271 | $r_to = explode( '-', $atts['to_date'] );
272 | $this->args['date_query'] = array(
273 | array(
274 | 'after' => array(
275 | 'year' => $r_from[2],
276 | 'month' => $r_from[1],
277 | 'day' => $r_from[0],
278 | ),
279 | 'inclusive' => true,
280 | ),
281 | );
282 | }
283 |
284 | $current_time_value = current_time( 'timestamp' );
285 | if ( isset( $atts['date'] ) ) {
286 | $date_data = explode( '-', $atts['date'] );
287 | if ( ! isset( $date_data[1] ) ) {
288 | $date_data[1] = 0;
289 | }
290 | switch ( $date_data[0] ) {
291 | case 'today':
292 | $today = getdate( $current_time_value - ( $date_data[1] * DAY_IN_SECONDS ) );
293 | $this->args['date_query'] = array(
294 | 'year' => $today['year'],
295 | 'month' => $today['mon'],
296 | 'day' => $today['mday'],
297 | );
298 | break;
299 | case 'week':
300 | $week = date( 'W', $current_time_value - $date_data[1] * WEEK_IN_SECONDS );
301 | $year = date( 'Y', $current_time_value - $date_data[1] * WEEK_IN_SECONDS );
302 | $Month = date( 'M', $current_time_value - $date_data[1] * WEEK_IN_SECONDS );
303 |
304 | if( ( $Month == 'Jan' ) && ( $week == 52 || $week == 53 ) ){
305 | $year = $year - 1;
306 | }
307 |
308 | $dateTime = new DateTime();
309 | $dateTime->setISODate($year, $week);
310 | $start_date = $dateTime->format('d-m-Y');
311 | $dateTime->modify('+6 days');
312 | $end_date = $dateTime->format('d-m-Y');
313 | $r_from = explode( '-', $start_date );
314 | $r_to = explode( '-', $end_date );
315 | $this->args['date_query'] = array(
316 | array(
317 | 'after' => array(
318 | 'year' => $r_from[2],
319 | 'month' => $r_from[1],
320 | 'day' => $r_from[0],
321 | ),
322 | 'before' => array(
323 | 'year' => $r_to[2],
324 | 'month' => $r_to[1],
325 | 'day' => $r_to[0],
326 | ),
327 | 'inclusive' => false,
328 | ),
329 | );
330 | break;
331 | case 'month':
332 | $month = date( 'm', strtotime( ( strval( - $date_data[1] ) . ' Months' ), $current_time_value ) );
333 | $year = date( 'Y', strtotime( ( strval( - $date_data[1] ) . ' Months' ), $current_time_value ) );
334 | $this->args['date_query'] = array(
335 | 'monthnum' => $month,
336 | 'year' => $year,
337 | );
338 | break;
339 | case 'year':
340 | $year = date( 'Y', strtotime( ( strval( - $date_data[1] ) . ' Years' ), $current_time_value ) );
341 | $this->args['date_query'] = array(
342 | 'year' => $year,
343 | );
344 | break;
345 | }
346 | }
347 | $this->args = apply_filters( 'posts_in_page_args', $this->args );
348 | }
349 |
350 | /**
351 | * Sets a shortcode boolean value to a real boolean.
352 | *
353 | * @param mixed $var Value to evaluate to a boolean.
354 | * @return bool
355 | */
356 | public function shortcode_bool( $var ) {
357 | $falsey = array( 'false', '0', 'no', 'n' );
358 |
359 | return ( ! $var || in_array( strtolower( $var ), $falsey, true ) ) ? false : true;
360 | }
361 |
362 | /**
363 | * Tests if a theme has a template file that exists in one of two locations
364 | * 1- posts-in-page directory or 2- theme directory.
365 | *
366 | * @return true if template exists, false otherwise.
367 | */
368 | protected function has_theme_template() {
369 | // Try default template filename if empty.
370 | $filename = empty( $this->args['template'] ) ? 'posts_loop_template.php' : $this->args['template'];
371 |
372 | // Checking first of two locations - theme root.
373 | $template_file = get_stylesheet_directory() . '/' . $filename;
374 |
375 | // Check for traversal attack.
376 | $path_parts = pathinfo( $template_file );
377 | if ( get_stylesheet_directory() . '/' . $path_parts['filename'] . '.' . $path_parts['extension'] !== $template_file ) {
378 | // Something fishy.
379 | return false;
380 | }
381 |
382 | return ( file_exists( $template_file ) ) ? $template_file : false;
383 | }
384 |
385 | /**
386 | * Retrieves the post loop template and returns the output.
387 | *
388 | * @param WP_Query $ic_posts Posts in Page query.
389 | * @param bool $singles Whether a single post should be set up.
390 | * @return string Results of the output.
391 | */
392 | protected function add_template_part( $ic_posts, $singles = false ) {
393 | if ( $singles ) {
394 | setup_postdata( $ic_posts );
395 | } else {
396 | $ic_posts->the_post();
397 | }
398 | // Because legacy versions of pip forced users to echo content in the filter callback
399 | // we are using both the filters and the output buffer to cover all bases of usage.
400 | ob_start();
401 | $output_start = apply_filters( 'posts_in_page_pre_loop', '' );
402 | $file_path = self::has_theme_template();
403 | require $file_path
404 | ? $file_path // Use template file in theme.
405 | : POSTSPAGE_DIR . '/templates/posts_loop_template.php'; // Use default plugin template file.
406 | $output_start .= ob_get_clean();
407 | // Output buffering to handle legacy versions which forced filter callbacks to echo content rather than return it.
408 | ob_start();
409 | // Standard use of filter.
410 | $output = apply_filters( 'posts_in_page_post_loop', $output_start );
411 | // Just in case someone has a legacy callback that doesn't return anything...
412 | if ( empty( $output ) ) {
413 | $output = $output_start;
414 | }
415 | // Allow for legacy use of filter which forced echoing content.
416 | $output .= ob_get_clean();
417 |
418 | return $output;
419 | }
420 |
421 | /**
422 | * Retrieve a custom more link for excerpts.
423 | *
424 | * @param string $more Link text.
425 | * @return string
426 | */
427 | public function custom_excerpt_more( $more ) {
428 | $more_tag = $this->args['more_tag'];
429 |
430 | return '
20 |
21 |
22 |
23 |
24 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
37 |
38 | %1$s %2$s',
42 | esc_html__( 'Posted in', 'posts-in-page' ),
43 | $categories_list // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
44 | );
45 | ?>
46 |
47 | |
48 |
49 |
54 |
55 | %1$s %2$s',
59 | esc_html__( 'Tagged', 'posts-in-page' ),
60 | $tags_list // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
61 | );
62 | ?>
63 |
64 | |
65 |
66 |
75 | | ', '' ); ?>
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------