ProShell v2.0
Dashboard
Server Info
Server: 158.106.128.192
PHP: 8.2.33
home
planet5
public_html
bansibaba.com
wp-includes
2026-09-17 15:55:09
Editing: any-post.php
Cancel
Save Changes
<?php /** * The manager to rule all (post) managers. * * This class dynamically registers container modules for the available post types * (including custom post types) and does stuff that pertain to all of them, such * as handling save/delete hooks and (re)creating synch records. * * @package Broken Link Checker * @author Janis Elsts * @access private */ class blcPostTypeOverlord { public $enabled_post_types = array(); //Post types currently selected for link checking public $enabled_post_statuses = array( 'publish' ); //Only posts that have one of these statuses shall be checked var $plugin_conf; var $resynch_already_done = false; /** * Class "constructor". Can't use an actual constructor due to how PHP4 handles object references. * * Specifically, this class is a singleton. The function needs to pass $this to several other * functions (to set up hooks), which will store the reference for later use. However, it appears * that in PHP4 the actual value of $this is thrown away right after the constructor finishes, and * `new` returns a *copy* of $this. The result is that getInstance() won't be returning a ref. * to the same object as is used for hook callbacks. And that's horrible. * * Sets up hooks that monitor added/modified/deleted posts and registers * virtual modules for all post types. * * @return void */ function init() { $this->plugin_conf = blc_get_configuration(); if ( isset( $this->plugin_conf->options['enabled_post_statuses'] ) ) { $this->enabled_post_statuses = $this->plugin_conf->options['enabled_post_statuses']; } //Register a virtual container module for each enabled post type $module_manager = blcModuleManager::getInstance(); $post_types = get_post_types( array(), 'objects' ); $exceptions = array( 'revision', 'nav_menu_item', 'attachment' ); foreach ( $post_types as $data ) { $post_type = $data->name; if ( in_array( $post_type, $exceptions ) ) { continue; } $module_manager->register_virtual_module( $post_type, array( 'Name' => $data->labels->name, 'ModuleCategory' => 'container', 'ModuleContext' => 'all', 'ModuleClassName' => 'blcAnyPostContainerManager', ) ); } if ( ! WPMUDEV_BLC\App\Options\Settings\Model::instance()->get( 'use_legacy_blc_version' ) ) { if ( ! WPMUDEV_BLC\Core\Utils\Utilities::is_subsite() ) { return; } //return; } //These hooks update the synch & instance records when posts are added, deleted or modified. add_action( 'delete_post', array( &$this, 'post_deleted' ) ); add_action( 'save_post', array( &$this, 'post_saved' ) ); //We also treat post trashing/untrashing as delete/save. add_action( 'trashed_post', array( &$this, 'post_deleted' ) ); add_action( 'untrash_post', array( &$this, 'post_saved' ) ); //Highlight and nofollow broken links in posts & pages // Only do this for logged-in users to avoid issues for regular visitors. if ( is_user_logged_in() && ( $this->plugin_conf->options['mark_broken_links'] || $this->plugin_conf->options['nofollow_broken_links'] ) ) { add_filter( 'the_content', array( &$this, 'hook_the_content' ) ); if ( $this->plugin_conf->options['mark_broken_links'] && ! empty( $this->plugin_conf->options['broken_link_css'] ) ) { add_action( 'wp_head', array( &$this, 'hook_wp_head' ) ); } } } /** * Retrieve an instance of the overlord class. * * @return blcPostTypeOverlord */ static function getInstance() { static $instance = null; if ( is_null( $instance ) ) { $instance = new blcPostTypeOverlord; $instance->init(); } return $instance; } /** * Notify the overlord that a post type is active. * * Called by individual instances of blcAnyPostContainerManager to let * the overlord know that they've been created. Since a module instance * is only created if the module is active, this event indicates that * the user has enabled the corresponding post type for link checking. * * @param string $post_type * @return void */ function post_type_enabled( $post_type ) { if ( ! in_array( $post_type, $this->enabled_post_types ) ) { $this->enabled_post_types[] = $post_type; } } /** * Remove the synch. record and link instances associated with a post when it's deleted * * @param int $post_id * @return void */ function post_deleted( $post_id ) { global $wpdb; $post_id = intval( $post_id ); //Get the container type matching the type of the deleted post $post = get_post( $post_id ); if ( ! $post ) { return; } //Get the associated container object $post_type = get_post_type( $post ); $post_container = blcContainerHelper::get_container( array( $post_type, $post_id ) ); if ( $post_container ) { //Delete the container $post_container->delete(); // Firstly: See if we have any current instances $q_current_instance_ids = $wpdb->prepare( 'SELECT instance_id FROM `' . $wpdb->prefix . 'blc_instances` WHERE container_id = %d AND container_type = %s', $post_id, $post_type ); $current_instance_ids_results = $wpdb->get_results( $q_current_instance_ids, ARRAY_A ); if ( $wpdb->num_rows == 0 ) { // No current instances present, skip cleanup at once return; } $current_instance_ids = wp_list_pluck( $current_instance_ids_results, 'instance_id' ); // Secondly: Get all link_ids used in our current instances $q_current_link_ids = 'SELECT DISTINCT link_id FROM `' . $wpdb->prefix . 'blc_instances` WHERE instance_id IN (\'' . implode( "', '", $current_instance_ids ) . '\')'; $q_current_link_ids_results = $wpdb->get_results( $q_current_link_ids, ARRAY_A ); $current_link_ids = wp_list_pluck( $q_current_link_ids_results, 'link_id' ); // Go ahead and remove blc_instances for this container, blc_cleanup_links( $current_link_ids ) will find and remove any dangling links in the blc_links table $wpdb->query( 'DELETE FROM `' . $wpdb->prefix . 'blc_instances` WHERE instance_id IN (\'' . implode( "', '", $current_instance_ids ) . '\')' ); //Clean up any dangling links blc_cleanup_links( $current_link_ids ); } } /** * When a post is saved or modified, mark it as unparsed. * * @param int $post_id * @return void */ function post_saved( $post_id ) { //Get the container type matching the type of the deleted post $post = get_post( $post_id ); if ( ! $post ) { return; } //Only check links in currently enabled post types if ( ! in_array( $post->post_type, $this->enabled_post_types ) ) { return; } //Only check posts that have one of the allowed statuses if ( ! in_array( $post->post_status, $this->enabled_post_statuses ) ) { return; } //Get the container & mark it as unparsed $args = array( $post->post_type, intval( $post_id ) ); $post_container = blcContainerHelper::get_container( $args ); $post_container->mark_as_unsynched(); } /** * Create or update synchronization records for all posts. * * @param string $container_type Optional. If specified, only resynch records for posts of this type. * Otherwise, resynch records for all post types. * @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch. * @return void */ public function resynch( $container_type = '', $forced = false ) { /** * Database manager. * * @var wpdb $wpdb */ global $wpdb; global $blclog; // Resynch is expensive in terms of DB performance. Thus we only do it once, processing // all post types in one go and ignoring any further resynch requests during this pageload. // BUG: This might be a problem if there ever is an actual need to run resynch twice or // more per pageload. if ( $this->resynch_already_done ) { $blclog->log( sprintf( '...... Skipping "%s" resyncyh since all post types were already synched.', $container_type ) ); return; } if ( empty( $this->enabled_post_types ) ) { $blclog->warn( sprintf( '...... Skipping "%s" resyncyh since no post types are enabled.', $container_type ) ); return; } if ( $forced ) { $blclog->log( '...... Creating synch records for these post types: ' . implode( ', ', $this->enabled_post_types ) . ' that have one of these statuses: ' . implode( ', ', $this->enabled_post_statuses ) ); $start = microtime( true ); // Create new synchronization records for all posts. $rows_inserted = $this->create_all_synch_records(); $blclog->log( sprintf( '...... %d rows inserted in %.3f seconds', $rows_inserted, microtime( true ) - $start ) ); } else { $blclog->log( '...... Deleting synch records for removed posts & post with invalid status' ); $start = microtime( true ); // Delete synch records corresponding to posts that no longer exist. // Also delete posts that don't have enabled post status. $rows_removed = $this->cleanup_synch_records(); $blclog->debug( $wpdb->last_query ); $elapsed = microtime( true ) - $start; $blclog->log( sprintf( '...... %d rows deleted in %.3f seconds', $rows_removed, $elapsed ) ); $blclog->log( '...... Marking changed posts as unsynched' ); $start = microtime( true ); // Remove the 'synched' flag from all posts that have been updated // since the last time they were parsed/synchronized. $rows_updated = $this->mark_unsynched(); $elapsed = microtime( true ) - $start; $blclog->debug( $wpdb->last_query ); $blclog->log( sprintf( '...... %d rows updated in %.3f seconds', $rows_updated, $elapsed ) ); $blclog->log( '...... Creating synch records for new posts' ); $start = microtime( true ); // Create synch. records for posts that don't have them. $records_created = $this->create_new_synch_records(); $elapsed = microtime( true ) - $start; $blclog->debug( $wpdb->last_query ); $blclog->log( sprintf( '...... %d rows inserted in %.3f seconds', $records_created, $elapsed ) ); } $this->resynch_already_done = true; } /** * Insert synchronization records for all posts with an enabled type and status. * Used during a forced full resynch. * * @return int Number of rows affected. */ public function create_all_synch_records() { global $wpdb; $status_placeholders = implode( ', ', array_fill( 0, count( $this->enabled_post_statuses ), '%s' ) ); $type_placeholders = implode( ', ', array_fill( 0, count( $this->enabled_post_types ), '%s' ) ); $q = $wpdb->prepare( "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched) SELECT posts.id, posts.post_type, 0 FROM {$wpdb->posts} AS posts WHERE posts.post_status IN ({$status_placeholders}) AND posts.post_type IN ({$type_placeholders})", array_merge( $this->enabled_post_statuses, $this->enabled_post_types ) ); $wpdb->query( $q ); return $wpdb->rows_affected; } /** * Insert synchronization records for posts that do not yet have one. * Used during an incremental resynch. * * @return int Number of rows affected. */ public function create_new_synch_records() { global $wpdb; $status_placeholders = implode( ', ', array_fill( 0, count( $this->enabled_post_statuses ), '%s' ) ); $type_placeholders = implode( ', ', array_fill( 0, count( $this->enabled_post_types ), '%s' ) ); $q = $wpdb->prepare( "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched) SELECT posts.id, posts.post_type, 0 FROM {$wpdb->posts} AS posts LEFT JOIN {$wpdb->prefix}blc_synch AS synch ON synch.container_id = posts.ID AND synch.container_type = posts.post_type WHERE posts.post_status IN ({$status_placeholders}) AND posts.post_type IN ({$type_placeholders}) AND synch.container_id IS NULL", array_merge( $this->enabled_post_statuses, $this->enabled_post_types ) ); $wpdb->query( $q ); return $wpdb->rows_affected; } /** * Delete synchronization records for posts that no longer exist or don't have enabled post status. * * @return int Number of rows affected. */ public function cleanup_synch_records() { /** * Note: The query below is a bit complex, but it's optimized for performance. It deletes all synch. records that don't have * a corresponding post with an enabled post type and status in one go, using a single query. * * @var wpdb $wpdb */ global $wpdb; global $blclog; if ( empty( $this->enabled_post_types ) ) { return 0; } $type_placeholders = implode( ', ', array_fill( 0, count( $this->enabled_post_types ), '%s' ) ); $status_placeholders = implode( ', ', array_fill( 0, count( $this->enabled_post_statuses ), '%s' ) ); // Post types appear twice (post_type column and container_type column), so merge accordingly. $q = $wpdb->prepare( "DELETE synch.* FROM {$wpdb->prefix}blc_synch AS synch LEFT JOIN {$wpdb->posts} AS posts ON posts.ID = synch.container_id AND posts.post_type IN ({$type_placeholders}) AND posts.post_status IN ({$status_placeholders}) WHERE posts.ID IS NULL AND synch.container_type IN ({$type_placeholders})", array_merge( $this->enabled_post_types, $this->enabled_post_statuses, $this->enabled_post_types ) ); $wpdb->query( $q ); return $wpdb->rows_affected; } /** * Mark posts that have been modified since the last synch. as unsynched. * * @return int Number of posts marked as unsynched. */ public function mark_unsynched() { /** * Note: The query below is a bit complex, but it's optimized for performance. It marks all posts that have been modified since * the last synch. as unsynched in one go, using a single query. */ global $wpdb; $q = "UPDATE {$wpdb->prefix}blc_synch AS synch JOIN {$wpdb->posts} AS posts ON (synch.container_id = posts.ID and synch.container_type=posts.post_type) SET synched = 0 WHERE synch.last_synch < posts.post_modified"; $wpdb->query( $q ); return $wpdb->rows_affected; } /** * Hook for the 'the_content' filter. Scans the current post and adds the 'broken_link' * CSS class to all links that are known to be broken. Currently works only on standard * HTML links (i.e. the '<a href=...' kind). * * @param string $content Post content * @return string Modified post content. */ function hook_the_content( $content ) { global $post, $wpdb; /** @var wpdb $wpdb */ if ( empty( $post ) || ! in_array( $post->post_type, $this->enabled_post_types ) ) { return $content; } //Retrieve info about all occurrences of broken links in the current post $q = " SELECT instances.raw_url FROM {$wpdb->prefix}blc_instances AS instances JOIN {$wpdb->prefix}blc_links AS links ON instances.link_id = links.link_id WHERE instances.container_type = %s AND instances.container_id = %d AND links.broken = 1 AND parser_type = 'link' "; $q = $wpdb->prepare( $q, $post->post_type, $post->ID ); $links = $wpdb->get_results( $q, ARRAY_A ); //Return the content unmodified if there are no broken links in this post. if ( empty( $links ) || ! is_array( $links ) ) { return $content; } //Put the broken link URLs in an array $broken_link_urls = array(); foreach ( $links as $link ) { $broken_link_urls[] = $link['raw_url']; } //Iterate over all HTML links and modify the broken ones $parser = blcParserHelper::get_parser( 'link' ); if ( $parser ) { $content = $parser->multi_edit( $content, array( &$this, 'highlight_broken_link' ), $broken_link_urls ); } return $content; } /** * Analyse a link and add 'broken_link' CSS class if the link is broken. * * @see blcHtmlLink::multi_edit() * * @param array $link Associative array of link data. * @param array $broken_link_urls List of broken link URLs present in the current post. * @return array|string The modified link */ function highlight_broken_link( $link, $broken_link_urls ) { if ( ! in_array( $link['href'], $broken_link_urls ) ) { //Link not broken = return the original link tag return $link['#raw']; } //Add 'broken_link' to the 'class' attribute (unless already present). if ( $this->plugin_conf->options['mark_broken_links'] ) { if ( isset( $link['class'] ) ) { $classes = explode( ' ', $link['class'] ); if ( ! in_array( 'broken_link', $classes ) ) { $classes[] = 'broken_link'; $link['class'] = implode( ' ', $classes ); } } else { $link['class'] = 'broken_link'; } } //Nofollow the link (unless it's already nofollow'ed) if ( $this->plugin_conf->options['nofollow_broken_links'] ) { if ( isset( $link['rel'] ) ) { $relations = explode( ' ', $link['rel'] ); if ( ! in_array( 'nofollow', $relations ) ) { $relations[] = 'nofollow'; $link['rel'] = implode( ' ', $relations ); } } else { $link['rel'] = 'nofollow'; } } return $link; } /** * A hook for the 'wp_head' action. Outputs the user-defined broken link CSS. * * @return void */ function hook_wp_head() { echo '<style>',$this->plugin_conf->options['broken_link_css'],'</style>'; } } //Start up the post overlord blcPostTypeOverlord::getInstance(); /** * Universal container item class used for all post types. * * @package Broken Link Checker * @author Janis Elsts * @access public */ class blcAnyPostContainer extends blcContainer { var $default_field = 'post_content'; public $updating_urls = null; /** * Get action links for this post. * * @param string $container_field Ignored. * @return array of action link HTML. */ function ui_get_action_links( $container_field = '' ) { $actions = array(); //Fetch the post (it should be cached already) $post = $this->get_wrapped_object(); if ( ! $post ) { return $actions; } $post_type_object = get_post_type_object( $post->post_type ); if ( ! $post_type_object ) { return $actions; } //Each post type can have its own cap requirements if ( current_user_can( $post_type_object->cap->edit_post, $this->container_id ) ) { $actions['edit'] = sprintf( '<span class="edit"><a href="%s" title="%s">%s</a>', $this->get_edit_url(), $post_type_object->labels->edit_item, __( 'Edit' ) ); //Trash/Delete link //Note: core's get_delete_post_link() has no special-case handling for //Site Editor post types (unlike get_edit_post_link()), so calling it for //them throws an ArgumentCountError. They're deleted via the Site Editor, //not this legacy link, so we simply omit the action for them. if ( current_user_can( $post_type_object->cap->delete_post, $this->container_id ) && ! $this->is_site_editor_post_type( $post->post_type ) ) { if ( $this->can_be_trashed() ) { $actions['trash'] = sprintf( "<span class='trash'><a class='submitdelete' title='%s' href='%s'>%s</a>", esc_attr( __( 'Move this item to the Trash' ) ), esc_attr( get_delete_post_link( $this->container_id, '', false ) ), __( 'Trash' ) ); } else { $actions['delete'] = sprintf( "<span><a class='submitdelete' title='%s' href='%s'>%s</a>", esc_attr( __( 'Delete this item permanently' ) ), esc_attr( get_delete_post_link( $this->container_id, '', true ) ), __( 'Delete' ) ); } } } //View/Preview link $title = get_the_title( $this->container_id ); if ( in_array( $post->post_status, array( 'pending', 'draft' ) ) ) { if ( current_user_can( $post_type_object->cap->edit_post, $this->container_id ) ) { $actions['view'] = sprintf( '<span class="view"><a href="%s" title="%s" rel="permalink">%s</a>', esc_url( add_query_arg( 'preview', 'true', get_permalink( $this->container_id ) ) ), esc_attr( sprintf( __( 'Preview “%s”' ), $title ) ), __( 'Preview' ) ); } } elseif ( 'trash' != $post->post_status ) { $actions['view'] = sprintf( '<span class="view"><a href="%s" title="%s" rel="permalink">%s</a>', esc_url( get_permalink( $this->container_id ) ), esc_attr( sprintf( __( 'View “%s”' ), $title ) ), __( 'View' ) ); } return $actions; } /** * Get the HTML for displaying the post title in the "Source" column. * * @param string $container_field Ignored. * @param string $context How to filter the output. Optional, defaults to 'display'. * @return string HTML */ function ui_get_source( $container_field = '', $context = 'display' ) { $source = '<a class="row-title" href="%s" title="%s">%s</a>'; if ( 'email' === $context ) { $source = sprintf( $source, get_the_permalink( $this->container_id ), esc_attr( __( 'View this item' ) ), get_the_title( $this->container_id ) ); } else { $source = sprintf( $source, $this->get_edit_url(), esc_attr( __( 'Edit this item' ) ), get_the_title( $this->container_id ) ); } return $source; } /** * Get edit URL for this container. Returns the URL of the Dashboard page where the item * associated with this container can be edited. * * @access protected * * @return string */ function get_edit_url() { /* The below is a near-exact copy of the get_post_edit_link() function. Unfortunately we can't just call that function because it has a hardcoded caps-check which fails when called from the email notification script executed by Cron. */ $post = $this->get_wrapped_object(); if ( ! $post ) { return ''; } $context = 'display'; $action = '&action=edit'; $post_type_object = get_post_type_object( $post->post_type ); if ( ! $post_type_object ) { return ''; } if ( empty( $post_type_object->_edit_link ) ) { $link = admin_url( 'post.php?post=' . $post->ID . $action ); // Fallback to default edit link. } else { if ( 'wp_template' === $post->post_type || 'wp_template_part' === $post->post_type ) { $slug = urlencode( get_stylesheet() . '//' . $post->post_name ); $link = admin_url( sprintf( $post_type_object->_edit_link, $post->post_type, $slug ) ); } elseif ( 'wp_navigation' === $post->post_type ) { $link = admin_url( sprintf( $post_type_object->_edit_link, (string) $post->ID ) ); } elseif ( $post_type_object->_edit_link ) { $link = admin_url( sprintf( $post_type_object->_edit_link . $action, $post->ID ) ); } $post_type_object->_edit_link = str_replace( 'postType=%s&', '', $post_type_object->_edit_link ); } return apply_filters( 'get_edit_post_link', $link, $post->ID, $context ); } /** * Retrieve the post associated with this container. * * @access protected * * @param bool $ensure_consistency Set this to true to ignore the cached $wrapped_object value and retrieve an up-to-date copy of the wrapped object from the DB (or WP's internal cache). * @return object Post data. */ function get_wrapped_object( $ensure_consistency = false ) { if ( $ensure_consistency || is_null( $this->wrapped_object ) ) { $this->wrapped_object = get_post( $this->container_id ); } return $this->wrapped_object; } /** * Update the post associated with this container. * * @access protected * * @return bool|WP_Error True on success, an error if something went wrong. */ function update_wrapped_object() { if ( is_null( $this->wrapped_object ) ) { return new WP_Error( 'no_wrapped_object', __( 'Nothing to update', 'broken-link-checker' ) ); } $post = $this->wrapped_object; $post->blc_post_modified = $post->post_modified; $post->blc_post_modified_gmt = $post->post_modified_gmt; $post_id = wp_update_post( $post, true ); if ( is_wp_error( $post_id ) ) { return $post_id; } elseif ( $post_id == 0 ) { return new WP_Error( 'update_failed', sprintf( __( 'Updating post %d failed', 'broken-link-checker' ), $this->container_id ) ); } else { $this->update_pagebuilders( $post_id ); return true; } } /** * Update the the links on pagebuilders * * @param int $post_id Post ID of whose content to update. */ function update_pagebuilders( $post_id ) { if ( ! $post_id ) { return; } // support for elementor page builder. if ( class_exists( '\Elementor\Plugin' ) && \Elementor\Plugin::$instance->db->is_built_with_elementor( $post_id ) ) { if ( is_array( $this->updating_urls ) ) { if ( isset( $this->updating_urls['old_url'] ) && isset( $this->updating_urls['new_url'] ) ) { // Editing case. $old_url = $this->updating_urls['old_url']; $new_url = $this->updating_urls['new_url']; blcElementor::instance()->update_blc_links( $old_url, $new_url, $post_id ); } else { // Unlinking case. foreach ( $this->updating_urls as $key => $link_info ) { $old_url = $link_info['#raw']; $new_url = $link_info['#new_raw']; if ( $old_url === $new_url ) { continue; } blcElementor::instance()->update_blc_links( $old_url, $new_url, $post_id ); } } } } // Support for Page Builder by SiteOrigin. if ( class_exists( '\SiteOrigin_Panels' ) && get_post_meta( $post_id, 'panels_data', true ) ) { if ( is_array( $this->updating_urls ) ) { if ( isset( $this->updating_urls['old_url'] ) && isset( $this->updating_urls['new_url'] ) ) { // Editing case. $old_url = $this->updating_urls['old_url']; $new_url = $this->updating_urls['new_url']; blcSiteOrigin::instance()->update_blc_links( $old_url, $new_url, $post_id ); } else { // Unlinking case. foreach ( $this->updating_urls as $key => $link_info ) { $old_url = $link_info['#raw']; $new_url = $link_info['#new_raw']; if ( $old_url === $new_url ) { continue; } blcSiteOrigin::instance()->update_blc_links( $old_url, $new_url, $post_id ); } } } } } /** * Get the base URL of the container. For posts, the post permalink is used * as the base URL when normalizing relative links. * * @return string */ function base_url() { return get_permalink( $this->container_id ); } /** * Delete or trash the post corresponding to this container. * Will always move to trash instead of deleting if trash is enabled. * * @return bool|WP_error */ function delete_wrapped_object() { //Note that we don't need to delete the synch record and instances here - //wp_delete_post()/wp_trash_post() will run the post_delete/trash hook, //which will be caught by blcPostContainerManager, which will in turn //delete anything that needs to be deleted. if ( EMPTY_TRASH_DAYS ) { return $this->trash_wrapped_object(); } else { if ( wp_delete_post( $this->container_id, true ) ) { return true; } else { return new WP_Error( 'delete_failed', sprintf( __( 'Failed to delete post "%1$s" (%2$d)', 'broken-link-checker' ), get_the_title( $this->container_id ), $this->container_id ) ); } } } /** * Move the post corresponding to this container to the Trash. * * @return bool|WP_Error */ function trash_wrapped_object() { if ( ! EMPTY_TRASH_DAYS ) { return new WP_Error( 'trash_disabled', sprintf( __( 'Can\'t move post "%1$s" (%2$d) to the trash because the trash feature is disabled', 'broken-link-checker' ), get_the_title( $this->container_id ), $this->container_id ) ); } $post = get_post( $this->container_id ); if ( $post->post_status == 'trash' ) { //Prevent conflicts between post and custom field containers trying to trash the same post. //BUG: Post and custom field containers shouldn't wrap the same object return true; } if ( wp_trash_post( $this->container_id ) ) { return true; } else { return new WP_Error( 'trash_failed', sprintf( __( 'Failed to move post "%1$s" (%2$d) to the trash', 'broken-link-checker' ), get_the_title( $this->container_id ), $this->container_id ) ); } } /** * Check if the current user can delete/trash this post. * * @return bool */ function current_user_can_delete() { $post = $this->get_wrapped_object(); $post_type_object = get_post_type_object( $post->post_type ); return current_user_can( $post_type_object->cap->delete_post, $this->container_id ); } function can_be_trashed() { return defined( 'EMPTY_TRASH_DAYS' ) && EMPTY_TRASH_DAYS; } } /** * Universal manager usable for most post types. * * @package Broken Link Checker * @access public */ class blcAnyPostContainerManager extends blcContainerManager { var $container_class_name = 'blcAnyPostContainer'; var $fields = array( 'post_content' => 'html', 'post_excerpt' => 'html' ); function init() { parent::init(); //Notify the overlord that the post/container type that this instance is //responsible for is enabled. $overlord = blcPostTypeOverlord::getInstance(); $overlord->post_type_enabled( $this->container_type ); } /** * Instantiate multiple containers of the container type managed by this class. * * @param array $containers Array of assoc. arrays containing container data. * @param string $purpose An optional code indicating how the retrieved containers will be used. * @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose. * * @return array of blcPostContainer indexed by "container_type|container_id" */ function get_containers( $containers, $purpose = '', $load_wrapped_objects = false ) { global $blclog; $containers = $this->make_containers( $containers ); //Preload post data if it is likely to be useful later $preload = $load_wrapped_objects || in_array( $purpose, array( BLC_FOR_DISPLAY, BLC_FOR_PARSING ) ); if ( $preload ) { $post_ids = array(); foreach ( $containers as $container ) { $post_ids[] = $container->container_id; } $args = array( 'include' => implode( ',', $post_ids ) ); $posts = get_posts( $args ); foreach ( $posts as $post ) { $key = $this->container_type . '|' . $post->ID; if ( isset( $containers[ $key ] ) ) { $containers[ $key ]->wrapped_object = $post; } } } return $containers; } /** * Create or update synchronization records for all posts. * * @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch. * @return void */ function resynch( $forced = false ) { $overlord = blcPostTypeOverlord::getInstance(); $overlord->resynch( $this->container_type, $forced ); } /** * Get the message to display after $n posts have been deleted. * * @param int $n Number of deleted posts. * @return string A delete confirmation message, e.g. "5 posts were moved deleted" */ function ui_bulk_delete_message( $n ) { //Since the "Trash" feature has been introduced, calling wp_delete_post //doesn't actually delete the post (unless you set force_delete to True), //just moves it to the trash. So we pick the message accordingly. //(If possible, BLC *always* moves to trash instead of deleting permanently.) if ( function_exists( 'wp_trash_post' ) && EMPTY_TRASH_DAYS ) { return blcAnyPostContainerManager::ui_bulk_trash_message( $n ); } else { $post_type_object = get_post_type_object( $this->container_type ); return self::build_delete_action_message( $n, $this->container_type, $post_type_object ); } } /** * Get the message to display after $n posts have been trashed. * * @param int $n Number of deleted posts. * @return string A confirmation message, e.g. "5 posts were moved to trash" */ function ui_bulk_trash_message( $n ) { $post_type_object = get_post_type_object( $this->container_type ); return self::build_trash_action_message( $n, $this->container_type, $post_type_object ); } /** * Get the message to display after $n posts have been deleted. * * @param int $n Number of deleted posts. * @param string $container_type The post type of the deleted posts. * @param WP_Post_Type|null $post_type_object The post type object of the deleted posts, or null if it couldn't be retrieved. * @return string A delete confirmation message, e.g. "5 posts were moved deleted" */ public static function build_delete_action_message( $n, $container_type, $post_type_object ) { $type_name = ''; if ( 'post' === $container_type || null === $post_type_object ) { // translators: %d is the number of deleted posts. $msg = _n( '%d post deleted.', '%d posts deleted.', $n, 'broken-link-checker' ); } elseif ( 'page' === $container_type ) { // translators: %d is the number of deleted pages. $msg = _n( '%d page deleted.', '%d pages deleted.', $n, 'broken-link-checker' ); } else { // translators: %1$d is the number of deleted items, %2$s is the item type. $msg = _n( '%1$d "%2$s" deleted.', '%1$d "%2$s" deleted.', $n, 'broken-link-checker' ); $type_name = ( 1 === (int) $n ? $post_type_object->labels->singular_name : $post_type_object->labels->name ); } return sprintf( $msg, $n, $type_name ); } /** * Get the message to display after $n posts have been moved to the Trash. * * @param int $n Number of trashed posts. * @param string $container_type The post type of the trashed posts. * @param WP_Post_Type|null $post_type_object The post type object of the trashed posts, or null if it couldn't be retrieved. * @return string A confirmation message, e.g. "5 posts were moved to trash" */ public static function build_trash_action_message( $n, $container_type, $post_type_object ) { if ( 'post' === $container_type || null === $post_type_object ) { // translators: %d is the number of posts moved to the Trash. $msg = _n( '%d post moved to the Trash.', '%d posts moved to the Trash.', $n, 'broken-link-checker' ); } elseif ( 'page' === $container_type ) { // translators: %d is the number of pages moved to the Trash. $msg = _n( '%d page moved to the Trash.', '%d pages moved to the Trash.', $n, 'broken-link-checker' ); } else { // translators: %1$d is the number of trashed items, %2$s is the item type. $msg = _n( '%1$d "%2$s" moved to the Trash.', '%1$d "%2$s" moved to the Trash.', $n, 'broken-link-checker' ); $type_name = ( 1 === (int) $n ? $post_type_object->labels->singular_name : $post_type_object->labels->name ); } return sprintf( $msg, $n, $type_name ); } }
Upload Files
Cancel
Upload
Create New
Cancel
Create
Change Permissions
Cancel
Save
Change Date
Cancel
Save
Rename Item
Cancel
Save
Confirm Delete
Are you sure you want to delete the selected items?
Cancel
Delete