├── .gitignore ├── .phpcs.xml.dist ├── README.md ├── admin ├── assets │ ├── css │ │ └── post-page_styles.css │ ├── images │ │ └── ivycat-sq.png │ └── js │ │ └── post-page_scripts.js └── views │ └── help-main.php ├── composer.json ├── composer.lock ├── includes └── class-page-posts.php ├── license.txt ├── posts_in_page.php ├── readme.txt └── templates └── posts_loop_template.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.komodoproject 3 | *.sublime-project 4 | *.sublime-workspace 5 | *.komodotools 6 | node_modules/**/* 7 | vendor/**/* 8 | *.idea/ 9 | -------------------------------------------------------------------------------- /.phpcs.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Custom ruleset for the Posts in Page plugin. 5 | 6 | 7 | . 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Posts in Page 2 | **Contributors:** ivycat, sewmyheadon, anvilzephyr, jasonm4563, pjackson1972 3 | **Tags:** shortcode, pages, posts, custom post types, taxonomy, terms 4 | **Requires at least:** 3.0 5 | **Tested up to:** 6.1.1 6 | **Stable tag:** 1.4.6 7 | **License:** GPLv2 or later 8 | **License URI:** https://www.gnu.org/licenses/gpl-2.0.html 9 | 10 | Easily add one or more posts to any page using simple shortcodes. 11 | 12 | 13 | ## Description 14 | 15 | Easily add one or more posts to any page using simple shortcodes. 16 | 17 | Supports categories, tags, custom post types, custom taxonomies, date ranges, post status, and much more. 18 | 19 | You can get all of the same functionality provided by this plugin by modifying your theme's template files; this plugin just makes it easy for anyone to _pull_ posts into other areas of the site without having to get their hands dirty with code. 20 | 21 | Plugin is depending upon your theme's styling; version 1.x of this plugin _does not_ contain native styles. 22 | 23 | This is a minimal plugin, function over form. Give us feedback, suggestions, bug reports, and any other contributions on the in the plugin's [GitHub repository](https://github.com/ivycat/posts-in-page). 24 | 25 | 26 | ## Installation 27 | 28 | You can install from within WordPress using the Plugin/Add New feature, or if you wish to manually install: 29 | 30 | 1. Download the plugin. 31 | 1. Upload the entire `posts-in-page` directory to your plugins folder 32 | 1. Activate the plugin from the plugin page in your WordPress Dashboard 33 | 1. Start embedding posts in whatever pages you like using shortcodes. 34 | 35 | ### Shortcode Usage 36 | 37 | To 'pull' posts into a page, you can: 38 | 39 | 1. place a shortcode in the editor window of the page you're editing (Classic Editor), 40 | 1. place a shortcode in a shortcode block on the page you're editing (Gutenberg Editor), 41 | 1. modify a theme template file using the shortcode in a PHP function. 42 | 43 | #### Using Shortcodes in the WordPress editor 44 | 45 | * `[ic_add_posts]` - Add all posts to a page (limit to what number posts in WordPress is set to), essentially adds blog "page" to page. 46 | * `[ic_add_posts post_type='post_type']` - Show posts from a custom post type by specifying the post type slug (must give post type if not a standard post). Add multiple post types by separating with commas (ex. `post_type='post_type1,post_type2'`). 47 | * `[ic_add_posts showposts='5']` - Limit number of posts (or override default setting). 48 | * `[ic_add_posts orderby='title' order='ASC']` - Order the post output using `orderby` - supports all WP [orderby parameters](https://codex.wordpress.org/Class_Reference/WP_Query#Order_.26_Orderby_Parameters). Order is optional, default is 'DESC'. 49 | * `[ic_add_posts ids='1,2,3']` - Show one or many posts by specifying the post ID(s) (specify all post types). 50 | * `[ic_add_posts exclude_ids='4,5,6']` - Exclude specific post ID(s) from the query. 51 | * `[ic_add_posts category='category-slug']` - Show posts within a specific category by category slug. Separate multiple categories with commas. 52 | * `[ic_add_posts cats='2,13']` - Show posts within a specific category by category IDs. Separate multiple categories with commas. 53 | * `[ic_add_posts exclude_category='category-slug']` - Exclude posts within specific category. Uses slugs, can list multiple category slugs separated by commas. 54 | * `[ic_add_posts tag='tag-slug']` - Show posts using a specific tag. Like categories, it uses slugs, and can accommodate multiple tags separated by commas. 55 | * `[ic_add_posts tax='taxonomy' term='term']` - Limit posts to those that exist in a taxonomy and have a specific term. Both are required for either one to work and you must specify custom post_types. 56 | * `[ic_add_posts post_format='post-format-status']` - Select post formats. Use 'post-format-' followed by the format type (chat, aside, video, etc.). Use comma to separate post formats. To pull all posts with the quotes format, you'd use `[ic_add_posts post_format='post-format-quote']`. 57 | * `[ic_add_posts ignore_sticky_posts='no']` - Show sticky posts too (they're ignored by default). 58 | * `[ic_add_posts paginate='yes']` - Use pagination links (off by default). 59 | * `[ic_add_posts label_next='Next' label_previous='Previous']` - Customize 'Next' and 'Previous' labels used by pagination. 60 | * `[ic_add_posts post_status='private']` - Show posts with the specified status. By default it shows only posts with 'publish' status. To select multiple statuses, separate them with commas like so: `post_status='private,publish'`. 61 | * `[ic_add_posts more_tag='Read more']` - Set the link text for read more links shown after an excerpt. 62 | * `[ic_add_posts date='today-1']` - Choose the relative date of included posts. Supports formatting like `date='today-1'` (today minus 1 day), `date='week-2'` (today minus 2 weeks), `date='month-1'` (today minus 1 month), `date='year-1'` (today minus 1 year). 63 | * `[ic_add_posts from_date='15-01-2016' to_date='31-12-2016']` - Shows posts published within a specified absolute date range. 64 | * `[ic_add_posts offset='3']` - Displays posts after the offset. An `offset='3'` will show all posts from the 4th one back. 65 | * `[ic_add_posts none_found='No Posts Found']` - Custom message to display when no posts are found. 66 | * `[ic_add_posts template='template-in-theme-dir.php']` - In case you want to style your markup, add meta data, etc. Each shortcode can reference a different template. These templates must exist in the theme directory or in a sub-directory named _posts-in-page_. 67 | 68 | Or any combination of the above. 69 | 70 | #### Shortcode Examples 71 | 72 | Not sure how to use the shortcodes above to get what you want? Here are a few examples to get you started: 73 | 74 | ** Example 1 ** 75 | 76 | Let's say you want to pull a specific post called _"What I love about coffee"_, which has a post ID of 34, somewhere on your About Us page. Your shortcode should look like this: 77 | 78 | `[ic_add_posts ids='34']` 79 | 80 | ** Example 2 ** 81 | 82 | Alright, now let's say that you want to pull in all posts from two categories into your WordPress page. One category is _WordPress Rocks_ and the other is _WordPress Rolls_. Plus, you'd like to display them three per page, rather than the default number of posts. Depending on your category slugs, your shortcode should probably look like this: 83 | 84 | `[ic_add_posts category='wordpress-rocks,wordpress-rolls' showposts='3']` 85 | 86 | ** Example 3 ** 87 | 88 | Now, you're ambitious and want to try something complex. Let's say you've got a page called _Plugins Are Awesome_ and, in it, you want to pull in posts that match the following criteria: 89 | 90 | * posts from a custom post type called _Testimonials_, 91 | * posts that are in the _Testimonial Type_ custom taxonomy using the term _Customer_, 92 | * you want to display six testimonials per page, 93 | * you'd like them displayed in ascending order, 94 | * finally, you've created a custom template to use in presenting these posts and named it `my-posts-in-page-template.php`. 95 | 96 | Your shortcode might look like this: 97 | 98 | `[ic_add_posts showposts='6' post_type='testimonials' tax='testimonial-type' term='customer' order='ASC' template='my-posts-in-page-template.php']` 99 | 100 | #### Using Shortcodes within a PHP function 101 | 102 | If you'd like to use this plugin to pull posts directly into your theme's template files, you can drop the following WordPress function in your template files, replacing the `[shortcode]` part with your, custom shortcode. 103 | 104 | `` 105 | 106 | ### Developer Hooks 107 | 108 | There are several hooks you can use to filter the output of your template files: 109 | 110 | * `posts_in_page_results` - Filter results 111 | * `posts_in_page_args` - Filter the query arguments 112 | * `posts_in_page_paginate` - Filter pagination 113 | * `posts_in_page_pre_loop` - Runs right before the loop (posts_loop_template.php) 114 | * `posts_in_page_post_loop` - Runs right after the loop 115 | 116 | 117 | ## Frequently Asked Questions 118 | 119 | 120 | ### What is the point of this plugin? 121 | 122 | It allows you to output or embed the posts in any page without modifying WordPress theme templates. 123 | 124 | 125 | ### Does it work with Gutenberg? 126 | 127 | Absolutely. Just use a Gutenberg Shortcode block or the Classic Edit block to add your shortcode. 128 | 129 | 130 | ### Wait! The posts aren't styled like the posts on the rest of my site. 131 | 132 | That is likely true. Currently, Posts in Page doesn't output any styles; just some basic markup. To change how the posts appear on the page, you'll need to change the _output template_. 133 | 134 | 135 | ### How do I change the output template? 136 | 137 | Simply copy the `posts_loop_template.php` to your theme directory and make changes as necessary. 138 | 139 | You can even rename it - but make sure to indicate that in the shortcode using the `template='my-new-template-name.php'`. 140 | 141 | For file housekeeping, you can also create a _posts-in-page_ folder in your theme to store all of your custom templates. It isn't necessary to specify the _posts-in-page_ folder in your shortcode - Posts in Page will find it automatically. 142 | You can even use multiple templates for use with different shortcodes. 143 | 144 | 145 | ### Does it work with custom post types? 146 | 147 | Absolutely. 148 | 149 | 150 | ### Does it work with custom taxonomies? 151 | 152 | You bet. 153 | 154 | 155 | ### Will it make me coffee? 156 | 157 | Not likely, but let us know if it does; then we'll *know* we have something special. 158 | 159 | 160 | ### How can I help? 161 | 162 | We'd love feedback, issues, pull requests, and ideas on the [Posts in Page GitHub repo](https://github.com/ivycat/posts-in-page). 163 | 164 | 165 | ## Screenshots 166 | 167 | ### 1. Embed a shortcode into a page, and it will automatically pull in the post(s) you need. 168 | ![Embed a shortcode into a page, and it will automatically pull in the post(s) you need.](https://ps.w.org/posts-in-page/assets/screenshot-1.png) 169 | 170 | ### 2. Embed shortcode using a Gutenberg shortcode block. 171 | ![Embed shortcode using a Gutenberg shortcode block.](https://ps.w.org/posts-in-page/assets/screenshot-2.png) 172 | 173 | ### 3. Embed shortcodes directly in your template using `do_shortcode`. 174 | [missing image] 175 | 176 | 177 | ## Changelog 178 | 179 | ### 1.4.4 180 | * Fix issue to prevent fatal errors caused by setting the global query to null. 181 | 182 | ### 1.4.3 183 | * Fix issue with missing wrapping pagination div. 184 | * Fix a few `esc_html_e` instances. 185 | 186 | ### 1.4.2 187 | * Thanks to Brady Vercher (@bradyvercher) for the thorough code review and fixes. 188 | * Cleanup code to better conform to WP Coding standards and remove legacy cruft. 189 | * PHPCS configuration. 190 | * Update docblock and comments. 191 | * Remove legacy i18n code. 192 | * Escaping output of URLs, translation strings, and more. 193 | * Updated enqueueing to add version for cache busting, add missing jQuery dependency, load admin script in footer. 194 | 195 | ### 1.4.1 196 | * Fix wp_reset_query bug 197 | * Patch pagination to make it more reliable across themes. 198 | 199 | ### 1.4.0 200 | * Add templates folder to structure and moved default template there. 201 | * Fix pagination issues #42, 59. 202 | * Fix bug preventing including or excluding multiple post_types or categories. 203 | * Add a few new date-based shortcode arguments including `date=` and `from_date=` and `to_date=`. 204 | * Document post format support, new shortcode arguments. 205 | * Code cleanup. 206 | * Updates to admin page layout and documentation. 207 | 208 | ### 1.3.1 209 | * File header housekeeping. 210 | * Code cleanup. 211 | * Fix WPML compatibility issue (thanks @azrall). 212 | * Document new shortcode functions including `exclude_ids`, `more_tag`. 213 | 214 | ### 1.3.0 215 | * File reorganization / housekeeping. 216 | * Admin UI cleanup. 217 | * Security: Fixed [directory traversal vulnerability](https://www.pluginvulnerabilities.com/2017/02/13/authenticated-local-file-inclusion-lfi-vulnerability-in-posts-in-page/). 218 | * Added ability to optionally include private posts - Thanks, StarsoftAnalysis! 219 | 220 | ### 1.2.4 221 | * now you can set `more_tag=""` to remove the `[...] …` that unfortunetly shows up as `&hellip`. 222 | 223 | ### 1.2.3 224 | * Added minor doc tweaks. 225 | 226 | ### 1.2.2 227 | * Added pagination, tweaked to turn off by default. 228 | * Bug fixes. 229 | 230 | ### 1.2.1 231 | * Added code to allow ignoring, or showing of sticky posts. By default, sticky posts are ignored, but can be re-enabled using the shortcode `[ic_add_posts ignore_sticky_posts='no']`. 232 | 233 | ### 1.2.0 234 | * Code maintenance to better comply with standards. 235 | * Added post pagination. 236 | * Plugin now honors default post reading settings under Settings/Reading in the WordPress Dashboard. 237 | * Improved and simplified documentation. 238 | 239 | ### 1.1.1 240 | * Code maintenance, fix for category bug, also added the ability for multiple post types per shortcode. 241 | 242 | ### 1.1.0 243 | * Code maintenance, squash non-critical debug notices. 244 | 245 | ### 1.0.10 246 | * Added check for published/private posts. 247 | 248 | ### 1.0.9 249 | * Fixed template bug introduced by comments. 250 | 251 | ### 1.0.8 252 | * Code cleanup & indentation. 253 | * Added comments and notes to output template file: `posts_loop_template.php`. 254 | 255 | ### 1.0.7 256 | * Added Help Page under Setting in WP Dashboard. 257 | 258 | ### 1.0.6 259 | * More plugin housekeeping. 260 | 261 | ### 1.0.4 262 | * Minor housekeeping, added author, updated readme.txt. 263 | 264 | ### 1.0.3 265 | * Added single post or specific post capabilities. 266 | 267 | 268 | ## Upgrade Notice 269 | 270 | ### 1.4.4 271 | * Bug fix - please upgrade for stability. 272 | 273 | ### 1.4.3 274 | * Pagination bug fix and two minor i18n updates for translatable strings. Please upgrade. 275 | 276 | ### 1.4.2 277 | * Code review, cleanup. Minor fixes and security updates. Please upgrade. 278 | 279 | ### 1.4.1 280 | * Critical bug fixes. Please upgrade. 281 | 282 | ### 1.4.0 283 | * Bug fixes, new shortcodes, and code improvements. Please upgrade. 284 | 285 | ### 1.3.0 286 | * Important security and version updates. Please upgrade. 287 | 288 | ### 1.2.4 289 | * Presentational fixes: clean up whitespace, extra tabs, add in customization of more tag. 290 | 291 | ### 1.2.3 292 | * Housekeeping only; not urgent. 293 | 294 | ### 1.2.2 295 | * Small bug fixes for tags, pagination; not critical. 296 | 297 | ### 1.2.1 298 | * Small feature update, not critical. 299 | 300 | ### 1.2.0 301 | * Important feature update - please upgrade. 302 | 303 | ### 1.1.1 304 | * Small bug fix - please upgrade. 305 | 306 | ### 1.1.0 307 | * Code maintenance & housekeeping - non-critical update. 308 | 309 | ### 1.0.10 310 | * Added feature - non-critical update. 311 | 312 | ### 1.0.9 313 | * Fixed template bug - please update. 314 | 315 | ### 1.0.8 316 | * Added features and documentation - non-critical update. 317 | 318 | ### 1.0.7 319 | * Added Help Page - non-critical update. 320 | 321 | ### 1.0.6 322 | * Plugin housekeeping - non-critical update. 323 | 324 | ### 1.0.4 325 | * Minor housekeeping, added author, updated readme.txt. Non-critical update. 326 | 327 | ### 1.0.3 328 | * Added single post or specific post capabilities. Important feature. 329 | -------------------------------------------------------------------------------- /admin/assets/css/post-page_styles.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Admin page styles 3 | */ 4 | .settings_page_posts_in_page th { 5 | width: 33% 6 | } 7 | 8 | /* Clearfix */ 9 | .clearfix:before, .clearfix:after { 10 | content: ""; 11 | display: table; 12 | } 13 | 14 | .clearfix:after { 15 | clear: both; 16 | } 17 | 18 | .clearfix { 19 | *zoom: 1; 20 | } 21 | 22 | /** 23 | * Help & Support metabox styles 24 | */ 25 | #ivycat_contribute .dashicons { 26 | font-size: 48px; 27 | margin-top: -.75em; 28 | color: #f1f1f1; 29 | } 30 | 31 | #ivycat_contribute h4 { 32 | margin-top: 0 33 | } 34 | 35 | /** 36 | * Connect with IvyCat metabox styles 37 | */ 38 | .ivycat-social { 39 | margin: 0; 40 | padding: 0; 41 | } 42 | 43 | .ivycat-social li { 44 | float: left; 45 | line-height: 1; 46 | margin: 0 .6em; 47 | padding: 0; 48 | display: inline-block; 49 | } 50 | 51 | .ivycat-social a { 52 | text-decoration: none; 53 | } 54 | 55 | .ivycat-social .dashicons { 56 | font-size: 32px; 57 | width: 32px; 58 | height: 32px; 59 | } 60 | 61 | /* MailChimp Form Embed Code - Slim - 08/17/2011 */ 62 | #mc_embed_signup form { 63 | display: block; 64 | position: relative; 65 | text-align: left; 66 | padding: 10px 0 10px 0; 67 | width: 250px; 68 | } 69 | 70 | #mc_embed_signup h2 { 71 | font-weight: bold; 72 | padding: 0; 73 | margin: 15px 0; 74 | font-size: 1.4em; 75 | } 76 | 77 | #mc_embed_signup input { 78 | border: 1px solid #e5e5e5; 79 | -webkit-appearance: none; 80 | } 81 | 82 | #mc_embed_signup input[type=checkbox] { 83 | -webkit-appearance: checkbox; 84 | } 85 | 86 | #mc_embed_signup input[type=radio] { 87 | -webkit-appearance: radio; 88 | } 89 | 90 | #mc_embed_signup input:focus { 91 | border-color: #333; 92 | } 93 | 94 | #mc_embed_signup .button { 95 | clear: both; 96 | background-color: #aaa; 97 | border: 0 none; 98 | border-radius: 4px; 99 | color: #FFF; 100 | cursor: pointer; 101 | display: inline-block; 102 | font-size: 16px; 103 | height: 34px; 104 | line-height: 34px; 105 | margin: 0 5px 10px 0; 106 | padding: 0; 107 | text-align: center; 108 | text-decoration: none; 109 | vertical-align: top; 110 | white-space: nowrap; 111 | width: auto; 112 | } 113 | 114 | #mc_embed_signup .button:hover { 115 | background-color: #777; 116 | } 117 | 118 | #mc_embed_signup .small-meta { 119 | font-size: 11px; 120 | } 121 | 122 | #mc_embed_signup .nowrap { 123 | white-space: nowrap; 124 | } 125 | 126 | #mc_embed_signup label { 127 | display: block; 128 | font-size: 14px; 129 | padding-bottom: 10px; 130 | font-weight: bold; 131 | color: #464646 132 | } 133 | 134 | #mc_embed_signup input.email { 135 | display: block; 136 | padding: 8px 0; 137 | margin: 0 0 10px 0; 138 | text-indent: 5px; 139 | width: 62%; 140 | min-width: 130px; 141 | float: left; 142 | } 143 | 144 | #mc_embed_signup input.button { 145 | display: block; 146 | clear: none; 147 | background: #628C29; 148 | width: 35%; 149 | margin: 0 0 10px 0; 150 | min-width: 90px; 151 | float: right; 152 | text-shadow: 0 1px 0 #666; 153 | } 154 | 155 | #mc_embed_signup div#mce-responses { 156 | float: left; 157 | top: -1.4em; 158 | padding: 0em .5em 0em .5em; 159 | overflow: hidden; 160 | width: 90%; 161 | margin: 0 5%; 162 | clear: both; 163 | } 164 | 165 | #mc_embed_signup div.response { 166 | margin: 1em 0; 167 | padding: 1em .5em .5em 0; 168 | font-weight: bold; 169 | float: left; 170 | top: -1.5em; 171 | z-index: 1; 172 | width: 80%; 173 | } 174 | 175 | #mc_embed_signup #mce-error-response { 176 | display: none; 177 | } 178 | 179 | #mc_embed_signup #mce-success-response { 180 | color: #529214; 181 | display: none; 182 | } 183 | 184 | #mc_embed_signup label.error { 185 | display: block; 186 | float: none; 187 | width: auto; 188 | margin-left: 1.05em; 189 | text-align: left; 190 | padding: .5em 0; 191 | } 192 | 193 | /** 194 | * Spread the Word styles & Support metabox styles 195 | */ 196 | .ivycat-rating { 197 | display: inline; 198 | color: #ffb900; 199 | } 200 | 201 | .ivycat-rating .dashicons { 202 | width: 16px; 203 | height: 16px; 204 | font-size: 16px; 205 | } 206 | 207 | /** 208 | IvyCat metabox styles 209 | */ 210 | .signature .inside { 211 | text-align: center; 212 | } 213 | 214 | .signature img { 215 | margin-left: -.95em; 216 | margin-right: .5em; 217 | } 218 | -------------------------------------------------------------------------------- /admin/assets/images/ivycat-sq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivycat/posts-in-page/fb705fb425067dd1e3a78287ce83a35c27922bcf/admin/assets/images/ivycat-sq.png -------------------------------------------------------------------------------- /admin/assets/js/post-page_scripts.js: -------------------------------------------------------------------------------- 1 | jQuery('document').ready(function ($) { 2 | $('#posts-in-page-settings .top-menu li a').click(function () { 3 | var toshow = $(this).attr('href').replace('#', ''); 4 | $('.top-menu li').removeClass('current-menu-tab'); 5 | $(this).parent('li').addClass('current-menu-tab'); 6 | $('.group').hide().removeClass('current-tab'); 7 | $('.' + toshow).show().addClass('current-tab'); 8 | return false; 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /admin/views/help-main.php: -------------------------------------------------------------------------------- 1 | Posts in Page. 4 | * 5 | * @package Posts_in_Page 6 | * @author Eric Amundson 7 | * @copyright Copyright (c) 2019, IvyCat, Inc. 8 | * @link https://ivycat.com 9 | * @since 1.0.0 10 | * @license GPL-2.0-or-later 11 | */ 12 | 13 | ?> 14 | 15 |
16 | 17 |
18 |

