core = $core; //Initialize layout and column definitions $this->setup_columns(); $this->setup_layouts(); //Figure out what the "safe" URL to acccess the current page would be. //This is used by the bulk action form. $special_args = array('_wpnonce', '_wp_http_referer', 'action', 'selected_links'); $this->neutral_current_url = remove_query_arg($special_args); } /** * Print the entire link table and associated navigation elements. * * @param array $current_filter * @param string $layout * @param array $visible_columns * @param bool $compact * @return void */ function print_table($current_filter, $layout = 'flexible', $visible_columns = null, $compact = false){ $this->current_filter = $current_filter; $this->page = $current_filter['page']; $this->per_page = $current_filter['per_page']; $current_layout = $this->layouts[$layout]; if ( empty($visible_columns) ){ $visible_columns = $current_layout; } //Only allow columns actually present in this layout $visible_columns = array_intersect($visible_columns, $current_layout); echo '
'; wp_nonce_field('bulk-action'); //Top navigation $this->prepare_nav_html(); $this->navigation($compact); //Table header $table_classes = array('widefat'); if ( $compact ) { $table_classes[] = 'compact'; }; if ( $this->core->conf->options['table_color_code_status'] ) { $table_classes[] = 'color-code-link-status'; }; $table_classes[] = 'base-filter-' . $current_filter['base_filter']; printf( '', implode(' ', $table_classes) ); //The select-all checkbox echo ''; //Column headers foreach($current_layout as $column_id){ $column = $this->columns[$column_id]; $column_classes = array('column-'.$column_id); if ( isset($column['class']) ){ $column_classes[] = $column['class']; } if ( !in_array($column_id, $visible_columns) ) { $column_classes[] = 'hidden'; } $heading = $column['heading']; if ( isset($column['sortable']) && $column['sortable'] ) { $orderby = $column['orderby']; $current_orderby = isset($_GET['orderby']) ? $_GET['orderby'] : ''; $current_order = isset($_GET['order']) ? $_GET['order'] : 'asc'; if ( !in_array($current_order, array('asc', 'desc')) ) { $current_order = 'asc'; } if ( $orderby == $current_orderby ) { $column_classes[] = 'sorted'; $column_classes[] = $current_order; $order = ($current_order == 'asc') ? 'desc' : 'asc'; //Reverse the sort direction } else { $order = 'asc'; $column_classes[] = 'desc'; $column_classes[] = 'sortable'; } $heading = sprintf( '%s', esc_attr(add_query_arg(array( 'orderby' => $orderby, 'order' => $order, ))), $heading ); } printf( '', implode(' ', $column_classes), isset($column['id']) ? ' id="' . $column['id'] . '"' : '', $heading ); } echo ''; //Table body echo ''; $this->bulk_edit_form($visible_columns); $rownum = 0; foreach ($this->current_filter['links'] as $link) { $rownum++; $this->link_row($link, $current_layout, $visible_columns, $rownum); $this->link_details_row($link, $visible_columns, $rownum); } echo ''; //Bottom navigation $this->navigation($compact, '2'); echo '
'; //Inline editor (hidden by default, JS will move it to the right place). $this->inline_editor($visible_columns); } /** * Print the "Bulk Actions" dropdown and navigation links * * @param bool $table_compact Whether to use the full or compact view. * @param string $suffix Optional. Appended to ID and name attributes of the bulk action dropdown. * @return void */ function navigation($table_compact = false, $suffix = ''){ //Display the "Bulk Actions" dropdown echo '
', '
', '', ' ', '
'; //Display pagination links if ( !empty($this->pagination_html) ){ echo $this->pagination_html; } //Display the view switch (only in the top nav. area) if ( empty($suffix) ){ ?>
'; } /** * Initialize the internal list of available table columns. * * @return void */ function setup_columns(){ $this->columns = array( 'status' => array( 'heading' => __('Status', 'broken-link-checker'), 'content' => array($this, 'column_status'), ), 'new-url' => array( 'heading' => __('URL', 'broken-link-checker'), 'content' => array($this, 'column_new_url'), 'sortable' => true, 'orderby' => 'url', ), 'used-in' => array( 'heading' => __('Source', 'broken-link-checker'), 'class' => 'column-title', 'content' => array($this, 'column_used_in'), ), 'new-link-text' => array( 'heading' => __('Link Text', 'broken-link-checker'), 'content' => array($this, 'column_new_link_text'), 'sortable' => true, 'orderby' => 'link_text', ), 'redirect-url' => array( 'heading' => __('Redirect URL', 'broken-link-checker'), 'content' => array($this, 'column_redirect_url'), 'sortable' => true, 'orderby' => 'redirect_url', ), ); } /** * Initialize the list of available layouts * * @return void */ function setup_layouts(){ $this->layouts = array( 'classic' => array('used-in', 'new-link-text', 'new-url'), 'flexible' => array('new-url', 'status', 'new-link-text', 'redirect-url', 'used-in', ), ); } /** * Get a list of columns available in a specific table layout. * * @param string $layout Layout ID. * @return array Associative array of column data indexed by column ID. */ function get_layout_columns($layout){ if ( isset($this->layouts[$layout]) ){ $result = array(); foreach($this->layouts[$layout] as $column_id){ if ( isset($this->columns[$column_id]) ) $result[$column_id] = $this->columns[$column_id]; } return $result; } else { return null; } } /** * Pre-generate some HTML fragments used for both the top and bottom navigation/bulk action boxes. * * @return void */ function prepare_nav_html(){ //Generate an ', $value, $name); } $this->bulk_actions_html = $bulk_actions_html; //Pagination links can also be pre-generated. //WP has a built-in function for pagination :) $page_links = paginate_links( array( 'base' => add_query_arg( 'paged', '%#%' ), 'format' => '', 'prev_text' => __('«'), 'next_text' => __('»'), 'total' => $this->current_filter['max_pages'], 'current' => $this->page )); if ( $page_links ) { $this->pagination_html = '
'; $this->pagination_html .= sprintf( '' . __( 'Displaying %s–%s of %s', 'broken-link-checker' ) . '%s', number_format_i18n( ( $this->page - 1 ) * $this->per_page + 1 ), number_format_i18n( min( $this->page * $this->per_page, $this->current_filter['count'] ) ), number_format_i18n( $this->current_filter['count'] ), $page_links ); $this->pagination_html .= '
'; } else { $this->pagination_html = ''; } } /** * Print the bulk edit form. * * @param array $visible_columns List of visible columns. * @return void */ function bulk_edit_form($visible_columns){ ?>

 

