broken-link-checker
Last commit date
images
17 years ago
languages
16 years ago
JSON.php
17 years ago
broken-link-checker.php
16 years ago
config-manager.php
16 years ago
core.php
16 years ago
highlighter-class.php
16 years ago
instance-classes.php
16 years ago
link-classes.php
16 years ago
readme.txt
16 years ago
uninstall.php
16 years ago
utility-class.php
16 years ago
core.php
3107 lines
| 1 | <?php |
| 2 | |
| 3 | //The plugin will use Snoopy in case CURL is not available |
| 4 | if (!class_exists('Snoopy')) require_once(ABSPATH. WPINC . '/class-snoopy.php'); |
| 5 | |
| 6 | /** |
| 7 | * Simple function to replicate PHP 5 behaviour |
| 8 | */ |
| 9 | if ( !function_exists( 'microtime_float' ) ) { |
| 10 | function microtime_float() |
| 11 | { |
| 12 | list($usec, $sec) = explode(" ", microtime()); |
| 13 | return ((float)$usec + (float)$sec); |
| 14 | } |
| 15 | } |
| 16 | |
| 17 | if (!class_exists('wsBrokenLinkChecker')) { |
| 18 | |
| 19 | class wsBrokenLinkChecker { |
| 20 | var $conf; |
| 21 | |
| 22 | var $loader; |
| 23 | var $my_basename = ''; |
| 24 | |
| 25 | var $db_version = 3; |
| 26 | |
| 27 | var $execution_start_time; //Used for a simple internal execution timer in start_timer()/execution_time() |
| 28 | var $lockfile_handle = null; |
| 29 | |
| 30 | var $native_filters = null; |
| 31 | |
| 32 | /** |
| 33 | * wsBrokenLinkChecker::wsBrokenLinkChecker() |
| 34 | * Class constructor |
| 35 | * |
| 36 | * @param string $loader The fully qualified filename of the loader script that WP identifies as the "main" plugin file. |
| 37 | * @param blcConfigurationManager $conf An instance of the configuration manager |
| 38 | * @return void |
| 39 | */ |
| 40 | function wsBrokenLinkChecker ( $loader, $conf ) { |
| 41 | global $wpdb; |
| 42 | |
| 43 | $this->loader = $loader; |
| 44 | $this->conf = $conf; |
| 45 | |
| 46 | add_action('activate_' . plugin_basename( $this->loader ), array(&$this,'activation')); |
| 47 | $this->my_basename = plugin_basename( $this->loader ); |
| 48 | |
| 49 | add_action('init', array(&$this,'load_language')); |
| 50 | |
| 51 | add_action('admin_menu', array(&$this,'admin_menu')); |
| 52 | |
| 53 | //These hooks update the plugin's internal records when posts are added, deleted or modified. |
| 54 | add_action('delete_post', array(&$this,'post_deleted')); |
| 55 | add_action('save_post', array(&$this,'post_saved')); |
| 56 | |
| 57 | //These do the same for (blogroll) links. |
| 58 | add_action('add_link', array(&$this,'hook_add_link')); |
| 59 | add_action('edit_link', array(&$this,'hook_edit_link')); |
| 60 | add_action('delete_link', array(&$this,'hook_delete_link')); |
| 61 | |
| 62 | //Load jQuery on Dashboard pages (probably redundant as WP already does that) |
| 63 | add_action('admin_print_scripts', array(&$this,'admin_print_scripts')); |
| 64 | |
| 65 | //The dashboard widget |
| 66 | add_action('wp_dashboard_setup', array(&$this, 'hook_wp_dashboard_setup')); |
| 67 | |
| 68 | //AJAXy hooks |
| 69 | //TODO: Check nonces in AJAX hooks |
| 70 | add_action( 'wp_ajax_blc_full_status', array(&$this,'ajax_full_status') ); |
| 71 | add_action( 'wp_ajax_blc_dashboard_status', array(&$this,'ajax_dashboard_status') ); |
| 72 | add_action( 'wp_ajax_blc_work', array(&$this,'ajax_work') ); |
| 73 | add_action( 'wp_ajax_blc_discard', array(&$this,'ajax_discard') ); |
| 74 | add_action( 'wp_ajax_blc_edit', array(&$this,'ajax_edit') ); |
| 75 | add_action( 'wp_ajax_blc_link_details', array(&$this,'ajax_link_details') ); |
| 76 | add_action( 'wp_ajax_blc_exclude_link', array(&$this,'ajax_exclude_link') ); |
| 77 | add_action( 'wp_ajax_blc_unlink', array(&$this,'ajax_unlink') ); |
| 78 | |
| 79 | //Check if it's possible to create a lockfile and nag the user about it if not. |
| 80 | if ( $this->lockfile_name() ){ |
| 81 | //Lockfiles work, so it's safe to enable the footer hook that will call the worker |
| 82 | //function via AJAX. |
| 83 | add_action('admin_footer', array(&$this,'admin_footer')); |
| 84 | } else { |
| 85 | //No lockfiles, nag nag nag! |
| 86 | add_action( 'admin_notices', array( &$this, 'lockfile_warning' ) ); |
| 87 | } |
| 88 | |
| 89 | //Initialize the built-in link filters |
| 90 | add_action('init', array(&$this,'init_native_filters')); |
| 91 | } |
| 92 | |
| 93 | function admin_footer(){ |
| 94 | ?> |
| 95 | <!-- wsblc admin footer --> |
| 96 | <div id='wsblc_updater_div'></div> |
| 97 | <script type='text/javascript'> |
| 98 | (function($){ |
| 99 | |
| 100 | //(Re)starts the background worker thread |
| 101 | function blcDoWork(){ |
| 102 | $.post( |
| 103 | "<?php echo admin_url('admin-ajax.php'); ?>", |
| 104 | { |
| 105 | 'action' : 'blc_work' |
| 106 | } |
| 107 | ); |
| 108 | } |
| 109 | //Call it the first time |
| 110 | blcDoWork(); |
| 111 | |
| 112 | //Then call it periodically every X seconds |
| 113 | setInterval(blcDoWork, <?php echo (intval($this->conf->options['max_execution_time']) + 1 )*1000; ?>); |
| 114 | |
| 115 | })(jQuery); |
| 116 | </script> |
| 117 | <!-- /wsblc admin footer --> |
| 118 | <?php |
| 119 | } |
| 120 | |
| 121 | function is_excluded($url){ |
| 122 | if (!is_array($this->conf->options['exclusion_list'])) return false; |
| 123 | foreach($this->conf->options['exclusion_list'] as $excluded_word){ |
| 124 | if (stristr($url, $excluded_word)){ |
| 125 | return true; |
| 126 | } |
| 127 | } |
| 128 | return false; |
| 129 | } |
| 130 | |
| 131 | function dashboard_widget(){ |
| 132 | ?> |
| 133 | <p id='wsblc_activity_box'><?php _e('Loading...', 'broken-link-checker'); ?></p> |
| 134 | <script type='text/javascript'> |
| 135 | jQuery( function($){ |
| 136 | var blc_was_autoexpanded = false; |
| 137 | |
| 138 | function blcDashboardStatus(){ |
| 139 | $.getJSON( |
| 140 | "<?php echo admin_url('admin-ajax.php'); ?>", |
| 141 | { |
| 142 | 'action' : 'blc_dashboard_status' |
| 143 | }, |
| 144 | function (data, textStatus){ |
| 145 | if ( data && ( typeof(data.text) != 'undefined' ) ) { |
| 146 | $('#wsblc_activity_box').html(data.text); |
| 147 | <?php if ( $this->conf->options['autoexpand_widget'] ) { ?> |
| 148 | //Expand the widget if there are broken links. |
| 149 | //Do this only once per pageload so as not to annoy the user. |
| 150 | if ( !blc_was_autoexpanded && ( data.status.broken_links > 0 ) ){ |
| 151 | $('#blc_dashboard_widget.postbox').removeClass('closed'); |
| 152 | blc_was_autoexpanded = true; |
| 153 | }; |
| 154 | <?php } ?> |
| 155 | } else { |
| 156 | $('#wsblc_activity_box').html('<?php _e('[ Network error ]', 'broken-link-checker'); ?>'); |
| 157 | } |
| 158 | |
| 159 | setTimeout( blcDashboardStatus, 120*1000 ); //...update every two minutes |
| 160 | } |
| 161 | ); |
| 162 | } |
| 163 | |
| 164 | blcDashboardStatus();//Call it the first time |
| 165 | |
| 166 | } ); |
| 167 | </script> |
| 168 | <?php |
| 169 | } |
| 170 | |
| 171 | function dashboard_widget_control( $widget_id, $form_inputs = array() ){ |
| 172 | if ( 'POST' == $_SERVER['REQUEST_METHOD'] && 'blc_dashboard_widget' == $_POST['widget_id'] ) { |
| 173 | //It appears $form_inputs isn't used in the current WP version, so lets just use $_POST |
| 174 | $this->conf->options['autoexpand_widget'] = !empty($_POST['blc-autoexpand']); |
| 175 | $this->conf->save_options(); |
| 176 | } |
| 177 | |
| 178 | ?> |
| 179 | <p><label for="blc-autoexpand"> |
| 180 | <input id="blc-autoexpand" name="blc-autoexpand" type="checkbox" value="1" <?php if ( $this->conf->options['autoexpand_widget'] ) echo 'checked="checked"'; ?> /> |
| 181 | <?php _e('Automatically expand the widget if broken links have been detected', 'broken-link-checker'); ?> |
| 182 | </label></p> |
| 183 | <?php |
| 184 | } |
| 185 | |
| 186 | function admin_print_scripts(){ |
| 187 | //jQuery is used for AJAX and effects |
| 188 | wp_enqueue_script('jquery'); |
| 189 | } |
| 190 | |
| 191 | function load_ui_scripts(){ |
| 192 | //jQuery UI is used on the settings page and in the link listings |
| 193 | wp_enqueue_script('jquery-ui-core'); |
| 194 | wp_enqueue_script('jquery-ui-dialog'); |
| 195 | } |
| 196 | |
| 197 | /** |
| 198 | * ws_broken_link_checker::post_deleted() |
| 199 | * A hook for post_deleted. Remove link instances associated with that post. |
| 200 | * |
| 201 | * @param int $post_id |
| 202 | * @return void |
| 203 | */ |
| 204 | function post_deleted($post_id){ |
| 205 | global $wpdb; |
| 206 | |
| 207 | //FB::log($post_id, "Post deleted"); |
| 208 | //Remove this post's instances |
| 209 | $q = "DELETE FROM {$wpdb->prefix}blc_instances |
| 210 | WHERE source_id = %d AND (source_type = 'post' OR source_type='custom_field')"; |
| 211 | $q = $wpdb->prepare($q, intval($post_id) ); |
| 212 | |
| 213 | //FB::log($q, 'Executing query'); |
| 214 | |
| 215 | if ( $wpdb->query( $q ) === false ){ |
| 216 | //FB::error($wpdb->last_error, "Database error"); |
| 217 | } |
| 218 | |
| 219 | //Remove the synch record |
| 220 | $q = "DELETE FROM {$wpdb->prefix}blc_synch |
| 221 | WHERE source_id = %d AND source_type = 'post'"; |
| 222 | $wpdb->query( $wpdb->prepare($q, intval($post_id)) ); |
| 223 | |
| 224 | //Remove any dangling link records |
| 225 | $this->cleanup_links(); |
| 226 | } |
| 227 | |
| 228 | function post_saved($post_id){ |
| 229 | global $wpdb; |
| 230 | |
| 231 | $post = get_post($post_id); |
| 232 | //Only check links in posts, not revisions and attachments |
| 233 | if ( ($post->post_type != 'post') && ($post->post_type != 'page') ) return null; |
| 234 | //Only check published posts |
| 235 | if ( $post->post_status != 'publish' ) return null; |
| 236 | |
| 237 | $this->mark_unsynched( $post_id, 'post' ); |
| 238 | } |
| 239 | |
| 240 | function initiate_recheck(){ |
| 241 | global $wpdb; |
| 242 | |
| 243 | //Delete all discovered instances |
| 244 | $wpdb->query("TRUNCATE {$wpdb->prefix}blc_instances"); |
| 245 | |
| 246 | //Delete all discovered links |
| 247 | $wpdb->query("TRUNCATE {$wpdb->prefix}blc_links"); |
| 248 | |
| 249 | //Mark all posts, custom fields and bookmarks for processing. |
| 250 | $this->resynch(); |
| 251 | } |
| 252 | |
| 253 | function resynch(){ |
| 254 | global $wpdb; |
| 255 | |
| 256 | //Drop all synchronization records |
| 257 | $wpdb->query("TRUNCATE {$wpdb->prefix}blc_synch"); |
| 258 | |
| 259 | //Create new synchronization records for posts |
| 260 | $q = "INSERT INTO {$wpdb->prefix}blc_synch(source_id, source_type, synched) |
| 261 | SELECT id, 'post', 0 |
| 262 | FROM {$wpdb->posts} |
| 263 | WHERE |
| 264 | {$wpdb->posts}.post_status = 'publish' |
| 265 | AND {$wpdb->posts}.post_type IN ('post', 'page')"; |
| 266 | $wpdb->query( $q ); |
| 267 | |
| 268 | //Create new synchronization records for bookmarks (the blogroll) |
| 269 | $q = "INSERT INTO {$wpdb->prefix}blc_synch(source_id, source_type, synched) |
| 270 | SELECT link_id, 'blogroll', 0 |
| 271 | FROM {$wpdb->links} |
| 272 | WHERE 1"; |
| 273 | $wpdb->query( $q ); |
| 274 | |
| 275 | //Delete invalid instances |
| 276 | $this->cleanup_instances(); |
| 277 | //Delete orphaned links |
| 278 | $this->cleanup_links(); |
| 279 | |
| 280 | $this->conf->options['need_resynch'] = true; |
| 281 | $this->conf->save_options(); |
| 282 | } |
| 283 | |
| 284 | function mark_unsynched( $source_id, $source_type ){ |
| 285 | global $wpdb; |
| 286 | |
| 287 | $q = "REPLACE INTO {$wpdb->prefix}blc_synch( source_id, source_type, synched, last_synch) |
| 288 | VALUES( %d, %s, %d, NOW() )"; |
| 289 | $rez = $wpdb->query( $wpdb->prepare( $q, $source_id, $source_type, 0 ) ); |
| 290 | |
| 291 | if ( !$this->conf->options['need_resynch'] ){ |
| 292 | $this->conf->options['need_resynch'] = true; |
| 293 | $this->conf->save_options(); |
| 294 | } |
| 295 | |
| 296 | return $rez; |
| 297 | } |
| 298 | |
| 299 | function mark_synched( $source_id, $source_type ){ |
| 300 | global $wpdb; |
| 301 | //FB::log("Marking $source_type $source_id as synched."); |
| 302 | $q = "REPLACE INTO {$wpdb->prefix}blc_synch( source_id, source_type, synched, last_synch) |
| 303 | VALUES( %d, %s, %d, NOW() )"; |
| 304 | return $wpdb->query( $wpdb->prepare( $q, $source_id, $source_type, 1 ) ); |
| 305 | } |
| 306 | |
| 307 | function activation(){ |
| 308 | //Prepare the database. |
| 309 | $this->upgrade_database(); |
| 310 | |
| 311 | //Clear the instance table and mark all posts and other parse-able objects as unsynchronized. |
| 312 | $this->resynch(); |
| 313 | |
| 314 | //Save the default options. |
| 315 | $this->conf->save_options(); |
| 316 | |
| 317 | //And optimize my DB tables, too (for good measure) |
| 318 | $this->optimize_database(); |
| 319 | } |
| 320 | |
| 321 | /** |
| 322 | * ws_broken_link_checker::upgrade_database() |
| 323 | * Create and/or upgrade database tables |
| 324 | * |
| 325 | * @param bool $die_on_error Whether the function should stop the script and display an error message if a DB error is encountered. |
| 326 | * @return void |
| 327 | */ |
| 328 | function upgrade_database( $die_on_error = true ){ |
| 329 | global $wpdb; |
| 330 | |
| 331 | //Do we need to upgrade? |
| 332 | //[ Disabled for now, was causing issues when the user manually deletes the plugin ] |
| 333 | //if ( $this->db_version == $this->conf->options['current_db_version'] ) return; |
| 334 | |
| 335 | //Delete tables used by older versions of the plugin |
| 336 | $rez = $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}blc_linkdata, {$wpdb->prefix}blc_postdata" ); |
| 337 | if ( $rez === false ){ |
| 338 | //FB::error($wpdb->last_error, "Database error"); |
| 339 | return false; |
| 340 | } |
| 341 | |
| 342 | require_once (ABSPATH . 'wp-admin/includes/upgrade.php'); |
| 343 | |
| 344 | //Create the link table if it doesn't exist yet. |
| 345 | $q = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}blc_links ( |
| 346 | link_id int(20) unsigned NOT NULL auto_increment, |
| 347 | url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL, |
| 348 | last_check datetime NOT NULL default '0000-00-00 00:00:00', |
| 349 | check_count int(2) unsigned NOT NULL default '0', |
| 350 | final_url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL, |
| 351 | redirect_count smallint(5) unsigned NOT NULL, |
| 352 | log text NOT NULL, |
| 353 | http_code smallint(6) NOT NULL, |
| 354 | request_duration float NOT NULL default '0', |
| 355 | timeout tinyint(1) unsigned NOT NULL default '0', |
| 356 | |
| 357 | PRIMARY KEY (link_id), |
| 358 | KEY url (url(150)), |
| 359 | KEY final_url (final_url(150)), |
| 360 | KEY http_code (http_code), |
| 361 | KEY timeout (timeout) |
| 362 | )"; |
| 363 | if ( $wpdb->query( $q ) === false ){ |
| 364 | if ( $die_on_error ) |
| 365 | die( sprintf( __('Database error : %s', 'broken-link-checker'), $wpdb->last_error) ); |
| 366 | }; |
| 367 | |
| 368 | //Fix URL fields so that they are collated as case-sensitive (this can't be done via dbDelta) |
| 369 | $q = "ALTER TABLE {$wpdb->prefix}blc_links |
| 370 | MODIFY url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL, |
| 371 | MODIFY final_url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL"; |
| 372 | if ( $wpdb->query( $q ) === false ){ |
| 373 | if ( $die_on_error ) |
| 374 | die( sprintf( __('Database error : %s', 'broken-link-checker'), $wpdb->last_error) ); |
| 375 | }; |
| 376 | |
| 377 | //Create the instance table |
| 378 | $q = "CREATE TABLE {$wpdb->prefix}blc_instances ( |
| 379 | instance_id int(10) unsigned NOT NULL auto_increment, |
| 380 | link_id int(10) unsigned NOT NULL, |
| 381 | source_id int(10) unsigned NOT NULL, |
| 382 | source_type enum('post','blogroll','custom_field') NOT NULL default 'post', |
| 383 | link_text varchar(250) NOT NULL, |
| 384 | instance_type enum('link','image') NOT NULL default 'link', |
| 385 | |
| 386 | PRIMARY KEY (instance_id), |
| 387 | KEY link_id (link_id), |
| 388 | KEY source_id (source_id,source_type), |
| 389 | FULLTEXT KEY link_text (link_text) |
| 390 | )"; |
| 391 | dbDelta($q); |
| 392 | |
| 393 | //Create the synchronization table |
| 394 | $q = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}blc_synch ( |
| 395 | source_id int(20) unsigned NOT NULL, |
| 396 | source_type enum('post','blogroll') NOT NULL, |
| 397 | synched tinyint(3) unsigned NOT NULL, |
| 398 | last_synch datetime NOT NULL, |
| 399 | PRIMARY KEY (source_id, source_type), |
| 400 | KEY synched (synched) |
| 401 | )"; |
| 402 | if ( $wpdb->query( $q ) === false ){ |
| 403 | if ( $die_on_error ) |
| 404 | die( sprintf( __('Database error : %s', 'broken-link-checker'), $wpdb->last_error) ); |
| 405 | }; |
| 406 | |
| 407 | //Create the custom filter table |
| 408 | $q = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}blc_filters ( |
| 409 | id int(10) unsigned NOT NULL AUTO_INCREMENT, |
| 410 | `name` varchar(100) NOT NULL, |
| 411 | params text NOT NULL, |
| 412 | PRIMARY KEY (id) |
| 413 | )"; |
| 414 | if ( $wpdb->query( $q ) === false ){ |
| 415 | if ( $die_on_error ) |
| 416 | die( sprintf( __('Database error : %s', 'broken-link-checker'), $wpdb->last_error) ); |
| 417 | }; |
| 418 | |
| 419 | $this->conf->options['current_db_version'] = $this->db_version; |
| 420 | $this->conf->save_options(); |
| 421 | |
| 422 | return true; |
| 423 | } |
| 424 | |
| 425 | /** |
| 426 | * wsBrokenLinkChecker::optimize_database() |
| 427 | * Optimize the plugin's tables |
| 428 | * |
| 429 | * @return void |
| 430 | */ |
| 431 | function optimize_database(){ |
| 432 | global $wpdb; |
| 433 | |
| 434 | $wpdb->query("OPTIMIZE TABLE {$wpdb->prefix}blc_links, {$wpdb->prefix}blc_instances, {$wpdb->prefix}blc_synch"); |
| 435 | } |
| 436 | |
| 437 | function admin_menu(){ |
| 438 | if (current_user_can('manage_options')) |
| 439 | add_filter('plugin_action_links', array(&$this, 'plugin_action_links'), 10, 2); |
| 440 | |
| 441 | $options_page_hook = add_options_page( |
| 442 | __('Link Checker Settings', 'broken-link-checker'), |
| 443 | __('Link Checker', 'broken-link-checker'), |
| 444 | 'manage_options', |
| 445 | 'link-checker-settings',array(&$this, 'options_page') |
| 446 | ); |
| 447 | |
| 448 | $links_page_hook = add_management_page( |
| 449 | __('View Broken Links', 'broken-link-checker'), |
| 450 | __('Broken Links', 'broken-link-checker'), |
| 451 | 'edit_others_posts', |
| 452 | 'view-broken-links',array(&$this, 'links_page') |
| 453 | ); |
| 454 | |
| 455 | //Add plugin-specific scripts and CSS only to the it's own pages |
| 456 | add_action( 'admin_print_styles-' . $options_page_hook, array(&$this, 'options_page_css') ); |
| 457 | add_action( 'admin_print_styles-' . $links_page_hook, array(&$this, 'links_page_css') ); |
| 458 | add_action( 'admin_print_scripts-' . $options_page_hook, array(&$this, 'load_ui_scripts') ); |
| 459 | add_action( 'admin_print_scripts-' . $links_page_hook, array(&$this, 'load_ui_scripts') ); |
| 460 | } |
| 461 | |
| 462 | /** |
| 463 | * plugin_action_links() |
| 464 | * Handler for the 'plugin_action_links' hook. Adds a "Settings" link to this plugin's entry |
| 465 | * on the plugin list. |
| 466 | * |
| 467 | * @param array $links |
| 468 | * @param string $file |
| 469 | * @return array |
| 470 | */ |
| 471 | function plugin_action_links($links, $file) { |
| 472 | if ($file == $this->my_basename) |
| 473 | $links[] = "<a href='options-general.php?page=link-checker-settings'>" . __('Settings') . "</a>"; |
| 474 | return $links; |
| 475 | } |
| 476 | |
| 477 | function mytruncate($str, $max_length=50){ |
| 478 | if(strlen($str)<=$max_length) return $str; |
| 479 | return (substr($str, 0, $max_length-3).'...'); |
| 480 | } |
| 481 | |
| 482 | function options_page(){ |
| 483 | if (isset($_GET['recheck']) && ($_GET['recheck'] == 'true')) { |
| 484 | $this->initiate_recheck(); |
| 485 | } |
| 486 | if(isset($_POST['submit'])) { |
| 487 | check_admin_referer('link-checker-options'); |
| 488 | |
| 489 | //The execution time limit must be above zero |
| 490 | $new_execution_time = intval($_POST['max_execution_time']); |
| 491 | if( $new_execution_time > 0 ){ |
| 492 | $this->conf->options['max_execution_time'] = $new_execution_time; |
| 493 | } |
| 494 | |
| 495 | //The check threshold also must be > 0 |
| 496 | $new_check_threshold=intval($_POST['check_threshold']); |
| 497 | if( $new_check_threshold > 0 ){ |
| 498 | $this->conf->options['check_threshold'] = $new_check_threshold; |
| 499 | } |
| 500 | |
| 501 | $this->conf->options['mark_broken_links'] = !empty($_POST['mark_broken_links']); |
| 502 | $new_broken_link_css = trim($_POST['broken_link_css']); |
| 503 | $this->conf->options['broken_link_css'] = $new_broken_link_css; |
| 504 | |
| 505 | $this->conf->options['mark_removed_links'] = !empty($_POST['mark_removed_links']); |
| 506 | $new_removed_link_css = trim($_POST['removed_link_css']); |
| 507 | $this->conf->options['removed_link_css'] = $new_removed_link_css; |
| 508 | |
| 509 | //TODO: Maybe update affected links when exclusion list changes (could be expensive resource-wise). |
| 510 | $this->conf->options['exclusion_list'] = array_filter( |
| 511 | preg_split( |
| 512 | '/[\s\r\n]+/', //split on newlines and whitespace |
| 513 | $_POST['exclusion_list'], |
| 514 | -1, |
| 515 | PREG_SPLIT_NO_EMPTY //skip empty values |
| 516 | ) |
| 517 | ); |
| 518 | |
| 519 | //Parse the custom field list |
| 520 | $new_custom_fields = array_filter( |
| 521 | preg_split( '/[\s\r\n]+/', $_POST['blc_custom_fields'], -1, PREG_SPLIT_NO_EMPTY ) |
| 522 | ); |
| 523 | |
| 524 | //Calculate the difference between the old custom field list and the new one (used later) |
| 525 | $diff1 = array_diff( $new_custom_fields, $this->conf->options['custom_fields'] ); |
| 526 | $diff2 = array_diff( $this->conf->options['custom_fields'], $new_custom_fields ); |
| 527 | $this->conf->options['custom_fields'] = $new_custom_fields; |
| 528 | |
| 529 | //Temporary file directory |
| 530 | $this->conf->options['custom_tmp_dir'] = trailingslashit( trim(stripslashes(strval($_POST['custom_tmp_dir']))) ); |
| 531 | |
| 532 | //HTTP timeout |
| 533 | $new_timeout = intval($_POST['timeout']); |
| 534 | if( $new_timeout > 0 ){ |
| 535 | $this->conf->options['timeout'] = $new_timeout ; |
| 536 | } |
| 537 | |
| 538 | $this->conf->save_options(); |
| 539 | |
| 540 | /* |
| 541 | If the list of custom fields was modified then we MUST resynchronize or |
| 542 | custom fields linked with existing posts may not be detected. This is somewhat |
| 543 | inefficient. |
| 544 | */ |
| 545 | if ( ( count($diff1) > 0 ) || ( count($diff2) > 0 ) ){ |
| 546 | $this->resynch(); |
| 547 | } |
| 548 | |
| 549 | $base_url = remove_query_arg( array('_wpnonce', 'noheader', 'updated', 'error', 'action', 'message') ); |
| 550 | wp_redirect( add_query_arg( array( 'updated' => 1), $base_url ) ); |
| 551 | } |
| 552 | |
| 553 | $debug = $this->get_debug_info(); |
| 554 | |
| 555 | ?> |
| 556 | |
| 557 | <div class="wrap"><h2><?php _e('Broken Link Checker Options', 'broken-link-checker'); ?></h2> |
| 558 | |
| 559 | <form name="link_checker_options" method="post" action="<?php |
| 560 | echo admin_url('options-general.php?page=link-checker-settings&noheader=1'); |
| 561 | ?>"> |
| 562 | <?php |
| 563 | wp_nonce_field('link-checker-options'); |
| 564 | ?> |
| 565 | |
| 566 | <table class="form-table"> |
| 567 | |
| 568 | <tr valign="top"> |
| 569 | <th scope="row"> |
| 570 | <?php _e('Status','broken-link-checker'); ?> |
| 571 | <br> |
| 572 | <a href="javascript:void(0)" id="blc-debug-info-toggle"><?php _e('Show debug info', 'broken-link-checker'); ?></a> |
| 573 | </th> |
| 574 | <td> |
| 575 | |
| 576 | |
| 577 | <div id='wsblc_full_status'> |
| 578 | <br/><br/><br/> |
| 579 | </div> |
| 580 | <script type='text/javascript'> |
| 581 | (function($){ |
| 582 | |
| 583 | function blcUpdateStatus(){ |
| 584 | $.getJSON( |
| 585 | "<?php echo admin_url('admin-ajax.php'); ?>", |
| 586 | { |
| 587 | 'action' : 'blc_full_status' |
| 588 | }, |
| 589 | function (data, textStatus){ |
| 590 | if ( data && ( typeof(data['text']) != 'undefined' ) ){ |
| 591 | $('#wsblc_full_status').html(data.text); |
| 592 | } else { |
| 593 | $('#wsblc_full_status').html('<?php _e('[ Network error ]', 'broken-link-checker'); ?>'); |
| 594 | } |
| 595 | |
| 596 | setTimeout(blcUpdateStatus, 10000); //...update every 10 seconds |
| 597 | } |
| 598 | ); |
| 599 | } |
| 600 | blcUpdateStatus();//Call it the first time |
| 601 | |
| 602 | })(jQuery); |
| 603 | </script> |
| 604 | <?php //JHS: Recheck all posts link: ?> |
| 605 | <p><input class="button" type="button" name="recheckbutton" |
| 606 | value="<?php _e('Re-check all pages', 'broken-link-checker'); ?>" |
| 607 | onclick="location.replace('<?php echo basename($_SERVER['PHP_SELF']); ?>?page=link-checker-settings&recheck=true')" /> |
| 608 | </p> |
| 609 | |
| 610 | <table id="blc-debug-info"> |
| 611 | <?php |
| 612 | |
| 613 | //Output the debug info in a table |
| 614 | foreach( $debug as $key => $value ){ |
| 615 | printf ( |
| 616 | '<tr valign="top" class="blc-debug-item-%s"><th scope="row">%s</th><td>%s<div class="blc-debug-message">%s</div></td></tr>', |
| 617 | $value['state'], |
| 618 | $key, |
| 619 | $value['value'], |
| 620 | ( array_key_exists('message', $value)?$value['message']:'') |
| 621 | ); |
| 622 | } |
| 623 | ?> |
| 624 | </table> |
| 625 | |
| 626 | </td> |
| 627 | </tr> |
| 628 | |
| 629 | <tr valign="top"> |
| 630 | <th scope="row"><?php _e('Check each link','broken-link-checker'); ?></th> |
| 631 | <td> |
| 632 | |
| 633 | <?php |
| 634 | printf( |
| 635 | __('Every %s hours','broken-link-checker'), |
| 636 | sprintf( |
| 637 | '<input type="text" name="check_threshold" id="check_threshold" value="%d" size="5" maxlength="5" />', |
| 638 | $this->conf->options['check_threshold'] |
| 639 | ) |
| 640 | ); |
| 641 | ?> |
| 642 | <br/> |
| 643 | <span class="description"> |
| 644 | <?php _e('Existing links will be checked this often. New links will usually be checked ASAP.', 'broken-link-checker'); ?> |
| 645 | </span> |
| 646 | |
| 647 | </td> |
| 648 | </tr> |
| 649 | |
| 650 | <tr valign="top"> |
| 651 | <th scope="row"><?php _e('Broken link CSS','broken-link-checker'); ?></th> |
| 652 | <td> |
| 653 | <label for='mark_broken_links'> |
| 654 | <input type="checkbox" name="mark_broken_links" id="mark_broken_links" |
| 655 | <?php if ($this->conf->options['mark_broken_links']) echo ' checked="checked"'; ?>/> |
| 656 | <?php _e('Apply <em>class="broken_link"</em> to broken links', 'broken-link-checker'); ?> |
| 657 | </label> |
| 658 | <br/> |
| 659 | <textarea name="broken_link_css" id="broken_link_css" cols='45' rows='4'/><?php |
| 660 | if( isset($this->conf->options['broken_link_css']) ) |
| 661 | echo $this->conf->options['broken_link_css']; |
| 662 | ?></textarea> |
| 663 | |
| 664 | </td> |
| 665 | </tr> |
| 666 | |
| 667 | <tr valign="top"> |
| 668 | <th scope="row"><?php _e('Removed link CSS','broken-link-checker'); ?></th> |
| 669 | <td> |
| 670 | <label for='mark_removed_links'> |
| 671 | <input type="checkbox" name="mark_removed_links" id="mark_removed_links" |
| 672 | <?php if ($this->conf->options['mark_removed_links']) echo ' checked="checked"'; ?>/> |
| 673 | <?php _e('Apply <em>class="removed_link"</em> to unlinked links', 'broken-link-checker'); ?> |
| 674 | </label> |
| 675 | <br/> |
| 676 | <textarea name="removed_link_css" id="removed_link_css" cols='45' rows='4'/><?php |
| 677 | if( isset($this->conf->options['removed_link_css']) ) |
| 678 | echo $this->conf->options['removed_link_css']; |
| 679 | ?></textarea> |
| 680 | |
| 681 | </td> |
| 682 | </tr> |
| 683 | |
| 684 | <tr valign="top"> |
| 685 | <th scope="row"><?php _e('Exclusion list', 'broken-link-checker'); ?></th> |
| 686 | <td><?php _e("Don't check links where the URL contains any of these words (one per line) :", 'broken-link-checker'); ?><br/> |
| 687 | <textarea name="exclusion_list" id="exclusion_list" cols='45' rows='4' wrap='off'/><?php |
| 688 | if( isset($this->conf->options['exclusion_list']) ) |
| 689 | echo implode("\n", $this->conf->options['exclusion_list']); |
| 690 | ?></textarea> |
| 691 | |
| 692 | </td> |
| 693 | </tr> |
| 694 | |
| 695 | <tr valign="top"> |
| 696 | <th scope="row"><?php _e('Custom fields', 'broken-link-checker'); ?></th> |
| 697 | <td><?php _e('Check URLs entered in these custom fields (one per line) :', 'broken-link-checker'); ?><br/> |
| 698 | <textarea name="blc_custom_fields" id="blc_custom_fields" cols='45' rows='4' /><?php |
| 699 | if( isset($this->conf->options['custom_fields']) ) |
| 700 | echo implode("\n", $this->conf->options['custom_fields']); |
| 701 | ?></textarea> |
| 702 | |
| 703 | </td> |
| 704 | </tr> |
| 705 | |
| 706 | </table> |
| 707 | |
| 708 | <h3><?php _e('Advanced','broken-link-checker'); ?></h3> |
| 709 | |
| 710 | <table class="form-table"> |
| 711 | |
| 712 | |
| 713 | <tr valign="top"> |
| 714 | <th scope="row"><?php _e('Timeout', 'broken-link-checker'); ?></th> |
| 715 | <td> |
| 716 | |
| 717 | <?php |
| 718 | |
| 719 | printf( |
| 720 | __('%s seconds', 'broken-link-checker'), |
| 721 | sprintf( |
| 722 | '<input type="text" name="timeout" id="blc_timeout" value="%d" size="5" maxlength="3" />', |
| 723 | $this->conf->options['timeout'] |
| 724 | ) |
| 725 | ); |
| 726 | |
| 727 | ?> |
| 728 | <br/><span class="description"> |
| 729 | <?php _e('Links that take longer than this to load will be marked as broken.','broken-link-checker'); ?> |
| 730 | </span> |
| 731 | |
| 732 | </td> |
| 733 | </tr> |
| 734 | |
| 735 | |
| 736 | <tr valign="top"> |
| 737 | <th scope="row"> |
| 738 | <a name='lockfile_directory'></a><?php _e('Custom temporary directory', 'broken-link-checker'); ?></th> |
| 739 | <td> |
| 740 | |
| 741 | <input type="text" name="custom_tmp_dir" id="custom_tmp_dir" |
| 742 | value="<?php echo htmlspecialchars( $this->conf->options['custom_tmp_dir'] ); ?>" size='53' maxlength='500'/> |
| 743 | <?php |
| 744 | if ( !empty( $this->conf->options['custom_tmp_dir'] ) ) { |
| 745 | if ( @is_dir( $this->conf->options['custom_tmp_dir'] ) ){ |
| 746 | if ( blcUtility::is_writable( $this->conf->options['custom_tmp_dir'] ) ){ |
| 747 | echo "<strong>", __('OK', 'broken-link-checker'), "</strong>"; |
| 748 | } else { |
| 749 | echo '<span class="error">'; |
| 750 | _e("Error : This directory isn't writable by PHP.", 'broken-link-checker'); |
| 751 | echo '</span>'; |
| 752 | } |
| 753 | } else { |
| 754 | echo '<span class="error">'; |
| 755 | _e("Error : This directory doesn't exist.", 'broken-link-checker'); |
| 756 | echo '</span>'; |
| 757 | } |
| 758 | } |
| 759 | |
| 760 | ?> |
| 761 | <br/> |
| 762 | <span class="description"> |
| 763 | <?php _e('Set this field if you want the plugin to use a custom directory for its lockfiles. Otherwise, leave it blank.','broken-link-checker'); ?> |
| 764 | </span> |
| 765 | |
| 766 | </td> |
| 767 | </tr> |
| 768 | |
| 769 | <tr valign="top"> |
| 770 | <th scope="row"><?php _e('Max. execution time', 'broken-link-checker'); ?></th> |
| 771 | <td> |
| 772 | |
| 773 | <?php |
| 774 | |
| 775 | printf( |
| 776 | __('%s seconds', 'broken-link-checker'), |
| 777 | sprintf( |
| 778 | '<input type="text" name="max_execution_time" id="max_execution_time" value="%d" size="5" maxlength="5" />', |
| 779 | $this->conf->options['max_execution_time'] |
| 780 | ) |
| 781 | ); |
| 782 | |
| 783 | ?> |
| 784 | <br/><span class="description"> |
| 785 | <?php |
| 786 | |
| 787 | _e('The plugin works by periodically creating a background worker instance that parses your posts looking for links, checks the discovered URLs, and performs other time-consuming tasks. Here you can set for how long, at most, the background instance may run each time before stopping.', 'broken-link-checker'); |
| 788 | |
| 789 | ?> |
| 790 | </span> |
| 791 | |
| 792 | </td> |
| 793 | </tr> |
| 794 | |
| 795 | </table> |
| 796 | |
| 797 | <p class="submit"><input type="submit" name="submit" class='button-primary' value="<?php _e('Save Changes') ?>" /></p> |
| 798 | </form> |
| 799 | </div> |
| 800 | |
| 801 | <script type='text/javascript'> |
| 802 | jQuery(function($){ |
| 803 | var toggleButton = $('#blc-debug-info-toggle'); |
| 804 | |
| 805 | toggleButton.click(function(){ |
| 806 | |
| 807 | var box = $('#blc-debug-info'); |
| 808 | box.toggle(); |
| 809 | if( box.is(':visible') ){ |
| 810 | toggleButton.text('<?php _e('Hide debug info', 'broken-link-checker'); ?>'); |
| 811 | } else { |
| 812 | toggleButton.text('<?php _e('Show debug info', 'broken-link-checker'); ?>'); |
| 813 | } |
| 814 | |
| 815 | }); |
| 816 | }); |
| 817 | </script> |
| 818 | <?php |
| 819 | } |
| 820 | |
| 821 | function options_page_css(){ |
| 822 | ?> |
| 823 | <style type='text/css'> |
| 824 | #blc-debug-info-toggle { |
| 825 | font-size: smaller; |
| 826 | } |
| 827 | |
| 828 | .blc-debug-item-ok { |
| 829 | background-color: #d7ffa2; |
| 830 | } |
| 831 | .blc-debug-item-warning { |
| 832 | background-color: #fcffa2; |
| 833 | } |
| 834 | .blc-debug-item-error { |
| 835 | background-color: #ffc4c4; |
| 836 | } |
| 837 | |
| 838 | #blc-debug-info { |
| 839 | display: none; |
| 840 | |
| 841 | text-align: left; |
| 842 | |
| 843 | border-width: 1px; |
| 844 | border-color: gray; |
| 845 | border-style: solid; |
| 846 | |
| 847 | border-spacing: 0px; |
| 848 | border-collapse: collapse; |
| 849 | } |
| 850 | |
| 851 | #blc-debug-info th, #blc-debug-info td { |
| 852 | padding: 6px; |
| 853 | font-weight: normal; |
| 854 | text-shadow: none; |
| 855 | |
| 856 | border-width: 1px ; |
| 857 | border-color: silver; |
| 858 | border-style: solid; |
| 859 | |
| 860 | border-collapse: collapse; |
| 861 | } |
| 862 | </style> |
| 863 | <?php |
| 864 | } |
| 865 | |
| 866 | /** |
| 867 | * wsBrokenLinkChecker::init_native_filters() |
| 868 | * Initializes (if necessary) and returns the list of built-in link filters |
| 869 | * |
| 870 | * @return array |
| 871 | */ |
| 872 | function init_native_filters(){ |
| 873 | if ( !empty($this->native_filters) ){ |
| 874 | return $this->native_filters; |
| 875 | } else { |
| 876 | //Available filters by link type + the appropriate WHERE expressions |
| 877 | $this->native_filters = array( |
| 878 | 'broken' => array( |
| 879 | 'where_expr' => '( http_code < 200 OR http_code >= 400 OR timeout = 1 ) AND ( check_count > 0 ) AND ( http_code <> ' . BLC_CHECKING . ')', |
| 880 | 'name' => __('Broken', 'broken-link-checker'), |
| 881 | 'heading' => __('Broken Links', 'broken-link-checker'), |
| 882 | 'heading_zero' => __('No broken links found', 'broken-link-checker') |
| 883 | ), |
| 884 | 'redirects' => array( |
| 885 | 'where_expr' => '( redirect_count > 0 )', |
| 886 | 'name' => __('Redirects', 'broken-link-checker'), |
| 887 | 'heading' => __('Redirected Links', 'broken-link-checker'), |
| 888 | 'heading_zero' => __('No redirects found', 'broken-link-checker') |
| 889 | ), |
| 890 | |
| 891 | 'all' => array( |
| 892 | 'where_expr' => '1', |
| 893 | 'name' => __('All', 'broken-link-checker'), |
| 894 | 'heading' => __('Detected Links', 'broken-link-checker'), |
| 895 | 'heading_zero' => __('No links found (yet)', 'broken-link-checker') |
| 896 | ), |
| 897 | ); |
| 898 | |
| 899 | return $this->native_filters; |
| 900 | } |
| 901 | } |
| 902 | |
| 903 | /** |
| 904 | * wsBrokenLinkChecker::get_custom_filters() |
| 905 | * Returns a list of user-defined link filters. |
| 906 | * |
| 907 | * @return array An array of custom filter definitions. If there are no custom filters defined returns an empty array. |
| 908 | */ |
| 909 | function get_custom_filters(){ |
| 910 | global $wpdb; |
| 911 | |
| 912 | $filter_data = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}blc_filters ORDER BY name ASC", ARRAY_A); |
| 913 | $filters = array(); |
| 914 | |
| 915 | if ( !empty($filter_data) ) { |
| 916 | foreach($filter_data as $data){ |
| 917 | $filters[ 'f'.$data['id'] ] = array( |
| 918 | 'name' => $data['name'], |
| 919 | 'params' => $data['params'], |
| 920 | 'is_search' => true, |
| 921 | 'heading' => ucwords($data['name']), |
| 922 | 'heading_zero' => __('No links found for your query', 'broken-link-checker'), |
| 923 | ); |
| 924 | } |
| 925 | } |
| 926 | |
| 927 | return $filters; |
| 928 | } |
| 929 | |
| 930 | function get_search_params( $filter = null ){ |
| 931 | //If present, the filter's parameters may be saved either as an array or a string. |
| 932 | $params = array(); |
| 933 | if ( !empty($filter) && !empty($filter['params']) ){ |
| 934 | $params = $filter['params']; |
| 935 | if ( is_string( $params ) ){ |
| 936 | wp_parse_str($params, $params); |
| 937 | } |
| 938 | } else { |
| 939 | //If the filter doesn't have it's own search query, use the URL parameters |
| 940 | $params = array_merge($params, $_GET); |
| 941 | } |
| 942 | |
| 943 | //Only leave valid search query parameters |
| 944 | $search_param_names = array( 's_link_text', 's_link_url', 's_http_code', 's_filter', 's_link_type' ); |
| 945 | $output = array(); |
| 946 | foreach ( $params as $name => $value ){ |
| 947 | if ( in_array($name, $search_param_names) ){ |
| 948 | $output[$name] = $value; |
| 949 | } |
| 950 | } |
| 951 | |
| 952 | return $output; |
| 953 | } |
| 954 | |
| 955 | function links_page(){ |
| 956 | global $wpdb; |
| 957 | |
| 958 | $action = !empty($_POST['action'])?$_POST['action']:''; |
| 959 | |
| 960 | if ( $action == 'create-custom-filter' ){ |
| 961 | //Create a custom filter! |
| 962 | |
| 963 | check_admin_referer( $action ); |
| 964 | |
| 965 | $message = ''; |
| 966 | $msg_class = 'updated'; |
| 967 | |
| 968 | //Filter name must be set |
| 969 | if ( empty($_POST['name']) ){ |
| 970 | $message = __("You must enter a filter name!", 'broken-link-checker'); |
| 971 | $msg_class = 'error'; |
| 972 | //Filter parameters (a search query) must also be set |
| 973 | } elseif ( empty($_POST['params']) ){ |
| 974 | $message = __("Invalid search query.", 'broken-link-checker'); |
| 975 | $msg_class = 'error'; |
| 976 | } else { |
| 977 | //Save the new filter |
| 978 | $q = $wpdb->prepare( |
| 979 | "INSERT INTO {$wpdb->prefix}blc_filters(name, params) VALUES (%s, %s)", |
| 980 | $_POST['name'], $_POST['params'] |
| 981 | ); |
| 982 | |
| 983 | if ( $wpdb->query($q) ){ |
| 984 | //Saved |
| 985 | $message = sprintf( __('Filter "%s" created', 'broken-link-checker'), $_POST['name']); |
| 986 | //A little hack to make the filter active immediately |
| 987 | $_GET['filter_id'] = 'f' . $wpdb->insert_id; |
| 988 | } else { |
| 989 | //Error |
| 990 | $message = sprintf( __("Database error : %s", 'broken-link-checker'), $wpdb->last_error); |
| 991 | $msg_class = 'error'; |
| 992 | } |
| 993 | } |
| 994 | |
| 995 | echo '<div id="message" class="'.$msg_class.' fade"><p><strong>'.$message.'</strong></p></div>'; |
| 996 | |
| 997 | } elseif ( $action == 'delete-custom-filter' ){ |
| 998 | //Delete an existing custom filter! |
| 999 | |
| 1000 | check_admin_referer( $action ); |
| 1001 | |
| 1002 | $message = ''; |
| 1003 | $msg_class = 'updated'; |
| 1004 | |
| 1005 | //Filter ID must be set |
| 1006 | if ( empty($_POST['filter_id']) ){ |
| 1007 | $message = __("Filter ID not specified.", 'broken-link-checker'); |
| 1008 | $msg_class = 'error'; |
| 1009 | } else { |
| 1010 | //Remove the "f" character from the filter ID to get its database key |
| 1011 | $filter_id = intval(ltrim($_POST['filter_id'], 'f')); |
| 1012 | //Try to delete the filter |
| 1013 | $q = $wpdb->prepare("DELETE FROM {$wpdb->prefix}blc_filters WHERE id = %d", $filter_id); |
| 1014 | if ( $wpdb->query($q) ){ |
| 1015 | //Success |
| 1016 | $message = __('Filter deleted', 'broken-link-checker'); |
| 1017 | } else { |
| 1018 | //Either the ID is wrong or there was some other error |
| 1019 | $message = __('Database error : %s', 'broken-link-checker'); |
| 1020 | $msg_class = 'error'; |
| 1021 | } |
| 1022 | } |
| 1023 | echo '<div id="message" class="'.$msg_class.' fade"><p><strong>'.$message.'</strong></p></div>'; |
| 1024 | } |
| 1025 | |
| 1026 | //Build the filter list |
| 1027 | $filters = array_merge($this->native_filters, $this->get_custom_filters()); |
| 1028 | |
| 1029 | //Add the special "search" filter |
| 1030 | $filters['search'] = array( |
| 1031 | 'name' => __('Search', 'broken-link-checker'), |
| 1032 | 'heading' => __('Search Results', 'broken-link-checker'), |
| 1033 | 'heading_zero' => __('No links found for your query', 'broken-link-checker'), |
| 1034 | 'is_search' => true, |
| 1035 | 'where_expr' => 1, |
| 1036 | 'hidden' => true, |
| 1037 | ); |
| 1038 | |
| 1039 | //Calculate the number of links for each filter |
| 1040 | foreach ($filters as $filter => $data){ |
| 1041 | $filters[$filter]['count'] = $this->get_links($data, 0, 0, true); |
| 1042 | } |
| 1043 | |
| 1044 | //Get the selected filter (defaults to displaying broken links) |
| 1045 | $filter_id = isset($_GET['filter_id'])?$_GET['filter_id']:'broken'; |
| 1046 | if ( !isset($filters[$filter_id]) ){ |
| 1047 | $filter_id = 'broken'; |
| 1048 | } |
| 1049 | |
| 1050 | //Get the desired page number (must be > 0) |
| 1051 | $page = isset($_GET['paged'])?intval($_GET['paged']):'1'; |
| 1052 | if ($page < 1) $page = 1; |
| 1053 | |
| 1054 | //Links per page [1 - 200] |
| 1055 | $per_page = isset($_GET['per_page'])?intval($_GET['per_page']):'30'; |
| 1056 | if ($per_page < 1){ |
| 1057 | $per_page = 30; |
| 1058 | } else if ($per_page > 200){ |
| 1059 | $per_page = 200; |
| 1060 | } |
| 1061 | |
| 1062 | $current_filter = $filters[$filter_id]; |
| 1063 | $max_pages = ceil($current_filter['count'] / $per_page); |
| 1064 | |
| 1065 | //Select the required links + 1 instance per link. |
| 1066 | $links = $this->get_links( $current_filter, ( ($page-1) * $per_page ), $per_page ); |
| 1067 | if ( is_null($links) && !empty($wpdb->last_error) ){ |
| 1068 | printf( __('Database error : %s', 'broken-link-checker'), $wpdb->last_error); |
| 1069 | } |
| 1070 | |
| 1071 | //Save the search params (if any) in a handy array for later |
| 1072 | if ( !empty($current_filter['is_search']) ){ |
| 1073 | $search_params = $this->get_search_params($current_filter); |
| 1074 | } else { |
| 1075 | $search_params = array(); |
| 1076 | } |
| 1077 | |
| 1078 | //Display the "Discard" button when listing broken links |
| 1079 | $show_discard_button = ('broken' == $filter_id) || (!empty($search_params['s_filter']) && ($search_params['s_filter'] == 'broken')); |
| 1080 | |
| 1081 | ?> |
| 1082 | |
| 1083 | <script type='text/javascript'> |
| 1084 | var blc_current_filter = '<?php echo $filter_id; ?>'; |
| 1085 | </script> |
| 1086 | |
| 1087 | <div class="wrap"> |
| 1088 | <h2><?php |
| 1089 | //Output a header matching the current filter |
| 1090 | if ( $current_filter['count'] > 0 ){ |
| 1091 | echo $current_filter['heading'] . " (<span class='current-link-count'>{$current_filter[count]}</span>)"; |
| 1092 | } else { |
| 1093 | echo $current_filter['heading_zero'] . "<span class='current-link-count'></span>"; |
| 1094 | } |
| 1095 | ?> |
| 1096 | </h2> |
| 1097 | <ul class="subsubsub"> |
| 1098 | <?php |
| 1099 | //Construct a submenu of filter types |
| 1100 | $items = array(); |
| 1101 | foreach ($filters as $filter => $data){ |
| 1102 | if ( !empty($data['hidden']) ) continue; //skip hidden filters |
| 1103 | |
| 1104 | $class = $number_class = ''; |
| 1105 | |
| 1106 | if ( $filter_id == $filter ) { |
| 1107 | $class = 'class="current"'; |
| 1108 | $number_class = 'current-link-count'; |
| 1109 | } |
| 1110 | |
| 1111 | $items[] = "<li><a href='tools.php?page=view-broken-links&filter_id=$filter' $class> |
| 1112 | {$data[name]}</a> <span class='count'>(<span class='$number_class'>{$data[count]}</span>)</span>"; |
| 1113 | } |
| 1114 | echo implode(' |</li>', $items); |
| 1115 | unset($items); |
| 1116 | ?> |
| 1117 | </ul> |
| 1118 | |
| 1119 | <div class="search-box"> |
| 1120 | |
| 1121 | <?php |
| 1122 | //If we're currently displaying search results offer the user the option to s |
| 1123 | //save the search query as a custom filter. |
| 1124 | if ( $filter_id == 'search' ){ |
| 1125 | ?> |
| 1126 | <form name="save-search-query" id="custom-filter-form" action="<?php echo admin_url("tools.php?page=view-broken-links"); ?>" method="post" class="blc-inline-form"> |
| 1127 | <?php wp_nonce_field('create-custom-filter'); ?> |
| 1128 | <input type="hidden" name="name" id="blc-custom-filter-name" value="" /> |
| 1129 | <input type="hidden" name="params" id="blc-custom-filter-params" value="<?php echo http_build_query($search_params, null, '&'); ?>" /> |
| 1130 | <input type="hidden" name="action" value="create-custom-filter" /> |
| 1131 | <input type="button" value="<?php esc_attr_e( 'Save This Search As a Filter', 'broken-link-checker' ); ?>" id="blc-create-filter" class="button" /> |
| 1132 | </form> |
| 1133 | <?php |
| 1134 | } elseif ( !empty($current_filter['is_search']) ){ |
| 1135 | //If we're displaying a custom filter give an option to delete it. |
| 1136 | ?> |
| 1137 | <form name="save-search-query" id="custom-filter-form" action="<?php echo admin_url("tools.php?page=view-broken-links"); ?>" method="post" class="blc-inline-form"> |
| 1138 | <?php wp_nonce_field('delete-custom-filter'); ?> |
| 1139 | <input type="hidden" name="filter_id" id="blc-custom-filter-id" value="<?php echo $filter_id; ?>" /> |
| 1140 | <input type="hidden" name="action" value="delete-custom-filter" /> |
| 1141 | <input type="submit" value="<?php esc_attr_e( 'Delete This Filter', 'broken-link-checker' ); ?>" id="blc-delete-filter" class="button" /> |
| 1142 | </form> |
| 1143 | <?php |
| 1144 | } |
| 1145 | ?> |
| 1146 | |
| 1147 | <input type="button" value="<?php esc_attr_e( 'Search', 'broken-link-checker' ); ?> »" id="blc-open-search-box" class="button" /> |
| 1148 | </div> |
| 1149 | |
| 1150 | <!-- The search dialog --> |
| 1151 | <div id='search-links-dialog' title='Search'> |
| 1152 | <form class="search-form" action="<?php echo admin_url('tools.php?page=view-broken-links'); ?>" method="get"> |
| 1153 | <input type="hidden" name="page" value="view-broken-links" /> |
| 1154 | <input type="hidden" name="filter_id" value="search" /> |
| 1155 | <fieldset> |
| 1156 | |
| 1157 | <label for="s_link_text"><?php _e('Link text', 'broken-link-checker'); ?></label> |
| 1158 | <input type="text" name="s_link_text" value="<?php if(!empty($search_params['s_link_text'])) echo esc_attr($search_params['s_link_text']); ?>" id="s_link_text" class="text ui-widget-content" /> |
| 1159 | |
| 1160 | <label for="s_link_url"><?php _e('URL', 'broken-link-checker'); ?></label> |
| 1161 | <input type="text" name="s_link_url" id="s_link_url" value="<?php if(!empty($search_params['s_link_url'])) echo esc_attr($search_params['s_link_url']); ?>" class="text ui-widget-content" /> |
| 1162 | |
| 1163 | <label for="s_http_code"><?php _e('HTTP code', 'broken-link-checker'); ?></label> |
| 1164 | <input type="text" name="s_http_code" id="s_http_code" value="<?php if(!empty($search_params['s_http_code'])) echo esc_attr($search_params['s_http_code']); ?>" class="text ui-widget-content" /> |
| 1165 | |
| 1166 | <label for="s_filter"><?php _e('Link status', 'broken-link-checker'); ?></label> |
| 1167 | <select name="s_filter" id="s_filter"> |
| 1168 | <?php |
| 1169 | if ( !empty($search_params['s_filter']) ){ |
| 1170 | $search_subfilter = $search_params['s_filter']; |
| 1171 | } else { |
| 1172 | $search_subfilter = $filter_id; |
| 1173 | } |
| 1174 | |
| 1175 | foreach ($this->native_filters as $filter => $data){ |
| 1176 | $selected = ($search_subfilter == $filter)?' selected="selected"':''; |
| 1177 | printf('<option value="%s"%s>%s</option>', $filter, $selected, $data['name']); |
| 1178 | } |
| 1179 | ?> |
| 1180 | </select> |
| 1181 | |
| 1182 | <label for="s_link_type"><?php _e('Link type', 'broken-link-checker'); ?></label> |
| 1183 | <select name="s_link_type" id="s_link_type"> |
| 1184 | <?php |
| 1185 | $link_types = array( |
| 1186 | __('Any', 'broken-link-checker') => '', |
| 1187 | __('Normal link', 'broken-link-checker') => 'link', |
| 1188 | __('Image', 'broken-link-checker') => 'image', |
| 1189 | __('Custom field', 'broken-link-checker') => 'custom_field', |
| 1190 | __('Bookmark', 'broken-link-checker') => 'blogroll', |
| 1191 | ); |
| 1192 | |
| 1193 | foreach ($link_types as $name => $value){ |
| 1194 | $selected = ( isset($search_params['s_link_type']) && $search_params['s_link_type'] == $value )?' selected="selected"':''; |
| 1195 | printf('<option value="%s"%s>%s</option>', $value, $selected, $name); |
| 1196 | } |
| 1197 | ?> |
| 1198 | </select> |
| 1199 | |
| 1200 | </fieldset> |
| 1201 | |
| 1202 | <div id="blc-search-button-row"> |
| 1203 | <input type="submit" value="<?php esc_attr_e( 'Search Links', 'broken-link-checker' ); ?>" id="blc-search-button" name="search_button" class="button-primary" /> |
| 1204 | <input type="button" value="<?php esc_attr_e( 'Cancel', 'broken-link-checker' ); ?>" id="blc-cancel-search" class="button" /> |
| 1205 | </div> |
| 1206 | |
| 1207 | </form> |
| 1208 | </div> |
| 1209 | |
| 1210 | <div class='tablenav'> |
| 1211 | |
| 1212 | <div class="alignleft actions"> |
| 1213 | <span class='description'> |
| 1214 | <?php |
| 1215 | /* |
| 1216 | //If this is a search filter, display the search query here |
| 1217 | if ( !empty($current_filter['is_search']) ){ |
| 1218 | $params = $search_params; |
| 1219 | $search_query = array(); |
| 1220 | |
| 1221 | if ( !empty($params['s_link_text']) ){ |
| 1222 | $search_query[] = sprintf('link text is like "%s"', $params['s_link_text']); |
| 1223 | } |
| 1224 | if ( !empty($params['s_link_url']) ){ |
| 1225 | $search_query[] = sprintf('the URL contains "%s"', $params['s_link_url']); |
| 1226 | } |
| 1227 | if ( !empty($params['s_http_code']) ){ |
| 1228 | $search_query[] = 'HTTP code matches ' . $params['s_http_code']; |
| 1229 | } |
| 1230 | if ( !empty($params['s_link_type']) ){ |
| 1231 | $search_query[] = sprintf('link type is "%s"', $params['s_link_type']); |
| 1232 | } |
| 1233 | |
| 1234 | echo sprintf("Showing %s links where ", $params['s_filter']) , implode(', ', $search_query); |
| 1235 | } |
| 1236 | */ |
| 1237 | ?> |
| 1238 | </span> |
| 1239 | </div> |
| 1240 | <?php |
| 1241 | //Display pagination links |
| 1242 | $page_links = paginate_links( array( |
| 1243 | 'base' => add_query_arg( 'paged', '%#%' ), |
| 1244 | 'format' => '', |
| 1245 | 'prev_text' => __('«'), |
| 1246 | 'next_text' => __('»'), |
| 1247 | 'total' => $max_pages, |
| 1248 | 'current' => $page |
| 1249 | )); |
| 1250 | |
| 1251 | if ( $page_links ) { |
| 1252 | echo '<div class="tablenav-pages">'; |
| 1253 | $page_links_text = sprintf( '<span class="displaying-num">' . __( 'Displaying %s–%s of <span class="current-link-count">%s</span>', 'broken-link-checker' ) . '</span>%s', |
| 1254 | number_format_i18n( ( $page - 1 ) * $per_page + 1 ), |
| 1255 | number_format_i18n( min( $page * $per_page, count($links) ) ), |
| 1256 | number_format_i18n( $current_filter['count'] ), |
| 1257 | $page_links |
| 1258 | ); |
| 1259 | echo $page_links_text; |
| 1260 | echo '</div>'; |
| 1261 | } |
| 1262 | ?> |
| 1263 | |
| 1264 | </div> |
| 1265 | |
| 1266 | <?php |
| 1267 | if($links && (count($links)>0)){ |
| 1268 | ?> |
| 1269 | <table class="widefat"> |
| 1270 | <thead> |
| 1271 | <tr> |
| 1272 | |
| 1273 | <th scope="col"><?php _e('Source', 'broken-link-checker'); ?> |
| 1274 | </th> |
| 1275 | <th scope="col"><?php _e('Link Text', 'broken-link-checker'); ?></th> |
| 1276 | <th scope="col"><?php _e('URL', 'broken-link-checker'); ?></th> |
| 1277 | |
| 1278 | <?php if ( $show_discard_button ) { ?> |
| 1279 | <th scope="col"> </th> |
| 1280 | <?php } ?> |
| 1281 | |
| 1282 | </tr> |
| 1283 | </thead> |
| 1284 | <tbody id="the-list"> |
| 1285 | <?php |
| 1286 | $rowclass = ''; $rownum = 0; |
| 1287 | foreach ($links as $link) { |
| 1288 | $rownum++; |
| 1289 | |
| 1290 | $rowclass = 'alternate' == $rowclass ? '' : 'alternate'; |
| 1291 | $excluded = $this->is_excluded( $link['url'] ); |
| 1292 | if ( $excluded ) $rowclass .= ' blc-excluded-link'; |
| 1293 | |
| 1294 | ?> |
| 1295 | <tr id='<?php echo "blc-row-$rownum"; ?>' class='blc-row <?php echo $rowclass; ?>'> |
| 1296 | <td class='post-title column-title'> |
| 1297 | <span class='blc-link-id' style='display:none;'><?php echo $link['link_id']; ?></span> |
| 1298 | <?php |
| 1299 | if ( ('post' == $link['source_type']) || ('custom_field' == $link['source_type']) ){ |
| 1300 | |
| 1301 | echo "<a class='row-title' href='post.php?action=edit&post=$link[source_id]' title='", |
| 1302 | attribute_escape(__('Edit this post')), |
| 1303 | "'>{$link[post_title]}</a>"; |
| 1304 | |
| 1305 | //Output inline action links (copied from edit-post-rows.php) |
| 1306 | $actions = array(); |
| 1307 | if ( current_user_can('edit_post', $link['source_id']) ) { |
| 1308 | $actions['edit'] = '<span class="edit"><a href="' . get_edit_post_link($link['source_id'], true) . '" title="' . attribute_escape(__('Edit this post')) . '">' . __('Edit') . '</a>'; |
| 1309 | $actions['delete'] = "<span class='delete'><a class='submitdelete' title='" . attribute_escape(__('Delete this post')) . "' href='" . wp_nonce_url("post.php?action=delete&post=".$link['source_id'], 'delete-post_' . $link['source_id']) . "' onclick=\"if ( confirm('" . js_escape(sprintf( __("You are about to delete this post '%s'\n 'Cancel' to stop, 'OK' to delete."), $link['post_title'] )) . "') ) { return true;}return false;\">" . __('Delete') . "</a>"; |
| 1310 | } |
| 1311 | $actions['view'] = '<span class="view"><a href="' . get_permalink($link['source_id']) . '" title="' . attribute_escape(sprintf(__('View "%s"', 'broken-link-checker'), $link['post_title'])) . '" rel="permalink">' . __('View') . '</a>'; |
| 1312 | echo '<div class="row-actions">'; |
| 1313 | echo implode(' | </span>', $actions); |
| 1314 | echo '</div>'; |
| 1315 | |
| 1316 | } elseif ( 'blogroll' == $link['source_type'] ) { |
| 1317 | |
| 1318 | echo "<a class='row-title' href='link.php?action=edit&link_id=$link[source_id]' title='" . __('Edit this bookmark', 'broken-link-checker') . "'>{$link[link_text]}</a>"; |
| 1319 | |
| 1320 | //Output inline action links |
| 1321 | $actions = array(); |
| 1322 | if ( current_user_can('manage_links') ) { |
| 1323 | $actions['edit'] = '<span class="edit"><a href="link.php?action=edit&link_id=' . $link['source_id'] . '" title="' . attribute_escape(__('Edit this bookmark', 'broken-link-checker')) . '">' . __('Edit') . '</a>'; |
| 1324 | $actions['delete'] = "<span class='delete'><a class='submitdelete' href='" . wp_nonce_url("link.php?action=delete&link_id={$link[source_id]}", 'delete-bookmark_' . $link['source_id']) . "' onclick=\"if ( confirm('" . js_escape(sprintf( __("You are about to delete this link '%s'\n 'Cancel' to stop, 'OK' to delete."), $link['link_text'])) . "') ) { return true;}return false;\">" . __('Delete') . "</a>"; |
| 1325 | } |
| 1326 | |
| 1327 | echo '<div class="row-actions">'; |
| 1328 | echo implode(' | </span>', $actions); |
| 1329 | echo '</div>'; |
| 1330 | |
| 1331 | } elseif ( empty($link['source_type']) ){ |
| 1332 | |
| 1333 | _e("[An orphaned link! This is a bug.]", 'broken-link-checker'); |
| 1334 | |
| 1335 | } |
| 1336 | ?> |
| 1337 | </td> |
| 1338 | <td class='blc-link-text'><?php |
| 1339 | if ( 'post' == $link['source_type'] ){ |
| 1340 | |
| 1341 | if ( 'link' == $link['instance_type'] ) { |
| 1342 | print strip_tags($link['link_text']); |
| 1343 | } elseif ( 'image' == $link['instance_type'] ){ |
| 1344 | printf( |
| 1345 | '<img src="%s/broken-link-checker/images/image.png" class="blc-small-image" alt="%2$s" title="%2$s"> %2$s', |
| 1346 | WP_PLUGIN_URL, |
| 1347 | __('Image', 'broken-link-checker') |
| 1348 | ); |
| 1349 | } else { |
| 1350 | echo '[ ??? ]'; |
| 1351 | } |
| 1352 | |
| 1353 | } elseif ( 'custom_field' == $link['source_type'] ){ |
| 1354 | |
| 1355 | printf( |
| 1356 | '<img src="%s/broken-link-checker/images/script_code.png" class="blc-small-image" title="%2$s" alt="%2$s"> ', |
| 1357 | WP_PLUGIN_URL, |
| 1358 | __('Custom field', 'broken-link-checker') |
| 1359 | ); |
| 1360 | echo "<code>".$link['link_text']."</code>"; |
| 1361 | |
| 1362 | } elseif ( 'blogroll' == $link['source_type'] ){ |
| 1363 | printf( |
| 1364 | '<img src="%s/broken-link-checker/images/link.png" class="blc-small-image" title="%2$s" alt="%2$s"> %2$s', |
| 1365 | WP_PLUGIN_URL, |
| 1366 | __('Bookmark', 'broken-link-checker') |
| 1367 | ); |
| 1368 | } |
| 1369 | ?> |
| 1370 | </td> |
| 1371 | <td class='column-url'> |
| 1372 | <a href='<?php print $link['url']; ?>' target='_blank' class='blc-link-url'> |
| 1373 | <?php print $this->mytruncate($link['url']); ?></a> |
| 1374 | <input type='text' id='link-editor-<?php print $rownum; ?>' |
| 1375 | value='<?php print attribute_escape($link['url']); ?>' |
| 1376 | class='blc-link-editor' style='display:none' /> |
| 1377 | <?php |
| 1378 | //Output inline action links for the link/URL |
| 1379 | $actions = array(); |
| 1380 | |
| 1381 | $actions['details'] = "<span class='view'><a class='blc-details-button' href='javascript:void(0)' title='". attribute_escape(__('Show more info about this link', 'broken-link-checker')) . "'>". __('Details', 'broken-link-checker') ."</a>"; |
| 1382 | |
| 1383 | $actions['delete'] = "<span class='delete'><a class='submitdelete blc-unlink-button' title='" . attribute_escape( __('Remove this link from all posts', 'broken-link-checker') ). "' ". |
| 1384 | "id='unlink-button-$rownum' href='javascript:void(0);'>" . __('Unlink', 'broken-link-checker') . "</a>"; |
| 1385 | |
| 1386 | if ( $excluded ){ |
| 1387 | $actions['exclude'] = "<span class='delete'>" . __('Excluded', 'broken-link-checker'); |
| 1388 | } else { |
| 1389 | $actions['exclude'] = "<span class='delete'><a class='submitdelete blc-exclude-button' title='" . attribute_escape( __('Add this URL to the exclusion list' , 'broken-link-checker') ) . "' ". |
| 1390 | "id='exclude-button-$rownum' href='javascript:void(0);'>" . __('Exclude' , 'broken-link-checker'). "</a>"; |
| 1391 | } |
| 1392 | |
| 1393 | $actions['edit'] = "<span class='edit'><a href='javascript:void(0)' class='blc-edit-button' title='" . attribute_escape( __('Edit link URL' , 'broken-link-checker') ) . "'>". __('Edit URL' , 'broken-link-checker') ."</a>"; |
| 1394 | |
| 1395 | echo '<div class="row-actions">'; |
| 1396 | echo implode(' | </span>', $actions); |
| 1397 | |
| 1398 | echo "<span style='display:none' class='blc-cancel-button-container'> ", |
| 1399 | "| <a href='javascript:void(0)' class='blc-cancel-button' title='". attribute_escape(__('Cancel URL editing' , 'broken-link-checker')) ."'>". __('Cancel' , 'broken-link-checker') ."</a></span>"; |
| 1400 | |
| 1401 | echo '</div>'; |
| 1402 | ?> |
| 1403 | </td> |
| 1404 | <?php |
| 1405 | //Display the "Discard" button when listing broken links |
| 1406 | if ( $show_discard_button ) { |
| 1407 | ?> |
| 1408 | <td><a href='javascript:void(0);' |
| 1409 | id='discard_button-<?php print $rownum; ?>' |
| 1410 | class='blc-discard-button' |
| 1411 | title='<?php |
| 1412 | echo attribute_escape( |
| 1413 | __('Remove this link from the list of broken links and mark it as valid', 'broken-link-checker') |
| 1414 | ); |
| 1415 | ?>'><?php _e('Discard', 'broken-link-checker'); ?></a> |
| 1416 | </td> |
| 1417 | <?php } ?> |
| 1418 | </tr> |
| 1419 | <!-- Link details --> |
| 1420 | <tr id='<?php print "link-details-$rownum"; ?>' style='display:none;' class='blc-link-details'> |
| 1421 | <td colspan='4'><?php $this->link_details_row($link); ?></td> |
| 1422 | </tr><?php |
| 1423 | } |
| 1424 | ?></tbody></table><?php |
| 1425 | |
| 1426 | //Also display pagination links at the bottom |
| 1427 | if ( $page_links ) { |
| 1428 | echo '<div class="tablenav"><div class="tablenav-pages">'; |
| 1429 | $page_links_text = sprintf( '<span class="displaying-num">' . __( 'Displaying %s–%s of <span class="current-link-count">%s</span>', 'broken-link-checker' ) . '</span>%s', |
| 1430 | number_format_i18n( ( $page - 1 ) * $per_page + 1 ), |
| 1431 | number_format_i18n( min( $page * $per_page, count($links) ) ), |
| 1432 | number_format_i18n( $current_filter['count'] ), |
| 1433 | $page_links |
| 1434 | ); |
| 1435 | echo $page_links_text; |
| 1436 | echo '</div></div>'; |
| 1437 | } |
| 1438 | }; |
| 1439 | ?> |
| 1440 | <?php $this->links_page_js(); ?> |
| 1441 | </div> |
| 1442 | <?php |
| 1443 | } |
| 1444 | |
| 1445 | function links_page_js(){ |
| 1446 | ?> |
| 1447 | <script type='text/javascript'> |
| 1448 | |
| 1449 | function alterLinkCounter(factor){ |
| 1450 | cnt = parseInt(jQuery('.current-link-count').eq(0).html()); |
| 1451 | cnt = cnt + factor; |
| 1452 | jQuery('.current-link-count').html(cnt); |
| 1453 | } |
| 1454 | |
| 1455 | jQuery(function($){ |
| 1456 | |
| 1457 | //The discard button - manually mark the link as valid. The link will be checked again later. |
| 1458 | $(".blc-discard-button").click(function () { |
| 1459 | var me = this; |
| 1460 | $(me).html('<?php echo js_escape(__('Wait...', 'broken-link-checker')); ?>'); |
| 1461 | |
| 1462 | var link_id = $(me).parents('.blc-row').find('.blc-link-id').html(); |
| 1463 | |
| 1464 | $.post( |
| 1465 | "<?php echo admin_url('admin-ajax.php'); ?>", |
| 1466 | { |
| 1467 | 'action' : 'blc_discard', |
| 1468 | 'link_id' : link_id |
| 1469 | }, |
| 1470 | function (data, textStatus){ |
| 1471 | if (data == 'OK'){ |
| 1472 | var master = $(me).parents('.blc-row'); |
| 1473 | var details = master.next('.blc-link-details'); |
| 1474 | |
| 1475 | details.hide(); |
| 1476 | //Flash the main row green to indicate success, then hide it. |
| 1477 | var oldColor = master.css('background-color'); |
| 1478 | master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300, function(){ |
| 1479 | master.hide(); |
| 1480 | }); |
| 1481 | |
| 1482 | alterLinkCounter(-1); |
| 1483 | } else { |
| 1484 | $(me).html('<?php echo js_escape(__('Discard' , 'broken-link-checker')); ?>'); |
| 1485 | alert(data); |
| 1486 | } |
| 1487 | } |
| 1488 | ); |
| 1489 | }); |
| 1490 | |
| 1491 | //The details button - display/hide detailed info about a link |
| 1492 | $(".blc-details-button, .blc-link-text").click(function () { |
| 1493 | $(this).parents('.blc-row').next('.blc-link-details').toggle(); |
| 1494 | }); |
| 1495 | |
| 1496 | //The edit button - edit/save the link's URL |
| 1497 | $(".blc-edit-button").click(function () { |
| 1498 | var edit_button = $(this); |
| 1499 | var master = $(edit_button).parents('.blc-row'); |
| 1500 | var editor = $(master).find('.blc-link-editor'); |
| 1501 | var url_el = $(master).find('.blc-link-url'); |
| 1502 | var cancel_button_container = $(master).find('.blc-cancel-button-container'); |
| 1503 | |
| 1504 | //Find the current/original URL |
| 1505 | var orig_url = url_el.attr('href'); |
| 1506 | //Find the link ID |
| 1507 | var link_id = $(master).find('.blc-link-id').html(); |
| 1508 | |
| 1509 | if ( !$(editor).is(':visible') ){ |
| 1510 | //Begin editing |
| 1511 | url_el.hide(); |
| 1512 | //Reset the edit box to the actual URL value in case the user has already tried and failed to edit this link. |
| 1513 | editor.val( url_el.attr('href') ); |
| 1514 | editor.show(); |
| 1515 | cancel_button_container.show(); |
| 1516 | editor.focus(); |
| 1517 | editor.select(); |
| 1518 | edit_button.html('<?php echo js_escape(__('Save URL' , 'broken-link-checker')); ?>'); |
| 1519 | } else { |
| 1520 | editor.hide(); |
| 1521 | cancel_button_container.hide(); |
| 1522 | url_el.show(); |
| 1523 | |
| 1524 | new_url = editor.val(); |
| 1525 | |
| 1526 | if (new_url != orig_url){ |
| 1527 | //Save the changed link |
| 1528 | url_el.html('<?php echo js_escape(__('Saving changes...' , 'broken-link-checker')); ?>'); |
| 1529 | |
| 1530 | $.getJSON( |
| 1531 | "<?php echo admin_url('admin-ajax.php'); ?>", |
| 1532 | { |
| 1533 | 'action' : 'blc_edit', |
| 1534 | 'link_id' : link_id, |
| 1535 | 'new_url' : new_url |
| 1536 | }, |
| 1537 | function (data, textStatus){ |
| 1538 | var display_url = ''; |
| 1539 | |
| 1540 | if ( data && (typeof(data['error']) != 'undefined') ){ |
| 1541 | //data.error is an error message |
| 1542 | alert(data.error); |
| 1543 | display_url = orig_url; |
| 1544 | } else { |
| 1545 | //data contains info about the performed edit |
| 1546 | if ( data.cnt_okay > 0 ){ |
| 1547 | display_url = new_url; |
| 1548 | |
| 1549 | url_el.attr('href', new_url); |
| 1550 | |
| 1551 | if ( data.cnt_error > 0 ){ |
| 1552 | //TODO: Interationalize this error message |
| 1553 | var msg = "The link was successfully modifed."; |
| 1554 | msg = msg + "\nHowever, "+data.cnt_error+" instances couldn't be edited and still point to the old URL." |
| 1555 | alert(msg); |
| 1556 | } else { |
| 1557 | //Flash the row green to indicate success |
| 1558 | var oldColor = master.css('background-color'); |
| 1559 | master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300); |
| 1560 | |
| 1561 | //Save the new ID |
| 1562 | master.find('.blc-link-id').html(data.new_link_id); |
| 1563 | //Load up the new link info (so sue me) |
| 1564 | master.next('.blc-link-details').find('td').html('<center><?php echo js_escape(__('Loading...' , 'broken-link-checker')); ?></center>').load( |
| 1565 | "<?php echo admin_url('admin-ajax.php'); ?>", |
| 1566 | { |
| 1567 | 'action' : 'blc_link_details', |
| 1568 | 'link_id' : data.new_link_id |
| 1569 | } |
| 1570 | ); |
| 1571 | } |
| 1572 | } else { |
| 1573 | //TODO: Internationalize this error message |
| 1574 | alert("Something went wrong. The plugin failed to edit "+ |
| 1575 | data.cnt_error + ' instance(s) of this link.'); |
| 1576 | |
| 1577 | display_url = orig_url; |
| 1578 | } |
| 1579 | }; |
| 1580 | |
| 1581 | //Shorten the displayed URL if it's > 50 characters |
| 1582 | if ( display_url.length > 50 ){ |
| 1583 | display_url = display_url.substr(0, 47) + '...'; |
| 1584 | } |
| 1585 | url_el.html(display_url); |
| 1586 | } |
| 1587 | ); |
| 1588 | |
| 1589 | } else { |
| 1590 | //It's the same URL, so do nothing. |
| 1591 | } |
| 1592 | edit_button.html('<?php echo js_escape(__('Edit URL', 'broken-link-checker')); ?>'); |
| 1593 | } |
| 1594 | }); |
| 1595 | |
| 1596 | //Let the user use Enter and Esc as shortcuts for "Save URL" and "Cancel" |
| 1597 | $('input.blc-link-editor').keypress(function (e) { |
| 1598 | if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) { |
| 1599 | $(this).parents('.blc-row').find('.blc-edit-button').click(); |
| 1600 | return false; |
| 1601 | } else if ((e.which && e.which == 27) || (e.keyCode && e.keyCode == 27)) { |
| 1602 | $(this).parents('.blc-row').find('.blc-cancel-button').click(); |
| 1603 | return false; |
| 1604 | } else { |
| 1605 | return true; |
| 1606 | } |
| 1607 | }); |
| 1608 | |
| 1609 | $(".blc-cancel-button").click(function () { |
| 1610 | var master = $(this).parents('.blc-row'); |
| 1611 | var url_el = $(master).find('.blc-link-url'); |
| 1612 | |
| 1613 | //Hide the cancel button |
| 1614 | $(this).parent().hide(); |
| 1615 | //Show the un-editable URL again |
| 1616 | url_el.show(); |
| 1617 | //reset and hide the editor |
| 1618 | master.find('.blc-link-editor').hide().val(url_el.attr('href')); |
| 1619 | //Set the edit button to say "Edit URL" |
| 1620 | master.find('.blc-edit-button').html('<?php echo js_escape(__('Edit URL' , 'broken-link-checker')); ?>'); |
| 1621 | }); |
| 1622 | |
| 1623 | //The unlink button - remove the link/image from all posts, custom fields, etc. |
| 1624 | $(".blc-unlink-button").click(function () { |
| 1625 | var me = this; |
| 1626 | var master = $(me).parents('.blc-row'); |
| 1627 | $(me).html('<?php echo js_escape(__('Wait...' , 'broken-link-checker')); ?>'); |
| 1628 | |
| 1629 | var link_id = $(me).parents('.blc-row').find('.blc-link-id').html(); |
| 1630 | |
| 1631 | $.post( |
| 1632 | "<?php echo admin_url('admin-ajax.php'); ?>", |
| 1633 | { |
| 1634 | 'action' : 'blc_unlink', |
| 1635 | 'link_id' : link_id |
| 1636 | }, |
| 1637 | function (data, textStatus){ |
| 1638 | eval('data = ' + data); |
| 1639 | |
| 1640 | if ( data && ( typeof(data['ok']) != 'undefined') ){ |
| 1641 | //Hide the details |
| 1642 | master.next('.blc-link-details').hide(); |
| 1643 | //Flash the main row green to indicate success, then hide it. |
| 1644 | var oldColor = master.css('background-color'); |
| 1645 | master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300, function(){ |
| 1646 | master.hide(); |
| 1647 | }); |
| 1648 | |
| 1649 | alterLinkCounter(-1); |
| 1650 | } else { |
| 1651 | $(me).html('<?php echo js_escape(__('Unlink' , 'broken-link-checker')); ?>'); |
| 1652 | //Show the error message |
| 1653 | alert(data.error); |
| 1654 | } |
| 1655 | } |
| 1656 | ); |
| 1657 | }); |
| 1658 | |
| 1659 | //The exclude button - Add this link to the exclusion list |
| 1660 | $(".blc-exclude-button").click(function () { |
| 1661 | var me = this; |
| 1662 | var master = $(me).parents('.blc-row'); |
| 1663 | var details = master.next('.blc-link-details'); |
| 1664 | $(me).html('<?php echo js_escape(__('Wait...' , 'broken-link-checker')); ?>'); |
| 1665 | |
| 1666 | var link_id = $(me).parents('.blc-row').find('.blc-link-id').html(); |
| 1667 | |
| 1668 | $.post( |
| 1669 | "<?php echo admin_url('admin-ajax.php'); ?>", |
| 1670 | { |
| 1671 | 'action' : 'blc_exclude_link', |
| 1672 | 'link_id' : link_id |
| 1673 | }, |
| 1674 | function (data, textStatus){ |
| 1675 | eval('data = ' + data); |
| 1676 | |
| 1677 | if ( data && ( typeof(data['ok']) != 'undefined' ) ){ |
| 1678 | |
| 1679 | if ( 'broken' == blc_current_filter ){ |
| 1680 | //Flash the row green to indicate success, then hide it. |
| 1681 | $(me).replaceWith('<?php echo js_escape(__('Excluded' , 'broken-link-checker')); ?>'); |
| 1682 | master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: '#E2E2E2' }, 200, function(){ |
| 1683 | details.hide(); |
| 1684 | master.hide(); |
| 1685 | alterLinkCounter(-1); |
| 1686 | }); |
| 1687 | master.addClass('blc-excluded-link'); |
| 1688 | } else { |
| 1689 | //Flash the row green to indicate success and fade to the "excluded link" color |
| 1690 | master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: '#E2E2E2' }, 300); |
| 1691 | master.addClass('blc-excluded-link'); |
| 1692 | $(me).replaceWith('<?php echo js_escape(__('Excluded' , 'broken-link-checker')); ?>'); |
| 1693 | } |
| 1694 | } else { |
| 1695 | $(me).html('<?php echo js_escape(__('Exclude' , 'broken-link-checker')); ?>'); |
| 1696 | alert(data.error); |
| 1697 | } |
| 1698 | } |
| 1699 | ); |
| 1700 | }); |
| 1701 | |
| 1702 | //-------------------------------------------- |
| 1703 | //The search box(es) |
| 1704 | //-------------------------------------------- |
| 1705 | |
| 1706 | var searchForm = $('#search-links-dialog'); |
| 1707 | |
| 1708 | searchForm.dialog({ |
| 1709 | autoOpen : false, |
| 1710 | dialogClass : 'blc-search-container', |
| 1711 | resizable: false, |
| 1712 | }); |
| 1713 | |
| 1714 | $('#blc-open-search-box').click(function(){ |
| 1715 | if ( searchForm.dialog('isOpen') ){ |
| 1716 | searchForm.dialog('close'); |
| 1717 | } else { |
| 1718 | var button_position = $('#blc-open-search-box').offset(); |
| 1719 | var button_height = $('#blc-open-search-box').outerHeight(true); |
| 1720 | var button_width = $('#blc-open-search-box').outerWidth(true); |
| 1721 | |
| 1722 | var dialog_width = searchForm.dialog('option', 'width'); |
| 1723 | |
| 1724 | searchForm.dialog('option', 'position', |
| 1725 | [ |
| 1726 | button_position.left - dialog_width + button_width/2, |
| 1727 | button_position.top + button_height + 1 - $(document).scrollTop() |
| 1728 | ] |
| 1729 | ); |
| 1730 | searchForm.dialog('open'); |
| 1731 | } |
| 1732 | }); |
| 1733 | |
| 1734 | $('#blc-cancel-search').click(function(){ |
| 1735 | searchForm.dialog('close'); |
| 1736 | }); |
| 1737 | |
| 1738 | //The "Save This Search Query" button creates a new custom filter based on the current search |
| 1739 | $('#blc-create-filter').click(function(){ |
| 1740 | var filter_name = prompt("<?php echo js_escape(__("Enter a name for the new custom filter", 'broken-link-checker')); ?>", ""); |
| 1741 | if ( filter_name ){ |
| 1742 | $('#blc-custom-filter-name').val(filter_name); |
| 1743 | $('#custom-filter-form').submit(); |
| 1744 | } |
| 1745 | }); |
| 1746 | |
| 1747 | //Display a confirmation dialog when the user clicks the "Delete This Filter" button |
| 1748 | $('#blc-delete-filter').click(function(){ |
| 1749 | if ( confirm('<?php |
| 1750 | echo js_escape( |
| 1751 | __("You are about to delete the current filter.\n'Cancel' to stop, 'OK' to delete", 'broken-link-checker') |
| 1752 | ); |
| 1753 | ?>') ){ |
| 1754 | return true; |
| 1755 | } else { |
| 1756 | return false; |
| 1757 | } |
| 1758 | }); |
| 1759 | |
| 1760 | }); |
| 1761 | |
| 1762 | </script> |
| 1763 | <?php |
| 1764 | } |
| 1765 | |
| 1766 | function links_page_css(){ |
| 1767 | ?> |
| 1768 | <style type='text/css'> |
| 1769 | .blc-link-editor { |
| 1770 | font-size: 1em; |
| 1771 | width: 95%; |
| 1772 | } |
| 1773 | |
| 1774 | .blc-excluded-link { |
| 1775 | background-color: #E2E2E2; |
| 1776 | } |
| 1777 | |
| 1778 | .blc-small-image { |
| 1779 | display : block; |
| 1780 | float: left; |
| 1781 | padding-top: 2px; |
| 1782 | margin-right: 3px; |
| 1783 | } |
| 1784 | |
| 1785 | .blc-search-container { |
| 1786 | background : white !important; |
| 1787 | border: 3px solid #EEEEEE; |
| 1788 | padding: 12px; |
| 1789 | } |
| 1790 | |
| 1791 | .blc-search-container .ui-dialog-titlebar { |
| 1792 | display: none; |
| 1793 | margin: 0px; |
| 1794 | } |
| 1795 | |
| 1796 | #search-links-dialog { |
| 1797 | display: none; |
| 1798 | } |
| 1799 | |
| 1800 | #search-links-dialog label, #search-links-dialog input.text, #search-links-dialog select { display:block; } |
| 1801 | #search-links-dialog input.text { margin-bottom:12px; width:95%; padding: .4em; } |
| 1802 | #search-links-dialog select { margin-bottom:12px; padding: .4em; } |
| 1803 | #search-links-dialog fieldset { padding:0; border:0; margin-top:25px; } |
| 1804 | |
| 1805 | #blc-search-button-row { |
| 1806 | text-align: center; |
| 1807 | } |
| 1808 | |
| 1809 | #blc-search-button-row input { |
| 1810 | padding: 0.4em; |
| 1811 | margin-left: 8px; |
| 1812 | margin-right: 8px; |
| 1813 | margin-top: 8px; |
| 1814 | } |
| 1815 | |
| 1816 | .blc-inline-form { |
| 1817 | display: inline; |
| 1818 | } |
| 1819 | |
| 1820 | div.search-box{ |
| 1821 | float: right; |
| 1822 | margin-top: -5px; |
| 1823 | margin-right: 0pt; |
| 1824 | margin-bottom: 0pt; |
| 1825 | margin-left: 0pt; |
| 1826 | } |
| 1827 | </style> |
| 1828 | <?php |
| 1829 | } |
| 1830 | |
| 1831 | function link_details_row($link){ |
| 1832 | ?> |
| 1833 | <span id='post_date_full' style='display:none;'><?php |
| 1834 | |
| 1835 | print $link['post_date']; |
| 1836 | |
| 1837 | ?></span> |
| 1838 | <span id='check_date_full' style='display:none;'><?php |
| 1839 | print $link['last_check']; |
| 1840 | ?></span> |
| 1841 | <ol style='list-style-type: none; width: 50%; float: right;'> |
| 1842 | <li><strong><?php _e('Log', 'broken-link-checker'); ?> :</strong> |
| 1843 | <span class='blc_log'><?php |
| 1844 | print nl2br($link['log']); |
| 1845 | ?></span></li> |
| 1846 | </ol> |
| 1847 | |
| 1848 | <ol style='list-style-type: none; padding-left: 2px;'> |
| 1849 | <?php if ( !empty($link['post_date']) ) { ?> |
| 1850 | <li><strong><?php _e('Post published on', 'broken-link-checker'); ?> :</strong> |
| 1851 | <span class='post_date'><?php |
| 1852 | echo date_i18n(get_option('date_format'),strtotime($link['post_date'])); |
| 1853 | ?></span></li> |
| 1854 | <?php } ?> |
| 1855 | <li><strong><?php _e('Link last checked', 'broken-link-checker'); ?> :</strong> |
| 1856 | <span class='check_date'><?php |
| 1857 | $last_check = strtotime($link['last_check']); |
| 1858 | if ( $last_check < strtotime('-10 years') ){ |
| 1859 | _e('Never', 'broken-link-checker'); |
| 1860 | } else { |
| 1861 | echo date_i18n(get_option('date_format'), $last_check); |
| 1862 | } |
| 1863 | ?></span></li> |
| 1864 | |
| 1865 | <li><strong><?php _e('HTTP code', 'broken-link-checker'); ?> :</strong> |
| 1866 | <span class='http_code'><?php |
| 1867 | print $link['http_code']; |
| 1868 | ?></span></li> |
| 1869 | |
| 1870 | <li><strong><?php _e('Response time', 'broken-link-checker'); ?> :</strong> |
| 1871 | <span class='request_duration'><?php |
| 1872 | printf( __('%2.3f seconds', 'broken-link-checker'), $link['request_duration']); |
| 1873 | ?></span></li> |
| 1874 | |
| 1875 | <li><strong><?php _e('Final URL', 'broken-link-checker'); ?> :</strong> |
| 1876 | <span class='final_url'><?php |
| 1877 | print $link['final_url']; |
| 1878 | ?></span></li> |
| 1879 | |
| 1880 | <li><strong><?php _e('Redirect count', 'broken-link-checker'); ?> :</strong> |
| 1881 | <span class='redirect_count'><?php |
| 1882 | print $link['redirect_count']; |
| 1883 | ?></span></li> |
| 1884 | |
| 1885 | <li><strong><?php _e('Instance count', 'broken-link-checker'); ?> :</strong> |
| 1886 | <span class='instance_count'><?php |
| 1887 | print $link['instance_count']; |
| 1888 | ?></span></li> |
| 1889 | |
| 1890 | <?php if ( intval( $link['check_count'] ) > 0 ){ ?> |
| 1891 | <li><br/> |
| 1892 | <?php |
| 1893 | printf( |
| 1894 | _n('This link has failed %d time.', 'This link has failed %d times.', $link['check_count'], 'broken-link-checker'), |
| 1895 | $link['check_count'] |
| 1896 | ); |
| 1897 | ?> |
| 1898 | </li> |
| 1899 | <?php } ?> |
| 1900 | </ol> |
| 1901 | <?php |
| 1902 | } |
| 1903 | |
| 1904 | /** |
| 1905 | * ws_broken_link_checker::cleanup_links() |
| 1906 | * Remove orphaned links that have no corresponding instances |
| 1907 | * |
| 1908 | * @param int $link_id (optional) Only check this link |
| 1909 | * @return bool |
| 1910 | */ |
| 1911 | function cleanup_links( $link_id = null ){ |
| 1912 | global $wpdb; |
| 1913 | |
| 1914 | $q = "DELETE FROM {$wpdb->prefix}blc_links |
| 1915 | USING {$wpdb->prefix}blc_links LEFT JOIN {$wpdb->prefix}blc_instances |
| 1916 | ON {$wpdb->prefix}blc_instances.link_id = {$wpdb->prefix}blc_links.link_id |
| 1917 | WHERE |
| 1918 | {$wpdb->prefix}blc_instances.link_id IS NULL"; |
| 1919 | |
| 1920 | if ( $link_id !==null ) { |
| 1921 | $q .= " AND {$wpdb->prefix}blc_links.link_id = " . intval( $link_id ); |
| 1922 | } |
| 1923 | |
| 1924 | return $wpdb->query( $q ); |
| 1925 | } |
| 1926 | |
| 1927 | /** |
| 1928 | * ws_broken_link_checker::cleanup_instances() |
| 1929 | * Remove instances that reference invalid posts or bookmarks |
| 1930 | * |
| 1931 | * @return bool |
| 1932 | */ |
| 1933 | function cleanup_instances(){ |
| 1934 | global $wpdb; |
| 1935 | |
| 1936 | //Delete all instances that reference non-existent posts |
| 1937 | $q = "DELETE FROM {$wpdb->prefix}blc_instances |
| 1938 | USING {$wpdb->prefix}blc_instances LEFT JOIN {$wpdb->posts} ON {$wpdb->prefix}blc_instances.source_id = {$wpdb->posts}.ID |
| 1939 | WHERE |
| 1940 | {$wpdb->posts}.ID IS NULL |
| 1941 | AND ( ( {$wpdb->prefix}blc_instances.source_type = 'post' ) OR ( {$wpdb->prefix}blc_instances.source_type = 'custom_field' ) )"; |
| 1942 | $rez = $wpdb->query($q); |
| 1943 | |
| 1944 | //Delete all instances that reference non-existent bookmarks |
| 1945 | $q = "DELETE FROM {$wpdb->prefix}blc_instances |
| 1946 | USING {$wpdb->prefix}blc_instances LEFT JOIN {$wpdb->links} ON {$wpdb->prefix}blc_instances.source_id = {$wpdb->links}.link_id |
| 1947 | WHERE |
| 1948 | {$wpdb->links}.link_id IS NULL |
| 1949 | AND {$wpdb->prefix}blc_instances.source_type = 'blogroll' "; |
| 1950 | $rez2 = $wpdb->query($q); |
| 1951 | |
| 1952 | return $rez and $rez2; |
| 1953 | } |
| 1954 | |
| 1955 | /** |
| 1956 | * ws_broken_link_checker::parse_post() |
| 1957 | * Parse a post for links and save them to the DB. |
| 1958 | * |
| 1959 | * @param string $content Post content |
| 1960 | * @param int $post_id Post ID |
| 1961 | * @return void |
| 1962 | */ |
| 1963 | function parse_post($content, $post_id){ |
| 1964 | //remove all <code></code> blocks first |
| 1965 | $content = preg_replace('/<code[^>]*>.+?<\/code>/si', ' ', $content); |
| 1966 | //Get the post permalink - it's used to resolve relative URLs |
| 1967 | $permalink = get_permalink( $post_id ); |
| 1968 | |
| 1969 | //Find links |
| 1970 | if(preg_match_all(blcUtility::link_pattern(), $content, $matches, PREG_SET_ORDER)){ |
| 1971 | foreach($matches as $link){ |
| 1972 | $url = $link[3]; |
| 1973 | $text = strip_tags( $link[5] ); |
| 1974 | //FB::log($url, "Found link"); |
| 1975 | |
| 1976 | $url = blcUtility::normalize_url($url, $permalink); |
| 1977 | //Skip invalid links |
| 1978 | if ( !$url || (strlen($url)<6) ) continue; |
| 1979 | |
| 1980 | //Create or load the link |
| 1981 | $link_obj = new blcLink($url); |
| 1982 | //Add & save a new instance |
| 1983 | $link_obj->add_instance($post_id, 'post', $text, 'link'); |
| 1984 | } |
| 1985 | }; |
| 1986 | |
| 1987 | //Find images (<img src=...>) |
| 1988 | if(preg_match_all(blcUtility::img_pattern(), $content, $matches, PREG_SET_ORDER)){ |
| 1989 | foreach($matches as $img){ |
| 1990 | $url = $img[3]; |
| 1991 | //FB::log($url, "Found image"); |
| 1992 | |
| 1993 | $url = blcUtility::normalize_url($url, $permalink); |
| 1994 | if ( !$url || (strlen($url)<6) ) continue; //skip invalid URLs |
| 1995 | |
| 1996 | //Create or load the link |
| 1997 | $link = new blcLink($url); |
| 1998 | //Add & save a new image instance |
| 1999 | $link->add_instance($post_id, 'post', '', 'image'); |
| 2000 | } |
| 2001 | }; |
| 2002 | } |
| 2003 | |
| 2004 | /** |
| 2005 | * ws_broken_link_checker::parse_post_meta() |
| 2006 | * Parse a post's custom fields for links and save them in the DB. |
| 2007 | * |
| 2008 | * @param id $post_id |
| 2009 | * @return void |
| 2010 | */ |
| 2011 | function parse_post_meta($post_id){ |
| 2012 | //Get all custom fields of this post |
| 2013 | $custom_fields = get_post_custom( $post_id ); |
| 2014 | //FB::log($custom_fields, "Custom fields loaded"); |
| 2015 | |
| 2016 | //Parse the enabled fields |
| 2017 | foreach( $this->conf->options['custom_fields'] as $field ){ |
| 2018 | if ( !isset($custom_fields[$field]) ) continue; |
| 2019 | |
| 2020 | //FB::log($field, "Parsing field"); |
| 2021 | |
| 2022 | $values = $custom_fields[$field]; |
| 2023 | if ( !is_array( $values ) ) $values = array($values); |
| 2024 | |
| 2025 | foreach( $values as $value ){ |
| 2026 | |
| 2027 | //If this is a multiline field take the first line (workaround for the enclosure field). |
| 2028 | $value = trim( array_shift( explode("\n", $value) ) ); |
| 2029 | |
| 2030 | //Attempt to parse the $value as URL |
| 2031 | $url = blcUtility::normalize_url($value); |
| 2032 | if ( empty($url) ){ |
| 2033 | //FB::warn($value, "Invalid URL in custom field ".$field); |
| 2034 | continue; |
| 2035 | } |
| 2036 | |
| 2037 | //FB::log($url, "Found URL"); |
| 2038 | $link = new blcLink( $url ); |
| 2039 | //FB::log($link, 'Created/loaded link'); |
| 2040 | $inst = $link->add_instance( $post_id, 'custom_field', $field, 'link' ); |
| 2041 | //FB::log($inst, 'Created instance'); |
| 2042 | } |
| 2043 | } |
| 2044 | |
| 2045 | } |
| 2046 | |
| 2047 | function parse_blogroll_link( $the_link ){ |
| 2048 | //FB::log($the_link, "Parsing blogroll link"); |
| 2049 | |
| 2050 | //Attempt to parse the URL |
| 2051 | $url = blcUtility::normalize_url( $the_link['link_url'] ); |
| 2052 | if ( empty($url) ){ |
| 2053 | //FB::warn( $the_link['link_url'], "Invalid URL in for a blogroll link".$the_link['link_name'] ); |
| 2054 | return false; |
| 2055 | } |
| 2056 | |
| 2057 | //FB::log($url, "Found URL"); |
| 2058 | $link = new blcLink( $url ); |
| 2059 | return $link->add_instance( $the_link['link_id'], 'blogroll', $the_link['link_name'], 'link' ); |
| 2060 | } |
| 2061 | |
| 2062 | function start_timer(){ |
| 2063 | $this->execution_start_time = microtime_float(); |
| 2064 | } |
| 2065 | |
| 2066 | function execution_time(){ |
| 2067 | return microtime_float() - $this->execution_start_time; |
| 2068 | } |
| 2069 | |
| 2070 | /** |
| 2071 | * ws_broken_link_checker::work() |
| 2072 | * The main worker function that does all kinds of things. |
| 2073 | * |
| 2074 | * @return void |
| 2075 | */ |
| 2076 | function work(){ |
| 2077 | global $wpdb; |
| 2078 | |
| 2079 | if ( !$this->acquire_lock() ){ |
| 2080 | //FB::warn("Another instance of BLC is already working. Stop."); |
| 2081 | return false; |
| 2082 | } |
| 2083 | |
| 2084 | $this->start_timer(); |
| 2085 | |
| 2086 | $max_execution_time = $this->conf->options['max_execution_time']; |
| 2087 | |
| 2088 | /***************************************** |
| 2089 | Preparation |
| 2090 | ******************************************/ |
| 2091 | // Check for safe mode |
| 2092 | if( blcUtility::is_safe_mode() ){ |
| 2093 | // Do it the safe mode way - obey the existing max_execution_time setting |
| 2094 | $t = ini_get('max_execution_time'); |
| 2095 | if ($t && ($t < $max_execution_time)) |
| 2096 | $max_execution_time = $t-1; |
| 2097 | } else { |
| 2098 | // Do it the regular way |
| 2099 | @set_time_limit( $max_execution_time * 2 ); //x2 should be plenty, running any longer would mean a glitch. |
| 2100 | } |
| 2101 | |
| 2102 | //Don't stop the script when the connection is closed |
| 2103 | ignore_user_abort( true ); |
| 2104 | |
| 2105 | //Close the connection as per http://www.php.net/manual/en/features.connection-handling.php#71172 |
| 2106 | //This reduces resource usage and may solve the mysterious slowdowns certain users have |
| 2107 | //encountered when activating the plugin. |
| 2108 | //(Comment out when debugging or you won't get the FirePHP output) |
| 2109 | ob_end_clean(); |
| 2110 | header("Connection: close"); |
| 2111 | ob_start(); |
| 2112 | echo ('Connection closed'); //This could be anything |
| 2113 | $size = ob_get_length(); |
| 2114 | header("Content-Length: $size"); |
| 2115 | ob_end_flush(); // Strange behaviour, will not work |
| 2116 | flush(); // Unless both are called ! |
| 2117 | |
| 2118 | $check_threshold = date('Y-m-d H:i:s', strtotime('-'.$this->conf->options['check_threshold'].' hours')); |
| 2119 | $recheck_threshold = date('Y-m-d H:i:s', strtotime('-20 minutes')); |
| 2120 | |
| 2121 | $orphans_possible = false; |
| 2122 | |
| 2123 | $still_need_resynch = $this->conf->options['need_resynch']; |
| 2124 | |
| 2125 | /***************************************** |
| 2126 | Parse posts and bookmarks |
| 2127 | ******************************************/ |
| 2128 | |
| 2129 | if ( $this->conf->options['need_resynch'] ) { |
| 2130 | |
| 2131 | //FB::log("Looking for posts and bookmarks that need parsing..."); |
| 2132 | |
| 2133 | $tsynch = $wpdb->prefix.'blc_synch'; |
| 2134 | $tposts = $wpdb->posts; |
| 2135 | $tlinks = $wpdb->links; |
| 2136 | |
| 2137 | $synch_q = "SELECT $tsynch.source_id, $tsynch.source_type, $tposts.post_content, $tlinks.link_url, $tlinks.link_id, $tlinks.link_name |
| 2138 | |
| 2139 | FROM |
| 2140 | $tsynch LEFT JOIN $tposts |
| 2141 | ON ($tposts.id = $tsynch.source_id AND $tsynch.source_type='post') |
| 2142 | LEFT JOIN $tlinks |
| 2143 | ON ($tlinks.link_id = $tsynch.source_id AND $tsynch.source_type='blogroll') |
| 2144 | |
| 2145 | WHERE |
| 2146 | $tsynch.synched = 0 |
| 2147 | |
| 2148 | LIMIT 50"; |
| 2149 | |
| 2150 | while ( $rows = $wpdb->get_results($synch_q, ARRAY_A) ) { |
| 2151 | |
| 2152 | //FB::log("Found ".count($rows)." items to analyze."); |
| 2153 | |
| 2154 | foreach ($rows as $row) { |
| 2155 | |
| 2156 | if ( $row['source_type'] == 'post' ){ |
| 2157 | |
| 2158 | //FB::log("Parsing post ".$row['source_id']); |
| 2159 | |
| 2160 | //Remove instances associated with this post |
| 2161 | $q = "DELETE FROM {$wpdb->prefix}blc_instances |
| 2162 | WHERE source_id = %d AND (source_type = 'post' OR source_type='custom_field')"; |
| 2163 | $q = $wpdb->prepare($q, intval($row['source_id'])); |
| 2164 | |
| 2165 | //FB::log($q, "Executing query"); |
| 2166 | |
| 2167 | if ( $wpdb->query( $q ) === false ){ |
| 2168 | //FB::error($wpdb->last_error, "Database error"); |
| 2169 | } |
| 2170 | |
| 2171 | //Gather links and images from the post |
| 2172 | $this->parse_post( $row['post_content'], $row['source_id'] ); |
| 2173 | //Gather links from custom fields |
| 2174 | $this->parse_post_meta( $row['source_id'] ); |
| 2175 | |
| 2176 | //Some link records might be orhpaned now |
| 2177 | $orphans_possible = true; |
| 2178 | |
| 2179 | } else { |
| 2180 | |
| 2181 | //FB::log("Parsing bookmark ".$row['source_id']); |
| 2182 | |
| 2183 | //Remove instances associated with this bookmark |
| 2184 | $q = "DELETE FROM {$wpdb->prefix}blc_instances |
| 2185 | WHERE source_id = %d AND source_type = 'blogroll'"; |
| 2186 | $q = $wpdb->prepare($q, intval($row['source_id'])); |
| 2187 | //FB::log($q, "Executing query"); |
| 2188 | |
| 2189 | if ( $wpdb->query( $q ) === false ){ |
| 2190 | //FB::error($wpdb->last_error, "Database error"); |
| 2191 | } |
| 2192 | |
| 2193 | //(Re)add the instance and link |
| 2194 | $this->parse_blogroll_link( $row ); |
| 2195 | |
| 2196 | //Some link records might be orhpaned now |
| 2197 | $orphans_possible = true; |
| 2198 | |
| 2199 | } |
| 2200 | |
| 2201 | //Update the table to indicate the item has been parsed |
| 2202 | $this->mark_synched( $row['source_id'], $row['source_type'] ); |
| 2203 | |
| 2204 | //Check if we still have some execution time left |
| 2205 | if( $this->execution_time() > $max_execution_time ){ |
| 2206 | //FB::log('The alloted execution time has run out'); |
| 2207 | $this->cleanup_links(); |
| 2208 | $this->release_lock(); |
| 2209 | return; |
| 2210 | } |
| 2211 | |
| 2212 | } |
| 2213 | |
| 2214 | } |
| 2215 | |
| 2216 | //FB::log('No unparsed items found.'); |
| 2217 | $still_need_resynch = false; |
| 2218 | |
| 2219 | if ( $wpdb->last_error ){ |
| 2220 | //FB::error($wpdb->last_error, "Database error"); |
| 2221 | } |
| 2222 | |
| 2223 | } else { |
| 2224 | //FB::log('Resynch not required.'); |
| 2225 | } |
| 2226 | |
| 2227 | /****************************************** |
| 2228 | Resynch done? |
| 2229 | *******************************************/ |
| 2230 | if ( $this->conf->options['need_resynch'] && !$still_need_resynch ){ |
| 2231 | $this->conf->options['need_resynch'] = $still_need_resynch; |
| 2232 | $this->conf->save_options(); |
| 2233 | } |
| 2234 | |
| 2235 | /****************************************** |
| 2236 | Remove orphaned links |
| 2237 | *******************************************/ |
| 2238 | |
| 2239 | if ( $orphans_possible ) { |
| 2240 | //FB::log('Cleaning up the link table.'); |
| 2241 | $this->cleanup_links(); |
| 2242 | } |
| 2243 | |
| 2244 | //Check if we still have some execution time left |
| 2245 | if( $this->execution_time() > $max_execution_time ){ |
| 2246 | //FB::log('The alloted execution time has run out'); |
| 2247 | $this->release_lock(); |
| 2248 | return; |
| 2249 | } |
| 2250 | |
| 2251 | /***************************************** |
| 2252 | Check links |
| 2253 | ******************************************/ |
| 2254 | //FB::log('Looking for links to check (threshold : '.$check_threshold.')...'); |
| 2255 | |
| 2256 | //Select some links that haven't been checked for a long time or |
| 2257 | //that are broken and need to be re-checked again. |
| 2258 | |
| 2259 | //Note : This is a slow query, but AFAIK there is no way to speed it up. |
| 2260 | //I could put an index on last_check, but that value is almost certainly unique |
| 2261 | //for each row so it wouldn't be much better than a full table scan. |
| 2262 | $q = "SELECT *, ( last_check < %s ) AS meets_check_threshold |
| 2263 | FROM {$wpdb->prefix}blc_links |
| 2264 | WHERE |
| 2265 | ( last_check < %s ) |
| 2266 | OR |
| 2267 | ( |
| 2268 | ( http_code >= 400 OR http_code < 200 OR timeout = 1) |
| 2269 | AND check_count < %d |
| 2270 | AND check_count > 0 |
| 2271 | AND last_check < %s |
| 2272 | ) |
| 2273 | ORDER BY last_check ASC |
| 2274 | LIMIT 50"; |
| 2275 | $link_q = $wpdb->prepare($q, $check_threshold, $check_threshold, $this->conf->options['recheck_count'], $recheck_threshold); |
| 2276 | //FB::log($link_q); |
| 2277 | |
| 2278 | while ( $links = $wpdb->get_results($link_q, ARRAY_A) ){ |
| 2279 | |
| 2280 | //some unchecked links found |
| 2281 | //FB::log("Checking ".count($links)." link(s)"); |
| 2282 | |
| 2283 | foreach ($links as $link) { |
| 2284 | $link_obj = new blcLink($link); |
| 2285 | |
| 2286 | //Does this link need to be checked? |
| 2287 | if ( !$this->is_excluded( $link['url'] ) ) { |
| 2288 | //Yes, do it |
| 2289 | //FB::log("Checking link {$link[link_id]}"); |
| 2290 | $link_obj->check( $this->conf->options['timeout'] ); |
| 2291 | $link_obj->save(); |
| 2292 | } else { |
| 2293 | //Nope, mark it as already checked. |
| 2294 | //FB::info("The URL {$link_obj->url} is excluded, marking link {$link_obj->link_id} as already checked."); |
| 2295 | $link_obj->last_check = date('Y-m-d H:i:s'); |
| 2296 | $link_obj->http_code = 200; //Use a fake code so that the link doesn't show up in queries looking for broken links. |
| 2297 | $link_obj->timeout = false; |
| 2298 | $link_obj->request_duration = 0; |
| 2299 | $link_obj->log = __("This link wasn't checked because a matching keyword was found on your exclusion list.", 'broken-link-checker'); |
| 2300 | $link_obj->save(); |
| 2301 | } |
| 2302 | |
| 2303 | //Check if we still have some execution time left |
| 2304 | if( $this->execution_time() > $max_execution_time ){ |
| 2305 | //FB::log('The alloted execution time has run out'); |
| 2306 | $this->release_lock(); |
| 2307 | return; |
| 2308 | } |
| 2309 | } |
| 2310 | } |
| 2311 | //FB::log('No links need to be checked right now.'); |
| 2312 | |
| 2313 | $this->release_lock(); |
| 2314 | //FB::log('All done.'); |
| 2315 | } |
| 2316 | |
| 2317 | function ajax_full_status( ){ |
| 2318 | $status = $this->get_status(); |
| 2319 | $text = $this->status_text( $status ); |
| 2320 | |
| 2321 | echo json_encode( array( |
| 2322 | 'text' => $text, |
| 2323 | 'status' => $status, |
| 2324 | ) ); |
| 2325 | |
| 2326 | die(); |
| 2327 | } |
| 2328 | |
| 2329 | /** |
| 2330 | * ws_broken_link_checker::status_text() |
| 2331 | * Generates a status message based on the status info in $status |
| 2332 | * |
| 2333 | * @param array $status |
| 2334 | * @return string |
| 2335 | */ |
| 2336 | function status_text( $status ){ |
| 2337 | $text = ''; |
| 2338 | |
| 2339 | if( $status['broken_links'] > 0 ){ |
| 2340 | $text .= sprintf( |
| 2341 | "<a href='%s' title='" . __('View broken links', 'broken-link-checker') . "'><strong>". |
| 2342 | _n('Found %d broken link', 'Found %d broken links', $status['broken_links'], 'broken-link-checker') . |
| 2343 | "</strong></a>", |
| 2344 | admin_url('tools.php?page=view-broken-links'), |
| 2345 | $status['broken_links'] |
| 2346 | ); |
| 2347 | } else { |
| 2348 | $text .= __("No broken links found.", 'broken-link-checker'); |
| 2349 | } |
| 2350 | |
| 2351 | $text .= "<br/>"; |
| 2352 | |
| 2353 | if( $status['unchecked_links'] > 0) { |
| 2354 | $text .= sprintf( |
| 2355 | _n('%d URL in the work queue', '%d URLs in the work queue', $status['unchecked_links'], 'broken-link-checker'), |
| 2356 | $status['unchecked_links'] ); |
| 2357 | } else { |
| 2358 | $text .= __("No URLs in the work queue.", 'broken-link-checker'); |
| 2359 | } |
| 2360 | |
| 2361 | $text .= "<br/>"; |
| 2362 | if ( $status['known_links'] > 0 ){ |
| 2363 | $text .= sprintf( |
| 2364 | _n('Detected %d unique URL', 'Detected %d unique URLs', $status['known_links'], 'broken-link-checker') . |
| 2365 | ' ' . _n('in %d link', 'in %d links', $status['known_instances'], 'broken-link-checker'), |
| 2366 | $status['known_links'], |
| 2367 | $status['known_instances'] |
| 2368 | ); |
| 2369 | if ($this->conf->options['need_resynch']){ |
| 2370 | $text .= ' ' . __('and still searching...', 'broken-link-checker'); |
| 2371 | } else { |
| 2372 | $text .= '.'; |
| 2373 | } |
| 2374 | } else { |
| 2375 | if ($this->conf->options['need_resynch']){ |
| 2376 | $text .= __('Searching your blog for links...', 'broken-link-checker'); |
| 2377 | } else { |
| 2378 | $text .= __('No links detected.', 'broken-link-checker'); |
| 2379 | } |
| 2380 | } |
| 2381 | |
| 2382 | return $text; |
| 2383 | } |
| 2384 | |
| 2385 | function ajax_dashboard_status(){ |
| 2386 | //Just display the full status. |
| 2387 | $this->ajax_full_status( ); |
| 2388 | } |
| 2389 | |
| 2390 | /** |
| 2391 | * ws_broken_link_checker::get_status() |
| 2392 | * Returns an array with various status information about the plugin. Array key reference: |
| 2393 | * check_threshold - date/time; links checked before this threshold should be checked again. |
| 2394 | * recheck_threshold - date/time; broken links checked before this threshold should be re-checked. |
| 2395 | * known_links - the number of detected unique URLs (a misleading name, yes). |
| 2396 | * known_instances - the number of detected link instances, i.e. actual link elements in posts and other places. |
| 2397 | * broken_links - the number of detected broken links. |
| 2398 | * unchecked_links - the number of URLs that need to be checked ASAP; based on check_threshold and recheck_threshold. |
| 2399 | * |
| 2400 | * @return array |
| 2401 | */ |
| 2402 | function get_status(){ |
| 2403 | global $wpdb; |
| 2404 | |
| 2405 | $check_threshold=date('Y-m-d H:i:s', strtotime('-'.$this->conf->options['check_threshold'].' hours')); |
| 2406 | $recheck_threshold=date('Y-m-d H:i:s', strtotime('-20 minutes')); |
| 2407 | |
| 2408 | $q = "SELECT count(*) FROM {$wpdb->prefix}blc_links WHERE 1"; |
| 2409 | $known_links = $wpdb->get_var($q); |
| 2410 | |
| 2411 | $q = "SELECT count(*) FROM {$wpdb->prefix}blc_instances WHERE 1"; |
| 2412 | $known_instances = $wpdb->get_var($q); |
| 2413 | |
| 2414 | /* |
| 2415 | $q = "SELECT count(*) FROM {$wpdb->prefix}blc_links |
| 2416 | WHERE check_count > 0 AND ( http_code < 200 OR http_code >= 400 OR timeout = 1 ) AND ( http_code <> ".BLC_CHECKING." )"; |
| 2417 | $broken_links = $wpdb->get_var($q); |
| 2418 | */ |
| 2419 | $broken_links = $this->get_links( $this->native_filters['broken'], 0, 0, true ); |
| 2420 | |
| 2421 | $q = "SELECT count(*) FROM {$wpdb->prefix}blc_links |
| 2422 | WHERE |
| 2423 | ( ( last_check < '$check_threshold' ) OR |
| 2424 | ( |
| 2425 | ( http_code >= 400 OR http_code < 200 ) |
| 2426 | AND check_count < 3 |
| 2427 | AND last_check < '$recheck_threshold' ) |
| 2428 | )"; |
| 2429 | $unchecked_links = $wpdb->get_var($q); |
| 2430 | |
| 2431 | return array( |
| 2432 | 'check_threshold' => $check_threshold, |
| 2433 | 'recheck_threshold' => $recheck_threshold, |
| 2434 | 'known_links' => $known_links, |
| 2435 | 'known_instances' => $known_instances, |
| 2436 | 'broken_links' => $broken_links, |
| 2437 | 'unchecked_links' => $unchecked_links, |
| 2438 | ); |
| 2439 | } |
| 2440 | |
| 2441 | function ajax_work(){ |
| 2442 | //Run the worker function |
| 2443 | $this->work(); |
| 2444 | die(); |
| 2445 | } |
| 2446 | |
| 2447 | function ajax_discard(){ |
| 2448 | //TODO:Rewrite to use JSON instead of plaintext |
| 2449 | if (!current_user_can('edit_others_posts')){ |
| 2450 | die( __("You're not allowed to do that!", 'broken-link-checker') ); |
| 2451 | } |
| 2452 | |
| 2453 | if ( isset($_POST['link_id']) ){ |
| 2454 | //Load the link |
| 2455 | $link = new blcLink( intval($_POST['link_id']) ); |
| 2456 | |
| 2457 | if ( !$link->valid() ){ |
| 2458 | printf( __("Oops, I can't find the link %d", 'broken-link-checker'), intval($_POST['link_id']) ); |
| 2459 | die(); |
| 2460 | } |
| 2461 | //Make it appear "not broken" |
| 2462 | $link->last_check = date('Y-m-d H:i:s'); |
| 2463 | $link->http_code = 200; |
| 2464 | $link->timeout = 0; |
| 2465 | $link->check_count = 0; |
| 2466 | $link->log = __("This link was manually marked as working by the user.", 'broken-link-checker'); |
| 2467 | |
| 2468 | //Save the changes |
| 2469 | if ( $link->save() ){ |
| 2470 | die( "OK" ); |
| 2471 | } else { |
| 2472 | die( __("Oops, couldn't modify the link!", 'broken-link-checker') ) ; |
| 2473 | } |
| 2474 | } else { |
| 2475 | die( __("Error : link_id not specified", 'broken-link-checker') ); |
| 2476 | } |
| 2477 | } |
| 2478 | |
| 2479 | function ajax_edit(){ |
| 2480 | if (!current_user_can('edit_others_posts')){ |
| 2481 | die( json_encode( array( |
| 2482 | 'error' => __("You're not allowed to do that!", 'broken-link-checker') |
| 2483 | ))); |
| 2484 | } |
| 2485 | |
| 2486 | if ( isset($_GET['link_id']) && !empty($_GET['new_url']) ){ |
| 2487 | //Load the link |
| 2488 | $link = new blcLink( intval($_GET['link_id']) ); |
| 2489 | |
| 2490 | if ( !$link->valid() ){ |
| 2491 | die( json_encode( array( |
| 2492 | 'error' => sprintf( __("Oops, I can't find the link %d", 'broken-link-checker'), intval($_GET['link_id']) ) |
| 2493 | ))); |
| 2494 | } |
| 2495 | |
| 2496 | $new_url = blcUtility::normalize_url($_GET['new_url']); |
| 2497 | if ( !$new_url ){ |
| 2498 | die( json_encode( array( |
| 2499 | 'error' => __("Oops, the new URL is invalid!", 'broken-link-checker') |
| 2500 | ))); |
| 2501 | } |
| 2502 | |
| 2503 | //Try and edit the link |
| 2504 | $rez = $link->edit($new_url); |
| 2505 | |
| 2506 | if ( $rez == false ){ |
| 2507 | die( json_encode( array( |
| 2508 | 'error' => __("An unexpected error occured!", 'broken-link-checker') |
| 2509 | ))); |
| 2510 | } else { |
| 2511 | $rez['ok'] = __('OK', 'broken-link-checker'); |
| 2512 | die( json_encode($rez) ); |
| 2513 | } |
| 2514 | |
| 2515 | } else { |
| 2516 | die( json_encode( array( |
| 2517 | 'error' => __("Error : link_id or new_url not specified", 'broken-link-checker') |
| 2518 | ))); |
| 2519 | } |
| 2520 | } |
| 2521 | |
| 2522 | function ajax_unlink(){ |
| 2523 | if (!current_user_can('edit_others_posts')){ |
| 2524 | die( json_encode( array( |
| 2525 | 'error' => __("You're not allowed to do that!", 'broken-link-checker') |
| 2526 | ))); |
| 2527 | } |
| 2528 | |
| 2529 | if ( isset($_POST['link_id']) ){ |
| 2530 | //Load the link |
| 2531 | $link = new blcLink( intval($_POST['link_id']) ); |
| 2532 | |
| 2533 | if ( !$link->valid() ){ |
| 2534 | die( json_encode( array( |
| 2535 | 'error' => sprintf( __("Oops, I can't find the link %d", 'broken-link-checker'), intval($_POST['link_id']) ) |
| 2536 | ))); |
| 2537 | } |
| 2538 | |
| 2539 | //Try and unlink it |
| 2540 | if ( $link->unlink() ){ |
| 2541 | die( json_encode( array( |
| 2542 | 'ok' => sprintf( __("URL %s was removed.", 'broken-link-checker'), $link->url ) |
| 2543 | ))); |
| 2544 | } else { |
| 2545 | die( json_encode( array( |
| 2546 | 'error' => __("The plugin failed to remove the link.", 'broken-link-checker') |
| 2547 | ))); |
| 2548 | } |
| 2549 | |
| 2550 | } else { |
| 2551 | die( json_encode( array( |
| 2552 | 'error' => __("Error : link_id not specified", 'broken-link-checker') |
| 2553 | ))); |
| 2554 | } |
| 2555 | } |
| 2556 | |
| 2557 | function ajax_link_details(){ |
| 2558 | global $wpdb; |
| 2559 | |
| 2560 | if (!current_user_can('edit_others_posts')){ |
| 2561 | die( __("You don't have sufficient privileges to access this information!", 'broken-link-checker') ); |
| 2562 | } |
| 2563 | |
| 2564 | //FB::log("Loading link details via AJAX"); |
| 2565 | |
| 2566 | if ( isset($_GET['link_id']) ){ |
| 2567 | //FB::info("Link ID found in GET"); |
| 2568 | $link_id = intval($_GET['link_id']); |
| 2569 | } else if ( isset($_POST['link_id']) ){ |
| 2570 | //FB::info("Link ID found in POST"); |
| 2571 | $link_id = intval($_POST['link_id']); |
| 2572 | } else { |
| 2573 | //FB::error('Link ID not specified, you hacking bastard.'); |
| 2574 | die( __('Error : link ID not specified', 'broken-link-checker') ); |
| 2575 | } |
| 2576 | |
| 2577 | //Load the link. link_details_row needs it as an array, so |
| 2578 | //we'll have to do this the long way. |
| 2579 | $q = "SELECT |
| 2580 | links.*, |
| 2581 | COUNT(*) as instance_count |
| 2582 | |
| 2583 | FROM |
| 2584 | {$wpdb->prefix}blc_links AS links, |
| 2585 | {$wpdb->prefix}blc_instances as instances |
| 2586 | |
| 2587 | WHERE |
| 2588 | links.link_id = %d |
| 2589 | |
| 2590 | GROUP BY links.link_id"; |
| 2591 | |
| 2592 | $link = $wpdb->get_row( $wpdb->prepare($q, $link_id), ARRAY_A ); |
| 2593 | if ( is_array($link) ){ |
| 2594 | //FB::info($link, 'Link loaded'); |
| 2595 | $this->link_details_row($link); |
| 2596 | die(); |
| 2597 | } else { |
| 2598 | printf( __('Failed to load link details (%s)', 'broken-link-checker'), $wpdb->last_error ); |
| 2599 | die (); |
| 2600 | } |
| 2601 | } |
| 2602 | |
| 2603 | function ajax_exclude_link(){ |
| 2604 | if ( !current_user_can('manage_options') ){ |
| 2605 | die( json_encode( array( |
| 2606 | 'error' => __("You're not allowed to do that!", 'broken-link-checker') |
| 2607 | ))); |
| 2608 | } |
| 2609 | |
| 2610 | if ( isset($_POST['link_id']) ){ |
| 2611 | //Load the link |
| 2612 | $link = new blcLink( intval($_POST['link_id']) ); |
| 2613 | |
| 2614 | if ( !$link->valid() ){ |
| 2615 | die( json_encode( array( |
| 2616 | 'error' => sprintf( __("Oops, I can't find the link %d", 'broken-link-checker'), intval($_POST['link_id']) ) |
| 2617 | ))); |
| 2618 | } |
| 2619 | |
| 2620 | //Add the URL to the exclusion list |
| 2621 | if ( !in_array( $link->url, $this->conf->options['exclusion_list'] ) ){ |
| 2622 | $this->conf->options['exclusion_list'][] = $link->url; |
| 2623 | //Also mark it as already checked so that it doesn't show up with other broken links. |
| 2624 | //FB::info("The URL {$link->url} is excluded, marking link {$link->link_id} as already checked."); |
| 2625 | $link->last_check = date('Y-m-d H:i:s'); |
| 2626 | $link->http_code = 200; //Use a fake code so that the link doesn't show up in queries looking for broken links. |
| 2627 | $link->timeout = false; |
| 2628 | $link->request_duration = 0; |
| 2629 | $link->log = __("This link wasn't checked because a matching keyword was found on your exclusion list.", 'broken-link-checker'); |
| 2630 | $link->save(); |
| 2631 | } |
| 2632 | |
| 2633 | $this->conf->save_options(); |
| 2634 | |
| 2635 | die( json_encode( array( |
| 2636 | 'ok' => sprintf( __('URL %s added to the exclusion list', 'broken-link-checker'), $link->url ) |
| 2637 | ))); |
| 2638 | } else { |
| 2639 | die( json_encode( array( |
| 2640 | 'error' => __("Link ID not specified", 'broken-link-checker') |
| 2641 | ))); |
| 2642 | } |
| 2643 | } |
| 2644 | |
| 2645 | /** |
| 2646 | * ws_broken_link_checker::acquire_lock() |
| 2647 | * Create and lock a temporary file. |
| 2648 | * |
| 2649 | * @return bool |
| 2650 | */ |
| 2651 | function acquire_lock(){ |
| 2652 | //Maybe we already have the lock? |
| 2653 | if ( $this->lockfile_handle ){ |
| 2654 | return true; |
| 2655 | } |
| 2656 | |
| 2657 | $fn = $this->lockfile_name(); |
| 2658 | if ( $fn ){ |
| 2659 | //Open the lockfile |
| 2660 | $this->lockfile_handle = fopen($fn, 'w+'); |
| 2661 | if ( $this->lockfile_handle ){ |
| 2662 | //Do an exclusive lock |
| 2663 | if (flock($this->lockfile_handle, LOCK_EX | LOCK_NB)) { |
| 2664 | //File locked successfully |
| 2665 | return true; |
| 2666 | } else { |
| 2667 | //Something went wrong |
| 2668 | fclose($this->lockfile_handle); |
| 2669 | $this->lockfile_handle = null; |
| 2670 | return false; |
| 2671 | } |
| 2672 | } else { |
| 2673 | //Can't open the file, fail. |
| 2674 | return false; |
| 2675 | } |
| 2676 | } else { |
| 2677 | //Uh oh, can't generate a lockfile name. This is bad. |
| 2678 | //FB::error("Can't find a writable directory to use for my lock file!"); |
| 2679 | return false; |
| 2680 | }; |
| 2681 | } |
| 2682 | |
| 2683 | /** |
| 2684 | * ws_broken_link_checker::release_lock() |
| 2685 | * Unlock and delete the temporary file |
| 2686 | * |
| 2687 | * @return bool |
| 2688 | */ |
| 2689 | function release_lock(){ |
| 2690 | if ( $this->lockfile_handle ){ |
| 2691 | //Close the file (implicitly releasing the lock) |
| 2692 | fclose( $this->lockfile_handle ); |
| 2693 | //Delete the file |
| 2694 | $fn = $this->lockfile_name(); |
| 2695 | if ( file_exists( $fn ) ) { |
| 2696 | unlink( $fn ); |
| 2697 | } |
| 2698 | $this->lockfile_handle = null; |
| 2699 | return true; |
| 2700 | } else { |
| 2701 | //We didn't have the lock anyway... |
| 2702 | return false; |
| 2703 | } |
| 2704 | } |
| 2705 | |
| 2706 | /** |
| 2707 | * ws_broken_link_checker::lockfile_name() |
| 2708 | * Generate system-specific lockfile filename |
| 2709 | * |
| 2710 | * @return string A filename or FALSE on error |
| 2711 | */ |
| 2712 | function lockfile_name(){ |
| 2713 | //Try the user-specified temp. directory first, if any |
| 2714 | if ( !empty( $this->conf->options['custom_tmp_dir'] ) ) { |
| 2715 | $custom_dir = trailingslashit($this->conf->options['custom_tmp_dir']); |
| 2716 | if ( blcUtility::is_writable( $custom_dir ) && @is_dir( $custom_dir ) ) { |
| 2717 | return $custom_dir . 'wp_blc_lock'; |
| 2718 | } else { |
| 2719 | return false; |
| 2720 | } |
| 2721 | } |
| 2722 | |
| 2723 | //Try the plugin's own directory. |
| 2724 | if ( blcUtility::is_writable( trailingslashit(dirname(__FILE__)) ) ){ |
| 2725 | return dirname(__FILE__) . '/wp_blc_lock'; |
| 2726 | } else { |
| 2727 | |
| 2728 | //Try the system-wide temp directory |
| 2729 | $path = trailingslashit( sys_get_temp_dir() ); |
| 2730 | if ( $path && blcUtility::is_writable($path)){ |
| 2731 | return $path . 'wp_blc_lock'; |
| 2732 | } |
| 2733 | |
| 2734 | //Try the upload directory. |
| 2735 | $path = trailingslashit( ini_get('upload_tmp_dir') ); |
| 2736 | if ( $path && blcUtility::is_writable($path)){ |
| 2737 | return $path . 'wp_blc_lock'; |
| 2738 | } |
| 2739 | |
| 2740 | //Fail |
| 2741 | return false; |
| 2742 | } |
| 2743 | } |
| 2744 | |
| 2745 | function hook_add_link( $link_id ){ |
| 2746 | $this->mark_unsynched( $link_id, 'blogroll' ); |
| 2747 | } |
| 2748 | |
| 2749 | function hook_edit_link( $link_id ){ |
| 2750 | $this->mark_unsynched( $link_id, 'blogroll' ); |
| 2751 | } |
| 2752 | |
| 2753 | function hook_delete_link( $link_id ){ |
| 2754 | global $wpdb; |
| 2755 | //Delete the synch record |
| 2756 | $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}blc_synch WHERE source_id = %d AND source_type='blogroll'", $link_id ) ); |
| 2757 | |
| 2758 | //Get the matching instance record. |
| 2759 | $inst = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$wpdb->prefix}blc_instances WHERE source_id = %d AND source_type = 'blogroll'", $link_id), ARRAY_A ); |
| 2760 | |
| 2761 | if ( !$inst ) { |
| 2762 | //No instance record? No problem. |
| 2763 | return; |
| 2764 | } |
| 2765 | |
| 2766 | //Remove it |
| 2767 | $wpdb->query( $wpdb->prepare("DELETE FROM {$wpdb->prefix}blc_instances WHERE instance_id = %d", $inst['instance_id']) ); |
| 2768 | |
| 2769 | //Remove the link that was associated with this instance if it has no more related instances. |
| 2770 | $this->cleanup_links( $inst['link_id'] ); |
| 2771 | } |
| 2772 | |
| 2773 | function hook_wp_dashboard_setup(){ |
| 2774 | if ( function_exists( 'wp_add_dashboard_widget' ) ) { |
| 2775 | wp_add_dashboard_widget( |
| 2776 | 'blc_dashboard_widget', |
| 2777 | 'Broken Link Checker', |
| 2778 | array( &$this, 'dashboard_widget' ), |
| 2779 | array( &$this, 'dashboard_widget_control' ) |
| 2780 | ); |
| 2781 | } |
| 2782 | } |
| 2783 | |
| 2784 | function lockfile_warning(){ |
| 2785 | $my_dir = '/plugins/' . basename(dirname(__FILE__)) . '/'; |
| 2786 | $settings_page = admin_url( 'options-general.php?page=link-checker-settings#lockfile_directory' ); |
| 2787 | |
| 2788 | //Make the notice customized to the current settings |
| 2789 | if ( !empty($this->conf->options['custom_tmp_dir']) ){ |
| 2790 | $action_notice = sprintf( |
| 2791 | __('The current temporary directory is not accessible; please <a href="%s">set a different one</a>.', 'broken-link-checker'), |
| 2792 | $settings_page |
| 2793 | ); |
| 2794 | } else { |
| 2795 | $action_notice = sprintf( |
| 2796 | __('Please make the directory <code>%1$s</code> writable by plugins or <a href="%2$s">set a custom temporary directory</a>.', 'broken-link-checker'), |
| 2797 | $my_dir, $settings_page |
| 2798 | ); |
| 2799 | } |
| 2800 | |
| 2801 | echo sprintf(' |
| 2802 | <div id="blc-lockfile-warning" class="error"><p> |
| 2803 | <strong>' . __("Broken Link Checker can't create a lockfile.", 'broken-link-checker') . |
| 2804 | '</strong> %s <a href="javascript:void(0)" onclick="jQuery(\'#blc-lockfile-details\').toggle()">' . |
| 2805 | __('Details', 'broken-link-checker') . '</a> </p> |
| 2806 | |
| 2807 | <div id="blc-lockfile-details" style="display:none;"><p>' . |
| 2808 | __("The plugin uses a file-based locking mechanism to ensure that only one instance of the resource-heavy link checking algorithm is running at any given time. Unfortunately, BLC can't find a writable directory where it could store the lockfile - it failed to detect the location of your server's temporary directory, and the plugin's own directory isn't writable by PHP. To fix this problem, please make the plugin's directory writable or enter a specify a custom temporary directory in the plugin's settings.", 'broken-link-checker') . |
| 2809 | '</p> |
| 2810 | </div> |
| 2811 | </div>', |
| 2812 | $action_notice); |
| 2813 | } |
| 2814 | |
| 2815 | /** |
| 2816 | * wsBrokenLinkChecker::get_debug_info() |
| 2817 | * Collect various debugging information and return it in an associative array |
| 2818 | * |
| 2819 | * @return array |
| 2820 | */ |
| 2821 | function get_debug_info(){ |
| 2822 | global $wpdb; |
| 2823 | |
| 2824 | //Collect some information that's useful for debugging |
| 2825 | $debug = array(); |
| 2826 | |
| 2827 | //PHP version. Any one is fine as long as WP supports it. |
| 2828 | $debug[ __('PHP version', 'broken-link-checker') ] = array( |
| 2829 | 'state' => 'ok', |
| 2830 | 'value' => phpversion(), |
| 2831 | ); |
| 2832 | |
| 2833 | //MySQL version |
| 2834 | $debug[ __('MySQL version', 'broken-link-checker') ] = array( |
| 2835 | 'state' => 'ok', |
| 2836 | 'value' => @mysql_get_server_info( $wpdb->dbh ), |
| 2837 | ); |
| 2838 | |
| 2839 | //CURL presence and version |
| 2840 | if ( function_exists('curl_version') ){ |
| 2841 | $version = curl_version(); |
| 2842 | |
| 2843 | if ( version_compare( $version['version'], '7.16.0', '<=' ) ){ |
| 2844 | $data = array( |
| 2845 | 'state' => 'warning', |
| 2846 | 'value' => $version['version'], |
| 2847 | 'message' => __('You have an old version of CURL. Redirect detection may not work properly.', 'broken-link-checker'), |
| 2848 | ); |
| 2849 | } else { |
| 2850 | $data = array( |
| 2851 | 'state' => 'ok', |
| 2852 | 'value' => $version['version'], |
| 2853 | ); |
| 2854 | } |
| 2855 | |
| 2856 | } else { |
| 2857 | $data = array( |
| 2858 | 'state' => 'warning', |
| 2859 | 'value' => __('Not installed', 'broken-link-checker'), |
| 2860 | ); |
| 2861 | } |
| 2862 | $debug[ __('CURL version', 'broken-link-checker') ] = $data; |
| 2863 | |
| 2864 | //Snoopy presence |
| 2865 | if ( class_exists('Snoopy') ){ |
| 2866 | $data = array( |
| 2867 | 'state' => 'ok', |
| 2868 | 'value' => __('Installed', 'broken-link-checker'), |
| 2869 | ); |
| 2870 | } else { |
| 2871 | //No Snoopy? This should never happen, but if it does we *must* have CURL. |
| 2872 | if ( function_exists('curl_init') ){ |
| 2873 | $data = array( |
| 2874 | 'state' => 'ok', |
| 2875 | 'value' => __('Not installed', 'broken-link-checker'), |
| 2876 | ); |
| 2877 | } else { |
| 2878 | $data = array( |
| 2879 | 'state' => 'error', |
| 2880 | 'value' => __('Not installed', 'broken-link-checker'), |
| 2881 | 'message' => __('You must have either CURL or Snoopy installed for the plugin to work!', 'broken-link-checker'), |
| 2882 | ); |
| 2883 | } |
| 2884 | |
| 2885 | } |
| 2886 | $debug['Snoopy'] = $data; |
| 2887 | |
| 2888 | //Safe_mode status |
| 2889 | if ( blcUtility::is_safe_mode() ){ |
| 2890 | $debug['Safe mode'] = array( |
| 2891 | 'state' => 'warning', |
| 2892 | 'value' => __('On', 'broken-link-checker'), |
| 2893 | 'message' => __('Redirects may be detected as broken links when safe_mode is on.', 'broken-link-checker'), |
| 2894 | ); |
| 2895 | } else { |
| 2896 | $debug['Safe mode'] = array( |
| 2897 | 'state' => 'ok', |
| 2898 | 'value' => __('Off', 'broken-link-checker'), |
| 2899 | ); |
| 2900 | } |
| 2901 | |
| 2902 | //Open_basedir status |
| 2903 | if ( blcUtility::is_open_basedir() ){ |
| 2904 | $debug['open_basedir'] = array( |
| 2905 | 'state' => 'warning', |
| 2906 | 'value' => sprintf( __('On ( %s )', 'broken-link-checker'), ini_get('open_basedir') ), |
| 2907 | 'message' => __('Redirects may be detected as broken links when open_basedir is on.', 'broken-link-checker'), |
| 2908 | ); |
| 2909 | } else { |
| 2910 | $debug['open_basedir'] = array( |
| 2911 | 'state' => 'ok', |
| 2912 | 'value' => __('Off', 'broken-link-checker'), |
| 2913 | ); |
| 2914 | } |
| 2915 | |
| 2916 | //Lockfile location |
| 2917 | $lockfile = $this->lockfile_name(); |
| 2918 | if ( $lockfile ){ |
| 2919 | $debug['Lockfile'] = array( |
| 2920 | 'state' => 'ok', |
| 2921 | 'value' => $lockfile, |
| 2922 | ); |
| 2923 | } else { |
| 2924 | $debug['Lockfile'] = array( |
| 2925 | 'state' => 'error', |
| 2926 | 'message' => __("Can't create a lockfile. Please specify a custom temporary directory.", 'broken-link-checker'), |
| 2927 | ); |
| 2928 | } |
| 2929 | |
| 2930 | return $debug; |
| 2931 | } |
| 2932 | |
| 2933 | /** |
| 2934 | * wsBrokenLinkChecker::load_language() |
| 2935 | * Load the plugin's textdomain |
| 2936 | * |
| 2937 | * @return void |
| 2938 | */ |
| 2939 | function load_language(){ |
| 2940 | load_plugin_textdomain( 'broken-link-checker', false, basename(dirname($this->loader)) . '/languages' ); |
| 2941 | } |
| 2942 | |
| 2943 | /** |
| 2944 | * wsBrokenLinkChecker::get_links() |
| 2945 | * Get the list of links that match a given filter. |
| 2946 | * |
| 2947 | * @param array|null $filter The filter to apply. Set this to null to return all links (default). |
| 2948 | * @param integer $offset Skip this many links from the beginning. If this parameter is nonzero you must also set the next one. |
| 2949 | * @param integer $max_results The maximum number of links to return. |
| 2950 | * @param bool $count_only Only return the total number of matching links, not the links themselves |
| 2951 | * @return array|int Either an array of links, or the number of matching links. Null on error. |
| 2952 | */ |
| 2953 | function get_links( $filter = null, $offset = 0, $max_results = 0, $count_only = false){ |
| 2954 | global $wpdb; |
| 2955 | |
| 2956 | //Figure out the WHERE expression for this filter |
| 2957 | $where_expr = '1'; //default = select all links |
| 2958 | |
| 2959 | if ( !empty($filter) ){ |
| 2960 | |
| 2961 | //Is this a custom search filter? |
| 2962 | if ( empty($filter['is_search']) ){ |
| 2963 | //It's a native filter, so it should have the WHERE epression already set |
| 2964 | $where_expr = $filter['where_expr']; |
| 2965 | } else { |
| 2966 | //It's a search filter, so we must build the WHERE expr for the specific query |
| 2967 | //from the query parameters. |
| 2968 | |
| 2969 | $params = $this->get_search_params($filter); |
| 2970 | |
| 2971 | //Generate the individual clauses of the WHERE expression |
| 2972 | $pieces = array(); |
| 2973 | |
| 2974 | //Anchor text - use fulltext search |
| 2975 | if ( !empty($params['s_link_text']) ){ |
| 2976 | $pieces[] = 'MATCH(instances.link_text) AGAINST("' . $wpdb->escape($params['s_link_text']) . '")'; |
| 2977 | } |
| 2978 | |
| 2979 | //URL - try to match both the initial URL and the final URL. |
| 2980 | //There is limited wildcard support, e.g. "google.*/search" will match both |
| 2981 | //"google.com/search" and "google.lv/search" |
| 2982 | if ( !empty($params['s_link_url']) ){ |
| 2983 | $s_link_url = like_escape($wpdb->escape($params['s_link_url'])); |
| 2984 | $s_link_url = str_replace('*', '%', $s_link_url); |
| 2985 | |
| 2986 | $pieces[] = '(links.url LIKE "%'. $s_link_url .'%") OR '. |
| 2987 | '(links.final_url LIKE "%'. $s_link_url .'%")'; |
| 2988 | } |
| 2989 | |
| 2990 | //Link type should match either the instance_type or the source_type |
| 2991 | if ( !empty($params['s_link_type']) ){ |
| 2992 | $s_link_type = $wpdb->escape($params['s_link_type']); |
| 2993 | $pieces[] = "instances.instance_type = '$s_link_type' OR instances.source_type='$s_link_type'"; |
| 2994 | } |
| 2995 | |
| 2996 | //HTTP code - the user can provide a list of HTTP response codes and code ranges. |
| 2997 | //Example : 201,400-410,500 |
| 2998 | if ( !empty($params['s_http_code']) ){ |
| 2999 | //Strip spaces. |
| 3000 | $params['s_http_code'] = str_replace(' ', '', $params['s_http_code']); |
| 3001 | //Split by comma |
| 3002 | $codes = explode(',', $params['s_http_code']); |
| 3003 | |
| 3004 | $individual_codes = array(); |
| 3005 | $ranges = array(); |
| 3006 | |
| 3007 | //Try to parse each response code or range. Invalid ones are simply ignored. |
| 3008 | foreach($codes as $code){ |
| 3009 | if ( is_numeric($code) ){ |
| 3010 | //It's a single number |
| 3011 | $individual_codes[] = abs(intval($code)); |
| 3012 | } elseif ( strpos($code, '-') !== false ) { |
| 3013 | //Try to parse it as a range |
| 3014 | $range = explode( '-', $code, 2 ); |
| 3015 | if ( (count($range) == 2) && is_numeric($range[0]) && is_numeric($range[0]) ){ |
| 3016 | //Make sure the smaller code comes first |
| 3017 | $range = array( intval($range[0]), intval($range[1]) ); |
| 3018 | $ranges[] = array( min($range), max($range) ); |
| 3019 | } |
| 3020 | } |
| 3021 | } |
| 3022 | |
| 3023 | $piece = array(); |
| 3024 | |
| 3025 | //All individual response codes get one "http_code IN (...)" clause |
| 3026 | if ( !empty($individual_codes) ){ |
| 3027 | $piece[] = '(links.http_code IN ('. implode(', ', $individual_codes) .'))'; |
| 3028 | } |
| 3029 | |
| 3030 | //Ranges get a "http_code BETWEEN min AND max" clause each |
| 3031 | if ( !empty($ranges) ){ |
| 3032 | $range_strings = array(); |
| 3033 | foreach($ranges as $range){ |
| 3034 | $range_strings[] = "(links.http_code BETWEEN $range[0] AND $range[1])"; |
| 3035 | } |
| 3036 | $piece[] = '( ' . implode(' OR ', $range_strings) . ' )'; |
| 3037 | } |
| 3038 | |
| 3039 | //Finally, generate a composite WHERE clause for both types of response code queries |
| 3040 | if ( !empty($piece) ){ |
| 3041 | $pieces[] = implode(' OR ', $piece); |
| 3042 | } |
| 3043 | |
| 3044 | } |
| 3045 | |
| 3046 | //Custom filters can optionally call one of the native filters |
| 3047 | //to narrow down the result set. |
| 3048 | if ( !empty($params['s_filter']) && isset($this->native_filters[$params['s_filter']]) ){ |
| 3049 | $pieces[] = $this->native_filters[$params['s_filter']]['where_expr']; |
| 3050 | } |
| 3051 | |
| 3052 | if ( !empty($pieces) ){ |
| 3053 | $where_expr = "\t( " . implode(" ) AND\n\t( ", $pieces) . ' ) '; |
| 3054 | } |
| 3055 | } |
| 3056 | |
| 3057 | } |
| 3058 | |
| 3059 | if ( $count_only ){ |
| 3060 | //Only get the number of matching links. This lets us use a simplified query with less joins. |
| 3061 | $q = " |
| 3062 | SELECT COUNT(*) |
| 3063 | FROM ( |
| 3064 | SELECT 0 |
| 3065 | |
| 3066 | FROM |
| 3067 | {$wpdb->prefix}blc_links AS links, |
| 3068 | {$wpdb->prefix}blc_instances as instances |
| 3069 | |
| 3070 | WHERE |
| 3071 | links.link_id = instances.link_id |
| 3072 | AND ". $where_expr ." |
| 3073 | |
| 3074 | GROUP BY links.link_id) AS foo"; |
| 3075 | return $wpdb->get_var($q); |
| 3076 | } else { |
| 3077 | //Select the required links + 1 instance per link + 1 post for instances contained in posts. |
| 3078 | $q = "SELECT |
| 3079 | links.*, |
| 3080 | instances.instance_id, instances.source_id, instances.source_type, |
| 3081 | instances.link_text, instances.instance_type, |
| 3082 | COUNT(*) as instance_count, |
| 3083 | posts.post_title, |
| 3084 | posts.post_date |
| 3085 | |
| 3086 | FROM |
| 3087 | {$wpdb->prefix}blc_links AS links, |
| 3088 | {$wpdb->prefix}blc_instances as instances LEFT JOIN {$wpdb->posts} as posts ON instances.source_id = posts.ID |
| 3089 | |
| 3090 | WHERE |
| 3091 | links.link_id = instances.link_id |
| 3092 | AND ". $where_expr ." |
| 3093 | |
| 3094 | GROUP BY links.link_id"; |
| 3095 | if ( $max_results || $offset ){ |
| 3096 | $q .= "\nLIMIT $offset, $max_results"; |
| 3097 | } |
| 3098 | |
| 3099 | return $wpdb->get_results($q, ARRAY_A); |
| 3100 | } |
| 3101 | } |
| 3102 | |
| 3103 | }//class ends here |
| 3104 | |
| 3105 | } // if class_exists... |
| 3106 | |
| 3107 | ?> |