PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/exclude-pages/exclude_pages.php

https://gitlab.com/blueprintmrk/bladencountyrecords
PHP | 371 lines | 185 code | 32 blank | 154 comment | 31 complexity | e9efa3bab941688b3aa7fda4007a6029 MD5 | raw file
  1. <?php
  2. /*
  3. Plugin Name: Exclude Pages from Navigation
  4. Plugin URI: http://wordpress.org/extend/plugins/exclude-pages/
  5. Description: Provides a checkbox on the editing page which you can check to exclude pages from the primary navigation. IMPORTANT NOTE: This will remove the pages from any "consumer" side page listings, which may not be limited to your page navigation listings.
  6. Version: 1.9
  7. Author: Simon Wheatley
  8. Author URI: http://simonwheatley.co.uk/wordpress/
  9. Copyright 2007 Simon Wheatley
  10. This script is free software; you can redistribute it and/or modify
  11. it under the terms of the GNU General Public License as published by
  12. the Free Software Foundation; either version 3 of the License, or
  13. (at your option) any later version.
  14. This script is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. GNU General Public License for more details.
  18. You should have received a copy of the GNU General Public License
  19. along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. // Full filesystem path to this dir
  22. define('EP_PLUGIN_DIR', dirname(__FILE__));
  23. // Option name for exclusion data
  24. define('EP_OPTION_NAME', 'ep_exclude_pages');
  25. // Separator for the string of IDs stored in the option value
  26. define('EP_OPTION_SEP', ',');
  27. // The textdomain for the WP i18n gear
  28. define( 'EP_TD', 'exclude-pages' );
  29. // Take the pages array, and return the pages array without the excluded pages
  30. // Doesn't do this when in the admin area
  31. function ep_exclude_pages( $pages ) {
  32. // If the URL includes "wp-admin", just return the unaltered list
  33. // This constant, WP_ADMIN, only came into WP on 2007-12-19 17:56:16 rev 6412, i.e. not something we can rely upon unfortunately.
  34. // May as well check it though.
  35. // Also check the URL... let's hope they haven't got a page called wp-admin (probably not)
  36. // SWTODO: Actually, you can create a page with an address of wp-admin (which is then inaccessible), I consider this a bug in WordPress (which I may file a report for, and patch, another time).
  37. $bail_out = ( ( defined( 'WP_ADMIN' ) && WP_ADMIN == true ) || ( strpos( $_SERVER[ 'PHP_SELF' ], 'wp-admin' ) !== false ) );
  38. $bail_out = apply_filters( 'ep_admin_bail_out', $bail_out );
  39. if ( $bail_out ) return $pages;
  40. $excluded_ids = ep_get_excluded_ids();
  41. $length = count($pages);
  42. // Ensure we catch all descendant pages, so that if a parent
  43. // is hidden, it's children are too.
  44. for ( $i=0; $i<$length; $i++ ) {
  45. $page = & $pages[$i];
  46. // If one of the ancestor pages is excluded, add it to our exclude array
  47. if ( ep_ancestor_excluded( $page, $excluded_ids, $pages ) ) {
  48. // Can't actually delete the pages at the moment,
  49. // it'll screw with our recursive search.
  50. // For the moment, just tag the ID onto our excluded IDs
  51. $excluded_ids[] = $page->ID;
  52. }
  53. }
  54. // Ensure the array only has unique values
  55. $delete_ids = array_unique( $excluded_ids );
  56. // Loop though the $pages array and actually unset/delete stuff
  57. for ( $i=0; $i<$length; $i++ ) {
  58. $page = & $pages[$i];
  59. // If one of the ancestor pages is excluded, add it to our exclude array
  60. if ( in_array( $page->ID, $delete_ids ) ) {
  61. // Finally, delete something(s)
  62. unset( $pages[$i] );
  63. }
  64. }
  65. // Reindex the array, for neatness
  66. // SWFIXME: Is reindexing the array going to create a memory optimisation problem for large arrays of WP post/page objects?
  67. if ( ! is_array( $pages ) ) $pages = (array) $pages;
  68. $pages = array_values( $pages );
  69. return $pages;
  70. }
  71. /**
  72. * Recurse down an ancestor chain, checking if one is excluded
  73. *
  74. * @param
  75. * @return boolean|int The ID of the "nearest" excluded ancestor, otherwise false
  76. * @author Simon Wheatley
  77. **/
  78. function ep_ancestor_excluded( $page, $excluded_ids, $pages ) {
  79. $parent = & ep_get_page( $page->post_parent, $pages );
  80. // Is there a parent?
  81. if ( ! $parent )
  82. return false;
  83. // Is it excluded?
  84. if ( in_array( $parent->ID, $excluded_ids ) )
  85. return (int) $parent->ID;
  86. // Is it the homepage?
  87. if ( $parent->ID == 0 )
  88. return false;
  89. // Otherwise we have another ancestor to check
  90. return ep_ancestor_excluded( $parent, $excluded_ids, $pages );
  91. }
  92. /**
  93. * {no description}
  94. *
  95. * @param int $page_id The ID of the WP page to search for
  96. * @param array $pages An array of WP page objects
  97. * @return boolean|object the page from the $pages array which corresponds to the $page_id
  98. * @author Simon Wheatley
  99. **/
  100. function ep_get_page( $page_id, $pages ) {
  101. // PHP 5 would be much nicer here, we could use foreach by reference, ah well.
  102. $length = count($pages);
  103. for ( $i=0; $i<$length; $i++ ) {
  104. $page = & $pages[$i];
  105. if ( $page->ID == $page_id ) return $page;
  106. }
  107. // Unusual.
  108. return false;
  109. }
  110. // Is this page we're editing (defined by global $post_ID var)
  111. // currently NOT excluded (i.e. included),
  112. // returns true if NOT excluded (i.e. included)
  113. // returns false is it IS excluded.
  114. // (Tricky this upside down flag business.)
  115. function ep_this_page_included() {
  116. global $post_ID;
  117. // New post? Must be included then.
  118. if ( ! $post_ID ) return true;
  119. $excluded_ids = ep_get_excluded_ids();
  120. // If there's no exclusion array, we can return true
  121. if ( empty($excluded_ids) ) return true;
  122. // Check if our page is in the exclusion array
  123. // The bang (!) reverses the polarity [1] of the boolean
  124. return ! in_array( $post_ID, $excluded_ids );
  125. // fn1. (of the neutron flow, ahem)
  126. }
  127. // Check the ancestors for the page we're editing (defined by
  128. // global $post_ID var), return the ID if the nearest one which
  129. // is excluded (if any);
  130. function ep_nearest_excluded_ancestor() {
  131. global $post_ID, $wpdb;
  132. // New post? No problem.
  133. if ( ! $post_ID ) return false;
  134. $excluded_ids = ep_get_excluded_ids();
  135. // Manually get all the pages, to avoid our own filter.
  136. $sql = "SELECT ID, post_parent FROM $wpdb->posts WHERE post_type = 'page'";
  137. $pages = $wpdb->get_results( $sql );
  138. // Start recursively checking the ancestors
  139. $parent = ep_get_page( $post_ID, $pages );
  140. return ep_ancestor_excluded( $parent, $excluded_ids, $pages );
  141. }
  142. function ep_get_excluded_ids() {
  143. $exclude_ids_str = get_option( EP_OPTION_NAME );
  144. // No excluded IDs? Return an empty array
  145. if ( empty($exclude_ids_str) ) return array();
  146. // Otherwise, explode the separated string into an array, and return that
  147. return explode( EP_OPTION_SEP, $exclude_ids_str );
  148. }
  149. // This function gets all the exclusions out of the options
  150. // table, updates them, and resaves them in the options table.
  151. // We're avoiding making this a postmeta (custom field) because we
  152. // don't want to have to retrieve meta for every page in order to
  153. // determine if it's to be excluded. Storing all the exclusions in
  154. // one row seems more sensible.
  155. function ep_update_exclusions( $post_ID ) {
  156. // Bang (!) to reverse the polarity of the boolean, turning include into exclude
  157. $exclude_this_page = ! (bool) $_POST['ep_this_page_included'];
  158. // SWTODO: Also check for a hidden var, which confirms that this checkbox was present
  159. // If hidden var not present, then default to including the page in the nav (i.e. bomb out here rather
  160. // than add the page ID to the list of IDs to exclude)
  161. $ctrl_present = (bool) @ $_POST['ep_ctrl_present'];
  162. if ( ! $ctrl_present ) return;
  163. $excluded_ids = ep_get_excluded_ids();
  164. // If we need to EXCLUDE the page from the navigation...
  165. if ( $exclude_this_page ) {
  166. // Add the post ID to the array of excluded IDs
  167. array_push( $excluded_ids, $post_ID );
  168. // De-dupe the array, in case it was there already
  169. $excluded_ids = array_unique( $excluded_ids );
  170. }
  171. // If we need to INCLUDE the page in the navigation...
  172. if ( ! $exclude_this_page ) {
  173. // Find the post ID in the array of excluded IDs
  174. $index = array_search( $post_ID, $excluded_ids );
  175. // Delete any index found
  176. if ( $index !== false ) unset( $excluded_ids[$index] );
  177. }
  178. $excluded_ids_str = implode( EP_OPTION_SEP, $excluded_ids );
  179. ep_set_option( EP_OPTION_NAME, $excluded_ids_str, __( "Comma separated list of post and page IDs to exclude when returning pages from the get_pages function.", "exclude-pages" ) );
  180. }
  181. // Take an option, delete it if it exists, then add it.
  182. function ep_set_option( $name, $value, $description ) {
  183. // Delete option
  184. delete_option($name);
  185. // Insert option
  186. add_option($name, $value, $description);
  187. }
  188. /**
  189. * Callback function for the metabox on the page edit screen.
  190. *
  191. * @return void
  192. * @author Simon Wheatley
  193. **/
  194. function ep_admin_sidebar_wp25() {
  195. $nearest_excluded_ancestor = ep_nearest_excluded_ancestor();
  196. echo ' <div id="excludepagediv" class="new-admin-wp25">';
  197. echo ' <div class="outer"><div class="inner">';
  198. echo ' <p><label for="ep_this_page_included" class="selectit">';
  199. echo ' <input ';
  200. echo ' type="checkbox" ';
  201. echo ' name="ep_this_page_included" ';
  202. echo ' id="ep_this_page_included" ';
  203. if ( ep_this_page_included() )
  204. echo 'checked="checked"';
  205. echo ' />';
  206. echo ' '.__( 'Include this page in lists of pages', EP_TD ).'</label>';
  207. echo ' <input type="hidden" name="ep_ctrl_present" value="1" /></p>';
  208. if ( $nearest_excluded_ancestor !== false ) {
  209. echo '<p class="ep_exclude_alert"><em>';
  210. printf( __( 'N.B. An ancestor of this page is excluded, so this page is too (<a href="%1$s" title="%2$s">edit ancestor</a>).', EP_TD), "post.php?action=edit&amp;post=$nearest_excluded_ancestor", __( 'edit the excluded ancestor', EP_TD ) );
  211. echo '</em></p>';
  212. }
  213. // If there are custom menus (WP 3.0+) then we need to clear up some
  214. // potential confusion here.
  215. if ( ep_has_menu() ) {
  216. echo '<p id="ep_custom_menu_alert"><em>';
  217. if ( current_user_can( 'edit_theme_options' ) )
  218. printf( __( 'N.B. This page can still appear in explicitly created <a href="%1$s">menus</a> (<a id="ep_toggle_more" href="#ep_explain_more">explain more</a>)', EP_TD),
  219. "nav-menus.php" );
  220. else
  221. _e( 'N.B. This page can still appear in explicitly created menus (<a id="ep_toggle_more" href="#ep_explain_more">explain more</a>)', EP_TD);
  222. echo '</em></p>';
  223. echo '<div id="ep_explain_more"><p>';
  224. if ( current_user_can( 'edit_theme_options' ) )
  225. printf( __( 'WordPress provides a simple function for you to maintain your site <a href="%1$s">menus</a>. If you create a menu which includes this page, the checkbox above will not have any effect on the visibility of that menu item.', EP_TD),
  226. "nav-menus.php" );
  227. else
  228. _e( 'WordPress provides a simple function for you to maintain the site menus, which your site administrator is using. If a menu includes this page, the checkbox above will not have any effect on the visibility of that menu item.', EP_TD);
  229. echo '</p><p>';
  230. echo _e( 'If you think you no longer need the Exclude Pages plugin you should talk to your WordPress administrator about disabling it.', EP_TD );
  231. echo '</p></div>';
  232. }
  233. echo ' </div><!-- .inner --></div><!-- .outer -->';
  234. echo ' </div><!-- #excludepagediv -->';
  235. }
  236. /**
  237. * A conditional function to determine whether there are any menus
  238. * defined in this WordPress installation.
  239. *
  240. * @return bool Indicates the presence or absence of menus
  241. * @author Simon Wheatley
  242. **/
  243. function ep_has_menu() {
  244. if ( ! function_exists( 'wp_get_nav_menus' ) )
  245. return false;
  246. $menus = wp_get_nav_menus();
  247. foreach ( $menus as $menu_maybe ) {
  248. if ( $menu_items = wp_get_nav_menu_items($menu_maybe->term_id) )
  249. return true;
  250. }
  251. }
  252. /**
  253. * Hooks the WordPress admin_head action to inject some CSS.
  254. *
  255. * @return void
  256. * @author Simon Wheatley
  257. **/
  258. function ep_admin_css() {
  259. echo <<<END
  260. <style type="text/css" media="screen">
  261. .ep_exclude_alert { font-size: 11px; }
  262. .new-admin-wp25 { font-size: 11px; background-color: #fff; }
  263. .new-admin-wp25 .inner { padding: 8px 12px; background-color: #EAF3FA; border: 1px solid #EAF3FA; -moz-border-radius: 3px; -khtml-border-bottom-radius: 3px; -webkit-border-bottom-radius: 3px; border-bottom-radius: 3px; }
  264. #ep_admin_meta_box .inner { padding: inherit; background-color: transparent; border: none; }
  265. #ep_admin_meta_box .inner label { background-color: none; }
  266. .new-admin-wp25 .exclude_alert { padding-top: 5px; }
  267. .new-admin-wp25 .exclude_alert em { font-style: normal; }
  268. </style>
  269. END;
  270. }
  271. /**
  272. * Hooks the WordPress admin_head action to inject some JS.
  273. *
  274. * @return void
  275. * @author Simon Wheatley
  276. **/
  277. function ep_admin_js() {
  278. echo <<<END
  279. <script type="text/javascript">
  280. //<![CDATA[
  281. jQuery( '#ep_explain_more' ).hide();
  282. jQuery( '#ep_toggle_more' ).click( function() {
  283. jQuery( '#ep_explain_more' ).toggle();
  284. return false;
  285. } );
  286. //]]>
  287. </script>
  288. END;
  289. }
  290. // Add our ctrl to the list of controls which AREN'T hidden
  291. function ep_hec_show_dbx( $to_show ) {
  292. array_push( $to_show, 'excludepagediv' );
  293. return $to_show;
  294. }
  295. // PAUSE & RESUME FUNCTIONS
  296. function pause_exclude_pages() {
  297. remove_filter('get_pages','ep_exclude_pages');
  298. }
  299. function resume_exclude_pages() {
  300. add_filter('get_pages','ep_exclude_pages');
  301. }
  302. // INIT FUNCTIONS
  303. function ep_init() {
  304. // Call this function on the get_pages filter
  305. // (get_pages filter appears to only be called on the "consumer" side of WP,
  306. // the admin side must use another function to get the pages. So we're safe to
  307. // remove these pages every time.)
  308. add_filter('get_pages','ep_exclude_pages');
  309. // Load up the translation gear
  310. $locale = get_locale();
  311. $folder = rtrim( basename( dirname( __FILE__ ) ), '/' );
  312. $mo_file = trailingslashit( WP_PLUGIN_DIR ) . "$folder/locale/" . EP_TD . "-$locale.mo";
  313. load_textdomain( EP_TD, $mo_file );
  314. }
  315. function ep_admin_init() {
  316. // Add panels into the editing sidebar(s)
  317. global $wp_version;
  318. add_meta_box('ep_admin_meta_box', __( 'Exclude Pages', EP_TD ), 'ep_admin_sidebar_wp25', 'page', 'side', 'low');
  319. // Set the exclusion when the post is saved
  320. add_action('save_post', 'ep_update_exclusions');
  321. // Add the JS & CSS to the admin header
  322. add_action('admin_head', 'ep_admin_css');
  323. add_action('admin_footer', 'ep_admin_js');
  324. // Call this function on our very own hec_show_dbx filter
  325. // This filter is harmless to add, even if we don't have the
  326. // Hide Editor Clutter plugin installed as it's using a custom filter
  327. // which won't be called except by the HEC plugin.
  328. // Uncomment to show the control by default
  329. // add_filter('hec_show_dbx','ep_hec_show_dbx');
  330. }
  331. // HOOK IT UP TO WORDPRESS
  332. add_action( 'init', 'ep_init' );
  333. add_action( 'admin_init', 'ep_admin_init' )
  334. ?>