core->is_excluded( $link->url ); if ( $excluded ) $rowclass .= ' blc-excluded-link'; if ( $link->redirect_count > 0){ $rowclass .= ' blc-redirect'; } $days_broken = 0; if ( $link->broken ){ //Add a highlight to broken links that appear to be permanently broken $days_broken = intval( (time() - $link->first_failure) / (3600*24) ); if ( $days_broken >= $this->core->conf->options['failure_duration_threshold'] ){ $rowclass .= ' blc-permanently-broken'; if ( $this->core->conf->options['highlight_permanent_failures'] ){ $rowclass .= ' blc-permanently-broken-hl'; } } } $status = $link->analyse_status(); $rowclass .= ' link-status-' . $status['code']; //Retrieve link instances to display in the table $instances = $link->get_instances(); if ( !empty($instances) ){ //Put instances that match the selected link type at the top. Makes search results look better. if ( !empty($this->current_filter['search_params']['s_link_type']) ){ $s_link_type = $this->current_filter['search_params']['s_link_type']; } else { $s_link_type = ''; } $instances = $this->sort_instances_for_display($instances, $s_link_type); } //For inline editing, we'll need to know if any instances have editable link text, and what it is. $can_edit_text = false; $can_edit_url = false; $editable_link_texts = $non_editable_link_texts = array(); foreach($instances as $instance) { if ( $instance->is_link_text_editable() ) { $can_edit_text = true; $editable_link_texts[$instance->link_text] = true; } else { $non_editable_link_texts[$instance->link_text] = true; } if ( $instance->is_url_editable() ) { $can_edit_url = true; } } $link_texts = $can_edit_text ? $editable_link_texts : $non_editable_link_texts; $data_link_text = ''; if ( count($link_texts) === 1 ) { //All instances have the same text - use it. $link_text = key($link_texts); $data_link_text = ' data-link-text="' . esc_attr($link_text) . '"'; } printf( '', $link->link_id, $rowclass, $days_broken, $can_edit_url ? 1 : 0, $can_edit_text ? 1 : 0, $data_link_text ); //The checkbox used to select links is automatically printed in all layouts //and can't be disabled. Without it, bulk actions wouldn't work. $this->column_checkbox($link); foreach($layout as $column_id){ $column = $this->columns[$column_id]; printf( '', $column_id, in_array($column_id, $visible_columns) ? '' : ' hidden' ); if ( isset($column['content']) ){ if ( is_callable($column['content']) ){ call_user_func($column['content'], $link, $instances); } else { echo $column['content']; } } else { echo '[', $column_id, ']'; } echo ''; } echo ''; } /** * Print the details row for a specific link. * * @uses blcTablePrinter::details_row_contents() * * @param blcLink $link The link to display. * @param array $visible_columns List of visible columns. * @param integer $rownum Table row number. * @return void */ function link_details_row($link, $visible_columns, $rownum = 0){ printf( '', $link->link_id, count($visible_columns)+1 ); $this->details_row_contents($link); echo ''; } /** * Print the contents of the details row for a specific link. * * @param blcLink $link * @return void */ public static function details_row_contents($link){ ?>
    post_date) ) { ?>
  1. :
  2. : last_check; if ( $last_check < strtotime('-10 years') ){ _e('Never', 'broken-link-checker'); } else { printf( '', esc_attr(date('c', $last_check)), date_i18n(get_option('date_format'), $last_check) ); } ?>
  3. : http_code; ?>
  4. : request_duration); ?>
  5. : final_url); ?>
  6. : redirect_count; ?>
  7. : get_instances()); ?>
  8. broken || $link->warning) && (intval( $link->check_count ) > 0) ){ ?>

  9. check_count, 'broken-link-checker'), $link->check_count ); echo '
    '; $delta = time() - $link->first_failure; printf( __('This link has been broken for %s.', 'broken-link-checker'), blcUtility::fuzzy_delta($delta) ); ?>
  1. : log); ?>
