get_wrapped_object(); $image = sprintf( '%2$s', esc_attr( plugins_url( '/images/font-awesome/font-awesome-link.png', BLC_PLUGIN_FILE ) ), __( 'Bookmark', 'broken-link-checker' ) ); $link_name = sprintf( '%s', $this->get_edit_url(), __( 'Edit this bookmark', 'broken-link-checker' ), sanitize_bookmark_field( 'link_name', $bookmark->link_name, $this->container_id, 'display' ) ); if ( 'email' != $context ) { return "$image $link_name"; } else { return $link_name; } } function ui_get_action_links( $container_field ) { //Inline action links for bookmarks $bookmark = $this->get_wrapped_object(); $delete_url = admin_url( wp_nonce_url( "link.php?action=delete&link_id={$this->container_id}", 'delete-bookmark_' . $this->container_id ) ); $actions = array(); if ( current_user_can( 'manage_links' ) ) { $actions['edit'] = '' . __( 'Edit' ) . ''; $actions['delete'] = "link_name ) ) . "') ) { return true;}return false;\">" . __( 'Delete' ) . ''; } return $actions; } function get_edit_url() { return esc_url( admin_url( "link.php?action=edit&link_id={$this->container_id}" ) ); } /** * Retrieve the bookmark 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 Bookmark data. */ function get_wrapped_object( $ensure_consistency = false ) { if ( $ensure_consistency || is_null( $this->wrapped_object ) ) { $this->wrapped_object = get_bookmark( $this->container_id ); } return $this->wrapped_object; } /** * Update the bookmark 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' ) ); } //wp_update_link() expects it's argument to be an array. $data = (array) $this->wrapped_object; //Update the bookmark $rez = wp_update_link( $data ); if ( ! empty( $rez ) ) { return true; } else { return new WP_Error( 'update_failed', sprintf( __( 'Updating bookmark %d failed', 'broken-link-checker' ), $this->container_id ) ); } } /** * Delete the bookmark corresponding to this container. * Also removes the synch. record of the container and removes all associated instances. * * @return bool|WP_error */ function delete_wrapped_object() { if ( wp_delete_link( $this->container_id ) ) { //Note that there is no need to explicitly delete the synch. record and instances //associated with this link - wp_delete_link() will execute the 'delete_link' action, //which will be noticed by blcBookmarkManager, which will then delete anything that needs //to be deleted. //But in case the (undocumented) behaviour of wp_delete_link() changes in a later WP version, //add a call to $this->delete() here. return true; } else { $bookmark = $this->get_wrapped_object(); if ( is_null( $bookmark ) ) { $link_name = '[nonexistent]'; } else { $link_name = sanitize_bookmark_field( 'link_name', $bookmark->link_name, $this->container_id, 'display' ); } $msg = sprintf( __( 'Failed to delete blogroll link "%1$s" (%2$d)', 'broken-link-checker' ), $link_name, $this->container_id ); return new WP_Error( 'delete_failed', $msg ); } } function current_user_can_delete() { return current_user_can( 'manage_links' ); } function can_be_trashed() { return false; } /** * Get the default link text. For bookmarks, this is the bookmark name. * * @param string $field * @return string */ function default_link_text( $field = '' ) { $bookmark = $this->get_wrapped_object(); return sanitize_bookmark_field( 'link_name', $bookmark->link_name, $this->container_id, 'display' ); } /** * For bookmarks, calling unlink() simply removes the bookmark. * * @return bool|WP_Error True on success, or an error object if something went wrong. */ function unlink( $field_name, $parser, $url, $raw_url = '' ) { return $this->delete_wrapped_object(); } } class blcBookmarkManager extends blcContainerManager { var $container_class_name = 'blcBookmark'; var $fields = array( 'link_url' => 'url_field' ); /** * Set up hooks that monitor added/modified/deleted bookmarks. * * @return void */ function init() { parent::init(); add_action( 'add_link', array( $this, 'hook_add_link' ) ); add_action( 'edit_link', array( $this, 'hook_edit_link' ) ); add_action( 'delete_link', array( $this, 'hook_delete_link' ) ); } /** * 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 blcBookmark indexed by "container_type|container_id" */ function get_containers( $containers, $purpose = '', $load_wrapped_objects = false ) { $containers = $this->make_containers( $containers ); //Preload bookmark 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 ) { $bookmark_ids = array(); foreach ( $containers as $container ) { $bookmark_ids[] = $container->container_id; } $args = array( 'include' => implode( ',', $bookmark_ids ) ); $bookmarks = get_bookmarks( $args ); foreach ( $bookmarks as $bookmark ) { $key = $this->container_type . '|' . $bookmark->link_id; if ( isset( $containers[ $key ] ) ) { $containers[ $key ]->wrapped_object = $bookmark; } } } 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 ) { global $wpdb; /** @var wpdb $wpdb */ if ( ! $forced ) { //Usually the number of bookmarks is rather small, so it's cheap enough to always //drop the entire list of bookmark-related synch records and recreate it from scratch. $q = $wpdb->prepare( "DELETE FROM {$wpdb->prefix}blc_synch WHERE container_type = %s", $this->container_type ); $wpdb->query( $q ); //phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } //Create new synchronization records for all bookmarks (AKA the blogroll). $q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched) SELECT link_id, %s, 0 FROM {$wpdb->links} WHERE 1"; $q = $wpdb->prepare( $q, $this->container_type ); //phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $wpdb->query( $q ); //phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } /** * When a bookmark is added mark it as unsynched. * * @param int $link_id * @return void */ function hook_add_link( $link_id ) { $container = blcContainerHelper::get_container( array( $this->container_type, $link_id ) ); $container->mark_as_unsynched(); } /** * Ditto for modified bookmarks. * * @param int $link_id * @return void */ function hook_edit_link( $link_id ) { $this->hook_add_link( $link_id ); } /** * When a bookmark is deleted, remove the related DB records. * * @param int $link_id * @return void */ function hook_delete_link( $link_id ) { //Get the container object. $container = blcContainerHelper::get_container( array( $this->container_type, $link_id ) ); //Get the link(s) associated with it. $links = $container->get_links(); //Remove synch. record & instance records. $container->delete(); //Clean up links associated with this bookmark (there's probably only one) $link_ids = array(); foreach ( $links as $link ) { $link_ids[] = $link->link_id; } blc_cleanup_links( $link_ids ); } /** * Get the message to display after $n bookmarks have been deleted. * * @param int $n Number of deleted bookmarks. * @return string The delete confirmation message. */ function ui_bulk_delete_message( $n ) { return sprintf( _n( '%d blogroll link deleted.', '%d blogroll links deleted.', $n, 'broken-link-checker' ), $n ); } }