19 | 20 |
21 | 22 |
23 | 24 | 25 |
26 | 27 |
28 | 29 |
30 | 31 |

32 | 33 | 34 |

35 | 36 |

37 | 38 |
39 | 40 |

To 'pull' posts into a page, you can either:

41 | 42 |
    43 |
  1. Place a shortcode in the WordPress 44 | editor, or 45 |
  2. 46 |
  3. Embed a PHP function in a theme 47 | template file
  4. 48 |
49 | 50 |

Place 51 | a Shortcode in the WordPress Editor

52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 |
TaskShortcodeNotes
TaskShortcodeNotes
Add all posts[ic_add_posts]
Show posts by Post Type[ic_add_posts post_type='post_type'] 78 | post_type='post_type1,post_type2') 79 |
Show specific number of posts[ic_add_posts showposts='5']
Change post order[ic_add_posts orderby='title' order='ASC']
Show posts by ID[ic_add_posts ids='1,2,3']
Exclude posts by ID[ic_add_posts exclude_ids='4,5,6']
Include posts from specific categories[ic_add_posts category='category-slug']
Exclude posts from specific categories[ic_add_posts exclude_category='category-slug']
Specify tags[ic_add_posts tag='tag-slug']
Specify custom taxonomy[ic_add_posts tax='taxonomy' term='term']
Change output template[ic_add_posts template='template-in-theme-dir.php']
Sticky posts[ic_add_posts ignore_sticky_posts='no']
Pagination[ic_add_posts paginate='yes']
Pagination - Post navigation links[ic_add_posts label_next='Next' label_previous='Previous']
Post status[ic_add_posts post_status='private']post_status='private,publish'.", 'posts-in-page' ); ?>
Post offset[ic_add_posts offset='3']
Specific Dates[ic_add_posts date='today']
Date Ranges[ic_add_posts from_date='15-01-2016' to_date='31-12-2016']
Read more[ic_add_posts more_tag='Read more...']
Custom error message[ic_add_posts none_found='No Posts Found']
173 |