', esc_attr(__('Show more info about this link', 'broken-link-checker')) ); $status = $link->analyse_status(); printf( ' %s %s ', $status['code'], empty($link->http_code)?'':$link->http_code, $status['text'] ); //Last checked... if ( $link->last_check != 0 ){ $last_check = _x('Checked', 'checked how long ago', 'broken-link-checker') . ' '; $last_check .= blcUtility::fuzzy_delta(time() - $link->last_check, 'ago'); printf( '%s', $last_check ); } //Broken for... if ( $link->broken ){ $delta = time() - $link->first_failure; $broken_for = blcUtility::fuzzy_delta($delta); printf( '%s %s', __('Broken for', 'broken-link-checker'), $broken_for ); } echo ''; //"Details" link. echo '
'; printf( '%s', esc_attr(__('Show more info about this link', 'broken-link-checker')), _x('Details', 'link in the "Status" column', 'broken-link-checker') ); echo '
'; } /** * @param blcLink $link */ function column_new_url($link){ ?> url); ?> ". __('Edit URL' , 'broken-link-checker') .""; $actions['delete'] = "" . __('Unlink', 'broken-link-checker') . ""; if ( $link->broken || $link->warning ){ $actions['blc-discard-action'] = sprintf( '%s', esc_attr(__('Remove this link from the list of broken links and mark it as valid', 'broken-link-checker')), __('Not broken', 'broken-link-checker') ); } if ( !$link->dismissed && ($link->broken || $link->warning || ($link->redirect_count > 0)) ) { $actions['blc-dismiss-action'] = sprintf( '%s', esc_attr(__('Hide this link and do not report it again unless its status changes' , 'broken-link-checker')), __('Dismiss', 'broken-link-checker') ); } else if ( $link->dismissed ) { $actions['blc-undismiss-action'] = sprintf( '%s', esc_attr(__('Undismiss this link', 'broken-link-checker')), __('Undismiss', 'broken-link-checker') ); } $actions['blc-recheck-action'] = sprintf( '%s', __('Recheck', 'broken-link-checker') ); if ( $link->redirect_count > 0 && !empty($link->final_url) && ($link->url != $link->final_url) ) { //TODO: Check if at least one instance has an editable URL. Otherwise this won't work. $actions['blc-deredirect-action'] = sprintf( '%s', __('Replace this redirect with a direct link', 'broken-link-checker'), _x('Fix redirect', 'link action; replace one redirect with a direct link', 'broken-link-checker') ); } //Only show the enabled actions. $conf = blc_get_configuration(); foreach($conf->get('show_link_actions', $actions) as $name => $enabled) { if ( !$enabled ) { unset($actions[$name]); } } //Wrap actions with and separate them with | characters. //Basically, this emulates the HTML structure that WP uses for post actions under Posts -> All Posts. $spans = array(); $is_first_action = true; foreach($actions as $name => $html) { $spans[] = sprintf( '%s%s', esc_attr($name), $is_first_action ? '' : ' | ', $html ); $is_first_action = false; } echo '
'; echo implode('', $spans); echo '
'; ?>
', $link->link_id, ''; if ( !empty($instances) ){ /** @var $instance blcLinkInstance */ $instance = reset($instances); echo $instance->ui_get_source(); $actions = $instance->ui_get_action_links(); echo '
'; echo implode(' | ', $actions); echo '
'; } else { _e("[An orphaned link! This is a bug.]", 'broken-link-checker'); } } /** * @param blcLink $link * @param blcLinkInstance[] $instances */ function column_new_link_text($link, $instances){ if ( empty($instances) ){ echo 'N/A'; } else { $instance = reset($instances); /** @var blcLinkInstance $instance */ echo $instance->ui_get_link_text(); } } function column_redirect_url($link, $instances) { if ( $link->redirect_count > 0 ) { printf( '%2$s', esc_attr($link->final_url), esc_html($link->final_url) ); } } /** * Sort a list of link instances to be displayed in the "Broken Links" page. * * Groups instances by container type and, if $search_link_type is specified, * puts instances that have a matching container type or parser type at the * beginning. * * @param array $instances An array of blcLinkInstance objects. * @param string $searched_link_type Optional. The required container/parser type. * @return array Sorted array. */ function sort_instances_for_display($instances, $searched_link_type = ''){ $this->searched_link_type = $searched_link_type; usort($instances, array($this, 'compare_link_instances')); return $instances; } /** * Callback function for sorting link instances. * * @see blcTablePrinter::sort_instances_for_display() * * @param blcLinkInstance $a * @param blcLinkInstance $b * @return int */ function compare_link_instances($a, $b){ if ( !empty($this->searched_link_type) ){ if ( ($a->container_type == $this->searched_link_type) || ($a->parser_type == $this->searched_link_type) ){ if ( ($b->container_type == $this->searched_link_type) || ($b->parser_type == $this->searched_link_type) ){ return 0; } else { return -1; } } else { if ( ($b->container_type == $this->searched_link_type) || ($b->parser_type == $this->searched_link_type) ){ return 1; } } } return strcmp($a->container_type, $b->container_type); } protected function inline_editor($visible_columns) { ?>