174 | 175 |

177 | 178 |

[shortcode] part with your, custom shortcode.', 'posts-in-page' ); ?>

179 | 180 |
<?php echo do_shortcode("[shortcode]"); ?>
181 |
182 | 183 | 184 |
185 | 186 | 187 |
188 | 189 | 190 |
191 | 192 | 193 | 194 |
195 | 196 |
197 | 198 |
199 | 200 |

201 | 202 | 203 |

204 | 205 |
206 |
207 |
208 |
209 |

Questions, bugs, or great ideas?

211 |
218 |
219 |
220 |
221 | 222 | 223 |
224 | 225 |
226 | 227 |

228 | 229 | 230 |

231 | 232 |
233 |
234 | 235 |
236 |
239 | 240 | 242 | 244 |
245 |
246 | 247 | 248 |
249 | 250 | 265 | 266 |
267 |
268 | 269 | 270 |
271 | 272 | 273 |
274 | 275 |

276 | 277 | 278 |

279 | 280 |
281 |
282 |

Help make this plugin better

283 | 296 |
297 |
298 | 299 | 300 |
301 | 302 |
303 | 304 |

305 | 306 | 307 |

308 | 309 |
310 |
311 | 313 | 320 |
321 |
322 | 323 | 324 |
325 | 326 |
327 | 328 | 329 |
330 | 331 | 332 |
333 | 334 | 335 |
336 |
337 | 338 | 339 |
340 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ivycat/posts-in-page", 3 | "description": "Easily add one or more posts to any page using simple shortcodes.", 4 | "keywords": ["wordpress", "posts-in-page"], 5 | "minimum-stability": "stable", 6 | "license": "GPL-2.0-or-later", 7 | "authors": [ 8 | { 9 | "name": "Eric Amundson", 10 | "email": "info@ivycat.com" 11 | } 12 | ], 13 | "require-dev": { 14 | "squizlabs/php_codesniffer": "3.4.0", 15 | "wp-coding-standards/wpcs": "^2.0", 16 | "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "110dc9c389812180ddd1381da351fa91", 8 | "content-hash": "2ac26eb4d49b3a3de65db8055665bd48", 9 | "packages": [], 10 | "packages-dev": [ 11 | { 12 | "name": "dealerdirect/phpcodesniffer-composer-installer", 13 | "version": "v0.5.0", 14 | "source": { 15 | "type": "git", 16 | "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", 17 | "reference": "e749410375ff6fb7a040a68878c656c2e610b132" 18 | }, 19 | "dist": { 20 | "type": "zip", 21 | "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/e749410375ff6fb7a040a68878c656c2e610b132", 22 | "reference": "e749410375ff6fb7a040a68878c656c2e610b132", 23 | "shasum": "" 24 | }, 25 | "require": { 26 | "composer-plugin-api": "^1.0", 27 | "php": "^5.3|^7", 28 | "squizlabs/php_codesniffer": "^2|^3" 29 | }, 30 | "require-dev": { 31 | "composer/composer": "*", 32 | "phpcompatibility/php-compatibility": "^9.0", 33 | "sensiolabs/security-checker": "^4.1.0" 34 | }, 35 | "type": "composer-plugin", 36 | "extra": { 37 | "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" 38 | }, 39 | "autoload": { 40 | "psr-4": { 41 | "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" 42 | } 43 | }, 44 | "notification-url": "https://packagist.org/downloads/", 45 | "license": [ 46 | "MIT" 47 | ], 48 | "authors": [ 49 | { 50 | "name": "Franck Nijhof", 51 | "email": "franck.nijhof@dealerdirect.com", 52 | "homepage": "http://www.frenck.nl", 53 | "role": "Developer / IT Manager" 54 | } 55 | ], 56 | "description": "PHP_CodeSniffer Standards Composer Installer Plugin", 57 | "homepage": "http://www.dealerdirect.com", 58 | "keywords": [ 59 | "PHPCodeSniffer", 60 | "PHP_CodeSniffer", 61 | "code quality", 62 | "codesniffer", 63 | "composer", 64 | "installer", 65 | "phpcs", 66 | "plugin", 67 | "qa", 68 | "quality", 69 | "standard", 70 | "standards", 71 | "style guide", 72 | "stylecheck", 73 | "tests" 74 | ], 75 | "time": "2018-10-26 13:21:45" 76 | }, 77 | { 78 | "name": "squizlabs/php_codesniffer", 79 | "version": "3.4.0", 80 | "source": { 81 | "type": "git", 82 | "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", 83 | "reference": "379deb987e26c7cd103a7b387aea178baec96e48" 84 | }, 85 | "dist": { 86 | "type": "zip", 87 | "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/379deb987e26c7cd103a7b387aea178baec96e48", 88 | "reference": "379deb987e26c7cd103a7b387aea178baec96e48", 89 | "shasum": "" 90 | }, 91 | "require": { 92 | "ext-simplexml": "*", 93 | "ext-tokenizer": "*", 94 | "ext-xmlwriter": "*", 95 | "php": ">=5.4.0" 96 | }, 97 | "require-dev": { 98 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" 99 | }, 100 | "bin": [ 101 | "bin/phpcs", 102 | "bin/phpcbf" 103 | ], 104 | "type": "library", 105 | "extra": { 106 | "branch-alias": { 107 | "dev-master": "3.x-dev" 108 | } 109 | }, 110 | "notification-url": "https://packagist.org/downloads/", 111 | "license": [ 112 | "BSD-3-Clause" 113 | ], 114 | "authors": [ 115 | { 116 | "name": "Greg Sherwood", 117 | "role": "lead" 118 | } 119 | ], 120 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", 121 | "homepage": "http://www.squizlabs.com/php-codesniffer", 122 | "keywords": [ 123 | "phpcs", 124 | "standards" 125 | ], 126 | "time": "2018-12-19 23:57:18" 127 | }, 128 | { 129 | "name": "wp-coding-standards/wpcs", 130 | "version": "2.0.0", 131 | "source": { 132 | "type": "git", 133 | "url": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git", 134 | "reference": "c9eaadaafefce36b3cb7e06eb15305b8c4cae9ce" 135 | }, 136 | "dist": { 137 | "type": "zip", 138 | "url": "https://api.github.com/repos/WordPress-Coding-Standards/WordPress-Coding-Standards/zipball/c9eaadaafefce36b3cb7e06eb15305b8c4cae9ce", 139 | "reference": "c9eaadaafefce36b3cb7e06eb15305b8c4cae9ce", 140 | "shasum": "" 141 | }, 142 | "require": { 143 | "php": ">=5.4", 144 | "squizlabs/php_codesniffer": "^3.3.1" 145 | }, 146 | "require-dev": { 147 | "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", 148 | "phpcompatibility/php-compatibility": "^9.0", 149 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" 150 | }, 151 | "suggest": { 152 | "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically." 153 | }, 154 | "type": "phpcodesniffer-standard", 155 | "notification-url": "https://packagist.org/downloads/", 156 | "license": [ 157 | "MIT" 158 | ], 159 | "authors": [ 160 | { 161 | "name": "Contributors", 162 | "homepage": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/graphs/contributors" 163 | } 164 | ], 165 | "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", 166 | "keywords": [ 167 | "phpcs", 168 | "standards", 169 | "wordpress" 170 | ], 171 | "time": "2019-01-16 10:13:16" 172 | } 173 | ], 174 | "aliases": [], 175 | "minimum-stability": "stable", 176 | "stability-flags": [], 177 | "prefer-stable": false, 178 | "prefer-lowest": false, 179 | "platform": [], 180 | "platform-dev": [] 181 | } 182 | -------------------------------------------------------------------------------- /includes/class-page-posts.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright Copyright (c) 2019, IvyCat, Inc. 8 | * @link https://ivycat.com 9 | * @since 1.0.0 10 | * @license GPL-2.0-or-later 11 | */ 12 | 13 | if ( ! function_exists( 'add_action' ) ) { 14 | wp_die( 'You are trying to access this file in a manner not allowed.', 'Direct Access Forbidden', array( 'response' => '403' ) ); 15 | } 16 | 17 | /** 18 | * Page in posts class. 19 | */ 20 | class ICPagePosts { 21 | /** 22 | * Arguments. 23 | * 24 | * @var array 25 | */ 26 | protected $args = array(); 27 | 28 | /** 29 | * Constructor method. 30 | * 31 | * @param array $atts Shortcode attributes. 32 | */ 33 | public function __construct( $atts ) { 34 | $this->set_default_args(); 35 | $this->set_args( $atts ); 36 | } 37 | 38 | /** 39 | * Set default arguments. 40 | */ 41 | protected function set_default_args() { 42 | $this->args = array( 43 | 'post_type' => 'post', 44 | 'post_status' => 'publish', 45 | 'orderby' => 'date', 46 | 'order' => 'DESC', 47 | 'paginate' => false, 48 | 'template' => false, 49 | 'label_next' => esc_html__( 'Next', 'posts-in-page' ), 50 | 'label_previous' => esc_html__( 'Previous', 'posts-in-page' ), 51 | 'end_size' => 1, 52 | 'mid_size' => 2, 53 | 'date_query' => '', 54 | 'none_found' => '', 55 | 'paged' => false, 56 | ); 57 | } 58 | 59 | /** 60 | * Spits out the posts, in a gentlemanly way. 61 | * 62 | * @return string Output of template file. 63 | */ 64 | public function output_posts() { 65 | global $wp_query; 66 | 67 | if ( ! $this->args ) { 68 | return ''; 69 | } 70 | 71 | if ( $this->args['paginate'] ) { 72 | if (get_query_var('paged')) { 73 | $this->args['paged'] = get_query_var('paged'); 74 | } elseif (get_query_var('page')) { 75 | $this->args['paged'] = get_query_var('page'); 76 | } else { 77 | $this->args['paged'] = 1; 78 | } 79 | } 80 | 81 | // Commandeering wp_query for pagination quirkiness. 82 | $temp = $wp_query; 83 | $wp_query = apply_filters( 'posts_in_page_results', new WP_Query( $this->args ) ); 84 | 85 | $output = ''; 86 | if ( have_posts() ) { 87 | while ( have_posts() ) { 88 | $output .= self::add_template_part( $wp_query ); 89 | } 90 | 91 | if ( $this->args['paginate'] ) { 92 | $output .= apply_filters( 'posts_in_page_paginate', $this->paginate_links() ); 93 | } 94 | } else { 95 | $output = '
' . esc_html( $this->args['none_found'] ) . '
'; 96 | } 97 | 98 | // Restore wp_query. 99 | $wp_query = $temp; 100 | unset( $temp ); 101 | wp_reset_query(); // phpcs:ignore WordPress.WP.DiscouragedFunctions.wp_reset_query_wp_reset_query 102 | remove_filter( 'excerpt_more', array( $this, 'custom_excerpt_more' ) ); 103 | 104 | return $output; 105 | } 106 | 107 | /** 108 | * Retrieve pagination links. 109 | * 110 | * @return string 111 | */ 112 | protected function paginate_links() { 113 | global $wp_query; 114 | $output = ''; 115 | $args_pagi = array( 116 | 'base' => add_query_arg( 'paged', '%#%' ), 117 | 'total' => $wp_query->max_num_pages, 118 | 'current' => $this->args['paged'], 119 | 'prev_next' => true, 120 | 'end_size' => $this->args['end_size'], 121 | 'mid_size' => $this->args['mid_size'], 122 | 'prev_text' => $this->args['label_previous'], 123 | 'next_text' => $this->args['label_next'] 124 | ); 125 | $output .= '
'; 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 ' ' . $more_tag . ''; 431 | } 432 | } 433 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /posts_in_page.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright Copyright (c) 2019, IvyCat, Inc. 8 | * @license GPL-2.0-or-later 9 | * 10 | * @wordpress-plugin 11 | * Plugin Name: Posts in Page 12 | * Plugin URI: https://ivycat.com/wordpress/wordpress-plugins/posts-in-page/ 13 | * Description: Easily add one or more posts to any page using simple shortcodes. Supports categories, tags, custom post types, custom taxonomies, and more. 14 | * Version: 1.4.6 15 | * Author: IvyCat, Inc. 16 | * Author URI: https://ivycat.com/wordpress/ 17 | * Text Domain: posts-in-page 18 | * License: GNU General Public License v2.0 19 | * License URI: https://www.gnu.org/licenses/gpl-2.0.html 20 | */ 21 | 22 | if ( ! function_exists( 'add_action' ) ) { 23 | wp_die( 'You are trying to access this file in a manner not allowed.', 'Direct Access Forbidden', array( 'response' => '403' ) ); 24 | } 25 | 26 | if ( ! defined( 'POSTSPAGE_DIR' ) ) { 27 | define( 'POSTSPAGE_DIR', plugin_dir_path( __FILE__ ) ); 28 | } 29 | 30 | if ( ! defined( 'POSTPAGE_URL' ) ) { 31 | define( 'POSTPAGE_URL', plugin_dir_url( __FILE__ ) ); 32 | } 33 | 34 | require_once 'includes/class-page-posts.php'; 35 | 36 | /** 37 | * Main plugin class. 38 | */ 39 | class ICAddPostsToPage { 40 | /** 41 | * Constructor method. 42 | */ 43 | public function __construct() { 44 | add_shortcode( 'ic_add_posts', array( $this, 'posts_in_page' ) ); 45 | add_shortcode( 'ic_add_post', array( $this, 'post_in_page' ) ); 46 | add_action( 'admin_menu', array( $this, 'plugin_page_init' ) ); 47 | add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'plugin_action_links' ), 10, 2 ); 48 | load_plugin_textdomain( 'posts-in-page' ); 49 | } 50 | 51 | /** 52 | * Add settings link on plugins page. 53 | * 54 | * @param string[] $actions An array of plugin action links. By default this can include 'activate', 55 | * 'deactivate', and 'delete'. 56 | * @param string $plugin_file Path to the plugin file relative to the plugins directory. 57 | * @return string 58 | */ 59 | public function plugin_action_links( $actions, $plugin_file ) { 60 | if ( is_plugin_active( $plugin_file ) ) { 61 | $actions[] = '' . esc_html__( ' Help', 'posts-in-page' ) . ''; 62 | } 63 | 64 | return apply_filters( 'post_in_page_actions', $actions ); 65 | } 66 | 67 | /** 68 | * Main shortcode. 69 | * 70 | * @param array $atts An array of shortcode parameters. None required. 71 | * @return array 72 | */ 73 | public function posts_in_page( $atts ) { 74 | $posts = new ICPagePosts( $atts ); 75 | 76 | return $posts->output_posts(); 77 | } 78 | 79 | /** 80 | * Deprecated shortcode (routing to posts in page function now). 81 | * 82 | * @deprecated Deprecated since 1.1.0. 83 | * 84 | * @param array $atts An array of shortcode parameters. None required. 85 | * @return array 86 | */ 87 | public function post_in_page( $atts ) { 88 | return self::posts_in_page( $atts ); 89 | } 90 | 91 | /** 92 | * Init plugin, add menu page, and setup hooks to load assets on the plugin options page. 93 | */ 94 | public function plugin_page_init() { 95 | $hook = add_options_page( 96 | esc_html__( 'Posts in Page', 'posts-in-page' ), 97 | esc_html__( 'Posts in Page', 'posts-in-page' ), 98 | 'manage_options', 99 | 'posts_in_page', 100 | array( $this, 'plugin_page' ) 101 | ); 102 | 103 | add_action( "admin_print_styles-{$hook}", array( $this, 'load_assets' ) ); 104 | } 105 | 106 | /** 107 | * Enqueue plugin assets (scripts & styles). 108 | */ 109 | public function load_assets() { 110 | wp_enqueue_style( 111 | 'postpagestyle', 112 | POSTPAGE_URL . 'admin/assets/css/post-page_styles.css', 113 | array(), 114 | '20190311' 115 | ); 116 | 117 | wp_enqueue_script( 118 | 'postpagescript', 119 | POSTPAGE_URL . 'admin/assets/js/post-page_scripts.js', 120 | array( 'jquery' ), 121 | '20190311', 122 | true 123 | ); 124 | } 125 | 126 | /** 127 | * Plugin Settings page - includes view for the page. 128 | */ 129 | public function plugin_page() { 130 | require_once 'admin/views/help-main.php'; 131 | } 132 | 133 | } 134 | 135 | /** 136 | * Instantiate the Plugin - called using the plugins_loaded action hook. 137 | */ 138 | function init_ic_posts_in_page() { 139 | new ICAddPostsToPage(); 140 | } 141 | 142 | add_action( 'plugins_loaded', 'init_ic_posts_in_page' ); 143 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | === Posts in Page === 2 | Contributors: ivycat, sewmyheadon, anvilzephyr, bradyvercher, jasonm4563, pjackson1972 3 | Tags: shortcode, pages, posts, custom post types, taxonomy, terms 4 | Requires at least: 3.0 5 | Tested up to: 5.6.1 6 | Stable tag: 1.4.6 7 | License: GPLv2 or later 8 | License URI: https://www.gnu.org/licenses/gpl-2.0.html 9 | 10 | Easily add one or more posts to any page using simple shortcodes. 11 | 12 | == Description == 13 | 14 | Easily add one or more posts to any page using simple shortcodes. 15 | 16 | Supports categories, tags, custom post types, custom taxonomies, date ranges, post status, and much more. 17 | 18 | You can get all of the same functionality provided by this plugin by modifying your theme's template files; this plugin just makes it easy for anyone to _pull_ posts into other areas of the site without having to get their hands dirty with code. 19 | 20 | Plugin is depending upon your theme's styling; version 1.x of this plugin _does not_ contain native styles. 21 | 22 | This is a minimal plugin, function over form. Give us feedback, suggestions, bug reports, and any other contributions on the in the plugin's [GitHub repository](https://github.com/ivycat/posts-in-page). 23 | 24 | == Installation == 25 | 26 | You can install from within WordPress using the Plugin/Add New feature, or if you wish to manually install: 27 | 28 | 1. Download the plugin. 29 | 1. Upload the entire `posts-in-page` directory to your plugins folder 30 | 1. Activate the plugin from the plugin page in your WordPress Dashboard 31 | 1. Start embedding posts in whatever pages you like using shortcodes. 32 | 33 | ### Shortcode Usage 34 | 35 | To 'pull' posts into a page, you can: 36 | 37 | 1. place a shortcode in the editor window of the page you're editing (Classic Editor), 38 | 1. place a shortcode in a shortcode block on the page you're editing (Gutenberg Editor), 39 | 1. modify a theme template file using the shortcode in a PHP function. 40 | 41 | #### Using Shortcodes in the WordPress editor 42 | 43 | * `[ic_add_posts]` - Add all posts to a page (limit to what number posts in WordPress is set to), essentially adds blog "page" to page. 44 | * `[ic_add_posts post_type='post_type']` - Show posts from a custom post type by specifying the post type slug (must give post type if not a standard post). Add multiple post types by separating with commas (ex. `post_type='post_type1,post_type2'`). 45 | * `[ic_add_posts showposts='5']` - Limit number of posts (or override default setting). 46 | * `[ic_add_posts orderby='title' order='ASC']` - Order the post output using `orderby` - supports all WP [orderby parameters](https://codex.wordpress.org/Class_Reference/WP_Query#Order_.26_Orderby_Parameters). Order is optional, default is 'DESC'. 47 | * `[ic_add_posts ids='1,2,3']` - Show one or many posts by specifying the post ID(s) (specify all post types). 48 | * `[ic_add_posts exclude_ids='4,5,6']` - Exclude specific post ID(s) from the query. 49 | * `[ic_add_posts category='category-slug']` - Show posts within a specific category by category slug. Separate multiple categories with commas. 50 | * `[ic_add_posts cats='2,13']` - Show posts within a specific category by category IDs. Separate multiple categories with commas. 51 | * `[ic_add_posts exclude_category='category-slug']` - Exclude posts within specific category. Uses slugs, can list multiple category slugs separated by commas. 52 | * `[ic_add_posts tag='tag-slug']` - Show posts using a specific tag. Like categories, it uses slugs, and can accommodate multiple tags separated by commas. 53 | * `[ic_add_posts tax='taxonomy' term='term']` - Limit posts to those that exist in a taxonomy and have a specific term. Both are required for either one to work and you must specify custom post_types. 54 | * `[ic_add_posts post_format='post-format-status']` - Select post formats. Use 'post-format-' followed by the format type (chat, aside, video, etc.). Use comma to separate post formats. To pull all posts with the quotes format, you'd use `[ic_add_posts post_format='post-format-quote']`. 55 | * `[ic_add_posts ignore_sticky_posts='no']` - Show sticky posts too (they're ignored by default). 56 | * `[ic_add_posts paginate='yes']` - Use pagination links (off by default). 57 | * `[ic_add_posts label_next='Next' label_previous='Previous']` - Customize 'Next' and 'Previous' labels used by pagination. 58 | * `[ic_add_posts post_status='private']` - Show posts with the specified status. By default it shows only posts with 'publish' status. To select multiple statuses, separate them with commas like so: `post_status='private,publish'`. 59 | * `[ic_add_posts more_tag='Read more']` - Set the link text for read more links shown after an excerpt. 60 | * `[ic_add_posts date='today-1']` - Choose the relative date of included posts. Supports formatting like `date='today-1'` (today minus 1 day), `date='week-2'` (today minus 2 weeks), `date='month-1'` (today minus 1 month), `date='year-1'` (today minus 1 year). 61 | * `[ic_add_posts from_date='15-01-2016' to_date='31-12-2016']` - Shows posts published within a specified absolute date range. 62 | * `[ic_add_posts offset='3']` - Displays posts after the offset. An `offset='3'` will show all posts from the 4th one back. 63 | * `[ic_add_posts none_found='No Posts Found']` - Custom message to display when no posts are found. 64 | * `[ic_add_posts template='template-in-theme-dir.php']` - In case you want to style your markup, add meta data, etc. Each shortcode can reference a different template. These templates must exist in the theme directory or in a sub-directory named _posts-in-page_. 65 | 66 | Or any combination of the above. 67 | 68 | #### Shortcode Examples 69 | 70 | Not sure how to use the shortcodes above to get what you want? Here are a few examples to get you started: 71 | 72 | ** Example 1 ** 73 | 74 | Let's say you want to pull a specific post called _"What I love about coffee"_, which has a post ID of 34, somewhere on your About Us page. Your shortcode should look like this: 75 | 76 | `[ic_add_posts ids='34']` 77 | 78 | ** Example 2 ** 79 | 80 | Alright, now let's say that you want to pull in all posts from two categories into your WordPress page. One category is _WordPress Rocks_ and the other is _WordPress Rolls_. Plus, you'd like to display them three per page, rather than the default number of posts. Depending on your category slugs, your shortcode should probably look like this: 81 | 82 | `[ic_add_posts category='wordpress-rocks,wordpress-rolls' showposts='3']` 83 | 84 | ** Example 3 ** 85 | 86 | Now, you're ambitious and want to try something complex. Let's say you've got a page called _Plugins Are Awesome_ and, in it, you want to pull in posts that match the following criteria: 87 | 88 | * posts from a custom post type called _Testimonials_, 89 | * posts that are in the _Testimonial Type_ custom taxonomy using the term _Customer_, 90 | * you want to display six testimonials per page, 91 | * you'd like them displayed in ascending order, 92 | * finally, you've created a custom template to use in presenting these posts and named it `my-posts-in-page-template.php`. 93 | 94 | Your shortcode might look like this: 95 | 96 | `[ic_add_posts showposts='6' post_type='testimonials' tax='testimonial-type' term='customer' order='ASC' template='my-posts-in-page-template.php']` 97 | 98 | #### Using Shortcodes within a PHP function 99 | 100 | If you'd like to use this plugin to pull posts directly into your theme's template files, you can drop the following WordPress function in your template files, replacing the `[shortcode]` part with your, custom shortcode. 101 | 102 | `` 103 | 104 | ### Developer Hooks 105 | 106 | There are several hooks you can use to filter the output of your template files: 107 | 108 | * `posts_in_page_results` - Filter results 109 | * `posts_in_page_args` - Filter the query arguments 110 | * `posts_in_page_paginate` - Filter pagination 111 | * `posts_in_page_pre_loop` - Runs right before the loop (posts_loop_template.php) 112 | * `posts_in_page_post_loop` - Runs right after the loop 113 | 114 | == Frequently Asked Questions == 115 | 116 | = What is the point of this plugin? = 117 | 118 | Posts in Page makes it easy to output or embed the posts, pages, or custom post types in any page without modifying WordPress theme templates. 119 | 120 | = Does it work with Gutenberg? = 121 | 122 | Absolutely. Just use a Gutenberg Shortcode block or the Classic Edit block to add your shortcode. 123 | 124 | = Wait! The posts aren't styled like the posts on the rest of my site. 125 | 126 | That is likely true. Currently, Posts in Page doesn't output any styles; just some basic markup. To change how the posts appear on the page, you'll need to change the _output template_. 127 | 128 | = How do I change the output template? = 129 | 130 | Simply copy the `posts_loop_template.php` to your theme directory and make changes as necessary. 131 | 132 | You can even rename it - but make sure to indicate that in the shortcode using the `template='my-new-template-name.php'`. 133 | 134 | For file housekeeping, you can also create a _posts-in-page_ folder in your theme to store all of your custom templates. It isn't necessary to specify the _posts-in-page_ folder in your shortcode - Posts in Page will find it automatically. 135 | You can even use multiple templates for use with different shortcodes. 136 | 137 | = Does it work with custom post types? = 138 | 139 | Absolutely. 140 | 141 | = Does it work with custom taxonomies? 142 | 143 | You bet. 144 | 145 | = Will it make me coffee? = 146 | 147 | Not likely, but let us know if it does; then we'll *know* we have something special. 148 | 149 | = How can I help? = 150 | 151 | We'd love feedback, issues, pull requests, and ideas on the [Posts in Page GitHub repo](https://github.com/ivycat/posts-in-page). 152 | 153 | == Screenshots == 154 | 155 | 1. Embed a shortcode into a page, and it will automatically pull in the post(s) you need. 156 | 2. Embed shortcode using a Gutenberg shortcode block. 157 | 3. Embed shortcodes directly in your template using `do_shortcode`. 158 | 159 | == Changelog == 160 | 161 | = 1.4.4 = 162 | * Fix issue to prevent fatal errors caused by setting the global query to null. 163 | 164 | = 1.4.3 = 165 | * Fix issue with missing wrapping pagination div. 166 | * Fix a few `esc_html_e` instances. 167 | 168 | = 1.4.2 = 169 | * Thanks to Brady Vercher (@bradyvercher) for the thorough code review and fixes. 170 | * Cleanup code to better conform to WP Coding standards and remove legacy cruft. 171 | * PHPCS configuration. 172 | * Update docblock and comments. 173 | * Remove legacy i18n code. 174 | * Escaping output of URLs, translation strings, and more. 175 | * Updated enqueueing to add version for cache busting, add missing jQuery dependency, load admin script in footer. 176 | 177 | = 1.4.1 = 178 | * Fix wp_reset_query bug 179 | * Patch pagination to make it more reliable across themes. 180 | 181 | = 1.4.0 = 182 | * Add templates folder to structure and moved default template there. 183 | * Fix pagination issues #42, 59. 184 | * Fix bug preventing including or excluding multiple post_types or categories. 185 | * Add a few new date-based shortcode arguments including `date=` and `from_date=` and `to_date=`. 186 | * Document post format support, new shortcode arguments. 187 | * Code cleanup. 188 | * Updates to admin page layout and documentation. 189 | 190 | = 1.3.1 = 191 | * File header housekeeping. 192 | * Code cleanup. 193 | * Fix WPML compatibility issue (thanks @azrall). 194 | * Document new shortcode functions including `exclude_ids`, `more_tag`. 195 | 196 | = 1.3.0 = 197 | * File reorganization / housekeeping. 198 | * Admin UI cleanup. 199 | * Security: Fixed [directory traversal vulnerability](https://www.pluginvulnerabilities.com/2017/02/13/authenticated-local-file-inclusion-lfi-vulnerability-in-posts-in-page/). 200 | * Added ability to optionally include private posts - Thanks, StarsoftAnalysis! 201 | 202 | = 1.2.4 = 203 | * now you can set `more_tag=""` to remove the `[...] …` that unfortunetly shows up as `&hellip`. 204 | 205 | = 1.2.3 = 206 | * Added minor doc tweaks. 207 | 208 | = 1.2.2 = 209 | * Added pagination, tweaked to turn off by default. 210 | * Bug fixes. 211 | 212 | = 1.2.1 = 213 | * Added code to allow ignoring, or showing of sticky posts. By default, sticky posts are ignored, but can be re-enabled using the shortcode `[ic_add_posts ignore_sticky_posts='no']`. 214 | 215 | = 1.2.0 = 216 | * Code maintenance to better comply with standards. 217 | * Added post pagination. 218 | * Plugin now honors default post reading settings under Settings/Reading in the WordPress Dashboard. 219 | * Improved and simplified documentation. 220 | 221 | = 1.1.1 = 222 | * Code maintenance, fix for category bug, also added the ability for multiple post types per shortcode. 223 | 224 | = 1.1.0 = 225 | * Code maintenance, squash non-critical debug notices. 226 | 227 | = 1.0.10 = 228 | * Added check for published/private posts. 229 | 230 | = 1.0.9 = 231 | * Fixed template bug introduced by comments. 232 | 233 | = 1.0.8 = 234 | * Code cleanup & indentation. 235 | * Added comments and notes to output template file: `posts_loop_template.php`. 236 | 237 | = 1.0.7 = 238 | * Added Help Page under Setting in WP Dashboard. 239 | 240 | = 1.0.6 = 241 | * More plugin housekeeping. 242 | 243 | = 1.0.4 = 244 | * Minor housekeeping, added author, updated readme.txt. 245 | 246 | = 1.0.3 = 247 | * Added single post or specific post capabilities. 248 | 249 | == Upgrade Notice == 250 | 251 | = 1.4.4 = 252 | * Bug fix - please upgrade for stability. 253 | 254 | = 1.4.3 = 255 | * Pagination bug fix and two minor i18n updates for translatable strings. Please upgrade. 256 | 257 | = 1.4.2 = 258 | * Code review, cleanup. Minor fixes and security updates. Please upgrade. 259 | 260 | = 1.4.1 = 261 | * Critical bug fixes. Please upgrade. 262 | 263 | = 1.4.0 = 264 | * Bug fixes, new shortcodes, and code improvements. Please upgrade. 265 | 266 | = 1.3.0 = 267 | * Important security and version updates. Please upgrade. 268 | 269 | = 1.2.4 = 270 | * Presentational fixes: clean up whitespace, extra tabs, add in customization of more tag. 271 | 272 | = 1.2.3 = 273 | * Housekeeping only; not urgent. 274 | 275 | = 1.2.2 = 276 | * Small bug fixes for tags, pagination; not critical. 277 | 278 | = 1.2.1 = 279 | * Small feature update, not critical. 280 | 281 | = 1.2.0 = 282 | * Important feature update - please upgrade. 283 | 284 | = 1.1.1 = 285 | * Small bug fix; please upgrade. 286 | 287 | = 1.1.0 = 288 | * Code maintenance & housekeeping - non-critical update. 289 | 290 | = 1.0.10 = 291 | * Added feature - non-critical update. 292 | 293 | = 1.0.9 = 294 | * Fixed template bug - please update. 295 | 296 | = 1.0.8 = 297 | * Added features and documentation - non-critical update. 298 | 299 | = 1.0.7 = 300 | * Added Help Page - non-critical update. 301 | 302 | = 1.0.6 = 303 | * Plugin housekeeping - non-critical update. 304 | 305 | = 1.0.4 = 306 | * Minor housekeeping, added author, updated readme.txt. Non-critical update. 307 | 308 | = 1.0.3 = 309 | * Added single post or specific post capabilities. Important feature. 310 | -------------------------------------------------------------------------------- /templates/posts_loop_template.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright Copyright (c) 2019, IvyCat, Inc. 8 | * @link https://ivycat.com 9 | * @since 1.0.0 10 | * @license GPL-2.0-or-later 11 | */ 12 | 13 | ?> 14 | 15 | 17 | 18 | 19 |
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 | 67 | 74 | 75 | | ', '' ); ?> 76 |
77 |
78 | 79 | --------------------------------------------------------------------------------