Version Description
- Fixed a few more PHP 7.x/5.6 compatibility issues
Download this release
Release Info
| Developer | freediver |
| Plugin | |
| Version | 1.11.4 |
| Comparing to | |
| See all releases | |
Code changes from version 1.11.3 to 1.11.4
- broken-link-checker.php +1 -1
- core/core.php +579 -533
- core/init.php +1 -0
- includes/activation.php +3 -0
- includes/admin/links-page-js.php +4 -1
- includes/admin/options-page-js.php +10 -0
- includes/admin/table-printer.php +907 -904
- includes/modules.php +2 -0
- includes/utility-class.php +377 -377
- modules/checkers/http.php +8 -0
- modules/containers/acf_field.php +710 -0
- modules/containers/custom_field.php +102 -99
- modules/parsers/acf_field.php +134 -0
- readme.txt +4 -1
- uninstall.php +21 -22
broken-link-checker.php
CHANGED
|
@@ -3,7 +3,7 @@
|
|
| 3 |
Plugin Name: Broken Link Checker
|
| 4 |
Plugin URI: https://wordpress.org/plugins/broken-link-checker/
|
| 5 |
Description: Checks your blog for broken links and missing images and notifies you on the dashboard if any are found.
|
| 6 |
-
Version: 1.11.
|
| 7 |
Author: Janis Elsts, Vladimir Prelovac
|
| 8 |
Text Domain: broken-link-checker
|
| 9 |
*/
|
| 3 |
Plugin Name: Broken Link Checker
|
| 4 |
Plugin URI: https://wordpress.org/plugins/broken-link-checker/
|
| 5 |
Description: Checks your blog for broken links and missing images and notifies you on the dashboard if any are found.
|
| 6 |
+
Version: 1.11.4
|
| 7 |
Author: Janis Elsts, Vladimir Prelovac
|
| 8 |
Text Domain: broken-link-checker
|
| 9 |
*/
|
core/core.php
CHANGED
|
@@ -1,13 +1,11 @@
|
|
| 1 |
<?php
|
| 2 |
-
|
| 3 |
/**
|
| 4 |
* Simple function to replicate PHP 5 behaviour
|
| 5 |
*/
|
| 6 |
-
if ( !function_exists( 'microtime_float' ) ) {
|
| 7 |
-
function microtime_float()
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
return ((float)$usec + (float)$sec);
|
| 11 |
}
|
| 12 |
}
|
| 13 |
|
|
@@ -19,17 +17,16 @@ require BLC_DIRECTORY . '/includes/transactions-manager.php';
|
|
| 19 |
if (!class_exists('wsBrokenLinkChecker')) {
|
| 20 |
|
| 21 |
class wsBrokenLinkChecker {
|
| 22 |
-
|
| 23 |
-
|
| 24 |
var $loader;
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
|
| 31 |
private $is_textdomain_loaded = false;
|
| 32 |
-
|
| 33 |
/**
|
| 34 |
* wsBrokenLinkChecker::wsBrokenLinkChecker()
|
| 35 |
* Class constructor
|
|
@@ -40,26 +37,26 @@ class wsBrokenLinkChecker {
|
|
| 40 |
*/
|
| 41 |
function __construct ( $loader, $conf ) {
|
| 42 |
$this->db_version = BLC_DATABASE_VERSION;
|
| 43 |
-
|
| 44 |
$this->conf = $conf;
|
| 45 |
$this->loader = $loader;
|
| 46 |
$this->my_basename = plugin_basename( $this->loader );
|
| 47 |
|
| 48 |
$this->load_language();
|
| 49 |
-
|
| 50 |
//Unlike the activation hook, the deactivation callback *can* be registered in this file
|
| 51 |
-
//because deactivation happens after this class has already been instantiated (durinng the
|
| 52 |
-
//'init' action).
|
| 53 |
register_deactivation_hook($loader, array($this, 'deactivation'));
|
| 54 |
-
|
| 55 |
add_action('admin_menu', array($this,'admin_menu'));
|
| 56 |
|
| 57 |
//Load jQuery on Dashboard pages (probably redundant as WP already does that)
|
| 58 |
add_action('admin_print_scripts', array($this,'admin_print_scripts'));
|
| 59 |
-
|
| 60 |
//The dashboard widget
|
| 61 |
add_action('wp_dashboard_setup', array($this, 'hook_wp_dashboard_setup'));
|
| 62 |
-
|
| 63 |
//AJAXy hooks
|
| 64 |
add_action( 'wp_ajax_blc_full_status', array($this,'ajax_full_status') );
|
| 65 |
add_action( 'wp_ajax_blc_dashboard_status', array($this,'ajax_dashboard_status') );
|
|
@@ -74,18 +71,17 @@ class wsBrokenLinkChecker {
|
|
| 74 |
|
| 75 |
add_action( 'wp_ajax_blc_dismiss', array($this, 'ajax_dismiss') );
|
| 76 |
add_action( 'wp_ajax_blc_undismiss', array($this, 'ajax_undismiss') );
|
| 77 |
-
|
| 78 |
//Add/remove Cron events
|
| 79 |
$this->setup_cron_events();
|
| 80 |
-
|
| 81 |
//Set hooks that listen for our Cron actions
|
| 82 |
-
add_action('blc_cron_email_notifications', array( $this, 'maybe_send_email_notifications' ));
|
| 83 |
-
add_action('blc_cron_check_links', array($this, 'cron_check_links'));
|
| 84 |
-
add_action('blc_cron_database_maintenance', array($this, 'database_maintenance'));
|
| 85 |
|
| 86 |
//Set the footer hook that will call the worker function via AJAX.
|
| 87 |
-
add_action('admin_footer', array($this,'admin_footer'));
|
| 88 |
-
|
| 89 |
//Add a "Screen Options" panel to the "Broken Links" page
|
| 90 |
add_screen_options_panel(
|
| 91 |
'blc-screen-options',
|
|
@@ -97,7 +93,25 @@ class wsBrokenLinkChecker {
|
|
| 97 |
);
|
| 98 |
|
| 99 |
//Display an explanatory note on the "Tools -> Broken Links -> Warnings" page.
|
| 100 |
-
add_action('admin_notices', array($this, 'show_warnings_section_notice'));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
}
|
| 102 |
|
| 103 |
/**
|
|
@@ -114,8 +128,8 @@ class wsBrokenLinkChecker {
|
|
| 114 |
<!-- wsblc admin footer -->
|
| 115 |
<script type='text/javascript'>
|
| 116 |
(function($){
|
| 117 |
-
|
| 118 |
-
//(Re)starts the background worker thread
|
| 119 |
function blcDoWork(){
|
| 120 |
$.post(
|
| 121 |
"<?php echo admin_url('admin-ajax.php'); ?>",
|
|
@@ -127,16 +141,16 @@ class wsBrokenLinkChecker {
|
|
| 127 |
}
|
| 128 |
//Call it the first time
|
| 129 |
blcDoWork();
|
| 130 |
-
|
| 131 |
-
//Then call it periodically every X seconds
|
| 132 |
setInterval(blcDoWork, <?php echo (intval($this->conf->options['max_execution_time']) + 1 )*1000; ?>);
|
| 133 |
-
|
| 134 |
})(jQuery);
|
| 135 |
</script>
|
| 136 |
<!-- /wsblc admin footer -->
|
| 137 |
<?php
|
| 138 |
}
|
| 139 |
-
|
| 140 |
/**
|
| 141 |
* Check if an URL matches the exclusion list.
|
| 142 |
*
|
|
@@ -155,11 +169,11 @@ class wsBrokenLinkChecker {
|
|
| 155 |
|
| 156 |
function dashboard_widget(){
|
| 157 |
?>
|
| 158 |
-
<p id='wsblc_activity_box'><?php _e('Loading...', 'broken-link-checker'); ?></p>
|
| 159 |
<script type='text/javascript'>
|
| 160 |
jQuery( function($){
|
| 161 |
var blc_was_autoexpanded = false;
|
| 162 |
-
|
| 163 |
function blcDashboardStatus(){
|
| 164 |
$.getJSON(
|
| 165 |
"<?php echo admin_url('admin-ajax.php'); ?>",
|
|
@@ -169,7 +183,7 @@ class wsBrokenLinkChecker {
|
|
| 169 |
},
|
| 170 |
function (data){
|
| 171 |
if ( data && ( typeof(data.text) != 'undefined' ) ) {
|
| 172 |
-
$('#wsblc_activity_box').html(data.text);
|
| 173 |
<?php if ( $this->conf->options['autoexpand_widget'] ) { ?>
|
| 174 |
//Expand the widget if there are broken links.
|
| 175 |
//Do this only once per pageload so as not to annoy the user.
|
|
@@ -181,14 +195,14 @@ class wsBrokenLinkChecker {
|
|
| 181 |
} else {
|
| 182 |
$('#wsblc_activity_box').html('<?php _e('[ Network error ]', 'broken-link-checker'); ?>');
|
| 183 |
}
|
| 184 |
-
|
| 185 |
setTimeout( blcDashboardStatus, 120*1000 ); //...update every two minutes
|
| 186 |
}
|
| 187 |
);
|
| 188 |
}
|
| 189 |
-
|
| 190 |
blcDashboardStatus();//Call it the first time
|
| 191 |
-
|
| 192 |
} );
|
| 193 |
</script>
|
| 194 |
<?php
|
|
@@ -202,7 +216,7 @@ class wsBrokenLinkChecker {
|
|
| 202 |
$this->conf->options['autoexpand_widget'] = !empty($_POST['blc-autoexpand']);
|
| 203 |
$this->conf->save_options();
|
| 204 |
}
|
| 205 |
-
|
| 206 |
?>
|
| 207 |
<p><label for="blc-autoexpand">
|
| 208 |
<input id="blc-autoexpand" name="blc-autoexpand" type="checkbox" value="1" <?php if ( $this->conf->options['autoexpand_widget'] ) echo 'checked="checked"'; ?> />
|
|
@@ -215,7 +229,7 @@ class wsBrokenLinkChecker {
|
|
| 215 |
//jQuery is used for triggering the link monitor via AJAX when any admin page is open.
|
| 216 |
wp_enqueue_script('jquery');
|
| 217 |
}
|
| 218 |
-
|
| 219 |
function enqueue_settings_scripts(){
|
| 220 |
//jQuery UI is used on the settings page
|
| 221 |
wp_enqueue_script('jquery-ui-core'); //Used for background color animation
|
|
@@ -223,16 +237,16 @@ class wsBrokenLinkChecker {
|
|
| 223 |
wp_enqueue_script('jquery-ui-tabs');
|
| 224 |
wp_enqueue_script('jquery-cookie', plugins_url('js/jquery.cookie.js', BLC_PLUGIN_FILE)); //Used for storing last widget states, etc
|
| 225 |
}
|
| 226 |
-
|
| 227 |
function enqueue_link_page_scripts(){
|
| 228 |
wp_enqueue_script('jquery-ui-core');
|
| 229 |
wp_enqueue_script('jquery-ui-dialog'); //Used for the search form
|
| 230 |
wp_enqueue_script('jquery-color'); //Used for background color animation
|
| 231 |
wp_enqueue_script('sprintf', plugins_url('js/sprintf.js', BLC_PLUGIN_FILE)); //Used in error messages
|
| 232 |
}
|
| 233 |
-
|
| 234 |
/**
|
| 235 |
-
* Initiate a full recheck - reparse everything and check all links anew.
|
| 236 |
*
|
| 237 |
* @return void
|
| 238 |
*/
|
|
@@ -241,10 +255,10 @@ class wsBrokenLinkChecker {
|
|
| 241 |
|
| 242 |
//Delete all discovered instances
|
| 243 |
$wpdb->query("TRUNCATE {$wpdb->prefix}blc_instances");
|
| 244 |
-
|
| 245 |
//Delete all discovered links
|
| 246 |
$wpdb->query("TRUNCATE {$wpdb->prefix}blc_links");
|
| 247 |
-
|
| 248 |
//Mark all posts, custom fields and bookmarks for processing.
|
| 249 |
blc_resynch(true);
|
| 250 |
}
|
|
@@ -260,7 +274,7 @@ class wsBrokenLinkChecker {
|
|
| 260 |
wp_clear_scheduled_hook('blc_cron_email_notifications');
|
| 261 |
wp_clear_scheduled_hook('blc_cron_database_maintenance');
|
| 262 |
wp_clear_scheduled_hook('blc_cron_check_news'); //Unused event.
|
| 263 |
-
//Note the deactivation time for each module. This will help them
|
| 264 |
//synch up propely if/when the plugin is reactivated.
|
| 265 |
$moduleManager = blcModuleManager::getInstance();
|
| 266 |
$the_time = current_time('timestamp');
|
|
@@ -269,68 +283,68 @@ class wsBrokenLinkChecker {
|
|
| 269 |
}
|
| 270 |
$this->conf->save_options();
|
| 271 |
}
|
| 272 |
-
|
| 273 |
/**
|
| 274 |
* Perform various database maintenance tasks on the plugin's tables.
|
| 275 |
-
*
|
| 276 |
* Removes records that reference disabled containers and parsers,
|
| 277 |
* deletes invalid instances and links, optimizes tables, etc.
|
| 278 |
-
*
|
| 279 |
* @return void
|
| 280 |
*/
|
| 281 |
function database_maintenance(){
|
| 282 |
blcContainerHelper::cleanup_containers();
|
| 283 |
blc_cleanup_instances();
|
| 284 |
blc_cleanup_links();
|
| 285 |
-
|
| 286 |
blcUtility::optimize_database();
|
| 287 |
}
|
| 288 |
|
| 289 |
/**
|
| 290 |
* Create the plugin's menu items and enqueue their scripts and CSS.
|
| 291 |
-
* Callback for the 'admin_menu' action.
|
| 292 |
-
*
|
| 293 |
* @return void
|
| 294 |
*/
|
| 295 |
function admin_menu(){
|
| 296 |
if (current_user_can('manage_options'))
|
| 297 |
add_filter('plugin_action_links', array($this, 'plugin_action_links'), 10, 2);
|
| 298 |
-
|
| 299 |
-
$options_page_hook = add_options_page(
|
| 300 |
-
__('Link Checker Settings', 'broken-link-checker'),
|
| 301 |
-
__('Link Checker', 'broken-link-checker'),
|
| 302 |
'manage_options',
|
| 303 |
'link-checker-settings',array($this, 'options_page')
|
| 304 |
);
|
| 305 |
-
|
| 306 |
$menu_title = __('Broken Links', 'broken-link-checker');
|
| 307 |
if ( $this->conf->options['show_link_count_bubble'] ){
|
| 308 |
-
//To make it easier to notice when broken links appear, display the current number of
|
| 309 |
-
//broken links in a little bubble notification in the "Broken Links" menu.
|
| 310 |
//(Similar to how the number of plugin updates and unmoderated comments is displayed).
|
| 311 |
$blc_link_query = blcLinkQuery::getInstance();
|
| 312 |
$broken_links = $blc_link_query->get_filter_links('broken', array('count_only' => true));
|
| 313 |
if ( $broken_links > 0 ){
|
| 314 |
-
//TODO: Appropriating existing CSS classes for my own purposes is hacky. Fix eventually.
|
| 315 |
$menu_title .= sprintf(
|
| 316 |
-
' <span class="update-plugins"><span class="update-count blc-menu-bubble">%d</span></span>',
|
| 317 |
$broken_links
|
| 318 |
);
|
| 319 |
}
|
| 320 |
-
}
|
| 321 |
$links_page_hook = add_management_page(
|
| 322 |
-
__('View Broken Links', 'broken-link-checker'),
|
| 323 |
-
$menu_title,
|
| 324 |
'edit_others_posts',
|
| 325 |
'view-broken-links',array($this, 'links_page')
|
| 326 |
);
|
| 327 |
-
|
| 328 |
//Add plugin-specific scripts and CSS only to the it's own pages
|
| 329 |
add_action( 'admin_print_styles-' . $options_page_hook, array($this, 'options_page_css') );
|
| 330 |
add_action( 'admin_print_styles-' . $links_page_hook, array($this, 'links_page_css') );
|
| 331 |
add_action( 'admin_print_scripts-' . $options_page_hook, array($this, 'enqueue_settings_scripts') );
|
| 332 |
add_action( 'admin_print_scripts-' . $links_page_hook, array($this, 'enqueue_link_page_scripts') );
|
| 333 |
-
|
| 334 |
//Make the Settings page link to the link list
|
| 335 |
add_screen_meta_link(
|
| 336 |
'blc-links-page-link',
|
|
@@ -340,7 +354,7 @@ class wsBrokenLinkChecker {
|
|
| 340 |
array('style' => 'font-weight: bold;')
|
| 341 |
);
|
| 342 |
}
|
| 343 |
-
|
| 344 |
/**
|
| 345 |
* plugin_action_links()
|
| 346 |
* Handler for the 'plugin_action_links' hook. Adds a "Settings" link to this plugin's entry
|
|
@@ -373,7 +387,7 @@ class wsBrokenLinkChecker {
|
|
| 373 |
|
| 374 |
if (isset($_POST['recheck']) && !empty($_POST['recheck']) ){
|
| 375 |
$this->initiate_recheck();
|
| 376 |
-
|
| 377 |
//Redirect back to the settings page
|
| 378 |
$base_url = remove_query_arg( array('_wpnonce', 'noheader', 'updated', 'error', 'action', 'message') );
|
| 379 |
wp_redirect( add_query_arg( array( 'recheck-initiated' => true), $base_url ) );
|
|
@@ -388,7 +402,7 @@ class wsBrokenLinkChecker {
|
|
| 388 |
'blc-recheck-action' => __('Recheck', 'broken-link-checker'),
|
| 389 |
'blc-deredirect-action' => _x('Fix redirect', 'link action; replace one redirect with a direct link', 'broken-link-checker')
|
| 390 |
);
|
| 391 |
-
|
| 392 |
if(isset($_POST['submit'])) {
|
| 393 |
check_admin_referer('link-checker-options');
|
| 394 |
|
|
@@ -396,17 +410,17 @@ class wsBrokenLinkChecker {
|
|
| 396 |
if ( function_exists('wp_magic_quotes') ){
|
| 397 |
$cleanPost = stripslashes_deep($cleanPost); //Ceterum censeo, WP shouldn't mangle superglobals.
|
| 398 |
}
|
| 399 |
-
|
| 400 |
//Activate/deactivate modules
|
| 401 |
if ( !empty($_POST['module']) ){
|
| 402 |
$active = array_keys($_POST['module']);
|
| 403 |
$moduleManager->set_active_modules($active);
|
| 404 |
}
|
| 405 |
-
|
| 406 |
//Only post statuses that actually exist can be selected
|
| 407 |
if ( isset($_POST['enabled_post_statuses']) && is_array($_POST['enabled_post_statuses']) ){
|
| 408 |
$available_statuses = get_post_stati();
|
| 409 |
-
$enabled_post_statuses = array_intersect($_POST['enabled_post_statuses'], $available_statuses);
|
| 410 |
} else {
|
| 411 |
$enabled_post_statuses = array();
|
| 412 |
}
|
|
@@ -433,28 +447,28 @@ class wsBrokenLinkChecker {
|
|
| 433 |
if( $new_check_threshold > 0 ){
|
| 434 |
$this->conf->options['check_threshold'] = $new_check_threshold;
|
| 435 |
}
|
| 436 |
-
|
| 437 |
$this->conf->options['mark_broken_links'] = !empty($_POST['mark_broken_links']);
|
| 438 |
$new_broken_link_css = trim($cleanPost['broken_link_css']);
|
| 439 |
$this->conf->options['broken_link_css'] = $new_broken_link_css;
|
| 440 |
-
|
| 441 |
$this->conf->options['mark_removed_links'] = !empty($_POST['mark_removed_links']);
|
| 442 |
$new_removed_link_css = trim($cleanPost['removed_link_css']);
|
| 443 |
$this->conf->options['removed_link_css'] = $new_removed_link_css;
|
| 444 |
-
|
| 445 |
$this->conf->options['nofollow_broken_links'] = !empty($_POST['nofollow_broken_links']);
|
| 446 |
-
|
| 447 |
$this->conf->options['suggestions_enabled'] = !empty($_POST['suggestions_enabled']);
|
| 448 |
|
| 449 |
$this->conf->options['exclusion_list'] = array_filter(
|
| 450 |
-
preg_split(
|
| 451 |
-
'/[\s\r\n]+/', //split on newlines and whitespace
|
| 452 |
$cleanPost['exclusion_list'],
|
| 453 |
-1,
|
| 454 |
PREG_SPLIT_NO_EMPTY //skip empty values
|
| 455 |
-
)
|
| 456 |
);
|
| 457 |
-
|
| 458 |
//Parse the custom field list
|
| 459 |
$new_custom_fields = array_filter(
|
| 460 |
preg_split( '/[\r\n]+/', $cleanPost['blc_custom_fields'], -1, PREG_SPLIT_NO_EMPTY )
|
|
@@ -465,7 +479,15 @@ class wsBrokenLinkChecker {
|
|
| 465 |
$diff2 = array_diff( $this->conf->options['custom_fields'], $new_custom_fields );
|
| 466 |
$this->conf->options['custom_fields'] = $new_custom_fields;
|
| 467 |
|
| 468 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 469 |
$warnings_enabled = !empty($_POST['warnings_enabled']);
|
| 470 |
if ( $this->conf->get('warnings_enabled') && !$warnings_enabled ) {
|
| 471 |
$this->promote_warnings_to_broken();
|
|
@@ -477,14 +499,14 @@ class wsBrokenLinkChecker {
|
|
| 477 |
if( $new_timeout > 0 ){
|
| 478 |
$this->conf->options['timeout'] = $new_timeout ;
|
| 479 |
}
|
| 480 |
-
|
| 481 |
-
//Server load limit
|
| 482 |
if ( isset($_POST['server_load_limit']) ){
|
| 483 |
$this->conf->options['server_load_limit'] = floatval($_POST['server_load_limit']);
|
| 484 |
if ( $this->conf->options['server_load_limit'] < 0 ){
|
| 485 |
$this->conf->options['server_load_limit'] = 0;
|
| 486 |
}
|
| 487 |
-
|
| 488 |
$this->conf->options['enable_load_limit'] = $this->conf->options['server_load_limit'] > 0;
|
| 489 |
}
|
| 490 |
|
|
@@ -494,11 +516,11 @@ class wsBrokenLinkChecker {
|
|
| 494 |
$usage = max(min($usage / 100, 1), 0.01);
|
| 495 |
$this->conf->options['target_resource_usage'] = $usage;
|
| 496 |
}
|
| 497 |
-
|
| 498 |
//When to run the checker
|
| 499 |
$this->conf->options['run_in_dashboard'] = !empty($_POST['run_in_dashboard']);
|
| 500 |
$this->conf->options['run_via_cron'] = !empty($_POST['run_via_cron']);
|
| 501 |
-
|
| 502 |
//Email notifications on/off
|
| 503 |
$email_notifications = !empty($_POST['send_email_notifications']);
|
| 504 |
$send_authors_email_notifications = !empty($_POST['send_authors_email_notifications']);
|
|
@@ -572,13 +594,13 @@ class wsBrokenLinkChecker {
|
|
| 572 |
|
| 573 |
//Make settings that affect our Cron events take effect immediately
|
| 574 |
$this->setup_cron_events();
|
| 575 |
-
|
| 576 |
$this->conf->save_options();
|
| 577 |
-
|
| 578 |
/*
|
| 579 |
If the list of custom fields was modified then we MUST resynchronize or
|
| 580 |
custom fields linked with existing posts may not be detected. This is somewhat
|
| 581 |
-
inefficient.
|
| 582 |
*/
|
| 583 |
if ( ( count($diff1) > 0 ) || ( count($diff2) > 0 ) ){
|
| 584 |
$manager = blcContainerHelper::get_manager('custom_field');
|
|
@@ -588,6 +610,19 @@ class wsBrokenLinkChecker {
|
|
| 588 |
}
|
| 589 |
}
|
| 590 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 591 |
//Resynchronize posts when the user enables or disables post statuses.
|
| 592 |
if ( $post_statuses_changed ) {
|
| 593 |
$overlord = blcPostTypeOverlord::getInstance();
|
|
@@ -598,49 +633,49 @@ class wsBrokenLinkChecker {
|
|
| 598 |
blc_cleanup_instances();
|
| 599 |
blc_cleanup_links();
|
| 600 |
}
|
| 601 |
-
|
| 602 |
//Redirect back to the settings page
|
| 603 |
$base_url = remove_query_arg( array('_wpnonce', 'noheader', 'updated', 'error', 'action', 'message') );
|
| 604 |
wp_redirect( add_query_arg( array( 'settings-updated' => true), $base_url ) );
|
| 605 |
}
|
| 606 |
-
|
| 607 |
-
//Show a confirmation message when settings are saved.
|
| 608 |
if ( !empty($_GET['settings-updated']) ){
|
| 609 |
echo '<div id="message" class="updated fade"><p><strong>',__('Settings saved.', 'broken-link-checker'), '</strong></p></div>';
|
| 610 |
-
|
| 611 |
}
|
| 612 |
-
|
| 613 |
//Show a thank-you message when a donation is made.
|
| 614 |
if ( !empty($_GET['donated']) ){
|
| 615 |
echo '<div id="message" class="updated fade"><p><strong>',__('Thank you for your donation!', 'broken-link-checker'), '</strong></p></div>';
|
| 616 |
$this->conf->set('user_has_donated', true);
|
| 617 |
$this->conf->save_options();
|
| 618 |
}
|
| 619 |
-
|
| 620 |
-
//Show one when recheck is started, too.
|
| 621 |
if ( !empty($_GET['recheck-initiated']) ){
|
| 622 |
echo '<div id="message" class="updated fade"><p><strong>',
|
| 623 |
-
__('Complete site recheck started.', 'broken-link-checker'), // -- Yoda
|
| 624 |
'</strong></p></div>';
|
| 625 |
}
|
| 626 |
-
|
| 627 |
//Cull invalid and missing modules
|
| 628 |
$moduleManager->validate_active_modules();
|
| 629 |
-
|
| 630 |
$debug = $this->get_debug_info();
|
| 631 |
-
|
| 632 |
add_filter('blc-module-settings-custom_field', array($this, 'make_custom_field_input'), 10, 2);
|
| 633 |
-
|
| 634 |
//Translate and markup-ify module headers for display
|
| 635 |
$modules = $moduleManager->get_modules_by_category('', true, true);
|
| 636 |
-
|
| 637 |
//Output the custom broken link/removed link styles for example links
|
| 638 |
printf(
|
| 639 |
-
'<style type="text/css">%s %s</style>',
|
| 640 |
$this->conf->options['broken_link_css'],
|
| 641 |
$this->conf->options['removed_link_css']
|
| 642 |
);
|
| 643 |
-
|
| 644 |
$section_names = array(
|
| 645 |
'general' => __('General', 'broken-link-checker'),
|
| 646 |
'where' => __('Look For Links In', 'broken-link-checker'),
|
|
@@ -649,56 +684,56 @@ class wsBrokenLinkChecker {
|
|
| 649 |
'advanced' => __('Advanced', 'broken-link-checker'),
|
| 650 |
);
|
| 651 |
?>
|
| 652 |
-
|
| 653 |
<!--[if lte IE 7]>
|
| 654 |
<style type="text/css">
|
| 655 |
/* Simulate inline-block in IE7 */
|
| 656 |
ul.ui-tabs-nav li {
|
| 657 |
-
display: inline;
|
| 658 |
zoom: 1;
|
| 659 |
}
|
| 660 |
</style>
|
| 661 |
<![endif]-->
|
| 662 |
-
|
| 663 |
<div class="wrap" id="blc-settings-wrap">
|
| 664 |
<h2><?php _e('Broken Link Checker Options', 'broken-link-checker'); ?></h2>
|
| 665 |
-
|
| 666 |
-
|
| 667 |
<div id="blc-sidebar">
|
| 668 |
<div class="metabox-holder">
|
| 669 |
<?php include BLC_DIRECTORY . '/includes/admin/sidebar.php'; ?>
|
| 670 |
</div>
|
| 671 |
</div>
|
| 672 |
-
|
| 673 |
-
|
| 674 |
<div id="blc-admin-content">
|
| 675 |
-
|
| 676 |
-
<form name="link_checker_options" id="link_checker_options" method="post" action="<?php
|
| 677 |
-
echo admin_url('options-general.php?page=link-checker-settings&noheader=1');
|
| 678 |
?>">
|
| 679 |
-
<?php
|
| 680 |
wp_nonce_field('link-checker-options');
|
| 681 |
?>
|
| 682 |
-
|
| 683 |
<div id="blc-tabs">
|
| 684 |
-
|
| 685 |
<ul class="hide-if-no-js">
|
| 686 |
<?php
|
| 687 |
foreach($section_names as $section_id => $section_name){
|
| 688 |
printf(
|
| 689 |
'<li id="tab-button-%s"><a href="#section-%s" title="%s">%s</a></li>',
|
| 690 |
-
esc_attr($section_id),
|
| 691 |
esc_attr($section_id),
|
| 692 |
-
esc_attr($
|
|
|
|
| 693 |
$section_name
|
| 694 |
-
);
|
| 695 |
}
|
| 696 |
?>
|
| 697 |
</ul>
|
| 698 |
|
| 699 |
<div id="section-general" class="blc-section">
|
| 700 |
<h3 class="hide-if-js"><?php echo $section_names['general']; ?></h3>
|
| 701 |
-
|
| 702 |
<table class="form-table">
|
| 703 |
|
| 704 |
<tr valign="top">
|
|
@@ -712,23 +747,23 @@ class wsBrokenLinkChecker {
|
|
| 712 |
<div id='wsblc_full_status'>
|
| 713 |
<br/><br/><br/>
|
| 714 |
</div>
|
| 715 |
-
|
| 716 |
<table id="blc-debug-info">
|
| 717 |
<?php
|
| 718 |
-
|
| 719 |
//Output the debug info in a table
|
| 720 |
foreach( $debug as $key => $value ){
|
| 721 |
printf (
|
| 722 |
'<tr valign="top" class="blc-debug-item-%s"><th scope="row">%s</th><td>%s<div class="blc-debug-message">%s</div></td></tr>',
|
| 723 |
$value['state'],
|
| 724 |
$key,
|
| 725 |
-
$value['value'],
|
| 726 |
( array_key_exists('message', $value)?$value['message']:'')
|
| 727 |
);
|
| 728 |
}
|
| 729 |
?>
|
| 730 |
</table>
|
| 731 |
-
|
| 732 |
</td>
|
| 733 |
</tr>
|
| 734 |
|
|
@@ -737,13 +772,13 @@ class wsBrokenLinkChecker {
|
|
| 737 |
<td>
|
| 738 |
|
| 739 |
<?php
|
| 740 |
-
printf(
|
| 741 |
__('Every %s hours','broken-link-checker'),
|
| 742 |
sprintf(
|
| 743 |
'<input type="text" name="check_threshold" id="check_threshold" value="%d" size="5" maxlength="5" />',
|
| 744 |
$this->conf->options['check_threshold']
|
| 745 |
)
|
| 746 |
-
);
|
| 747 |
?>
|
| 748 |
<br/>
|
| 749 |
<span class="description">
|
|
@@ -752,7 +787,7 @@ class wsBrokenLinkChecker {
|
|
| 752 |
|
| 753 |
</td>
|
| 754 |
</tr>
|
| 755 |
-
|
| 756 |
<tr valign="top">
|
| 757 |
<th scope="row"><?php _e('E-mail notifications', 'broken-link-checker'); ?></th>
|
| 758 |
<td>
|
|
@@ -807,11 +842,11 @@ class wsBrokenLinkChecker {
|
|
| 807 |
_e('Edit CSS', 'broken-link-checker');
|
| 808 |
?></a>
|
| 809 |
</p>
|
| 810 |
-
|
| 811 |
-
<div id="broken-link-css-wrap"<?php
|
| 812 |
if ( !blcUtility::get_cookie('broken-link-css-wrap', false) ){
|
| 813 |
echo ' class="hidden"';
|
| 814 |
-
}
|
| 815 |
?>>
|
| 816 |
<textarea name="broken_link_css" id="broken_link_css" cols='45' rows='4'><?php
|
| 817 |
if( isset($this->conf->options['broken_link_css']) ) {
|
|
@@ -826,7 +861,7 @@ class wsBrokenLinkChecker {
|
|
| 826 |
echo ' ', __('Click "Save Changes" to update example output.', 'broken-link-checker');
|
| 827 |
?></p>
|
| 828 |
</div>
|
| 829 |
-
|
| 830 |
<p style="margin-bottom: 0.5em;">
|
| 831 |
<label for='mark_removed_links'>
|
| 832 |
<input type="checkbox" name="mark_removed_links" id="mark_removed_links"
|
|
@@ -838,17 +873,17 @@ class wsBrokenLinkChecker {
|
|
| 838 |
_e('Edit CSS', 'broken-link-checker');
|
| 839 |
?></a>
|
| 840 |
</p>
|
| 841 |
-
|
| 842 |
-
<div id="removed-link-css-wrap" <?php
|
| 843 |
if ( !blcUtility::get_cookie('removed-link-css-wrap', false) ){
|
| 844 |
echo ' class="hidden"';
|
| 845 |
-
}
|
| 846 |
?>>
|
| 847 |
<textarea name="removed_link_css" id="removed_link_css" cols='45' rows='4'><?php
|
| 848 |
if( isset($this->conf->options['removed_link_css']) )
|
| 849 |
echo $this->conf->options['removed_link_css'];
|
| 850 |
?></textarea>
|
| 851 |
-
|
| 852 |
<p class="description"><?php
|
| 853 |
printf(
|
| 854 |
__('Example : Lorem ipsum <span %s>removed link</span>, dolor sit amet.', 'broken-link-checker'),
|
|
@@ -859,7 +894,7 @@ class wsBrokenLinkChecker {
|
|
| 859 |
|
| 860 |
</p>
|
| 861 |
</div>
|
| 862 |
-
|
| 863 |
<p>
|
| 864 |
<label for='nofollow_broken_links'>
|
| 865 |
<input type="checkbox" name="nofollow_broken_links" id="nofollow_broken_links"
|
|
@@ -906,14 +941,14 @@ class wsBrokenLinkChecker {
|
|
| 906 |
</tr>
|
| 907 |
|
| 908 |
</table>
|
| 909 |
-
|
| 910 |
</div>
|
| 911 |
-
|
| 912 |
<div id="section-where" class="blc-section">
|
| 913 |
<h3 class="hide-if-js"><?php echo $section_names['where']; ?></h3>
|
| 914 |
-
|
| 915 |
<table class="form-table">
|
| 916 |
-
|
| 917 |
<tr valign="top">
|
| 918 |
<th scope="row"><?php _e('Look for links in', 'broken-link-checker'); ?></th>
|
| 919 |
<td>
|
|
@@ -921,22 +956,22 @@ class wsBrokenLinkChecker {
|
|
| 921 |
if ( !empty($modules['container']) ){
|
| 922 |
uasort($modules['container'], create_function('$a, $b', 'return strcasecmp($a["Name"], $b["Name"]);'));
|
| 923 |
$this->print_module_list($modules['container'], $this->conf->options);
|
| 924 |
-
}
|
| 925 |
?>
|
| 926 |
</td></tr>
|
| 927 |
-
|
| 928 |
<tr valign="top">
|
| 929 |
<th scope="row"><?php _e('Post statuses', 'broken-link-checker'); ?></th>
|
| 930 |
<td>
|
| 931 |
<?php
|
| 932 |
$available_statuses = get_post_stati(array('internal' => false), 'objects');
|
| 933 |
-
|
| 934 |
if ( isset($this->conf->options['enabled_post_statuses']) ){
|
| 935 |
$enabled_post_statuses = $this->conf->options['enabled_post_statuses'];
|
| 936 |
} else {
|
| 937 |
$enabled_post_statuses = array();
|
| 938 |
}
|
| 939 |
-
|
| 940 |
foreach($available_statuses as $status => $status_object){
|
| 941 |
printf(
|
| 942 |
'<p><label><input type="checkbox" name="enabled_post_statuses[]" value="%s"%s> %s</label></p>',
|
|
@@ -947,17 +982,17 @@ class wsBrokenLinkChecker {
|
|
| 947 |
}
|
| 948 |
?>
|
| 949 |
</td></tr>
|
| 950 |
-
|
| 951 |
</table>
|
| 952 |
-
|
| 953 |
</div>
|
| 954 |
-
|
| 955 |
-
|
| 956 |
<div id="section-which" class="blc-section">
|
| 957 |
<h3 class="hide-if-js"><?php echo $section_names['which']; ?></h3>
|
| 958 |
-
|
| 959 |
<table class="form-table">
|
| 960 |
-
|
| 961 |
<tr valign="top">
|
| 962 |
<th scope="row"><?php _e('Link types', 'broken-link-checker'); ?></th>
|
| 963 |
<td>
|
|
@@ -970,7 +1005,7 @@ class wsBrokenLinkChecker {
|
|
| 970 |
?>
|
| 971 |
</td>
|
| 972 |
</tr>
|
| 973 |
-
|
| 974 |
<tr valign="top">
|
| 975 |
<th scope="row"><?php _e('Exclusion list', 'broken-link-checker'); ?></th>
|
| 976 |
<td><?php _e("Don't check links where the URL contains any of these words (one per line) :", 'broken-link-checker'); ?><br/>
|
|
@@ -981,15 +1016,15 @@ class wsBrokenLinkChecker {
|
|
| 981 |
|
| 982 |
</td>
|
| 983 |
</tr>
|
| 984 |
-
|
| 985 |
</table>
|
| 986 |
</div>
|
| 987 |
-
|
| 988 |
<div id="section-how" class="blc-section">
|
| 989 |
<h3 class="hide-if-js"><?php echo $section_names['how']; ?></h3>
|
| 990 |
-
|
| 991 |
<table class="form-table">
|
| 992 |
-
|
| 993 |
<tr valign="top">
|
| 994 |
<th scope="row"><?php _e('Check links using', 'broken-link-checker'); ?></th>
|
| 995 |
<td>
|
|
@@ -1000,57 +1035,57 @@ class wsBrokenLinkChecker {
|
|
| 1000 |
}
|
| 1001 |
?>
|
| 1002 |
</td></tr>
|
| 1003 |
-
|
| 1004 |
</table>
|
| 1005 |
</div>
|
| 1006 |
-
|
| 1007 |
<div id="section-advanced" class="blc-section">
|
| 1008 |
<h3 class="hide-if-js"><?php echo $section_names['advanced']; ?></h3>
|
| 1009 |
-
|
| 1010 |
<table class="form-table">
|
| 1011 |
-
|
| 1012 |
<tr valign="top">
|
| 1013 |
<th scope="row"><?php _e('Timeout', 'broken-link-checker'); ?></th>
|
| 1014 |
<td>
|
| 1015 |
|
| 1016 |
<?php
|
| 1017 |
-
|
| 1018 |
printf(
|
| 1019 |
__('%s seconds', 'broken-link-checker'),
|
| 1020 |
sprintf(
|
| 1021 |
-
'<input type="text" name="timeout" id="blc_timeout" value="%d" size="5" maxlength="3" />',
|
| 1022 |
$this->conf->options['timeout']
|
| 1023 |
)
|
| 1024 |
);
|
| 1025 |
-
|
| 1026 |
?>
|
| 1027 |
<br/><span class="description">
|
| 1028 |
-
<?php _e('Links that take longer than this to load will be marked as broken.','broken-link-checker'); ?>
|
| 1029 |
</span>
|
| 1030 |
|
| 1031 |
</td>
|
| 1032 |
</tr>
|
| 1033 |
-
|
| 1034 |
<tr valign="top">
|
| 1035 |
<th scope="row"><?php _e('Link monitor', 'broken-link-checker'); ?></th>
|
| 1036 |
<td>
|
| 1037 |
-
|
| 1038 |
<p>
|
| 1039 |
<label for='run_in_dashboard'>
|
| 1040 |
-
|
| 1041 |
<input type="checkbox" name="run_in_dashboard" id="run_in_dashboard"
|
| 1042 |
<?php if ($this->conf->options['run_in_dashboard']) echo ' checked="checked"'; ?>/>
|
| 1043 |
<?php _e('Run continuously while the Dashboard is open', 'broken-link-checker'); ?>
|
| 1044 |
</label>
|
| 1045 |
</p>
|
| 1046 |
-
|
| 1047 |
<p>
|
| 1048 |
<label for='run_via_cron'>
|
| 1049 |
<input type="checkbox" name="run_via_cron" id="run_via_cron"
|
| 1050 |
<?php if ($this->conf->options['run_via_cron']) echo ' checked="checked"'; ?>/>
|
| 1051 |
<?php _e('Run hourly in the background', 'broken-link-checker'); ?>
|
| 1052 |
</label>
|
| 1053 |
-
</p>
|
| 1054 |
|
| 1055 |
</td>
|
| 1056 |
</tr>
|
|
@@ -1095,38 +1130,38 @@ class wsBrokenLinkChecker {
|
|
| 1095 |
?>
|
| 1096 |
</td>
|
| 1097 |
</tr>
|
| 1098 |
-
|
| 1099 |
<tr valign="top">
|
| 1100 |
<th scope="row"><?php _e('Max. execution time', 'broken-link-checker'); ?></th>
|
| 1101 |
<td>
|
| 1102 |
|
| 1103 |
<?php
|
| 1104 |
-
|
| 1105 |
printf(
|
| 1106 |
__('%s seconds', 'broken-link-checker'),
|
| 1107 |
sprintf(
|
| 1108 |
-
'<input type="text" name="max_execution_time" id="max_execution_time" value="%d" size="5" maxlength="5" />',
|
| 1109 |
$this->conf->options['max_execution_time']
|
| 1110 |
)
|
| 1111 |
);
|
| 1112 |
-
|
| 1113 |
-
?>
|
| 1114 |
<br/><span class="description">
|
| 1115 |
<?php
|
| 1116 |
-
|
| 1117 |
_e('The plugin works by periodically launching a background job that parses your posts for links, checks the discovered URLs, and performs other time-consuming tasks. Here you can set for how long, at most, the link monitor may run each time before stopping.', 'broken-link-checker');
|
| 1118 |
-
|
| 1119 |
-
?>
|
| 1120 |
</span>
|
| 1121 |
|
| 1122 |
</td>
|
| 1123 |
</tr>
|
| 1124 |
-
|
| 1125 |
<tr valign="top">
|
| 1126 |
<th scope="row"><?php _e('Server load limit', 'broken-link-checker'); ?></th>
|
| 1127 |
<td>
|
| 1128 |
<?php
|
| 1129 |
-
|
| 1130 |
$load = blcUtility::get_server_load();
|
| 1131 |
$available = !empty($load);
|
| 1132 |
|
|
@@ -1136,7 +1171,7 @@ class wsBrokenLinkChecker {
|
|
| 1136 |
'<input type="text" name="server_load_limit" id="server_load_limit" value="%s" size="5" maxlength="5"/> ',
|
| 1137 |
$value
|
| 1138 |
);
|
| 1139 |
-
|
| 1140 |
printf(
|
| 1141 |
__('Current load : %s', 'broken-link-checker'),
|
| 1142 |
'<span id="wsblc_current_load">...</span>'
|
|
@@ -1144,20 +1179,20 @@ class wsBrokenLinkChecker {
|
|
| 1144 |
echo '<br/><span class="description">';
|
| 1145 |
printf(
|
| 1146 |
__(
|
| 1147 |
-
'Link checking will be suspended if the average <a href="%s">server load</a> rises above this number. Leave this field blank to disable load limiting.',
|
| 1148 |
'broken-link-checker'
|
| 1149 |
),
|
| 1150 |
'http://en.wikipedia.org/wiki/Load_(computing)'
|
| 1151 |
);
|
| 1152 |
echo '</span>';
|
| 1153 |
-
|
| 1154 |
} else {
|
| 1155 |
echo '<input type="text" disabled="disabled" value="', esc_attr(__('Not available', 'broken-link-checker')), '" size="13"/><br>';
|
| 1156 |
echo '<span class="description">';
|
| 1157 |
_e('Load limiting only works on Linux-like systems where <code>/proc/loadavg</code> is present and accessible.', 'broken-link-checker');
|
| 1158 |
echo '</span>';
|
| 1159 |
}
|
| 1160 |
-
?>
|
| 1161 |
</td>
|
| 1162 |
</tr>
|
| 1163 |
|
|
@@ -1226,87 +1261,87 @@ class wsBrokenLinkChecker {
|
|
| 1226 |
</td>
|
| 1227 |
</tr>
|
| 1228 |
|
| 1229 |
-
|
| 1230 |
<tr valign="top">
|
| 1231 |
<th scope="row"><?php _e('Forced recheck', 'broken-link-checker'); ?></th>
|
| 1232 |
<td>
|
| 1233 |
-
<input class="button" type="button" name="start-recheck" id="start-recheck"
|
| 1234 |
value="<?php _e('Re-check all pages', 'broken-link-checker'); ?>" />
|
| 1235 |
<input type="hidden" name="recheck" value="" id="recheck" />
|
| 1236 |
<br />
|
| 1237 |
<span class="description"><?php
|
| 1238 |
_e('The "Nuclear Option". Click this button to make the plugin empty its link database and recheck the entire site from scratch.', 'broken-link-checker');
|
| 1239 |
-
|
| 1240 |
?></span>
|
| 1241 |
</td>
|
| 1242 |
</tr>
|
| 1243 |
-
|
| 1244 |
</table>
|
| 1245 |
</div>
|
| 1246 |
-
|
| 1247 |
</div>
|
| 1248 |
-
|
| 1249 |
<p class="submit"><input type="submit" name="submit" class='button-primary' value="<?php _e('Save Changes') ?>" /></p>
|
| 1250 |
</form>
|
| 1251 |
-
|
| 1252 |
</div> <!-- First postbox-container -->
|
| 1253 |
-
|
| 1254 |
-
|
| 1255 |
</div>
|
| 1256 |
-
|
| 1257 |
-
|
| 1258 |
-
|
| 1259 |
<?php
|
| 1260 |
//The various JS for this page is stored in a separate file for the purposes readability.
|
| 1261 |
include dirname($this->loader) . '/includes/admin/options-page-js.php';
|
| 1262 |
}
|
| 1263 |
-
|
| 1264 |
/**
|
| 1265 |
* Output a list of modules and their settings.
|
| 1266 |
-
*
|
| 1267 |
-
* Each list entry will contain a checkbox that is checked if the module is
|
| 1268 |
-
* currently active.
|
| 1269 |
-
*
|
| 1270 |
* @param array $modules Array of modules to display
|
| 1271 |
* @param array $current_settings
|
| 1272 |
* @return void
|
| 1273 |
*/
|
| 1274 |
function print_module_list($modules, $current_settings){
|
| 1275 |
$moduleManager = blcModuleManager::getInstance();
|
| 1276 |
-
|
| 1277 |
foreach($modules as $module_id => $module_data){
|
| 1278 |
$module_id = $module_data['ModuleID'];
|
| 1279 |
-
|
| 1280 |
$style = $module_data['ModuleHidden']?' style="display:none;"':'';
|
| 1281 |
-
|
| 1282 |
printf(
|
| 1283 |
'<div class="module-container" id="module-container-%s"%s>',
|
| 1284 |
$module_id,
|
| 1285 |
$style
|
| 1286 |
);
|
| 1287 |
$this->print_module_checkbox($module_id, $module_data, $moduleManager->is_active($module_id));
|
| 1288 |
-
|
| 1289 |
$extra_settings = apply_filters(
|
| 1290 |
'blc-module-settings-'.$module_id,
|
| 1291 |
'',
|
| 1292 |
$current_settings
|
| 1293 |
);
|
| 1294 |
-
|
| 1295 |
if ( !empty($extra_settings) ){
|
| 1296 |
-
|
| 1297 |
printf(
|
| 1298 |
' | <a class="blc-toggle-link toggle-module-settings" id="toggle-module-settings-%s" href="#">%s</a>',
|
| 1299 |
esc_attr($module_id),
|
| 1300 |
__('Configure', 'broken-link-checker')
|
| 1301 |
);
|
| 1302 |
-
|
| 1303 |
//The plugin remembers the last open/closed state of module configuration boxes
|
| 1304 |
-
$box_id = 'module-extra-settings-' . $module_id;
|
| 1305 |
$show = blcUtility::get_cookie(
|
| 1306 |
$box_id,
|
| 1307 |
$moduleManager->is_active($module_id)
|
| 1308 |
);
|
| 1309 |
-
|
| 1310 |
printf(
|
| 1311 |
'<div class="module-extra-settings%s" id="%s">%s</div>',
|
| 1312 |
$show?'':' hidden',
|
|
@@ -1314,19 +1349,19 @@ class wsBrokenLinkChecker {
|
|
| 1314 |
$extra_settings
|
| 1315 |
);
|
| 1316 |
}
|
| 1317 |
-
|
| 1318 |
echo '</div>';
|
| 1319 |
}
|
| 1320 |
}
|
| 1321 |
-
|
| 1322 |
/**
|
| 1323 |
* Output a checkbox for a module.
|
| 1324 |
-
*
|
| 1325 |
* Generates a simple checkbox that can be used to mark a module as active/inactive.
|
| 1326 |
* If the specified module can't be deactivated (ModuleAlwaysActive = true), the checkbox
|
| 1327 |
* will be displayed in a disabled state and a hidden field will be created to make
|
| 1328 |
* form submissions work correctly.
|
| 1329 |
-
*
|
| 1330 |
* @param string $module_id Module ID.
|
| 1331 |
* @param array $module_data Associative array of module data.
|
| 1332 |
* @param bool $active If true, the newly created checkbox will start out checked.
|
|
@@ -1337,17 +1372,17 @@ class wsBrokenLinkChecker {
|
|
| 1337 |
$name_prefix = 'module';
|
| 1338 |
$label_class = '';
|
| 1339 |
$active = $active || $module_data['ModuleAlwaysActive'];
|
| 1340 |
-
|
| 1341 |
if ( $module_data['ModuleAlwaysActive'] ){
|
| 1342 |
$disabled = true;
|
| 1343 |
$name_prefix = 'module-always-active';
|
| 1344 |
}
|
| 1345 |
-
|
| 1346 |
$checked = $active ? ' checked="checked"':'';
|
| 1347 |
if ( $disabled ){
|
| 1348 |
$checked .= ' disabled="disabled"';
|
| 1349 |
}
|
| 1350 |
-
|
| 1351 |
printf(
|
| 1352 |
'<label class="%s">
|
| 1353 |
<input type="checkbox" name="%s[%s]" id="module-checkbox-%s"%s /> %s
|
|
@@ -1359,7 +1394,7 @@ class wsBrokenLinkChecker {
|
|
| 1359 |
$checked,
|
| 1360 |
$module_data['Name']
|
| 1361 |
);
|
| 1362 |
-
|
| 1363 |
if ( $module_data['ModuleAlwaysActive'] ){
|
| 1364 |
printf(
|
| 1365 |
'<input type="hidden" name="module[%s]" value="on">',
|
|
@@ -1367,12 +1402,12 @@ class wsBrokenLinkChecker {
|
|
| 1367 |
);
|
| 1368 |
}
|
| 1369 |
}
|
| 1370 |
-
|
| 1371 |
/**
|
| 1372 |
* Add extra settings to the "Custom fields" entry on the plugin's config. page.
|
| 1373 |
-
*
|
| 1374 |
-
* Callback for the 'blc-module-settings-custom_field' filter.
|
| 1375 |
-
*
|
| 1376 |
* @param string $html Current extra HTML
|
| 1377 |
* @param array $current_settings The current plugin configuration.
|
| 1378 |
* @return string New extra HTML.
|
|
@@ -1385,51 +1420,61 @@ class wsBrokenLinkChecker {
|
|
| 1385 |
) .
|
| 1386 |
'</span>';
|
| 1387 |
$html .= '<br><textarea name="blc_custom_fields" id="blc_custom_fields" cols="45" rows="4">';
|
| 1388 |
-
if( isset($current_settings['custom_fields']) )
|
| 1389 |
$html .= esc_textarea(implode("\n", $current_settings['custom_fields']));
|
|
|
|
| 1390 |
$html .= '</textarea>';
|
| 1391 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1392 |
return $html;
|
| 1393 |
}
|
| 1394 |
-
|
| 1395 |
/**
|
| 1396 |
* Enqueue CSS file for the plugin's Settings page.
|
| 1397 |
-
*
|
| 1398 |
* @return void
|
| 1399 |
*/
|
| 1400 |
function options_page_css(){
|
| 1401 |
wp_enqueue_style('blc-options-page', plugins_url('css/options-page.css', BLC_PLUGIN_FILE), array(), '20141113');
|
| 1402 |
wp_enqueue_style('dashboard');
|
| 1403 |
}
|
| 1404 |
-
|
| 1405 |
|
| 1406 |
/**
|
| 1407 |
* Display the "Broken Links" page, listing links detected by the plugin and their status.
|
| 1408 |
-
*
|
| 1409 |
* @return void
|
| 1410 |
*/
|
| 1411 |
function links_page(){
|
| 1412 |
global $wpdb; /* @var wpdb $wpdb */
|
| 1413 |
-
|
| 1414 |
$blc_link_query = blcLinkQuery::getInstance();
|
| 1415 |
|
| 1416 |
//Cull invalid and missing modules so that we don't get dummy links/instances showing up.
|
| 1417 |
$moduleManager = blcModuleManager::getInstance();
|
| 1418 |
$moduleManager->validate_active_modules();
|
| 1419 |
-
|
| 1420 |
if ( defined('BLC_DEBUG') && constant('BLC_DEBUG') ){
|
| 1421 |
-
//Make module headers translatable. They need to be formatted corrrectly and
|
| 1422 |
//placed in a .php file to be visible to the script(s) that generate .pot files.
|
| 1423 |
$code = $moduleManager->_build_header_translation_code();
|
| 1424 |
file_put_contents( dirname($this->loader) . '/includes/extra-strings.php', $code );
|
| 1425 |
}
|
| 1426 |
-
|
| 1427 |
$action = !empty($_POST['action'])?$_POST['action']:'';
|
| 1428 |
if ( intval($action) == -1 ){
|
| 1429 |
//Try the second bulk actions box
|
| 1430 |
$action = !empty($_POST['action2'])?$_POST['action2']:'';
|
| 1431 |
}
|
| 1432 |
-
|
| 1433 |
//Get the list of link IDs selected via checkboxes
|
| 1434 |
$selected_links = array();
|
| 1435 |
if ( isset($_POST['selected_links']) && is_array($_POST['selected_links']) ){
|
|
@@ -1438,17 +1483,17 @@ class wsBrokenLinkChecker {
|
|
| 1438 |
//Remove all zeroes
|
| 1439 |
$selected_links = array_filter($selected_links);
|
| 1440 |
}
|
| 1441 |
-
|
| 1442 |
$message = '';
|
| 1443 |
$msg_class = 'updated';
|
| 1444 |
-
|
| 1445 |
//Run the selected bulk action, if any
|
| 1446 |
$force_delete = false;
|
| 1447 |
switch ( $action ){
|
| 1448 |
case 'create-custom-filter':
|
| 1449 |
list($message, $msg_class) = $this->do_create_custom_filter();
|
| 1450 |
break;
|
| 1451 |
-
|
| 1452 |
case 'delete-custom-filter':
|
| 1453 |
list($message, $msg_class) = $this->do_delete_custom_filter();
|
| 1454 |
break;
|
|
@@ -1459,19 +1504,19 @@ class wsBrokenLinkChecker {
|
|
| 1459 |
case 'bulk-trash-sources':
|
| 1460 |
list($message, $msg_class) = $this->do_bulk_delete_sources($selected_links, $force_delete);
|
| 1461 |
break;
|
| 1462 |
-
|
| 1463 |
case 'bulk-unlink':
|
| 1464 |
list($message, $msg_class) = $this->do_bulk_unlink($selected_links);
|
| 1465 |
break;
|
| 1466 |
-
|
| 1467 |
case 'bulk-deredirect':
|
| 1468 |
list($message, $msg_class) = $this->do_bulk_deredirect($selected_links);
|
| 1469 |
break;
|
| 1470 |
-
|
| 1471 |
case 'bulk-recheck':
|
| 1472 |
list($message, $msg_class) = $this->do_bulk_recheck($selected_links);
|
| 1473 |
break;
|
| 1474 |
-
|
| 1475 |
case 'bulk-not-broken':
|
| 1476 |
list($message, $msg_class) = $this->do_bulk_discard($selected_links);
|
| 1477 |
break;
|
|
@@ -1484,26 +1529,26 @@ class wsBrokenLinkChecker {
|
|
| 1484 |
list($message, $msg_class) = $this->do_bulk_edit($selected_links);
|
| 1485 |
break;
|
| 1486 |
}
|
| 1487 |
-
|
| 1488 |
-
|
| 1489 |
if ( !empty($message) ){
|
| 1490 |
echo '<div id="message" class="'.$msg_class.' fade"><p>'.$message.'</p></div>';
|
| 1491 |
}
|
| 1492 |
-
|
| 1493 |
$start_time = microtime_float();
|
| 1494 |
-
|
| 1495 |
//Load custom filters, if any
|
| 1496 |
$blc_link_query->load_custom_filters();
|
| 1497 |
-
|
| 1498 |
//Calculate the number of links matching each filter
|
| 1499 |
$blc_link_query->count_filter_results();
|
| 1500 |
-
|
| 1501 |
//Run the selected filter (defaults to displaying broken links)
|
| 1502 |
$selected_filter_id = isset($_GET['filter_id'])?$_GET['filter_id']:'broken';
|
| 1503 |
$current_filter = $blc_link_query->exec_filter(
|
| 1504 |
$selected_filter_id,
|
| 1505 |
isset($_GET['paged']) ? intval($_GET['paged']) : 1,
|
| 1506 |
-
$this->conf->options['table_links_per_page'],
|
| 1507 |
'broken',
|
| 1508 |
isset($_GET['orderby']) ? $_GET['orderby'] : '',
|
| 1509 |
isset($_GET['order']) ? $_GET['order'] : ''
|
|
@@ -1512,29 +1557,29 @@ class wsBrokenLinkChecker {
|
|
| 1512 |
//exec_filter() returns an array with filter data, including the actual filter ID that was used.
|
| 1513 |
$filter_id = $current_filter['filter_id'];
|
| 1514 |
|
| 1515 |
-
//Error?
|
| 1516 |
if ( empty($current_filter['links']) && !empty($wpdb->last_error) ){
|
| 1517 |
printf( __('Database error : %s', 'broken-link-checker'), $wpdb->last_error);
|
| 1518 |
}
|
| 1519 |
?>
|
| 1520 |
-
|
| 1521 |
<script type='text/javascript'>
|
| 1522 |
var blc_current_filter = '<?php echo $filter_id; ?>';
|
| 1523 |
var blc_is_broken_filter = <?php echo $current_filter['is_broken_filter'] ? 'true' : 'false'; ?>;
|
| 1524 |
var blc_current_base_filter = '<?php echo esc_js($current_filter['base_filter']); ?>';
|
| 1525 |
var blc_suggestions_enabled = <?php echo $this->conf->options['suggestions_enabled'] ? 'true' : 'false'; ?>;
|
| 1526 |
</script>
|
| 1527 |
-
|
| 1528 |
<div class="wrap">
|
| 1529 |
<?php
|
| 1530 |
$blc_link_query->print_filter_heading($current_filter);
|
| 1531 |
$blc_link_query->print_filter_menu($filter_id);
|
| 1532 |
-
|
| 1533 |
//Display the "Search" form and associated buttons.
|
| 1534 |
//The form requires the $filter_id and $current_filter variables to be set.
|
| 1535 |
include dirname($this->loader) . '/includes/admin/search-form.php';
|
| 1536 |
-
|
| 1537 |
-
//If the user has decided to switch the table to a different mode (compact/full),
|
| 1538 |
//save the new setting.
|
| 1539 |
if ( isset($_GET['compact']) ){
|
| 1540 |
$this->conf->options['table_compact'] = (bool)$_GET['compact'];
|
|
@@ -1543,32 +1588,32 @@ class wsBrokenLinkChecker {
|
|
| 1543 |
|
| 1544 |
//Display the links, if any
|
| 1545 |
if( $current_filter['links'] && ( count($current_filter['links']) > 0 ) ) {
|
| 1546 |
-
|
| 1547 |
include dirname($this->loader) . '/includes/admin/table-printer.php';
|
| 1548 |
$table = new blcTablePrinter($this);
|
| 1549 |
$table->print_table(
|
| 1550 |
$current_filter,
|
| 1551 |
-
$this->conf->options['table_layout'],
|
| 1552 |
$this->conf->options['table_visible_columns'],
|
| 1553 |
$this->conf->options['table_compact']
|
| 1554 |
);
|
| 1555 |
|
| 1556 |
};
|
| 1557 |
-
printf('<!-- Total elapsed : %.4f seconds -->', microtime_float() - $start_time);
|
| 1558 |
-
|
| 1559 |
//Load assorted JS event handlers and other shinies
|
| 1560 |
include dirname($this->loader) . '/includes/admin/links-page-js.php';
|
| 1561 |
-
|
| 1562 |
?></div><?php
|
| 1563 |
}
|
| 1564 |
-
|
| 1565 |
/**
|
| 1566 |
* Create a custom link filter using params passed in $_POST.
|
| 1567 |
*
|
| 1568 |
* @uses $_POST
|
| 1569 |
-
* @uses $_GET to replace the current filter ID (if any) with that of the newly created filter.
|
| 1570 |
*
|
| 1571 |
-
* @return array Message and the CSS class to apply to the message.
|
| 1572 |
*/
|
| 1573 |
function do_create_custom_filter(){
|
| 1574 |
global $wpdb;
|
|
@@ -1590,34 +1635,34 @@ class wsBrokenLinkChecker {
|
|
| 1590 |
$name = strip_tags(strval($_POST['name']));
|
| 1591 |
$blc_link_query = blcLinkQuery::getInstance();
|
| 1592 |
$filter_id = $blc_link_query->create_custom_filter($name, $_POST['params']);
|
| 1593 |
-
|
| 1594 |
if ( $filter_id ){
|
| 1595 |
//Saved
|
| 1596 |
$message = sprintf( __('Filter "%s" created', 'broken-link-checker'), $name);
|
| 1597 |
//A little hack to make the filter active immediately
|
| 1598 |
-
$_GET['filter_id'] = $filter_id;
|
| 1599 |
} else {
|
| 1600 |
//Error
|
| 1601 |
$message = sprintf( __("Database error : %s", 'broken-link-checker'), $wpdb->last_error);
|
| 1602 |
$msg_class = 'error';
|
| 1603 |
}
|
| 1604 |
}
|
| 1605 |
-
|
| 1606 |
return array($message, $msg_class);
|
| 1607 |
}
|
| 1608 |
-
|
| 1609 |
/**
|
| 1610 |
* Delete a custom link filter.
|
| 1611 |
*
|
| 1612 |
* @uses $_POST
|
| 1613 |
*
|
| 1614 |
-
* @return array Message and a CSS class to apply to the message.
|
| 1615 |
*/
|
| 1616 |
function do_delete_custom_filter(){
|
| 1617 |
//Delete an existing custom filter!
|
| 1618 |
check_admin_referer( 'delete-custom-filter' );
|
| 1619 |
$msg_class = 'updated';
|
| 1620 |
-
|
| 1621 |
//Filter ID must be set
|
| 1622 |
if ( empty($_POST['filter_id']) ){
|
| 1623 |
$message = __("Filter ID not specified.", 'broken-link-checker');
|
|
@@ -1634,10 +1679,10 @@ class wsBrokenLinkChecker {
|
|
| 1634 |
$msg_class = 'error';
|
| 1635 |
}
|
| 1636 |
}
|
| 1637 |
-
|
| 1638 |
return array($message, $msg_class);
|
| 1639 |
}
|
| 1640 |
-
|
| 1641 |
/**
|
| 1642 |
* Modify multiple links to point to their target URLs.
|
| 1643 |
*
|
|
@@ -1646,23 +1691,23 @@ class wsBrokenLinkChecker {
|
|
| 1646 |
*/
|
| 1647 |
function do_bulk_deredirect($selected_links){
|
| 1648 |
//For all selected links, replace the URL with the final URL that it redirects to.
|
| 1649 |
-
|
| 1650 |
$message = '';
|
| 1651 |
$msg_class = 'updated';
|
| 1652 |
-
|
| 1653 |
check_admin_referer( 'bulk-action' );
|
| 1654 |
-
|
| 1655 |
-
if ( count($selected_links) > 0 ) {
|
| 1656 |
//Fetch all the selected links
|
| 1657 |
$links = blc_get_links(array(
|
| 1658 |
'link_ids' => $selected_links,
|
| 1659 |
'purpose' => BLC_FOR_EDITING,
|
| 1660 |
));
|
| 1661 |
-
|
| 1662 |
if ( count($links) > 0 ) {
|
| 1663 |
$processed_links = 0;
|
| 1664 |
$failed_links = 0;
|
| 1665 |
-
|
| 1666 |
//Deredirect all selected links
|
| 1667 |
foreach($links as $link){
|
| 1668 |
$rez = $link->deredirect();
|
|
@@ -1671,22 +1716,22 @@ class wsBrokenLinkChecker {
|
|
| 1671 |
} else {
|
| 1672 |
$failed_links++;
|
| 1673 |
}
|
| 1674 |
-
}
|
| 1675 |
-
|
| 1676 |
$message = sprintf(
|
| 1677 |
_n(
|
| 1678 |
'Replaced %d redirect with a direct link',
|
| 1679 |
'Replaced %d redirects with direct links',
|
| 1680 |
-
$processed_links,
|
| 1681 |
'broken-link-checker'
|
| 1682 |
),
|
| 1683 |
$processed_links
|
| 1684 |
-
);
|
| 1685 |
-
|
| 1686 |
if ( $failed_links > 0 ) {
|
| 1687 |
$message .= '<br>' . sprintf(
|
| 1688 |
_n(
|
| 1689 |
-
'Failed to fix %d redirect',
|
| 1690 |
'Failed to fix %d redirects',
|
| 1691 |
$failed_links,
|
| 1692 |
'broken-link-checker'
|
|
@@ -1699,10 +1744,10 @@ class wsBrokenLinkChecker {
|
|
| 1699 |
$message = __('None of the selected links are redirects!', 'broken-link-checker');
|
| 1700 |
}
|
| 1701 |
}
|
| 1702 |
-
|
| 1703 |
return array($message, $msg_class);
|
| 1704 |
}
|
| 1705 |
-
|
| 1706 |
/**
|
| 1707 |
* Edit multiple links in one go.
|
| 1708 |
*
|
|
@@ -1712,19 +1757,19 @@ class wsBrokenLinkChecker {
|
|
| 1712 |
function do_bulk_edit($selected_links){
|
| 1713 |
$message = '';
|
| 1714 |
$msg_class = 'updated';
|
| 1715 |
-
|
| 1716 |
check_admin_referer( 'bulk-action' );
|
| 1717 |
-
|
| 1718 |
$post = $_POST;
|
| 1719 |
if ( function_exists('wp_magic_quotes') ){
|
| 1720 |
$post = stripslashes_deep($post); //Ceterum censeo, WP shouldn't mangle superglobals.
|
| 1721 |
}
|
| 1722 |
-
|
| 1723 |
$search = isset($post['search']) ? $post['search'] : '';
|
| 1724 |
-
$replace = isset($post['replace']) ? $post['replace'] : '';
|
| 1725 |
$use_regex = !empty($post['regex']);
|
| 1726 |
$case_sensitive = !empty($post['case_sensitive']);
|
| 1727 |
-
|
| 1728 |
$delimiter = '`'; //Pick a char that's uncommon in URLs so that escaping won't usually be a problem
|
| 1729 |
if ( $use_regex ){
|
| 1730 |
$search = $delimiter . $this->escape_regex_delimiter($search, $delimiter) . $delimiter;
|
|
@@ -1737,21 +1782,21 @@ class wsBrokenLinkChecker {
|
|
| 1737 |
$search = $delimiter . preg_quote($search, $delimiter) . $delimiter . 'i';
|
| 1738 |
$use_regex = true;
|
| 1739 |
}
|
| 1740 |
-
|
| 1741 |
-
if ( count($selected_links) > 0 ) {
|
| 1742 |
set_time_limit(300); //In case the user decides to edit hundreds of links at once
|
| 1743 |
-
|
| 1744 |
//Fetch all the selected links
|
| 1745 |
$links = blc_get_links(array(
|
| 1746 |
'link_ids' => $selected_links,
|
| 1747 |
'purpose' => BLC_FOR_EDITING,
|
| 1748 |
));
|
| 1749 |
-
|
| 1750 |
if ( count($links) > 0 ) {
|
| 1751 |
$processed_links = 0;
|
| 1752 |
$failed_links = 0;
|
| 1753 |
$skipped_links = 0;
|
| 1754 |
-
|
| 1755 |
//Edit the links
|
| 1756 |
foreach($links as $link){
|
| 1757 |
if ( $use_regex ){
|
|
@@ -1759,34 +1804,34 @@ class wsBrokenLinkChecker {
|
|
| 1759 |
} else {
|
| 1760 |
$new_url = str_replace($search, $replace, $link->url);
|
| 1761 |
}
|
| 1762 |
-
|
| 1763 |
if ( $new_url == $link->url ){
|
| 1764 |
$skipped_links++;
|
| 1765 |
continue;
|
| 1766 |
}
|
| 1767 |
-
|
| 1768 |
$rez = $link->edit($new_url);
|
| 1769 |
if ( !is_wp_error($rez) && empty($rez['errors'] )){
|
| 1770 |
$processed_links++;
|
| 1771 |
} else {
|
| 1772 |
$failed_links++;
|
| 1773 |
}
|
| 1774 |
-
}
|
| 1775 |
-
|
| 1776 |
$message .= sprintf(
|
| 1777 |
_n(
|
| 1778 |
'%d link updated.',
|
| 1779 |
'%d links updated.',
|
| 1780 |
-
$processed_links,
|
| 1781 |
'broken-link-checker'
|
| 1782 |
),
|
| 1783 |
$processed_links
|
| 1784 |
);
|
| 1785 |
-
|
| 1786 |
if ( $failed_links > 0 ) {
|
| 1787 |
$message .= '<br>' . sprintf(
|
| 1788 |
_n(
|
| 1789 |
-
'Failed to update %d link.',
|
| 1790 |
'Failed to update %d links.',
|
| 1791 |
$failed_links,
|
| 1792 |
'broken-link-checker'
|
|
@@ -1797,7 +1842,7 @@ class wsBrokenLinkChecker {
|
|
| 1797 |
}
|
| 1798 |
}
|
| 1799 |
}
|
| 1800 |
-
|
| 1801 |
return array($message, $msg_class);
|
| 1802 |
}
|
| 1803 |
|
|
@@ -1835,7 +1880,7 @@ class wsBrokenLinkChecker {
|
|
| 1835 |
|
| 1836 |
return $output;
|
| 1837 |
}
|
| 1838 |
-
|
| 1839 |
/**
|
| 1840 |
* Unlink multiple links.
|
| 1841 |
*
|
|
@@ -1846,21 +1891,21 @@ class wsBrokenLinkChecker {
|
|
| 1846 |
//Unlink all selected links.
|
| 1847 |
$message = '';
|
| 1848 |
$msg_class = 'updated';
|
| 1849 |
-
|
| 1850 |
check_admin_referer( 'bulk-action' );
|
| 1851 |
-
|
| 1852 |
-
if ( count($selected_links) > 0 ) {
|
| 1853 |
-
|
| 1854 |
//Fetch all the selected links
|
| 1855 |
$links = blc_get_links(array(
|
| 1856 |
'link_ids' => $selected_links,
|
| 1857 |
'purpose' => BLC_FOR_EDITING,
|
| 1858 |
));
|
| 1859 |
-
|
| 1860 |
if ( count($links) > 0 ) {
|
| 1861 |
$processed_links = 0;
|
| 1862 |
$failed_links = 0;
|
| 1863 |
-
|
| 1864 |
//Unlink (delete) each one
|
| 1865 |
foreach($links as $link){
|
| 1866 |
$rez = $link->unlink();
|
|
@@ -1869,24 +1914,24 @@ class wsBrokenLinkChecker {
|
|
| 1869 |
} else {
|
| 1870 |
$processed_links++;
|
| 1871 |
}
|
| 1872 |
-
}
|
| 1873 |
-
|
| 1874 |
-
//This message is slightly misleading - it doesn't account for the fact that
|
| 1875 |
//a link can be present in more than one post.
|
| 1876 |
$message = sprintf(
|
| 1877 |
_n(
|
| 1878 |
'%d link removed',
|
| 1879 |
'%d links removed',
|
| 1880 |
-
$processed_links,
|
| 1881 |
'broken-link-checker'
|
| 1882 |
),
|
| 1883 |
$processed_links
|
| 1884 |
-
);
|
| 1885 |
-
|
| 1886 |
if ( $failed_links > 0 ) {
|
| 1887 |
$message .= '<br>' . sprintf(
|
| 1888 |
_n(
|
| 1889 |
-
'Failed to remove %d link',
|
| 1890 |
'Failed to remove %d links',
|
| 1891 |
$failed_links,
|
| 1892 |
'broken-link-checker'
|
|
@@ -1897,14 +1942,14 @@ class wsBrokenLinkChecker {
|
|
| 1897 |
}
|
| 1898 |
}
|
| 1899 |
}
|
| 1900 |
-
|
| 1901 |
return array($message, $msg_class);
|
| 1902 |
}
|
| 1903 |
-
|
| 1904 |
/**
|
| 1905 |
* Delete or trash posts, bookmarks and other items that contain any of the specified links.
|
| 1906 |
-
*
|
| 1907 |
-
* Will prefer moving stuff to trash to permanent deletion. If it encounters an item that
|
| 1908 |
* can't be moved to the trash, it will skip that item by default.
|
| 1909 |
*
|
| 1910 |
* @param array $selected_links An array of link IDs
|
|
@@ -1914,25 +1959,25 @@ class wsBrokenLinkChecker {
|
|
| 1914 |
function do_bulk_delete_sources($selected_links, $force_delete = false){
|
| 1915 |
$message = '';
|
| 1916 |
$msg_class = 'updated';
|
| 1917 |
-
|
| 1918 |
//Delete posts, blogroll entries and any other link containers that contain any of the selected links.
|
| 1919 |
//
|
| 1920 |
//Note that once all containers containing a particular link have been deleted,
|
| 1921 |
-
//there is no need to explicitly delete the link record itself. The hooks attached to
|
| 1922 |
-
//the actions that execute when something is deleted (e.g. "post_deleted") will
|
| 1923 |
-
//take care of that.
|
| 1924 |
-
|
| 1925 |
check_admin_referer( 'bulk-action' );
|
| 1926 |
-
|
| 1927 |
-
if ( count($selected_links) > 0 ) {
|
| 1928 |
$messages = array();
|
| 1929 |
-
|
| 1930 |
//Fetch all the selected links
|
| 1931 |
$links = blc_get_links(array(
|
| 1932 |
'link_ids' => $selected_links,
|
| 1933 |
'load_instances' => true,
|
| 1934 |
));
|
| 1935 |
-
|
| 1936 |
//Make a list of all containers associated with these links, with each container
|
| 1937 |
//listed only once.
|
| 1938 |
$containers = array();
|
|
@@ -1943,7 +1988,7 @@ class wsBrokenLinkChecker {
|
|
| 1943 |
$containers[$key] = array($instance->container_type, $instance->container_id);
|
| 1944 |
}
|
| 1945 |
}
|
| 1946 |
-
|
| 1947 |
//Instantiate the containers
|
| 1948 |
$containers = blcContainerHelper::get_containers($containers);
|
| 1949 |
|
|
@@ -1954,18 +1999,18 @@ class wsBrokenLinkChecker {
|
|
| 1954 |
if ( !$container->current_user_can_delete() ){
|
| 1955 |
continue;
|
| 1956 |
}
|
| 1957 |
-
|
| 1958 |
if ( $force_delete ){
|
| 1959 |
$rez = $container->delete_wrapped_object();
|
| 1960 |
} else {
|
| 1961 |
if ( $container->can_be_trashed() ){
|
| 1962 |
$rez = $container->trash_wrapped_object();
|
| 1963 |
} else {
|
| 1964 |
-
$skipped[] = $container;
|
| 1965 |
continue;
|
| 1966 |
}
|
| 1967 |
}
|
| 1968 |
-
|
| 1969 |
if ( is_wp_error($rez) ){ /* @var WP_Error $rez */
|
| 1970 |
//Record error messages for later display
|
| 1971 |
$messages[] = $rez->get_error_message();
|
|
@@ -1980,7 +2025,7 @@ class wsBrokenLinkChecker {
|
|
| 1980 |
}
|
| 1981 |
}
|
| 1982 |
}
|
| 1983 |
-
|
| 1984 |
//Generate delete confirmation messages
|
| 1985 |
foreach($deleted as $container_type => $number){
|
| 1986 |
if ( $force_delete ){
|
|
@@ -1988,9 +2033,9 @@ class wsBrokenLinkChecker {
|
|
| 1988 |
} else {
|
| 1989 |
$messages[] = blcContainerHelper::ui_bulk_trash_message($container_type, $number);
|
| 1990 |
}
|
| 1991 |
-
|
| 1992 |
}
|
| 1993 |
-
|
| 1994 |
//If some items couldn't be trashed, let the user know
|
| 1995 |
if ( count($skipped) > 0 ){
|
| 1996 |
$message = sprintf(
|
|
@@ -2009,10 +2054,10 @@ class wsBrokenLinkChecker {
|
|
| 2009 |
);
|
| 2010 |
}
|
| 2011 |
$message .= '</ul>';
|
| 2012 |
-
|
| 2013 |
$messages[] = $message;
|
| 2014 |
}
|
| 2015 |
-
|
| 2016 |
if ( count($messages) > 0 ){
|
| 2017 |
$message = implode('<p>', $messages);
|
| 2018 |
} else {
|
|
@@ -2020,10 +2065,10 @@ class wsBrokenLinkChecker {
|
|
| 2020 |
$msg_class = 'error';
|
| 2021 |
}
|
| 2022 |
}
|
| 2023 |
-
|
| 2024 |
return array($message, $msg_class);
|
| 2025 |
}
|
| 2026 |
-
|
| 2027 |
/**
|
| 2028 |
* Mark multiple links as unchecked.
|
| 2029 |
*
|
|
@@ -2033,61 +2078,61 @@ class wsBrokenLinkChecker {
|
|
| 2033 |
function do_bulk_recheck($selected_links){
|
| 2034 |
/** @var wpdb $wpdb */
|
| 2035 |
global $wpdb;
|
| 2036 |
-
|
| 2037 |
$message = '';
|
| 2038 |
$msg_class = 'updated';
|
| 2039 |
|
| 2040 |
check_admin_referer('bulk-action');
|
| 2041 |
-
|
| 2042 |
if ( count($selected_links) > 0 ){
|
| 2043 |
-
$q = "UPDATE {$wpdb->prefix}blc_links
|
| 2044 |
-
SET last_check_attempt = '0000-00-00 00:00:00'
|
| 2045 |
WHERE link_id IN (".implode(', ', $selected_links).")";
|
| 2046 |
$changes = $wpdb->query($q);
|
| 2047 |
-
|
| 2048 |
$message = sprintf(
|
| 2049 |
_n(
|
| 2050 |
"%d link scheduled for rechecking",
|
| 2051 |
"%d links scheduled for rechecking",
|
| 2052 |
-
$changes,
|
| 2053 |
'broken-link-checker'
|
| 2054 |
),
|
| 2055 |
$changes
|
| 2056 |
);
|
| 2057 |
}
|
| 2058 |
-
|
| 2059 |
return array($message, $msg_class);
|
| 2060 |
}
|
| 2061 |
-
|
| 2062 |
-
|
| 2063 |
/**
|
| 2064 |
* Mark multiple links as not broken.
|
| 2065 |
-
*
|
| 2066 |
* @param array $selected_links An array of link IDs
|
| 2067 |
* @return array Confirmation nessage and the CSS class to use with that message.
|
| 2068 |
*/
|
| 2069 |
function do_bulk_discard($selected_links){
|
| 2070 |
check_admin_referer( 'bulk-action' );
|
| 2071 |
-
|
| 2072 |
$messages = array();
|
| 2073 |
$msg_class = 'updated';
|
| 2074 |
$processed_links = 0;
|
| 2075 |
-
|
| 2076 |
if ( count($selected_links) > 0 ){
|
| 2077 |
foreach($selected_links as $link_id){
|
| 2078 |
//Load the link
|
| 2079 |
$link = new blcLink( intval($link_id) );
|
| 2080 |
-
|
| 2081 |
//Skip links that don't actually exist
|
| 2082 |
if ( !$link->valid() ){
|
| 2083 |
continue;
|
| 2084 |
}
|
| 2085 |
-
|
| 2086 |
//Skip links that weren't actually detected as broken
|
| 2087 |
if ( !$link->broken && !$link->warning ){
|
| 2088 |
continue;
|
| 2089 |
}
|
| 2090 |
-
|
| 2091 |
//Make it appear "not broken"
|
| 2092 |
$link->broken = false;
|
| 2093 |
$link->warning = false;
|
|
@@ -2108,19 +2153,19 @@ class wsBrokenLinkChecker {
|
|
| 2108 |
}
|
| 2109 |
}
|
| 2110 |
}
|
| 2111 |
-
|
| 2112 |
if ( $processed_links > 0 ){
|
| 2113 |
$messages[] = sprintf(
|
| 2114 |
_n(
|
| 2115 |
'%d link marked as not broken',
|
| 2116 |
'%d links marked as not broken',
|
| 2117 |
-
$processed_links,
|
| 2118 |
'broken-link-checker'
|
| 2119 |
),
|
| 2120 |
$processed_links
|
| 2121 |
);
|
| 2122 |
}
|
| 2123 |
-
|
| 2124 |
return array(implode('<br>', $messages), $msg_class);
|
| 2125 |
}
|
| 2126 |
|
|
@@ -2182,11 +2227,11 @@ class wsBrokenLinkChecker {
|
|
| 2182 |
|
| 2183 |
return array(implode('<br>', $messages), $msg_class);
|
| 2184 |
}
|
| 2185 |
-
|
| 2186 |
-
|
| 2187 |
/**
|
| 2188 |
* Enqueue CSS files for the "Broken Links" page
|
| 2189 |
-
*
|
| 2190 |
* @return void
|
| 2191 |
*/
|
| 2192 |
function links_page_css(){
|
|
@@ -2245,10 +2290,10 @@ class wsBrokenLinkChecker {
|
|
| 2245 |
)
|
| 2246 |
);
|
| 2247 |
}
|
| 2248 |
-
|
| 2249 |
/**
|
| 2250 |
* Generate the HTML for the plugin's Screen Options panel.
|
| 2251 |
-
*
|
| 2252 |
* @return string
|
| 2253 |
*/
|
| 2254 |
function screen_options_html(){
|
|
@@ -2261,16 +2306,16 @@ class wsBrokenLinkChecker {
|
|
| 2261 |
$this->conf->save_options();
|
| 2262 |
}
|
| 2263 |
}
|
| 2264 |
-
|
| 2265 |
//Let the user show/hide individual table columns
|
| 2266 |
$html = '<h5>' . __('Table columns', 'broken-link-checker') . '</h5>';
|
| 2267 |
-
|
| 2268 |
include dirname($this->loader) . '/includes/admin/table-printer.php';
|
| 2269 |
$table = new blcTablePrinter($this);
|
| 2270 |
$available_columns = $table->get_layout_columns($this->conf->options['table_layout']);
|
| 2271 |
-
|
| 2272 |
$html .= '<div id="blc-column-selector" class="metabox-prefs">';
|
| 2273 |
-
|
| 2274 |
foreach( $available_columns as $column_id => $data ){
|
| 2275 |
$html .= sprintf(
|
| 2276 |
'<label><input type="checkbox" name="visible_columns[%s]"%s>%s</label>',
|
|
@@ -2278,11 +2323,11 @@ class wsBrokenLinkChecker {
|
|
| 2278 |
in_array($column_id, $this->conf->options['table_visible_columns']) ? ' checked="checked"' : '',
|
| 2279 |
$data['heading']
|
| 2280 |
);
|
| 2281 |
-
}
|
| 2282 |
-
|
| 2283 |
$html .= '</div>';
|
| 2284 |
-
|
| 2285 |
-
$html .= '<h5>' . __('Show on screen') . '</h5>';
|
| 2286 |
$html .= '<div class="screen-options">';
|
| 2287 |
$html .= sprintf(
|
| 2288 |
'<input type="text" name="per_page" maxlength="3" value="%d" class="screen-per-page" id="blc_links_per_page" />
|
|
@@ -2293,12 +2338,12 @@ class wsBrokenLinkChecker {
|
|
| 2293 |
__('Apply')
|
| 2294 |
);
|
| 2295 |
$html .= '</div>';
|
| 2296 |
-
|
| 2297 |
$html .= '<h5>' . __('Misc', 'broken-link-checker') . '</h5>';
|
| 2298 |
$html .= '<div class="screen-options">';
|
| 2299 |
/*
|
| 2300 |
-
Display a checkbox in "Screen Options" that lets the user highlight links that
|
| 2301 |
-
have been broken for at least X days.
|
| 2302 |
*/
|
| 2303 |
$html .= sprintf(
|
| 2304 |
'<label><input type="checkbox" id="highlight_permanent_failures" name="highlight_permanent_failures"%s> ',
|
|
@@ -2313,56 +2358,56 @@ class wsBrokenLinkChecker {
|
|
| 2313 |
$input_box
|
| 2314 |
);
|
| 2315 |
$html .= '</label>';
|
| 2316 |
-
|
| 2317 |
//Display a checkbox for turning colourful link status messages on/off
|
| 2318 |
$html .= sprintf(
|
| 2319 |
'<br/><label><input type="checkbox" id="table_color_code_status" name="table_color_code_status"%s> %s</label>',
|
| 2320 |
$this->conf->options['table_color_code_status'] ? ' checked="checked"' : '',
|
| 2321 |
__('Color-code status codes', 'broken-link-checker')
|
| 2322 |
);
|
| 2323 |
-
|
| 2324 |
$html .= '</div>';
|
| 2325 |
-
|
| 2326 |
return $html;
|
| 2327 |
}
|
| 2328 |
-
|
| 2329 |
/**
|
| 2330 |
* AJAX callback for saving the "Screen Options" panel settings
|
| 2331 |
-
*
|
| 2332 |
* @param array $form
|
| 2333 |
* @return void
|
| 2334 |
*/
|
| 2335 |
function ajax_save_screen_options($form){
|
| 2336 |
if ( !current_user_can('edit_others_posts') ){
|
| 2337 |
die( json_encode( array(
|
| 2338 |
-
'error' => __("You're not allowed to do that!", 'broken-link-checker')
|
| 2339 |
)));
|
| 2340 |
}
|
| 2341 |
-
|
| 2342 |
$this->conf->options['highlight_permanent_failures'] = !empty($form['highlight_permanent_failures']);
|
| 2343 |
$this->conf->options['table_color_code_status'] = !empty($form['table_color_code_status']);
|
| 2344 |
-
|
| 2345 |
$failure_duration_threshold = intval($form['failure_duration_threshold']);
|
| 2346 |
if ( $failure_duration_threshold >=1 ){
|
| 2347 |
$this->conf->options['failure_duration_threshold'] = $failure_duration_threshold;
|
| 2348 |
}
|
| 2349 |
-
|
| 2350 |
if ( isset($form['visible_columns']) && is_array($form['visible_columns']) ){
|
| 2351 |
$this->conf->options['table_visible_columns'] = array_keys($form['visible_columns']);
|
| 2352 |
}
|
| 2353 |
-
|
| 2354 |
$this->conf->save_options();
|
| 2355 |
die('1');
|
| 2356 |
}
|
| 2357 |
-
|
| 2358 |
function start_timer(){
|
| 2359 |
$this->execution_start_time = microtime_float();
|
| 2360 |
}
|
| 2361 |
-
|
| 2362 |
function execution_time(){
|
| 2363 |
return microtime_float() - $this->execution_start_time;
|
| 2364 |
}
|
| 2365 |
-
|
| 2366 |
/**
|
| 2367 |
* The main worker function that does all kinds of things.
|
| 2368 |
*
|
|
@@ -2379,24 +2424,24 @@ class wsBrokenLinkChecker {
|
|
| 2379 |
if ( session_id() != '' ) {
|
| 2380 |
session_write_close();
|
| 2381 |
}
|
| 2382 |
-
|
| 2383 |
if ( !$this->acquire_lock() ){
|
| 2384 |
//FB::warn("Another instance of BLC is already working. Stop.");
|
| 2385 |
$blclog->info('Another instance of BLC is already working. Stop.');
|
| 2386 |
return;
|
| 2387 |
}
|
| 2388 |
-
|
| 2389 |
if ( $this->server_too_busy() ){
|
| 2390 |
//FB::warn("Server is too busy. Stop.");
|
| 2391 |
$blclog->warn('Server load is too high, stopping.');
|
| 2392 |
return;
|
| 2393 |
}
|
| 2394 |
-
|
| 2395 |
$this->start_timer();
|
| 2396 |
$blclog->info('work() starts');
|
| 2397 |
|
| 2398 |
$max_execution_time = $this->conf->options['max_execution_time'];
|
| 2399 |
-
|
| 2400 |
/*****************************************
|
| 2401 |
Preparation
|
| 2402 |
******************************************/
|
|
@@ -2404,13 +2449,13 @@ class wsBrokenLinkChecker {
|
|
| 2404 |
if( blcUtility::is_safe_mode() ){
|
| 2405 |
// Do it the safe mode way - obey the existing max_execution_time setting
|
| 2406 |
$t = ini_get('max_execution_time');
|
| 2407 |
-
if ($t && ($t < $max_execution_time))
|
| 2408 |
$max_execution_time = $t-1;
|
| 2409 |
} else {
|
| 2410 |
// Do it the regular way
|
| 2411 |
@set_time_limit( $max_execution_time * 2 ); //x2 should be plenty, running any longer would mean a glitch.
|
| 2412 |
}
|
| 2413 |
-
|
| 2414 |
//Don't stop the script when the connection is closed
|
| 2415 |
ignore_user_abort( true );
|
| 2416 |
|
|
@@ -2431,7 +2476,7 @@ class wsBrokenLinkChecker {
|
|
| 2431 |
ob_end_flush(); // Strange behaviour, will not work
|
| 2432 |
flush(); // Unless both are called !
|
| 2433 |
}
|
| 2434 |
-
|
| 2435 |
//Load modules for this context
|
| 2436 |
$moduleManager = blcModuleManager::getInstance();
|
| 2437 |
$moduleManager->load_modules('work');
|
|
@@ -2439,15 +2484,15 @@ class wsBrokenLinkChecker {
|
|
| 2439 |
$target_usage_fraction = $this->conf->get('target_resource_usage', 0.25);
|
| 2440 |
//Target usage must be between 1% and 100%.
|
| 2441 |
$target_usage_fraction = max(min($target_usage_fraction, 1), 0.01);
|
| 2442 |
-
|
| 2443 |
-
|
| 2444 |
/*****************************************
|
| 2445 |
Parse posts and bookmarks
|
| 2446 |
******************************************/
|
| 2447 |
-
|
| 2448 |
$orphans_possible = false;
|
| 2449 |
$still_need_resynch = $this->conf->options['need_resynch'];
|
| 2450 |
-
|
| 2451 |
if ( $still_need_resynch ) {
|
| 2452 |
|
| 2453 |
//FB::log("Looking for containers that need parsing...");
|
|
@@ -2460,7 +2505,7 @@ class wsBrokenLinkChecker {
|
|
| 2460 |
while( !empty($containers) ){
|
| 2461 |
//FB::log($containers, 'Found containers');
|
| 2462 |
$this->sleep_to_maintain_ratio($get_containers_time, $target_usage_fraction);
|
| 2463 |
-
|
| 2464 |
foreach($containers as $container){
|
| 2465 |
$synch_start_time = microtime(true);
|
| 2466 |
|
|
@@ -2474,7 +2519,7 @@ class wsBrokenLinkChecker {
|
|
| 2474 |
$container->container_id,
|
| 2475 |
$synch_elapsed_time * 1000
|
| 2476 |
));
|
| 2477 |
-
|
| 2478 |
//Check if we still have some execution time left
|
| 2479 |
if( $this->execution_time() > $max_execution_time ){
|
| 2480 |
//FB::log('The allotted execution time has run out');
|
|
@@ -2482,7 +2527,7 @@ class wsBrokenLinkChecker {
|
|
| 2482 |
$this->release_lock();
|
| 2483 |
return;
|
| 2484 |
}
|
| 2485 |
-
|
| 2486 |
//Check if the server isn't overloaded
|
| 2487 |
if ( $this->server_too_busy() ){
|
| 2488 |
//FB::log('Server overloaded, bailing out.');
|
|
@@ -2501,14 +2546,14 @@ class wsBrokenLinkChecker {
|
|
| 2501 |
$containers = blcContainerHelper::get_unsynched_containers($max_containers_per_query);
|
| 2502 |
$get_containers_time = microtime(true) - $start;
|
| 2503 |
}
|
| 2504 |
-
|
| 2505 |
//FB::log('No unparsed items found.');
|
| 2506 |
$still_need_resynch = false;
|
| 2507 |
-
|
| 2508 |
} else {
|
| 2509 |
//FB::log('Resynch not required.');
|
| 2510 |
}
|
| 2511 |
-
|
| 2512 |
/******************************************
|
| 2513 |
Resynch done?
|
| 2514 |
*******************************************/
|
|
@@ -2516,11 +2561,11 @@ class wsBrokenLinkChecker {
|
|
| 2516 |
$this->conf->options['need_resynch'] = $still_need_resynch;
|
| 2517 |
$this->conf->save_options();
|
| 2518 |
}
|
| 2519 |
-
|
| 2520 |
/******************************************
|
| 2521 |
Remove orphaned links
|
| 2522 |
*******************************************/
|
| 2523 |
-
|
| 2524 |
if ( $orphans_possible ) {
|
| 2525 |
$start = microtime(true);
|
| 2526 |
|
|
@@ -2530,7 +2575,7 @@ class wsBrokenLinkChecker {
|
|
| 2530 |
$get_links_time = microtime(true) - $start;
|
| 2531 |
$this->sleep_to_maintain_ratio($get_links_time, $target_usage_fraction);
|
| 2532 |
}
|
| 2533 |
-
|
| 2534 |
//Check if we still have some execution time left
|
| 2535 |
if( $this->execution_time() > $max_execution_time ){
|
| 2536 |
//FB::log('The allotted execution time has run out');
|
|
@@ -2538,14 +2583,14 @@ class wsBrokenLinkChecker {
|
|
| 2538 |
$this->release_lock();
|
| 2539 |
return;
|
| 2540 |
}
|
| 2541 |
-
|
| 2542 |
if ( $this->server_too_busy() ){
|
| 2543 |
//FB::log('Server overloaded, bailing out.');
|
| 2544 |
$blclog->info('Server load too high, stopping.');
|
| 2545 |
$this->release_lock();
|
| 2546 |
return;
|
| 2547 |
}
|
| 2548 |
-
|
| 2549 |
/*****************************************
|
| 2550 |
Check links
|
| 2551 |
******************************************/
|
|
@@ -2557,7 +2602,7 @@ class wsBrokenLinkChecker {
|
|
| 2557 |
|
| 2558 |
while ( $links ){
|
| 2559 |
$this->sleep_to_maintain_ratio($get_links_time, $target_usage_fraction);
|
| 2560 |
-
|
| 2561 |
//Some unchecked links found
|
| 2562 |
//FB::log("Checking ".count($links)." link(s)");
|
| 2563 |
$blclog->info("Checking ".count($links)." link(s)");
|
|
@@ -2580,7 +2625,7 @@ class wsBrokenLinkChecker {
|
|
| 2580 |
$link->last_check_attempt = time();
|
| 2581 |
$link->save();
|
| 2582 |
}
|
| 2583 |
-
|
| 2584 |
//Check if we still have some execution time left
|
| 2585 |
if( $this->execution_time() > $max_execution_time ){
|
| 2586 |
//FB::log('The allotted execution time has run out');
|
|
@@ -2588,7 +2633,7 @@ class wsBrokenLinkChecker {
|
|
| 2588 |
$this->release_lock();
|
| 2589 |
return;
|
| 2590 |
}
|
| 2591 |
-
|
| 2592 |
//Check if the server isn't overloaded
|
| 2593 |
if ( $this->server_too_busy() ){
|
| 2594 |
//FB::log('Server overloaded, bailing out.');
|
|
@@ -2604,7 +2649,7 @@ class wsBrokenLinkChecker {
|
|
| 2604 |
$get_links_time = microtime(true) - $start;
|
| 2605 |
}
|
| 2606 |
//FB::log('No links need to be checked right now.');
|
| 2607 |
-
|
| 2608 |
$this->release_lock();
|
| 2609 |
$blclog->info('work(): All done.');
|
| 2610 |
//FB::log('All done.');
|
|
@@ -2634,48 +2679,48 @@ class wsBrokenLinkChecker {
|
|
| 2634 |
usleep($sleep_time * 1000000);
|
| 2635 |
}
|
| 2636 |
}
|
| 2637 |
-
|
| 2638 |
/**
|
| 2639 |
* This function is called when the plugin's cron hook executes.
|
| 2640 |
* Its only purpose is to invoke the worker function.
|
| 2641 |
*
|
| 2642 |
-
* @uses wsBrokenLinkChecker::work()
|
| 2643 |
*
|
| 2644 |
* @return void
|
| 2645 |
*/
|
| 2646 |
function cron_check_links(){
|
| 2647 |
$this->work();
|
| 2648 |
}
|
| 2649 |
-
|
| 2650 |
/**
|
| 2651 |
* Retrieve links that need to be checked or re-checked.
|
| 2652 |
*
|
| 2653 |
* @param integer $max_results The maximum number of links to return. Defaults to 0 = no limit.
|
| 2654 |
-
* @param bool $count_only If true, only the number of found links will be returned, not the links themselves.
|
| 2655 |
* @return int|blcLink[]
|
| 2656 |
*/
|
| 2657 |
function get_links_to_check($max_results = 0, $count_only = false){
|
| 2658 |
global $wpdb; /* @var wpdb $wpdb */
|
| 2659 |
-
|
| 2660 |
$check_threshold = date('Y-m-d H:i:s', strtotime('-'.$this->conf->options['check_threshold'].' hours'));
|
| 2661 |
$recheck_threshold = date('Y-m-d H:i:s', time() - $this->conf->options['recheck_threshold']);
|
| 2662 |
-
|
| 2663 |
//FB::log('Looking for links to check (threshold : '.$check_threshold.', recheck_threshold : '.$recheck_threshold.')...');
|
| 2664 |
-
|
| 2665 |
//Select some links that haven't been checked for a long time or
|
| 2666 |
//that are broken and need to be re-checked again. Links that are
|
| 2667 |
//marked as "being checked" and have been that way for several minutes
|
| 2668 |
-
//can also be considered broken/buggy, so those will be selected
|
| 2669 |
//as well.
|
| 2670 |
-
|
| 2671 |
-
//Only check links that have at least one valid instance (i.e. an instance exists and
|
| 2672 |
//it corresponds to one of the currently loaded container/parser types).
|
| 2673 |
$manager = blcModuleManager::getInstance();
|
| 2674 |
$loaded_containers = $manager->get_escaped_ids('container');
|
| 2675 |
$loaded_parsers = $manager->get_escaped_ids('parser');
|
| 2676 |
-
|
| 2677 |
//Note : This is a slow query, but AFAIK there is no way to speed it up.
|
| 2678 |
-
//I could put an index on last_check_attempt, but that value is almost
|
| 2679 |
//certainly unique for each row so it wouldn't be much better than a full table scan.
|
| 2680 |
if ( $count_only ){
|
| 2681 |
$q = "SELECT COUNT(DISTINCT links.link_id)\n";
|
|
@@ -2707,36 +2752,36 @@ class wsBrokenLinkChecker {
|
|
| 2707 |
$q .= "LIMIT " . intval($max_results);
|
| 2708 |
}
|
| 2709 |
}
|
| 2710 |
-
|
| 2711 |
$link_q = $wpdb->prepare(
|
| 2712 |
-
$q,
|
| 2713 |
-
$check_threshold,
|
| 2714 |
-
$this->conf->options['recheck_count'],
|
| 2715 |
$recheck_threshold
|
| 2716 |
);
|
| 2717 |
//FB::log($link_q, "Find links to check");
|
| 2718 |
//$blclog->debug("Find links to check: \n" . $link_q);
|
| 2719 |
-
|
| 2720 |
//If we just need the number of links, retrieve it and return
|
| 2721 |
if ( $count_only ){
|
| 2722 |
return $wpdb->get_var($link_q);
|
| 2723 |
}
|
| 2724 |
-
|
| 2725 |
//Fetch the link data
|
| 2726 |
$link_data = $wpdb->get_results($link_q, ARRAY_A);
|
| 2727 |
if ( empty($link_data) ){
|
| 2728 |
return array();
|
| 2729 |
}
|
| 2730 |
-
|
| 2731 |
//Instantiate blcLink objects for all fetched links
|
| 2732 |
$links = array();
|
| 2733 |
foreach($link_data as $data){
|
| 2734 |
$links[] = new blcLink($data);
|
| 2735 |
}
|
| 2736 |
-
|
| 2737 |
return $links;
|
| 2738 |
}
|
| 2739 |
-
|
| 2740 |
/**
|
| 2741 |
* Output the current link checker status in JSON format.
|
| 2742 |
* Ajax hook for the 'blc_full_status' action.
|
|
@@ -2746,15 +2791,15 @@ class wsBrokenLinkChecker {
|
|
| 2746 |
function ajax_full_status( ){
|
| 2747 |
$status = $this->get_status();
|
| 2748 |
$text = $this->status_text( $status );
|
| 2749 |
-
|
| 2750 |
echo json_encode( array(
|
| 2751 |
'text' => $text,
|
| 2752 |
-
'status' => $status,
|
| 2753 |
) );
|
| 2754 |
-
|
| 2755 |
die();
|
| 2756 |
}
|
| 2757 |
-
|
| 2758 |
/**
|
| 2759 |
* Generates a status message based on the status info in $status
|
| 2760 |
*
|
|
@@ -2763,10 +2808,10 @@ class wsBrokenLinkChecker {
|
|
| 2763 |
*/
|
| 2764 |
function status_text( $status ){
|
| 2765 |
$text = '';
|
| 2766 |
-
|
| 2767 |
if( $status['broken_links'] > 0 ){
|
| 2768 |
-
$text .= sprintf(
|
| 2769 |
-
"<a href='%s' title='" . __('View broken links', 'broken-link-checker') . "'><strong>".
|
| 2770 |
_n('Found %d broken link', 'Found %d broken links', $status['broken_links'], 'broken-link-checker') .
|
| 2771 |
"</strong></a>",
|
| 2772 |
esc_attr(admin_url('tools.php?page=view-broken-links')),
|
|
@@ -2775,17 +2820,17 @@ class wsBrokenLinkChecker {
|
|
| 2775 |
} else {
|
| 2776 |
$text .= __("No broken links found.", 'broken-link-checker');
|
| 2777 |
}
|
| 2778 |
-
|
| 2779 |
$text .= "<br/>";
|
| 2780 |
-
|
| 2781 |
if( $status['unchecked_links'] > 0) {
|
| 2782 |
-
$text .= sprintf(
|
| 2783 |
-
_n('%d URL in the work queue', '%d URLs in the work queue', $status['unchecked_links'], 'broken-link-checker'),
|
| 2784 |
$status['unchecked_links'] );
|
| 2785 |
} else {
|
| 2786 |
$text .= __("No URLs in the work queue.", 'broken-link-checker');
|
| 2787 |
}
|
| 2788 |
-
|
| 2789 |
$text .= "<br/>";
|
| 2790 |
if ( $status['known_links'] > 0 ){
|
| 2791 |
$url_count = sprintf(
|
|
@@ -2817,12 +2862,12 @@ class wsBrokenLinkChecker {
|
|
| 2817 |
$text .= __('No links detected.', 'broken-link-checker');
|
| 2818 |
}
|
| 2819 |
}
|
| 2820 |
-
|
| 2821 |
return $text;
|
| 2822 |
}
|
| 2823 |
-
|
| 2824 |
/**
|
| 2825 |
-
* @uses wsBrokenLinkChecker::ajax_full_status()
|
| 2826 |
*
|
| 2827 |
* @return void
|
| 2828 |
*/
|
|
@@ -2830,7 +2875,7 @@ class wsBrokenLinkChecker {
|
|
| 2830 |
//Just display the full status.
|
| 2831 |
$this->ajax_full_status();
|
| 2832 |
}
|
| 2833 |
-
|
| 2834 |
/**
|
| 2835 |
* Output the current average server load (over the last one-minute period).
|
| 2836 |
* Called via AJAX.
|
|
@@ -2842,36 +2887,36 @@ class wsBrokenLinkChecker {
|
|
| 2842 |
if ( empty($load) ){
|
| 2843 |
die( _x('Unknown', 'current load', 'broken-link-checker') );
|
| 2844 |
}
|
| 2845 |
-
|
| 2846 |
$one_minute = reset($load);
|
| 2847 |
printf('%.2f', $one_minute);
|
| 2848 |
die();
|
| 2849 |
}
|
| 2850 |
-
|
| 2851 |
/**
|
| 2852 |
-
* Returns an array with various status information about the plugin. Array key reference:
|
| 2853 |
* check_threshold - date/time; links checked before this threshold should be checked again.
|
| 2854 |
* recheck_threshold - date/time; broken links checked before this threshold should be re-checked.
|
| 2855 |
* known_links - the number of detected unique URLs (a misleading name, yes).
|
| 2856 |
* known_instances - the number of detected link instances, i.e. actual link elements in posts and other places.
|
| 2857 |
-
* broken_links - the number of detected broken links.
|
| 2858 |
* unchecked_links - the number of URLs that need to be checked ASAP; based on check_threshold and recheck_threshold.
|
| 2859 |
*
|
| 2860 |
* @return array
|
| 2861 |
*/
|
| 2862 |
function get_status(){
|
| 2863 |
$blc_link_query = blcLinkQuery::getInstance();
|
| 2864 |
-
|
| 2865 |
$check_threshold=date('Y-m-d H:i:s', strtotime('-'.$this->conf->options['check_threshold'].' hours'));
|
| 2866 |
$recheck_threshold=date('Y-m-d H:i:s', time() - $this->conf->options['recheck_threshold']);
|
| 2867 |
-
|
| 2868 |
$known_links = blc_get_links(array('count_only' => true));
|
| 2869 |
$known_instances = blc_get_usable_instance_count();
|
| 2870 |
-
|
| 2871 |
$broken_links = $blc_link_query->get_filter_links('broken', array('count_only' => true));
|
| 2872 |
-
|
| 2873 |
$unchecked_links = $this->get_links_to_check(0, true);
|
| 2874 |
-
|
| 2875 |
return array(
|
| 2876 |
'check_threshold' => $check_threshold,
|
| 2877 |
'recheck_threshold' => $recheck_threshold,
|
|
@@ -2881,15 +2926,15 @@ class wsBrokenLinkChecker {
|
|
| 2881 |
'unchecked_links' => $unchecked_links,
|
| 2882 |
);
|
| 2883 |
}
|
| 2884 |
-
|
| 2885 |
function ajax_work(){
|
| 2886 |
check_ajax_referer('blc_work');
|
| 2887 |
|
| 2888 |
-
//Run the worker function
|
| 2889 |
$this->work();
|
| 2890 |
die();
|
| 2891 |
}
|
| 2892 |
-
|
| 2893 |
/**
|
| 2894 |
* AJAX hook for the "Not broken" button. Marks a link as broken and as a likely false positive.
|
| 2895 |
*
|
|
@@ -2899,17 +2944,17 @@ class wsBrokenLinkChecker {
|
|
| 2899 |
if (!current_user_can('edit_others_posts') || !check_ajax_referer('blc_discard', false, false)){
|
| 2900 |
die( __("You're not allowed to do that!", 'broken-link-checker') );
|
| 2901 |
}
|
| 2902 |
-
|
| 2903 |
if ( isset($_POST['link_id']) ){
|
| 2904 |
//Load the link
|
| 2905 |
$link = new blcLink( intval($_POST['link_id']) );
|
| 2906 |
-
|
| 2907 |
if ( !$link->valid() ){
|
| 2908 |
printf( __("Oops, I can't find the link %d", 'broken-link-checker'), intval($_POST['link_id']) );
|
| 2909 |
die();
|
| 2910 |
}
|
| 2911 |
//Make it appear "not broken"
|
| 2912 |
-
$link->broken = false;
|
| 2913 |
$link->warning = false;
|
| 2914 |
$link->false_positive = true;
|
| 2915 |
$link->last_check_attempt = time();
|
|
@@ -2964,16 +3009,16 @@ class wsBrokenLinkChecker {
|
|
| 2964 |
die( __("Error : link_id not specified", 'broken-link-checker') );
|
| 2965 |
}
|
| 2966 |
}
|
| 2967 |
-
|
| 2968 |
/**
|
| 2969 |
-
* AJAX hook for the inline link editor on Tools -> Broken Links.
|
| 2970 |
*
|
| 2971 |
* @return void
|
| 2972 |
*/
|
| 2973 |
function ajax_edit(){
|
| 2974 |
if (!current_user_can('edit_others_posts') || !check_ajax_referer('blc_edit', false, false)){
|
| 2975 |
die( json_encode( array(
|
| 2976 |
-
'error' => __("You're not allowed to do that!", 'broken-link-checker')
|
| 2977 |
)));
|
| 2978 |
}
|
| 2979 |
|
|
@@ -3064,9 +3109,9 @@ class wsBrokenLinkChecker {
|
|
| 3064 |
die( json_encode($response) );
|
| 3065 |
}
|
| 3066 |
}
|
| 3067 |
-
|
| 3068 |
/**
|
| 3069 |
-
* AJAX hook for the "Unlink" action links in Tools -> Broken Links.
|
| 3070 |
* Removes the specified link from all posts and other supported items.
|
| 3071 |
*
|
| 3072 |
* @return void
|
|
@@ -3074,23 +3119,23 @@ class wsBrokenLinkChecker {
|
|
| 3074 |
function ajax_unlink(){
|
| 3075 |
if (!current_user_can('edit_others_posts') || !check_ajax_referer('blc_unlink', false, false)){
|
| 3076 |
die( json_encode( array(
|
| 3077 |
-
'error' => __("You're not allowed to do that!", 'broken-link-checker')
|
| 3078 |
)));
|
| 3079 |
}
|
| 3080 |
-
|
| 3081 |
if ( isset($_POST['link_id']) ){
|
| 3082 |
//Load the link
|
| 3083 |
$link = new blcLink( intval($_POST['link_id']) );
|
| 3084 |
-
|
| 3085 |
if ( !$link->valid() ){
|
| 3086 |
die( json_encode( array(
|
| 3087 |
-
'error' => sprintf( __("Oops, I can't find the link %d", 'broken-link-checker'), intval($_POST['link_id']) )
|
| 3088 |
)));
|
| 3089 |
}
|
| 3090 |
-
|
| 3091 |
//Try and unlink it
|
| 3092 |
$rez = $link->unlink();
|
| 3093 |
-
|
| 3094 |
if ( $rez === false ){
|
| 3095 |
die( json_encode( array(
|
| 3096 |
'error' => __("An unexpected error occured!", 'broken-link-checker')
|
|
@@ -3104,13 +3149,13 @@ class wsBrokenLinkChecker {
|
|
| 3104 |
foreach($rez['errors'] as $error){ /** @var WP_Error $error */
|
| 3105 |
array_push( $response['errors'], implode(', ', $error->get_error_messages()) );
|
| 3106 |
}
|
| 3107 |
-
|
| 3108 |
die( json_encode($response) );
|
| 3109 |
}
|
| 3110 |
-
|
| 3111 |
} else {
|
| 3112 |
die( json_encode( array(
|
| 3113 |
-
'error' => __("Error : link_id not specified", 'broken-link-checker')
|
| 3114 |
)));
|
| 3115 |
}
|
| 3116 |
}
|
|
@@ -3218,16 +3263,16 @@ class wsBrokenLinkChecker {
|
|
| 3218 |
|
| 3219 |
die(json_encode($response));
|
| 3220 |
}
|
| 3221 |
-
|
| 3222 |
function ajax_link_details(){
|
| 3223 |
global $wpdb; /* @var wpdb $wpdb */
|
| 3224 |
-
|
| 3225 |
if (!current_user_can('edit_others_posts')){
|
| 3226 |
die( __("You don't have sufficient privileges to access this information!", 'broken-link-checker') );
|
| 3227 |
}
|
| 3228 |
-
|
| 3229 |
//FB::log("Loading link details via AJAX");
|
| 3230 |
-
|
| 3231 |
if ( isset($_GET['link_id']) ){
|
| 3232 |
//FB::info("Link ID found in GET");
|
| 3233 |
$link_id = intval($_GET['link_id']);
|
|
@@ -3238,10 +3283,10 @@ class wsBrokenLinkChecker {
|
|
| 3238 |
//FB::error('Link ID not specified, you hacking bastard.');
|
| 3239 |
die( __('Error : link ID not specified', 'broken-link-checker') );
|
| 3240 |
}
|
| 3241 |
-
|
| 3242 |
-
//Load the link.
|
| 3243 |
$link = new blcLink($link_id);
|
| 3244 |
-
|
| 3245 |
if ( !$link->is_new ){
|
| 3246 |
//FB::info($link, 'Link loaded');
|
| 3247 |
if ( !class_exists('blcTablePrinter') ){
|
|
@@ -3254,7 +3299,7 @@ class wsBrokenLinkChecker {
|
|
| 3254 |
die();
|
| 3255 |
}
|
| 3256 |
}
|
| 3257 |
-
|
| 3258 |
/**
|
| 3259 |
* Acquire an exclusive lock.
|
| 3260 |
* If we already hold a lock, it will be released and a new one will be acquired.
|
|
@@ -3264,9 +3309,9 @@ class wsBrokenLinkChecker {
|
|
| 3264 |
function acquire_lock(){
|
| 3265 |
return WPMutex::acquire('blc_lock');
|
| 3266 |
}
|
| 3267 |
-
|
| 3268 |
/**
|
| 3269 |
-
* Relese our exclusive lock.
|
| 3270 |
* Does nothing if the lock has already been released.
|
| 3271 |
*
|
| 3272 |
* @return bool
|
|
@@ -3274,7 +3319,7 @@ class wsBrokenLinkChecker {
|
|
| 3274 |
function release_lock(){
|
| 3275 |
return WPMutex::release('blc_lock');
|
| 3276 |
}
|
| 3277 |
-
|
| 3278 |
/**
|
| 3279 |
* Check if server is currently too overloaded to run the link checker.
|
| 3280 |
*
|
|
@@ -3284,33 +3329,33 @@ class wsBrokenLinkChecker {
|
|
| 3284 |
if ( !$this->conf->options['enable_load_limit'] || !isset($this->conf->options['server_load_limit']) ){
|
| 3285 |
return false;
|
| 3286 |
}
|
| 3287 |
-
|
| 3288 |
$loads = blcUtility::get_server_load();
|
| 3289 |
if ( empty($loads) ){
|
| 3290 |
return false;
|
| 3291 |
}
|
| 3292 |
$one_minute = floatval(reset($loads));
|
| 3293 |
-
|
| 3294 |
return $one_minute > $this->conf->options['server_load_limit'];
|
| 3295 |
}
|
| 3296 |
-
|
| 3297 |
/**
|
| 3298 |
* Register BLC's Dashboard widget
|
| 3299 |
-
*
|
| 3300 |
* @return void
|
| 3301 |
*/
|
| 3302 |
function hook_wp_dashboard_setup(){
|
| 3303 |
$show_widget = current_user_can($this->conf->get('dashboard_widget_capability', 'edit_others_posts'));
|
| 3304 |
if ( function_exists( 'wp_add_dashboard_widget' ) && $show_widget ) {
|
| 3305 |
wp_add_dashboard_widget(
|
| 3306 |
-
'blc_dashboard_widget',
|
| 3307 |
-
__('Broken Link Checker', 'broken-link-checker'),
|
| 3308 |
array( $this, 'dashboard_widget' ),
|
| 3309 |
array( $this, 'dashboard_widget_control' )
|
| 3310 |
);
|
| 3311 |
}
|
| 3312 |
}
|
| 3313 |
-
|
| 3314 |
/**
|
| 3315 |
* Collect various debugging information and return it in an associative array
|
| 3316 |
*
|
|
@@ -3320,46 +3365,46 @@ class wsBrokenLinkChecker {
|
|
| 3320 |
/** @var wpdb $wpdb */
|
| 3321 |
global $wpdb;
|
| 3322 |
|
| 3323 |
-
//Collect some information that's useful for debugging
|
| 3324 |
$debug = array();
|
| 3325 |
-
|
| 3326 |
//PHP version. Any one is fine as long as WP supports it.
|
| 3327 |
$debug[ __('PHP version', 'broken-link-checker') ] = array(
|
| 3328 |
'state' => 'ok',
|
| 3329 |
-
'value' => phpversion(),
|
| 3330 |
);
|
| 3331 |
-
|
| 3332 |
//MySQL version
|
| 3333 |
$debug[ __('MySQL version', 'broken-link-checker') ] = array(
|
| 3334 |
'state' => 'ok',
|
| 3335 |
'value' => $wpdb->db_version(),
|
| 3336 |
);
|
| 3337 |
-
|
| 3338 |
//CURL presence and version
|
| 3339 |
if ( function_exists('curl_version') ){
|
| 3340 |
$version = curl_version();
|
| 3341 |
-
|
| 3342 |
if ( version_compare( $version['version'], '7.16.0', '<=' ) ){
|
| 3343 |
$data = array(
|
| 3344 |
-
'state' => 'warning',
|
| 3345 |
'value' => $version['version'],
|
| 3346 |
'message' => __('You have an old version of CURL. Redirect detection may not work properly.', 'broken-link-checker'),
|
| 3347 |
);
|
| 3348 |
} else {
|
| 3349 |
$data = array(
|
| 3350 |
-
'state' => 'ok',
|
| 3351 |
'value' => $version['version'],
|
| 3352 |
);
|
| 3353 |
}
|
| 3354 |
-
|
| 3355 |
} else {
|
| 3356 |
$data = array(
|
| 3357 |
-
'state' => 'warning',
|
| 3358 |
'value' => __('Not installed', 'broken-link-checker'),
|
| 3359 |
);
|
| 3360 |
}
|
| 3361 |
$debug[ __('CURL version', 'broken-link-checker') ] = $data;
|
| 3362 |
-
|
| 3363 |
//Snoopy presence
|
| 3364 |
if ( class_exists('Snoopy') || file_exists(ABSPATH. WPINC . '/class-snoopy.php') ){
|
| 3365 |
$data = array(
|
|
@@ -3367,7 +3412,7 @@ class wsBrokenLinkChecker {
|
|
| 3367 |
'value' => __('Installed', 'broken-link-checker'),
|
| 3368 |
);
|
| 3369 |
} else {
|
| 3370 |
-
//No Snoopy? This should never happen, but if it does we *must* have CURL.
|
| 3371 |
if ( function_exists('curl_init') ){
|
| 3372 |
$data = array(
|
| 3373 |
'state' => 'ok',
|
|
@@ -3380,10 +3425,10 @@ class wsBrokenLinkChecker {
|
|
| 3380 |
'message' => __('You must have either CURL or Snoopy installed for the plugin to work!', 'broken-link-checker'),
|
| 3381 |
);
|
| 3382 |
}
|
| 3383 |
-
|
| 3384 |
}
|
| 3385 |
$debug['Snoopy'] = $data;
|
| 3386 |
-
|
| 3387 |
//Safe_mode status
|
| 3388 |
if ( blcUtility::is_safe_mode() ){
|
| 3389 |
$debug['Safe mode'] = array(
|
|
@@ -3397,7 +3442,7 @@ class wsBrokenLinkChecker {
|
|
| 3397 |
'value' => __('Off', 'broken-link-checker'),
|
| 3398 |
);
|
| 3399 |
}
|
| 3400 |
-
|
| 3401 |
//Open_basedir status
|
| 3402 |
if ( blcUtility::is_open_basedir() ){
|
| 3403 |
$debug['open_basedir'] = array(
|
|
@@ -3411,7 +3456,7 @@ class wsBrokenLinkChecker {
|
|
| 3411 |
'value' => __('Off', 'broken-link-checker'),
|
| 3412 |
);
|
| 3413 |
}
|
| 3414 |
-
|
| 3415 |
//Default PHP execution time limit
|
| 3416 |
$debug['Default PHP execution time limit'] = array(
|
| 3417 |
'state' => 'ok',
|
|
@@ -3431,7 +3476,7 @@ class wsBrokenLinkChecker {
|
|
| 3431 |
'state' => 'ok',
|
| 3432 |
'value' => sprintf('%d', $this->conf->options['need_resynch'] ? '1 (resynch. required)' : '0 (resynch. not required)'),
|
| 3433 |
);
|
| 3434 |
-
|
| 3435 |
//Synch records
|
| 3436 |
$synch_records = intval($wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}blc_synch"));
|
| 3437 |
$data = array(
|
|
@@ -3443,21 +3488,21 @@ class wsBrokenLinkChecker {
|
|
| 3443 |
$data['message'] = __('If this value is zero even after several page reloads you have probably encountered a bug.', 'broken-link-checker');
|
| 3444 |
}
|
| 3445 |
$debug['Synch. records'] = $data;
|
| 3446 |
-
|
| 3447 |
//Total links and instances (including invalid ones)
|
| 3448 |
$all_links = intval($wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}blc_links"));
|
| 3449 |
$all_instances = intval($wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}blc_instances"));
|
| 3450 |
-
|
| 3451 |
-
//Show the number of unparsed containers. Useful for debugging. For performance,
|
| 3452 |
//this is only shown when we have no links/instances yet.
|
| 3453 |
if( ($all_links == 0) && ($all_instances == 0) ){
|
| 3454 |
$unparsed_items = intval($wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}blc_synch WHERE synched=0"));
|
| 3455 |
$debug['Unparsed items'] = array(
|
| 3456 |
-
'state' => 'warning',
|
| 3457 |
'value' => $unparsed_items,
|
| 3458 |
);
|
| 3459 |
-
}
|
| 3460 |
-
|
| 3461 |
//Links & instances
|
| 3462 |
if ( ($all_links > 0) && ($all_instances > 0) ){
|
| 3463 |
$debug['Link records'] = array(
|
|
@@ -3469,7 +3514,7 @@ class wsBrokenLinkChecker {
|
|
| 3469 |
'state' => 'warning',
|
| 3470 |
'value' => sprintf('%d (%d)', $all_links, $all_instances),
|
| 3471 |
);
|
| 3472 |
-
}
|
| 3473 |
|
| 3474 |
//Email notifications.
|
| 3475 |
if ( $this->conf->options['last_notification_sent'] ) {
|
|
@@ -3513,7 +3558,7 @@ class wsBrokenLinkChecker {
|
|
| 3513 |
'value' => 'No installation log found found.',
|
| 3514 |
);
|
| 3515 |
}
|
| 3516 |
-
|
| 3517 |
return $debug;
|
| 3518 |
}
|
| 3519 |
|
|
@@ -3707,7 +3752,7 @@ class wsBrokenLinkChecker {
|
|
| 3707 |
$this->send_html_email($author->user_email, $subject, $body);
|
| 3708 |
}
|
| 3709 |
}
|
| 3710 |
-
|
| 3711 |
function override_mail_content_type(/** @noinspection PhpUnusedParameterInspection */ $content_type){
|
| 3712 |
return 'text/html';
|
| 3713 |
}
|
|
@@ -3729,24 +3774,25 @@ class wsBrokenLinkChecker {
|
|
| 3729 |
'%d'
|
| 3730 |
);
|
| 3731 |
}
|
| 3732 |
-
|
| 3733 |
/**
|
| 3734 |
* Install or uninstall the plugin's Cron events based on current settings.
|
| 3735 |
*
|
| 3736 |
-
* @uses wsBrokenLinkChecker::$conf Uses $conf->options to determine if events need to be (un)installed.
|
| 3737 |
*
|
| 3738 |
* @return void
|
| 3739 |
*/
|
| 3740 |
function setup_cron_events(){
|
| 3741 |
-
|
|
|
|
| 3742 |
if ( $this->conf->options['run_via_cron'] ){
|
| 3743 |
if (!wp_next_scheduled('blc_cron_check_links')) {
|
| 3744 |
-
wp_schedule_event( time(), '
|
| 3745 |
}
|
| 3746 |
} else {
|
| 3747 |
wp_clear_scheduled_hook('blc_cron_check_links');
|
| 3748 |
}
|
| 3749 |
-
|
| 3750 |
//Email notifications about broken links
|
| 3751 |
if ( $this->conf->options['send_email_notifications'] || $this->conf->options['send_authors_email_notifications'] ){
|
| 3752 |
if ( !wp_next_scheduled('blc_cron_email_notifications') ){
|
|
@@ -3755,13 +3801,13 @@ class wsBrokenLinkChecker {
|
|
| 3755 |
} else {
|
| 3756 |
wp_clear_scheduled_hook('blc_cron_email_notifications');
|
| 3757 |
}
|
| 3758 |
-
|
| 3759 |
//Run database maintenance every two weeks or so
|
| 3760 |
if ( !wp_next_scheduled('blc_cron_database_maintenance') ){
|
| 3761 |
-
wp_schedule_event(time(), '
|
| 3762 |
}
|
| 3763 |
}
|
| 3764 |
-
|
| 3765 |
/**
|
| 3766 |
* Load the plugin's textdomain.
|
| 3767 |
*
|
|
@@ -3770,7 +3816,7 @@ class wsBrokenLinkChecker {
|
|
| 3770 |
function load_language(){
|
| 3771 |
$this->is_textdomain_loaded = load_plugin_textdomain( 'broken-link-checker', false, basename(dirname($this->loader)) . '/languages' );
|
| 3772 |
}
|
| 3773 |
-
|
| 3774 |
protected static function get_default_log_directory() {
|
| 3775 |
$uploads = wp_upload_dir();
|
| 3776 |
return $uploads['basedir'] . '/broken-link-checker';
|
| 1 |
<?php
|
|
|
|
| 2 |
/**
|
| 3 |
* Simple function to replicate PHP 5 behaviour
|
| 4 |
*/
|
| 5 |
+
if ( ! function_exists( 'microtime_float' ) ) {
|
| 6 |
+
function microtime_float() {
|
| 7 |
+
list($usec, $sec) = explode( ' ', microtime() );
|
| 8 |
+
return ( (float)$usec + (float)$sec);
|
|
|
|
| 9 |
}
|
| 10 |
}
|
| 11 |
|
| 17 |
if (!class_exists('wsBrokenLinkChecker')) {
|
| 18 |
|
| 19 |
class wsBrokenLinkChecker {
|
| 20 |
+
var $conf;
|
|
|
|
| 21 |
var $loader;
|
| 22 |
+
var $my_basename = '';
|
| 23 |
+
|
| 24 |
+
var $db_version; //The required version of the plugin's DB schema.
|
| 25 |
+
|
| 26 |
+
var $execution_start_time; //Used for a simple internal execution timer in start_timer()/execution_time()
|
| 27 |
|
| 28 |
private $is_textdomain_loaded = false;
|
| 29 |
+
|
| 30 |
/**
|
| 31 |
* wsBrokenLinkChecker::wsBrokenLinkChecker()
|
| 32 |
* Class constructor
|
| 37 |
*/
|
| 38 |
function __construct ( $loader, $conf ) {
|
| 39 |
$this->db_version = BLC_DATABASE_VERSION;
|
| 40 |
+
|
| 41 |
$this->conf = $conf;
|
| 42 |
$this->loader = $loader;
|
| 43 |
$this->my_basename = plugin_basename( $this->loader );
|
| 44 |
|
| 45 |
$this->load_language();
|
| 46 |
+
|
| 47 |
//Unlike the activation hook, the deactivation callback *can* be registered in this file
|
| 48 |
+
//because deactivation happens after this class has already been instantiated (durinng the
|
| 49 |
+
//'init' action).
|
| 50 |
register_deactivation_hook($loader, array($this, 'deactivation'));
|
| 51 |
+
|
| 52 |
add_action('admin_menu', array($this,'admin_menu'));
|
| 53 |
|
| 54 |
//Load jQuery on Dashboard pages (probably redundant as WP already does that)
|
| 55 |
add_action('admin_print_scripts', array($this,'admin_print_scripts'));
|
| 56 |
+
|
| 57 |
//The dashboard widget
|
| 58 |
add_action('wp_dashboard_setup', array($this, 'hook_wp_dashboard_setup'));
|
| 59 |
+
|
| 60 |
//AJAXy hooks
|
| 61 |
add_action( 'wp_ajax_blc_full_status', array($this,'ajax_full_status') );
|
| 62 |
add_action( 'wp_ajax_blc_dashboard_status', array($this,'ajax_dashboard_status') );
|
| 71 |
|
| 72 |
add_action( 'wp_ajax_blc_dismiss', array($this, 'ajax_dismiss') );
|
| 73 |
add_action( 'wp_ajax_blc_undismiss', array($this, 'ajax_undismiss') );
|
| 74 |
+
|
| 75 |
//Add/remove Cron events
|
| 76 |
$this->setup_cron_events();
|
| 77 |
+
|
| 78 |
//Set hooks that listen for our Cron actions
|
| 79 |
+
add_action( 'blc_cron_email_notifications', array( $this, 'maybe_send_email_notifications' ) );
|
| 80 |
+
add_action( 'blc_cron_check_links', array( $this, 'cron_check_links' ) );
|
| 81 |
+
add_action( 'blc_cron_database_maintenance', array( $this, 'database_maintenance' ) );
|
| 82 |
|
| 83 |
//Set the footer hook that will call the worker function via AJAX.
|
| 84 |
+
add_action( 'admin_footer', array( $this,'admin_footer' ) );
|
|
|
|
| 85 |
//Add a "Screen Options" panel to the "Broken Links" page
|
| 86 |
add_screen_options_panel(
|
| 87 |
'blc-screen-options',
|
| 93 |
);
|
| 94 |
|
| 95 |
//Display an explanatory note on the "Tools -> Broken Links -> Warnings" page.
|
| 96 |
+
add_action( 'admin_notices', array( $this, 'show_warnings_section_notice' ) );
|
| 97 |
+
|
| 98 |
+
add_filter('cron_schedules', array( $this, 'cron_add_every_10_minutes'));
|
| 99 |
+
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
/**
|
| 103 |
+
* @param $schedules
|
| 104 |
+
*
|
| 105 |
+
* @return mixed
|
| 106 |
+
*/
|
| 107 |
+
function cron_add_every_10_minutes( $schedules ) {
|
| 108 |
+
// Adds once weekly to the existing schedules.
|
| 109 |
+
$schedules['10min'] = [
|
| 110 |
+
'interval' => 600,
|
| 111 |
+
'display' => __('Every 10 minutes')
|
| 112 |
+
];
|
| 113 |
+
|
| 114 |
+
return $schedules;
|
| 115 |
}
|
| 116 |
|
| 117 |
/**
|
| 128 |
<!-- wsblc admin footer -->
|
| 129 |
<script type='text/javascript'>
|
| 130 |
(function($){
|
| 131 |
+
|
| 132 |
+
//(Re)starts the background worker thread
|
| 133 |
function blcDoWork(){
|
| 134 |
$.post(
|
| 135 |
"<?php echo admin_url('admin-ajax.php'); ?>",
|
| 141 |
}
|
| 142 |
//Call it the first time
|
| 143 |
blcDoWork();
|
| 144 |
+
|
| 145 |
+
//Then call it periodically every X seconds
|
| 146 |
setInterval(blcDoWork, <?php echo (intval($this->conf->options['max_execution_time']) + 1 )*1000; ?>);
|
| 147 |
+
|
| 148 |
})(jQuery);
|
| 149 |
</script>
|
| 150 |
<!-- /wsblc admin footer -->
|
| 151 |
<?php
|
| 152 |
}
|
| 153 |
+
|
| 154 |
/**
|
| 155 |
* Check if an URL matches the exclusion list.
|
| 156 |
*
|
| 169 |
|
| 170 |
function dashboard_widget(){
|
| 171 |
?>
|
| 172 |
+
<p id='wsblc_activity_box'><?php _e( 'Loading...', 'broken-link-checker' ); ?></p>
|
| 173 |
<script type='text/javascript'>
|
| 174 |
jQuery( function($){
|
| 175 |
var blc_was_autoexpanded = false;
|
| 176 |
+
|
| 177 |
function blcDashboardStatus(){
|
| 178 |
$.getJSON(
|
| 179 |
"<?php echo admin_url('admin-ajax.php'); ?>",
|
| 183 |
},
|
| 184 |
function (data){
|
| 185 |
if ( data && ( typeof(data.text) != 'undefined' ) ) {
|
| 186 |
+
$('#wsblc_activity_box').html(data.text);
|
| 187 |
<?php if ( $this->conf->options['autoexpand_widget'] ) { ?>
|
| 188 |
//Expand the widget if there are broken links.
|
| 189 |
//Do this only once per pageload so as not to annoy the user.
|
| 195 |
} else {
|
| 196 |
$('#wsblc_activity_box').html('<?php _e('[ Network error ]', 'broken-link-checker'); ?>');
|
| 197 |
}
|
| 198 |
+
|
| 199 |
setTimeout( blcDashboardStatus, 120*1000 ); //...update every two minutes
|
| 200 |
}
|
| 201 |
);
|
| 202 |
}
|
| 203 |
+
|
| 204 |
blcDashboardStatus();//Call it the first time
|
| 205 |
+
|
| 206 |
} );
|
| 207 |
</script>
|
| 208 |
<?php
|
| 216 |
$this->conf->options['autoexpand_widget'] = !empty($_POST['blc-autoexpand']);
|
| 217 |
$this->conf->save_options();
|
| 218 |
}
|
| 219 |
+
|
| 220 |
?>
|
| 221 |
<p><label for="blc-autoexpand">
|
| 222 |
<input id="blc-autoexpand" name="blc-autoexpand" type="checkbox" value="1" <?php if ( $this->conf->options['autoexpand_widget'] ) echo 'checked="checked"'; ?> />
|
| 229 |
//jQuery is used for triggering the link monitor via AJAX when any admin page is open.
|
| 230 |
wp_enqueue_script('jquery');
|
| 231 |
}
|
| 232 |
+
|
| 233 |
function enqueue_settings_scripts(){
|
| 234 |
//jQuery UI is used on the settings page
|
| 235 |
wp_enqueue_script('jquery-ui-core'); //Used for background color animation
|
| 237 |
wp_enqueue_script('jquery-ui-tabs');
|
| 238 |
wp_enqueue_script('jquery-cookie', plugins_url('js/jquery.cookie.js', BLC_PLUGIN_FILE)); //Used for storing last widget states, etc
|
| 239 |
}
|
| 240 |
+
|
| 241 |
function enqueue_link_page_scripts(){
|
| 242 |
wp_enqueue_script('jquery-ui-core');
|
| 243 |
wp_enqueue_script('jquery-ui-dialog'); //Used for the search form
|
| 244 |
wp_enqueue_script('jquery-color'); //Used for background color animation
|
| 245 |
wp_enqueue_script('sprintf', plugins_url('js/sprintf.js', BLC_PLUGIN_FILE)); //Used in error messages
|
| 246 |
}
|
| 247 |
+
|
| 248 |
/**
|
| 249 |
+
* Initiate a full recheck - reparse everything and check all links anew.
|
| 250 |
*
|
| 251 |
* @return void
|
| 252 |
*/
|
| 255 |
|
| 256 |
//Delete all discovered instances
|
| 257 |
$wpdb->query("TRUNCATE {$wpdb->prefix}blc_instances");
|
| 258 |
+
|
| 259 |
//Delete all discovered links
|
| 260 |
$wpdb->query("TRUNCATE {$wpdb->prefix}blc_links");
|
| 261 |
+
|
| 262 |
//Mark all posts, custom fields and bookmarks for processing.
|
| 263 |
blc_resynch(true);
|
| 264 |
}
|
| 274 |
wp_clear_scheduled_hook('blc_cron_email_notifications');
|
| 275 |
wp_clear_scheduled_hook('blc_cron_database_maintenance');
|
| 276 |
wp_clear_scheduled_hook('blc_cron_check_news'); //Unused event.
|
| 277 |
+
//Note the deactivation time for each module. This will help them
|
| 278 |
//synch up propely if/when the plugin is reactivated.
|
| 279 |
$moduleManager = blcModuleManager::getInstance();
|
| 280 |
$the_time = current_time('timestamp');
|
| 283 |
}
|
| 284 |
$this->conf->save_options();
|
| 285 |
}
|
| 286 |
+
|
| 287 |
/**
|
| 288 |
* Perform various database maintenance tasks on the plugin's tables.
|
| 289 |
+
*
|
| 290 |
* Removes records that reference disabled containers and parsers,
|
| 291 |
* deletes invalid instances and links, optimizes tables, etc.
|
| 292 |
+
*
|
| 293 |
* @return void
|
| 294 |
*/
|
| 295 |
function database_maintenance(){
|
| 296 |
blcContainerHelper::cleanup_containers();
|
| 297 |
blc_cleanup_instances();
|
| 298 |
blc_cleanup_links();
|
| 299 |
+
|
| 300 |
blcUtility::optimize_database();
|
| 301 |
}
|
| 302 |
|
| 303 |
/**
|
| 304 |
* Create the plugin's menu items and enqueue their scripts and CSS.
|
| 305 |
+
* Callback for the 'admin_menu' action.
|
| 306 |
+
*
|
| 307 |
* @return void
|
| 308 |
*/
|
| 309 |
function admin_menu(){
|
| 310 |
if (current_user_can('manage_options'))
|
| 311 |
add_filter('plugin_action_links', array($this, 'plugin_action_links'), 10, 2);
|
| 312 |
+
|
| 313 |
+
$options_page_hook = add_options_page(
|
| 314 |
+
__('Link Checker Settings', 'broken-link-checker'),
|
| 315 |
+
__('Link Checker', 'broken-link-checker'),
|
| 316 |
'manage_options',
|
| 317 |
'link-checker-settings',array($this, 'options_page')
|
| 318 |
);
|
| 319 |
+
|
| 320 |
$menu_title = __('Broken Links', 'broken-link-checker');
|
| 321 |
if ( $this->conf->options['show_link_count_bubble'] ){
|
| 322 |
+
//To make it easier to notice when broken links appear, display the current number of
|
| 323 |
+
//broken links in a little bubble notification in the "Broken Links" menu.
|
| 324 |
//(Similar to how the number of plugin updates and unmoderated comments is displayed).
|
| 325 |
$blc_link_query = blcLinkQuery::getInstance();
|
| 326 |
$broken_links = $blc_link_query->get_filter_links('broken', array('count_only' => true));
|
| 327 |
if ( $broken_links > 0 ){
|
| 328 |
+
//TODO: Appropriating existing CSS classes for my own purposes is hacky. Fix eventually.
|
| 329 |
$menu_title .= sprintf(
|
| 330 |
+
' <span class="update-plugins"><span class="update-count blc-menu-bubble">%d</span></span>',
|
| 331 |
$broken_links
|
| 332 |
);
|
| 333 |
}
|
| 334 |
+
}
|
| 335 |
$links_page_hook = add_management_page(
|
| 336 |
+
__('View Broken Links', 'broken-link-checker'),
|
| 337 |
+
$menu_title,
|
| 338 |
'edit_others_posts',
|
| 339 |
'view-broken-links',array($this, 'links_page')
|
| 340 |
);
|
| 341 |
+
|
| 342 |
//Add plugin-specific scripts and CSS only to the it's own pages
|
| 343 |
add_action( 'admin_print_styles-' . $options_page_hook, array($this, 'options_page_css') );
|
| 344 |
add_action( 'admin_print_styles-' . $links_page_hook, array($this, 'links_page_css') );
|
| 345 |
add_action( 'admin_print_scripts-' . $options_page_hook, array($this, 'enqueue_settings_scripts') );
|
| 346 |
add_action( 'admin_print_scripts-' . $links_page_hook, array($this, 'enqueue_link_page_scripts') );
|
| 347 |
+
|
| 348 |
//Make the Settings page link to the link list
|
| 349 |
add_screen_meta_link(
|
| 350 |
'blc-links-page-link',
|
| 354 |
array('style' => 'font-weight: bold;')
|
| 355 |
);
|
| 356 |
}
|
| 357 |
+
|
| 358 |
/**
|
| 359 |
* plugin_action_links()
|
| 360 |
* Handler for the 'plugin_action_links' hook. Adds a "Settings" link to this plugin's entry
|
| 387 |
|
| 388 |
if (isset($_POST['recheck']) && !empty($_POST['recheck']) ){
|
| 389 |
$this->initiate_recheck();
|
| 390 |
+
|
| 391 |
//Redirect back to the settings page
|
| 392 |
$base_url = remove_query_arg( array('_wpnonce', 'noheader', 'updated', 'error', 'action', 'message') );
|
| 393 |
wp_redirect( add_query_arg( array( 'recheck-initiated' => true), $base_url ) );
|
| 402 |
'blc-recheck-action' => __('Recheck', 'broken-link-checker'),
|
| 403 |
'blc-deredirect-action' => _x('Fix redirect', 'link action; replace one redirect with a direct link', 'broken-link-checker')
|
| 404 |
);
|
| 405 |
+
|
| 406 |
if(isset($_POST['submit'])) {
|
| 407 |
check_admin_referer('link-checker-options');
|
| 408 |
|
| 410 |
if ( function_exists('wp_magic_quotes') ){
|
| 411 |
$cleanPost = stripslashes_deep($cleanPost); //Ceterum censeo, WP shouldn't mangle superglobals.
|
| 412 |
}
|
| 413 |
+
|
| 414 |
//Activate/deactivate modules
|
| 415 |
if ( !empty($_POST['module']) ){
|
| 416 |
$active = array_keys($_POST['module']);
|
| 417 |
$moduleManager->set_active_modules($active);
|
| 418 |
}
|
| 419 |
+
|
| 420 |
//Only post statuses that actually exist can be selected
|
| 421 |
if ( isset($_POST['enabled_post_statuses']) && is_array($_POST['enabled_post_statuses']) ){
|
| 422 |
$available_statuses = get_post_stati();
|
| 423 |
+
$enabled_post_statuses = array_intersect($_POST['enabled_post_statuses'], $available_statuses);
|
| 424 |
} else {
|
| 425 |
$enabled_post_statuses = array();
|
| 426 |
}
|
| 447 |
if( $new_check_threshold > 0 ){
|
| 448 |
$this->conf->options['check_threshold'] = $new_check_threshold;
|
| 449 |
}
|
| 450 |
+
|
| 451 |
$this->conf->options['mark_broken_links'] = !empty($_POST['mark_broken_links']);
|
| 452 |
$new_broken_link_css = trim($cleanPost['broken_link_css']);
|
| 453 |
$this->conf->options['broken_link_css'] = $new_broken_link_css;
|
| 454 |
+
|
| 455 |
$this->conf->options['mark_removed_links'] = !empty($_POST['mark_removed_links']);
|
| 456 |
$new_removed_link_css = trim($cleanPost['removed_link_css']);
|
| 457 |
$this->conf->options['removed_link_css'] = $new_removed_link_css;
|
| 458 |
+
|
| 459 |
$this->conf->options['nofollow_broken_links'] = !empty($_POST['nofollow_broken_links']);
|
| 460 |
+
|
| 461 |
$this->conf->options['suggestions_enabled'] = !empty($_POST['suggestions_enabled']);
|
| 462 |
|
| 463 |
$this->conf->options['exclusion_list'] = array_filter(
|
| 464 |
+
preg_split(
|
| 465 |
+
'/[\s\r\n]+/', //split on newlines and whitespace
|
| 466 |
$cleanPost['exclusion_list'],
|
| 467 |
-1,
|
| 468 |
PREG_SPLIT_NO_EMPTY //skip empty values
|
| 469 |
+
)
|
| 470 |
);
|
| 471 |
+
|
| 472 |
//Parse the custom field list
|
| 473 |
$new_custom_fields = array_filter(
|
| 474 |
preg_split( '/[\r\n]+/', $cleanPost['blc_custom_fields'], -1, PREG_SPLIT_NO_EMPTY )
|
| 479 |
$diff2 = array_diff( $this->conf->options['custom_fields'], $new_custom_fields );
|
| 480 |
$this->conf->options['custom_fields'] = $new_custom_fields;
|
| 481 |
|
| 482 |
+
//Parse the custom field list
|
| 483 |
+
$new_acf_fields = array_filter(preg_split('/[\r\n]+/', $cleanPost['blc_acf_fields'], -1, PREG_SPLIT_NO_EMPTY));
|
| 484 |
+
|
| 485 |
+
//Calculate the difference between the old custom field list and the new one (used later)
|
| 486 |
+
$acf_fields_diff1 = array_diff($new_acf_fields, $this->conf->options['acf_fields']);
|
| 487 |
+
$acf_fields_diff2 = array_diff($this->conf->options['acf_fields'], $new_acf_fields);
|
| 488 |
+
$this->conf->options['acf_fields'] = $new_acf_fields;
|
| 489 |
+
|
| 490 |
+
//Turning off warnings turns existing warnings into "broken" links.
|
| 491 |
$warnings_enabled = !empty($_POST['warnings_enabled']);
|
| 492 |
if ( $this->conf->get('warnings_enabled') && !$warnings_enabled ) {
|
| 493 |
$this->promote_warnings_to_broken();
|
| 499 |
if( $new_timeout > 0 ){
|
| 500 |
$this->conf->options['timeout'] = $new_timeout ;
|
| 501 |
}
|
| 502 |
+
|
| 503 |
+
//Server load limit
|
| 504 |
if ( isset($_POST['server_load_limit']) ){
|
| 505 |
$this->conf->options['server_load_limit'] = floatval($_POST['server_load_limit']);
|
| 506 |
if ( $this->conf->options['server_load_limit'] < 0 ){
|
| 507 |
$this->conf->options['server_load_limit'] = 0;
|
| 508 |
}
|
| 509 |
+
|
| 510 |
$this->conf->options['enable_load_limit'] = $this->conf->options['server_load_limit'] > 0;
|
| 511 |
}
|
| 512 |
|
| 516 |
$usage = max(min($usage / 100, 1), 0.01);
|
| 517 |
$this->conf->options['target_resource_usage'] = $usage;
|
| 518 |
}
|
| 519 |
+
|
| 520 |
//When to run the checker
|
| 521 |
$this->conf->options['run_in_dashboard'] = !empty($_POST['run_in_dashboard']);
|
| 522 |
$this->conf->options['run_via_cron'] = !empty($_POST['run_via_cron']);
|
| 523 |
+
|
| 524 |
//Email notifications on/off
|
| 525 |
$email_notifications = !empty($_POST['send_email_notifications']);
|
| 526 |
$send_authors_email_notifications = !empty($_POST['send_authors_email_notifications']);
|
| 594 |
|
| 595 |
//Make settings that affect our Cron events take effect immediately
|
| 596 |
$this->setup_cron_events();
|
| 597 |
+
|
| 598 |
$this->conf->save_options();
|
| 599 |
+
|
| 600 |
/*
|
| 601 |
If the list of custom fields was modified then we MUST resynchronize or
|
| 602 |
custom fields linked with existing posts may not be detected. This is somewhat
|
| 603 |
+
inefficient.
|
| 604 |
*/
|
| 605 |
if ( ( count($diff1) > 0 ) || ( count($diff2) > 0 ) ){
|
| 606 |
$manager = blcContainerHelper::get_manager('custom_field');
|
| 610 |
}
|
| 611 |
}
|
| 612 |
|
| 613 |
+
/*
|
| 614 |
+
If the list of acf fields was modified then we MUST resynchronize or
|
| 615 |
+
acf fields linked with existing posts may not be detected. This is somewhat
|
| 616 |
+
inefficient.
|
| 617 |
+
*/
|
| 618 |
+
if ( ( count($acf_fields_diff1) > 0 ) || ( count($acf_fields_diff2) > 0 ) ){
|
| 619 |
+
$manager = blcContainerHelper::get_manager('acf_field');
|
| 620 |
+
if ( !is_null($manager) ){
|
| 621 |
+
$manager->resynch();
|
| 622 |
+
blc_got_unsynched_items();
|
| 623 |
+
}
|
| 624 |
+
}
|
| 625 |
+
|
| 626 |
//Resynchronize posts when the user enables or disables post statuses.
|
| 627 |
if ( $post_statuses_changed ) {
|
| 628 |
$overlord = blcPostTypeOverlord::getInstance();
|
| 633 |
blc_cleanup_instances();
|
| 634 |
blc_cleanup_links();
|
| 635 |
}
|
| 636 |
+
|
| 637 |
//Redirect back to the settings page
|
| 638 |
$base_url = remove_query_arg( array('_wpnonce', 'noheader', 'updated', 'error', 'action', 'message') );
|
| 639 |
wp_redirect( add_query_arg( array( 'settings-updated' => true), $base_url ) );
|
| 640 |
}
|
| 641 |
+
|
| 642 |
+
//Show a confirmation message when settings are saved.
|
| 643 |
if ( !empty($_GET['settings-updated']) ){
|
| 644 |
echo '<div id="message" class="updated fade"><p><strong>',__('Settings saved.', 'broken-link-checker'), '</strong></p></div>';
|
| 645 |
+
|
| 646 |
}
|
| 647 |
+
|
| 648 |
//Show a thank-you message when a donation is made.
|
| 649 |
if ( !empty($_GET['donated']) ){
|
| 650 |
echo '<div id="message" class="updated fade"><p><strong>',__('Thank you for your donation!', 'broken-link-checker'), '</strong></p></div>';
|
| 651 |
$this->conf->set('user_has_donated', true);
|
| 652 |
$this->conf->save_options();
|
| 653 |
}
|
| 654 |
+
|
| 655 |
+
//Show one when recheck is started, too.
|
| 656 |
if ( !empty($_GET['recheck-initiated']) ){
|
| 657 |
echo '<div id="message" class="updated fade"><p><strong>',
|
| 658 |
+
__('Complete site recheck started.', 'broken-link-checker'), // -- Yoda
|
| 659 |
'</strong></p></div>';
|
| 660 |
}
|
| 661 |
+
|
| 662 |
//Cull invalid and missing modules
|
| 663 |
$moduleManager->validate_active_modules();
|
| 664 |
+
|
| 665 |
$debug = $this->get_debug_info();
|
| 666 |
+
|
| 667 |
add_filter('blc-module-settings-custom_field', array($this, 'make_custom_field_input'), 10, 2);
|
| 668 |
+
add_filter('blc-module-settings-acf_field', array($this, 'make_acf_field_input'), 10, 2);
|
| 669 |
//Translate and markup-ify module headers for display
|
| 670 |
$modules = $moduleManager->get_modules_by_category('', true, true);
|
| 671 |
+
|
| 672 |
//Output the custom broken link/removed link styles for example links
|
| 673 |
printf(
|
| 674 |
+
'<style type="text/css">%s %s</style>',
|
| 675 |
$this->conf->options['broken_link_css'],
|
| 676 |
$this->conf->options['removed_link_css']
|
| 677 |
);
|
| 678 |
+
|
| 679 |
$section_names = array(
|
| 680 |
'general' => __('General', 'broken-link-checker'),
|
| 681 |
'where' => __('Look For Links In', 'broken-link-checker'),
|
| 684 |
'advanced' => __('Advanced', 'broken-link-checker'),
|
| 685 |
);
|
| 686 |
?>
|
| 687 |
+
|
| 688 |
<!--[if lte IE 7]>
|
| 689 |
<style type="text/css">
|
| 690 |
/* Simulate inline-block in IE7 */
|
| 691 |
ul.ui-tabs-nav li {
|
| 692 |
+
display: inline;
|
| 693 |
zoom: 1;
|
| 694 |
}
|
| 695 |
</style>
|
| 696 |
<![endif]-->
|
| 697 |
+
|
| 698 |
<div class="wrap" id="blc-settings-wrap">
|
| 699 |
<h2><?php _e('Broken Link Checker Options', 'broken-link-checker'); ?></h2>
|
| 700 |
+
|
| 701 |
+
|
| 702 |
<div id="blc-sidebar">
|
| 703 |
<div class="metabox-holder">
|
| 704 |
<?php include BLC_DIRECTORY . '/includes/admin/sidebar.php'; ?>
|
| 705 |
</div>
|
| 706 |
</div>
|
| 707 |
+
|
| 708 |
+
|
| 709 |
<div id="blc-admin-content">
|
| 710 |
+
|
| 711 |
+
<form name="link_checker_options" id="link_checker_options" method="post" action="<?php
|
| 712 |
+
echo admin_url('options-general.php?page=link-checker-settings&noheader=1');
|
| 713 |
?>">
|
| 714 |
+
<?php
|
| 715 |
wp_nonce_field('link-checker-options');
|
| 716 |
?>
|
| 717 |
+
|
| 718 |
<div id="blc-tabs">
|
| 719 |
+
|
| 720 |
<ul class="hide-if-no-js">
|
| 721 |
<?php
|
| 722 |
foreach($section_names as $section_id => $section_name){
|
| 723 |
printf(
|
| 724 |
'<li id="tab-button-%s"><a href="#section-%s" title="%s">%s</a></li>',
|
|
|
|
| 725 |
esc_attr($section_id),
|
| 726 |
+
esc_attr($section_id),
|
| 727 |
+
esc_attr($section_name),
|
| 728 |
$section_name
|
| 729 |
+
);
|
| 730 |
}
|
| 731 |
?>
|
| 732 |
</ul>
|
| 733 |
|
| 734 |
<div id="section-general" class="blc-section">
|
| 735 |
<h3 class="hide-if-js"><?php echo $section_names['general']; ?></h3>
|
| 736 |
+
|
| 737 |
<table class="form-table">
|
| 738 |
|
| 739 |
<tr valign="top">
|
| 747 |
<div id='wsblc_full_status'>
|
| 748 |
<br/><br/><br/>
|
| 749 |
</div>
|
| 750 |
+
|
| 751 |
<table id="blc-debug-info">
|
| 752 |
<?php
|
| 753 |
+
|
| 754 |
//Output the debug info in a table
|
| 755 |
foreach( $debug as $key => $value ){
|
| 756 |
printf (
|
| 757 |
'<tr valign="top" class="blc-debug-item-%s"><th scope="row">%s</th><td>%s<div class="blc-debug-message">%s</div></td></tr>',
|
| 758 |
$value['state'],
|
| 759 |
$key,
|
| 760 |
+
$value['value'],
|
| 761 |
( array_key_exists('message', $value)?$value['message']:'')
|
| 762 |
);
|
| 763 |
}
|
| 764 |
?>
|
| 765 |
</table>
|
| 766 |
+
|
| 767 |
</td>
|
| 768 |
</tr>
|
| 769 |
|
| 772 |
<td>
|
| 773 |
|
| 774 |
<?php
|
| 775 |
+
printf(
|
| 776 |
__('Every %s hours','broken-link-checker'),
|
| 777 |
sprintf(
|
| 778 |
'<input type="text" name="check_threshold" id="check_threshold" value="%d" size="5" maxlength="5" />',
|
| 779 |
$this->conf->options['check_threshold']
|
| 780 |
)
|
| 781 |
+
);
|
| 782 |
?>
|
| 783 |
<br/>
|
| 784 |
<span class="description">
|
| 787 |
|
| 788 |
</td>
|
| 789 |
</tr>
|
| 790 |
+
|
| 791 |
<tr valign="top">
|
| 792 |
<th scope="row"><?php _e('E-mail notifications', 'broken-link-checker'); ?></th>
|
| 793 |
<td>
|
| 842 |
_e('Edit CSS', 'broken-link-checker');
|
| 843 |
?></a>
|
| 844 |
</p>
|
| 845 |
+
|
| 846 |
+
<div id="broken-link-css-wrap"<?php
|
| 847 |
if ( !blcUtility::get_cookie('broken-link-css-wrap', false) ){
|
| 848 |
echo ' class="hidden"';
|
| 849 |
+
}
|
| 850 |
?>>
|
| 851 |
<textarea name="broken_link_css" id="broken_link_css" cols='45' rows='4'><?php
|
| 852 |
if( isset($this->conf->options['broken_link_css']) ) {
|
| 861 |
echo ' ', __('Click "Save Changes" to update example output.', 'broken-link-checker');
|
| 862 |
?></p>
|
| 863 |
</div>
|
| 864 |
+
|
| 865 |
<p style="margin-bottom: 0.5em;">
|
| 866 |
<label for='mark_removed_links'>
|
| 867 |
<input type="checkbox" name="mark_removed_links" id="mark_removed_links"
|
| 873 |
_e('Edit CSS', 'broken-link-checker');
|
| 874 |
?></a>
|
| 875 |
</p>
|
| 876 |
+
|
| 877 |
+
<div id="removed-link-css-wrap" <?php
|
| 878 |
if ( !blcUtility::get_cookie('removed-link-css-wrap', false) ){
|
| 879 |
echo ' class="hidden"';
|
| 880 |
+
}
|
| 881 |
?>>
|
| 882 |
<textarea name="removed_link_css" id="removed_link_css" cols='45' rows='4'><?php
|
| 883 |
if( isset($this->conf->options['removed_link_css']) )
|
| 884 |
echo $this->conf->options['removed_link_css'];
|
| 885 |
?></textarea>
|
| 886 |
+
|
| 887 |
<p class="description"><?php
|
| 888 |
printf(
|
| 889 |
__('Example : Lorem ipsum <span %s>removed link</span>, dolor sit amet.', 'broken-link-checker'),
|
| 894 |
|
| 895 |
</p>
|
| 896 |
</div>
|
| 897 |
+
|
| 898 |
<p>
|
| 899 |
<label for='nofollow_broken_links'>
|
| 900 |
<input type="checkbox" name="nofollow_broken_links" id="nofollow_broken_links"
|
| 941 |
</tr>
|
| 942 |
|
| 943 |
</table>
|
| 944 |
+
|
| 945 |
</div>
|
| 946 |
+
|
| 947 |
<div id="section-where" class="blc-section">
|
| 948 |
<h3 class="hide-if-js"><?php echo $section_names['where']; ?></h3>
|
| 949 |
+
|
| 950 |
<table class="form-table">
|
| 951 |
+
|
| 952 |
<tr valign="top">
|
| 953 |
<th scope="row"><?php _e('Look for links in', 'broken-link-checker'); ?></th>
|
| 954 |
<td>
|
| 956 |
if ( !empty($modules['container']) ){
|
| 957 |
uasort($modules['container'], create_function('$a, $b', 'return strcasecmp($a["Name"], $b["Name"]);'));
|
| 958 |
$this->print_module_list($modules['container'], $this->conf->options);
|
| 959 |
+
}
|
| 960 |
?>
|
| 961 |
</td></tr>
|
| 962 |
+
|
| 963 |
<tr valign="top">
|
| 964 |
<th scope="row"><?php _e('Post statuses', 'broken-link-checker'); ?></th>
|
| 965 |
<td>
|
| 966 |
<?php
|
| 967 |
$available_statuses = get_post_stati(array('internal' => false), 'objects');
|
| 968 |
+
|
| 969 |
if ( isset($this->conf->options['enabled_post_statuses']) ){
|
| 970 |
$enabled_post_statuses = $this->conf->options['enabled_post_statuses'];
|
| 971 |
} else {
|
| 972 |
$enabled_post_statuses = array();
|
| 973 |
}
|
| 974 |
+
|
| 975 |
foreach($available_statuses as $status => $status_object){
|
| 976 |
printf(
|
| 977 |
'<p><label><input type="checkbox" name="enabled_post_statuses[]" value="%s"%s> %s</label></p>',
|
| 982 |
}
|
| 983 |
?>
|
| 984 |
</td></tr>
|
| 985 |
+
|
| 986 |
</table>
|
| 987 |
+
|
| 988 |
</div>
|
| 989 |
+
|
| 990 |
+
|
| 991 |
<div id="section-which" class="blc-section">
|
| 992 |
<h3 class="hide-if-js"><?php echo $section_names['which']; ?></h3>
|
| 993 |
+
|
| 994 |
<table class="form-table">
|
| 995 |
+
|
| 996 |
<tr valign="top">
|
| 997 |
<th scope="row"><?php _e('Link types', 'broken-link-checker'); ?></th>
|
| 998 |
<td>
|
| 1005 |
?>
|
| 1006 |
</td>
|
| 1007 |
</tr>
|
| 1008 |
+
|
| 1009 |
<tr valign="top">
|
| 1010 |
<th scope="row"><?php _e('Exclusion list', 'broken-link-checker'); ?></th>
|
| 1011 |
<td><?php _e("Don't check links where the URL contains any of these words (one per line) :", 'broken-link-checker'); ?><br/>
|
| 1016 |
|
| 1017 |
</td>
|
| 1018 |
</tr>
|
| 1019 |
+
|
| 1020 |
</table>
|
| 1021 |
</div>
|
| 1022 |
+
|
| 1023 |
<div id="section-how" class="blc-section">
|
| 1024 |
<h3 class="hide-if-js"><?php echo $section_names['how']; ?></h3>
|
| 1025 |
+
|
| 1026 |
<table class="form-table">
|
| 1027 |
+
|
| 1028 |
<tr valign="top">
|
| 1029 |
<th scope="row"><?php _e('Check links using', 'broken-link-checker'); ?></th>
|
| 1030 |
<td>
|
| 1035 |
}
|
| 1036 |
?>
|
| 1037 |
</td></tr>
|
| 1038 |
+
|
| 1039 |
</table>
|
| 1040 |
</div>
|
| 1041 |
+
|
| 1042 |
<div id="section-advanced" class="blc-section">
|
| 1043 |
<h3 class="hide-if-js"><?php echo $section_names['advanced']; ?></h3>
|
| 1044 |
+
|
| 1045 |
<table class="form-table">
|
| 1046 |
+
|
| 1047 |
<tr valign="top">
|
| 1048 |
<th scope="row"><?php _e('Timeout', 'broken-link-checker'); ?></th>
|
| 1049 |
<td>
|
| 1050 |
|
| 1051 |
<?php
|
| 1052 |
+
|
| 1053 |
printf(
|
| 1054 |
__('%s seconds', 'broken-link-checker'),
|
| 1055 |
sprintf(
|
| 1056 |
+
'<input type="text" name="timeout" id="blc_timeout" value="%d" size="5" maxlength="3" />',
|
| 1057 |
$this->conf->options['timeout']
|
| 1058 |
)
|
| 1059 |
);
|
| 1060 |
+
|
| 1061 |
?>
|
| 1062 |
<br/><span class="description">
|
| 1063 |
+
<?php _e('Links that take longer than this to load will be marked as broken.','broken-link-checker'); ?>
|
| 1064 |
</span>
|
| 1065 |
|
| 1066 |
</td>
|
| 1067 |
</tr>
|
| 1068 |
+
|
| 1069 |
<tr valign="top">
|
| 1070 |
<th scope="row"><?php _e('Link monitor', 'broken-link-checker'); ?></th>
|
| 1071 |
<td>
|
| 1072 |
+
|
| 1073 |
<p>
|
| 1074 |
<label for='run_in_dashboard'>
|
| 1075 |
+
|
| 1076 |
<input type="checkbox" name="run_in_dashboard" id="run_in_dashboard"
|
| 1077 |
<?php if ($this->conf->options['run_in_dashboard']) echo ' checked="checked"'; ?>/>
|
| 1078 |
<?php _e('Run continuously while the Dashboard is open', 'broken-link-checker'); ?>
|
| 1079 |
</label>
|
| 1080 |
</p>
|
| 1081 |
+
|
| 1082 |
<p>
|
| 1083 |
<label for='run_via_cron'>
|
| 1084 |
<input type="checkbox" name="run_via_cron" id="run_via_cron"
|
| 1085 |
<?php if ($this->conf->options['run_via_cron']) echo ' checked="checked"'; ?>/>
|
| 1086 |
<?php _e('Run hourly in the background', 'broken-link-checker'); ?>
|
| 1087 |
</label>
|
| 1088 |
+
</p>
|
| 1089 |
|
| 1090 |
</td>
|
| 1091 |
</tr>
|
| 1130 |
?>
|
| 1131 |
</td>
|
| 1132 |
</tr>
|
| 1133 |
+
|
| 1134 |
<tr valign="top">
|
| 1135 |
<th scope="row"><?php _e('Max. execution time', 'broken-link-checker'); ?></th>
|
| 1136 |
<td>
|
| 1137 |
|
| 1138 |
<?php
|
| 1139 |
+
|
| 1140 |
printf(
|
| 1141 |
__('%s seconds', 'broken-link-checker'),
|
| 1142 |
sprintf(
|
| 1143 |
+
'<input type="text" name="max_execution_time" id="max_execution_time" value="%d" size="5" maxlength="5" />',
|
| 1144 |
$this->conf->options['max_execution_time']
|
| 1145 |
)
|
| 1146 |
);
|
| 1147 |
+
|
| 1148 |
+
?>
|
| 1149 |
<br/><span class="description">
|
| 1150 |
<?php
|
| 1151 |
+
|
| 1152 |
_e('The plugin works by periodically launching a background job that parses your posts for links, checks the discovered URLs, and performs other time-consuming tasks. Here you can set for how long, at most, the link monitor may run each time before stopping.', 'broken-link-checker');
|
| 1153 |
+
|
| 1154 |
+
?>
|
| 1155 |
</span>
|
| 1156 |
|
| 1157 |
</td>
|
| 1158 |
</tr>
|
| 1159 |
+
|
| 1160 |
<tr valign="top">
|
| 1161 |
<th scope="row"><?php _e('Server load limit', 'broken-link-checker'); ?></th>
|
| 1162 |
<td>
|
| 1163 |
<?php
|
| 1164 |
+
|
| 1165 |
$load = blcUtility::get_server_load();
|
| 1166 |
$available = !empty($load);
|
| 1167 |
|
| 1171 |
'<input type="text" name="server_load_limit" id="server_load_limit" value="%s" size="5" maxlength="5"/> ',
|
| 1172 |
$value
|
| 1173 |
);
|
| 1174 |
+
|
| 1175 |
printf(
|
| 1176 |
__('Current load : %s', 'broken-link-checker'),
|
| 1177 |
'<span id="wsblc_current_load">...</span>'
|
| 1179 |
echo '<br/><span class="description">';
|
| 1180 |
printf(
|
| 1181 |
__(
|
| 1182 |
+
'Link checking will be suspended if the average <a href="%s">server load</a> rises above this number. Leave this field blank to disable load limiting.',
|
| 1183 |
'broken-link-checker'
|
| 1184 |
),
|
| 1185 |
'http://en.wikipedia.org/wiki/Load_(computing)'
|
| 1186 |
);
|
| 1187 |
echo '</span>';
|
| 1188 |
+
|
| 1189 |
} else {
|
| 1190 |
echo '<input type="text" disabled="disabled" value="', esc_attr(__('Not available', 'broken-link-checker')), '" size="13"/><br>';
|
| 1191 |
echo '<span class="description">';
|
| 1192 |
_e('Load limiting only works on Linux-like systems where <code>/proc/loadavg</code> is present and accessible.', 'broken-link-checker');
|
| 1193 |
echo '</span>';
|
| 1194 |
}
|
| 1195 |
+
?>
|
| 1196 |
</td>
|
| 1197 |
</tr>
|
| 1198 |
|
| 1261 |
</td>
|
| 1262 |
</tr>
|
| 1263 |
|
| 1264 |
+
|
| 1265 |
<tr valign="top">
|
| 1266 |
<th scope="row"><?php _e('Forced recheck', 'broken-link-checker'); ?></th>
|
| 1267 |
<td>
|
| 1268 |
+
<input class="button" type="button" name="start-recheck" id="start-recheck"
|
| 1269 |
value="<?php _e('Re-check all pages', 'broken-link-checker'); ?>" />
|
| 1270 |
<input type="hidden" name="recheck" value="" id="recheck" />
|
| 1271 |
<br />
|
| 1272 |
<span class="description"><?php
|
| 1273 |
_e('The "Nuclear Option". Click this button to make the plugin empty its link database and recheck the entire site from scratch.', 'broken-link-checker');
|
| 1274 |
+
|
| 1275 |
?></span>
|
| 1276 |
</td>
|
| 1277 |
</tr>
|
| 1278 |
+
|
| 1279 |
</table>
|
| 1280 |
</div>
|
| 1281 |
+
|
| 1282 |
</div>
|
| 1283 |
+
|
| 1284 |
<p class="submit"><input type="submit" name="submit" class='button-primary' value="<?php _e('Save Changes') ?>" /></p>
|
| 1285 |
</form>
|
| 1286 |
+
|
| 1287 |
</div> <!-- First postbox-container -->
|
| 1288 |
+
|
| 1289 |
+
|
| 1290 |
</div>
|
| 1291 |
+
|
| 1292 |
+
|
| 1293 |
+
|
| 1294 |
<?php
|
| 1295 |
//The various JS for this page is stored in a separate file for the purposes readability.
|
| 1296 |
include dirname($this->loader) . '/includes/admin/options-page-js.php';
|
| 1297 |
}
|
| 1298 |
+
|
| 1299 |
/**
|
| 1300 |
* Output a list of modules and their settings.
|
| 1301 |
+
*
|
| 1302 |
+
* Each list entry will contain a checkbox that is checked if the module is
|
| 1303 |
+
* currently active.
|
| 1304 |
+
*
|
| 1305 |
* @param array $modules Array of modules to display
|
| 1306 |
* @param array $current_settings
|
| 1307 |
* @return void
|
| 1308 |
*/
|
| 1309 |
function print_module_list($modules, $current_settings){
|
| 1310 |
$moduleManager = blcModuleManager::getInstance();
|
| 1311 |
+
|
| 1312 |
foreach($modules as $module_id => $module_data){
|
| 1313 |
$module_id = $module_data['ModuleID'];
|
| 1314 |
+
|
| 1315 |
$style = $module_data['ModuleHidden']?' style="display:none;"':'';
|
| 1316 |
+
|
| 1317 |
printf(
|
| 1318 |
'<div class="module-container" id="module-container-%s"%s>',
|
| 1319 |
$module_id,
|
| 1320 |
$style
|
| 1321 |
);
|
| 1322 |
$this->print_module_checkbox($module_id, $module_data, $moduleManager->is_active($module_id));
|
| 1323 |
+
|
| 1324 |
$extra_settings = apply_filters(
|
| 1325 |
'blc-module-settings-'.$module_id,
|
| 1326 |
'',
|
| 1327 |
$current_settings
|
| 1328 |
);
|
| 1329 |
+
|
| 1330 |
if ( !empty($extra_settings) ){
|
| 1331 |
+
|
| 1332 |
printf(
|
| 1333 |
' | <a class="blc-toggle-link toggle-module-settings" id="toggle-module-settings-%s" href="#">%s</a>',
|
| 1334 |
esc_attr($module_id),
|
| 1335 |
__('Configure', 'broken-link-checker')
|
| 1336 |
);
|
| 1337 |
+
|
| 1338 |
//The plugin remembers the last open/closed state of module configuration boxes
|
| 1339 |
+
$box_id = 'module-extra-settings-' . $module_id;
|
| 1340 |
$show = blcUtility::get_cookie(
|
| 1341 |
$box_id,
|
| 1342 |
$moduleManager->is_active($module_id)
|
| 1343 |
);
|
| 1344 |
+
|
| 1345 |
printf(
|
| 1346 |
'<div class="module-extra-settings%s" id="%s">%s</div>',
|
| 1347 |
$show?'':' hidden',
|
| 1349 |
$extra_settings
|
| 1350 |
);
|
| 1351 |
}
|
| 1352 |
+
|
| 1353 |
echo '</div>';
|
| 1354 |
}
|
| 1355 |
}
|
| 1356 |
+
|
| 1357 |
/**
|
| 1358 |
* Output a checkbox for a module.
|
| 1359 |
+
*
|
| 1360 |
* Generates a simple checkbox that can be used to mark a module as active/inactive.
|
| 1361 |
* If the specified module can't be deactivated (ModuleAlwaysActive = true), the checkbox
|
| 1362 |
* will be displayed in a disabled state and a hidden field will be created to make
|
| 1363 |
* form submissions work correctly.
|
| 1364 |
+
*
|
| 1365 |
* @param string $module_id Module ID.
|
| 1366 |
* @param array $module_data Associative array of module data.
|
| 1367 |
* @param bool $active If true, the newly created checkbox will start out checked.
|
| 1372 |
$name_prefix = 'module';
|
| 1373 |
$label_class = '';
|
| 1374 |
$active = $active || $module_data['ModuleAlwaysActive'];
|
| 1375 |
+
|
| 1376 |
if ( $module_data['ModuleAlwaysActive'] ){
|
| 1377 |
$disabled = true;
|
| 1378 |
$name_prefix = 'module-always-active';
|
| 1379 |
}
|
| 1380 |
+
|
| 1381 |
$checked = $active ? ' checked="checked"':'';
|
| 1382 |
if ( $disabled ){
|
| 1383 |
$checked .= ' disabled="disabled"';
|
| 1384 |
}
|
| 1385 |
+
|
| 1386 |
printf(
|
| 1387 |
'<label class="%s">
|
| 1388 |
<input type="checkbox" name="%s[%s]" id="module-checkbox-%s"%s /> %s
|
| 1394 |
$checked,
|
| 1395 |
$module_data['Name']
|
| 1396 |
);
|
| 1397 |
+
|
| 1398 |
if ( $module_data['ModuleAlwaysActive'] ){
|
| 1399 |
printf(
|
| 1400 |
'<input type="hidden" name="module[%s]" value="on">',
|
| 1402 |
);
|
| 1403 |
}
|
| 1404 |
}
|
| 1405 |
+
|
| 1406 |
/**
|
| 1407 |
* Add extra settings to the "Custom fields" entry on the plugin's config. page.
|
| 1408 |
+
*
|
| 1409 |
+
* Callback for the 'blc-module-settings-custom_field' filter.
|
| 1410 |
+
*
|
| 1411 |
* @param string $html Current extra HTML
|
| 1412 |
* @param array $current_settings The current plugin configuration.
|
| 1413 |
* @return string New extra HTML.
|
| 1420 |
) .
|
| 1421 |
'</span>';
|
| 1422 |
$html .= '<br><textarea name="blc_custom_fields" id="blc_custom_fields" cols="45" rows="4">';
|
| 1423 |
+
if( isset($current_settings['custom_fields']) ){
|
| 1424 |
$html .= esc_textarea(implode("\n", $current_settings['custom_fields']));
|
| 1425 |
+
}
|
| 1426 |
$html .= '</textarea>';
|
| 1427 |
+
|
| 1428 |
+
return $html;
|
| 1429 |
+
}
|
| 1430 |
+
function make_acf_field_input($html, $current_settings) {
|
| 1431 |
+
$html .= '<span class="description">' . __('Enter the keys of acf fields you want to check (one per line). If a field contains HTML code, prefix its name with <code>html:</code>. For example, <code>html:field_586a3eaa4091b</code>.', 'broken-link-checker') . '</span>';
|
| 1432 |
+
$html .= '<br><textarea name="blc_acf_fields" id="blc_acf_fields" cols="45" rows="4">';
|
| 1433 |
+
if (isset($current_settings['acf_fields'])) {
|
| 1434 |
+
$html .= esc_textarea(implode("\n", $current_settings['acf_fields']));
|
| 1435 |
+
}
|
| 1436 |
+
$html .= '</textarea>';
|
| 1437 |
+
|
| 1438 |
return $html;
|
| 1439 |
}
|
|
|
|
| 1440 |
/**
|
| 1441 |
* Enqueue CSS file for the plugin's Settings page.
|
| 1442 |
+
*
|
| 1443 |
* @return void
|
| 1444 |
*/
|
| 1445 |
function options_page_css(){
|
| 1446 |
wp_enqueue_style('blc-options-page', plugins_url('css/options-page.css', BLC_PLUGIN_FILE), array(), '20141113');
|
| 1447 |
wp_enqueue_style('dashboard');
|
| 1448 |
}
|
| 1449 |
+
|
| 1450 |
|
| 1451 |
/**
|
| 1452 |
* Display the "Broken Links" page, listing links detected by the plugin and their status.
|
| 1453 |
+
*
|
| 1454 |
* @return void
|
| 1455 |
*/
|
| 1456 |
function links_page(){
|
| 1457 |
global $wpdb; /* @var wpdb $wpdb */
|
| 1458 |
+
|
| 1459 |
$blc_link_query = blcLinkQuery::getInstance();
|
| 1460 |
|
| 1461 |
//Cull invalid and missing modules so that we don't get dummy links/instances showing up.
|
| 1462 |
$moduleManager = blcModuleManager::getInstance();
|
| 1463 |
$moduleManager->validate_active_modules();
|
| 1464 |
+
|
| 1465 |
if ( defined('BLC_DEBUG') && constant('BLC_DEBUG') ){
|
| 1466 |
+
//Make module headers translatable. They need to be formatted corrrectly and
|
| 1467 |
//placed in a .php file to be visible to the script(s) that generate .pot files.
|
| 1468 |
$code = $moduleManager->_build_header_translation_code();
|
| 1469 |
file_put_contents( dirname($this->loader) . '/includes/extra-strings.php', $code );
|
| 1470 |
}
|
| 1471 |
+
|
| 1472 |
$action = !empty($_POST['action'])?$_POST['action']:'';
|
| 1473 |
if ( intval($action) == -1 ){
|
| 1474 |
//Try the second bulk actions box
|
| 1475 |
$action = !empty($_POST['action2'])?$_POST['action2']:'';
|
| 1476 |
}
|
| 1477 |
+
|
| 1478 |
//Get the list of link IDs selected via checkboxes
|
| 1479 |
$selected_links = array();
|
| 1480 |
if ( isset($_POST['selected_links']) && is_array($_POST['selected_links']) ){
|
| 1483 |
//Remove all zeroes
|
| 1484 |
$selected_links = array_filter($selected_links);
|
| 1485 |
}
|
| 1486 |
+
|
| 1487 |
$message = '';
|
| 1488 |
$msg_class = 'updated';
|
| 1489 |
+
|
| 1490 |
//Run the selected bulk action, if any
|
| 1491 |
$force_delete = false;
|
| 1492 |
switch ( $action ){
|
| 1493 |
case 'create-custom-filter':
|
| 1494 |
list($message, $msg_class) = $this->do_create_custom_filter();
|
| 1495 |
break;
|
| 1496 |
+
|
| 1497 |
case 'delete-custom-filter':
|
| 1498 |
list($message, $msg_class) = $this->do_delete_custom_filter();
|
| 1499 |
break;
|
| 1504 |
case 'bulk-trash-sources':
|
| 1505 |
list($message, $msg_class) = $this->do_bulk_delete_sources($selected_links, $force_delete);
|
| 1506 |
break;
|
| 1507 |
+
|
| 1508 |
case 'bulk-unlink':
|
| 1509 |
list($message, $msg_class) = $this->do_bulk_unlink($selected_links);
|
| 1510 |
break;
|
| 1511 |
+
|
| 1512 |
case 'bulk-deredirect':
|
| 1513 |
list($message, $msg_class) = $this->do_bulk_deredirect($selected_links);
|
| 1514 |
break;
|
| 1515 |
+
|
| 1516 |
case 'bulk-recheck':
|
| 1517 |
list($message, $msg_class) = $this->do_bulk_recheck($selected_links);
|
| 1518 |
break;
|
| 1519 |
+
|
| 1520 |
case 'bulk-not-broken':
|
| 1521 |
list($message, $msg_class) = $this->do_bulk_discard($selected_links);
|
| 1522 |
break;
|
| 1529 |
list($message, $msg_class) = $this->do_bulk_edit($selected_links);
|
| 1530 |
break;
|
| 1531 |
}
|
| 1532 |
+
|
| 1533 |
+
|
| 1534 |
if ( !empty($message) ){
|
| 1535 |
echo '<div id="message" class="'.$msg_class.' fade"><p>'.$message.'</p></div>';
|
| 1536 |
}
|
| 1537 |
+
|
| 1538 |
$start_time = microtime_float();
|
| 1539 |
+
|
| 1540 |
//Load custom filters, if any
|
| 1541 |
$blc_link_query->load_custom_filters();
|
| 1542 |
+
|
| 1543 |
//Calculate the number of links matching each filter
|
| 1544 |
$blc_link_query->count_filter_results();
|
| 1545 |
+
|
| 1546 |
//Run the selected filter (defaults to displaying broken links)
|
| 1547 |
$selected_filter_id = isset($_GET['filter_id'])?$_GET['filter_id']:'broken';
|
| 1548 |
$current_filter = $blc_link_query->exec_filter(
|
| 1549 |
$selected_filter_id,
|
| 1550 |
isset($_GET['paged']) ? intval($_GET['paged']) : 1,
|
| 1551 |
+
$this->conf->options['table_links_per_page'],
|
| 1552 |
'broken',
|
| 1553 |
isset($_GET['orderby']) ? $_GET['orderby'] : '',
|
| 1554 |
isset($_GET['order']) ? $_GET['order'] : ''
|
| 1557 |
//exec_filter() returns an array with filter data, including the actual filter ID that was used.
|
| 1558 |
$filter_id = $current_filter['filter_id'];
|
| 1559 |
|
| 1560 |
+
//Error?
|
| 1561 |
if ( empty($current_filter['links']) && !empty($wpdb->last_error) ){
|
| 1562 |
printf( __('Database error : %s', 'broken-link-checker'), $wpdb->last_error);
|
| 1563 |
}
|
| 1564 |
?>
|
| 1565 |
+
|
| 1566 |
<script type='text/javascript'>
|
| 1567 |
var blc_current_filter = '<?php echo $filter_id; ?>';
|
| 1568 |
var blc_is_broken_filter = <?php echo $current_filter['is_broken_filter'] ? 'true' : 'false'; ?>;
|
| 1569 |
var blc_current_base_filter = '<?php echo esc_js($current_filter['base_filter']); ?>';
|
| 1570 |
var blc_suggestions_enabled = <?php echo $this->conf->options['suggestions_enabled'] ? 'true' : 'false'; ?>;
|
| 1571 |
</script>
|
| 1572 |
+
|
| 1573 |
<div class="wrap">
|
| 1574 |
<?php
|
| 1575 |
$blc_link_query->print_filter_heading($current_filter);
|
| 1576 |
$blc_link_query->print_filter_menu($filter_id);
|
| 1577 |
+
|
| 1578 |
//Display the "Search" form and associated buttons.
|
| 1579 |
//The form requires the $filter_id and $current_filter variables to be set.
|
| 1580 |
include dirname($this->loader) . '/includes/admin/search-form.php';
|
| 1581 |
+
|
| 1582 |
+
//If the user has decided to switch the table to a different mode (compact/full),
|
| 1583 |
//save the new setting.
|
| 1584 |
if ( isset($_GET['compact']) ){
|
| 1585 |
$this->conf->options['table_compact'] = (bool)$_GET['compact'];
|
| 1588 |
|
| 1589 |
//Display the links, if any
|
| 1590 |
if( $current_filter['links'] && ( count($current_filter['links']) > 0 ) ) {
|
| 1591 |
+
|
| 1592 |
include dirname($this->loader) . '/includes/admin/table-printer.php';
|
| 1593 |
$table = new blcTablePrinter($this);
|
| 1594 |
$table->print_table(
|
| 1595 |
$current_filter,
|
| 1596 |
+
$this->conf->options['table_layout'],
|
| 1597 |
$this->conf->options['table_visible_columns'],
|
| 1598 |
$this->conf->options['table_compact']
|
| 1599 |
);
|
| 1600 |
|
| 1601 |
};
|
| 1602 |
+
printf('<!-- Total elapsed : %.4f seconds -->', microtime_float() - $start_time);
|
| 1603 |
+
|
| 1604 |
//Load assorted JS event handlers and other shinies
|
| 1605 |
include dirname($this->loader) . '/includes/admin/links-page-js.php';
|
| 1606 |
+
|
| 1607 |
?></div><?php
|
| 1608 |
}
|
| 1609 |
+
|
| 1610 |
/**
|
| 1611 |
* Create a custom link filter using params passed in $_POST.
|
| 1612 |
*
|
| 1613 |
* @uses $_POST
|
| 1614 |
+
* @uses $_GET to replace the current filter ID (if any) with that of the newly created filter.
|
| 1615 |
*
|
| 1616 |
+
* @return array Message and the CSS class to apply to the message.
|
| 1617 |
*/
|
| 1618 |
function do_create_custom_filter(){
|
| 1619 |
global $wpdb;
|
| 1635 |
$name = strip_tags(strval($_POST['name']));
|
| 1636 |
$blc_link_query = blcLinkQuery::getInstance();
|
| 1637 |
$filter_id = $blc_link_query->create_custom_filter($name, $_POST['params']);
|
| 1638 |
+
|
| 1639 |
if ( $filter_id ){
|
| 1640 |
//Saved
|
| 1641 |
$message = sprintf( __('Filter "%s" created', 'broken-link-checker'), $name);
|
| 1642 |
//A little hack to make the filter active immediately
|
| 1643 |
+
$_GET['filter_id'] = $filter_id;
|
| 1644 |
} else {
|
| 1645 |
//Error
|
| 1646 |
$message = sprintf( __("Database error : %s", 'broken-link-checker'), $wpdb->last_error);
|
| 1647 |
$msg_class = 'error';
|
| 1648 |
}
|
| 1649 |
}
|
| 1650 |
+
|
| 1651 |
return array($message, $msg_class);
|
| 1652 |
}
|
| 1653 |
+
|
| 1654 |
/**
|
| 1655 |
* Delete a custom link filter.
|
| 1656 |
*
|
| 1657 |
* @uses $_POST
|
| 1658 |
*
|
| 1659 |
+
* @return array Message and a CSS class to apply to the message.
|
| 1660 |
*/
|
| 1661 |
function do_delete_custom_filter(){
|
| 1662 |
//Delete an existing custom filter!
|
| 1663 |
check_admin_referer( 'delete-custom-filter' );
|
| 1664 |
$msg_class = 'updated';
|
| 1665 |
+
|
| 1666 |
//Filter ID must be set
|
| 1667 |
if ( empty($_POST['filter_id']) ){
|
| 1668 |
$message = __("Filter ID not specified.", 'broken-link-checker');
|
| 1679 |
$msg_class = 'error';
|
| 1680 |
}
|
| 1681 |
}
|
| 1682 |
+
|
| 1683 |
return array($message, $msg_class);
|
| 1684 |
}
|
| 1685 |
+
|
| 1686 |
/**
|
| 1687 |
* Modify multiple links to point to their target URLs.
|
| 1688 |
*
|
| 1691 |
*/
|
| 1692 |
function do_bulk_deredirect($selected_links){
|
| 1693 |
//For all selected links, replace the URL with the final URL that it redirects to.
|
| 1694 |
+
|
| 1695 |
$message = '';
|
| 1696 |
$msg_class = 'updated';
|
| 1697 |
+
|
| 1698 |
check_admin_referer( 'bulk-action' );
|
| 1699 |
+
|
| 1700 |
+
if ( count($selected_links) > 0 ) {
|
| 1701 |
//Fetch all the selected links
|
| 1702 |
$links = blc_get_links(array(
|
| 1703 |
'link_ids' => $selected_links,
|
| 1704 |
'purpose' => BLC_FOR_EDITING,
|
| 1705 |
));
|
| 1706 |
+
|
| 1707 |
if ( count($links) > 0 ) {
|
| 1708 |
$processed_links = 0;
|
| 1709 |
$failed_links = 0;
|
| 1710 |
+
|
| 1711 |
//Deredirect all selected links
|
| 1712 |
foreach($links as $link){
|
| 1713 |
$rez = $link->deredirect();
|
| 1716 |
} else {
|
| 1717 |
$failed_links++;
|
| 1718 |
}
|
| 1719 |
+
}
|
| 1720 |
+
|
| 1721 |
$message = sprintf(
|
| 1722 |
_n(
|
| 1723 |
'Replaced %d redirect with a direct link',
|
| 1724 |
'Replaced %d redirects with direct links',
|
| 1725 |
+
$processed_links,
|
| 1726 |
'broken-link-checker'
|
| 1727 |
),
|
| 1728 |
$processed_links
|
| 1729 |
+
);
|
| 1730 |
+
|
| 1731 |
if ( $failed_links > 0 ) {
|
| 1732 |
$message .= '<br>' . sprintf(
|
| 1733 |
_n(
|
| 1734 |
+
'Failed to fix %d redirect',
|
| 1735 |
'Failed to fix %d redirects',
|
| 1736 |
$failed_links,
|
| 1737 |
'broken-link-checker'
|
| 1744 |
$message = __('None of the selected links are redirects!', 'broken-link-checker');
|
| 1745 |
}
|
| 1746 |
}
|
| 1747 |
+
|
| 1748 |
return array($message, $msg_class);
|
| 1749 |
}
|
| 1750 |
+
|
| 1751 |
/**
|
| 1752 |
* Edit multiple links in one go.
|
| 1753 |
*
|
| 1757 |
function do_bulk_edit($selected_links){
|
| 1758 |
$message = '';
|
| 1759 |
$msg_class = 'updated';
|
| 1760 |
+
|
| 1761 |
check_admin_referer( 'bulk-action' );
|
| 1762 |
+
|
| 1763 |
$post = $_POST;
|
| 1764 |
if ( function_exists('wp_magic_quotes') ){
|
| 1765 |
$post = stripslashes_deep($post); //Ceterum censeo, WP shouldn't mangle superglobals.
|
| 1766 |
}
|
| 1767 |
+
|
| 1768 |
$search = isset($post['search']) ? $post['search'] : '';
|
| 1769 |
+
$replace = isset($post['replace']) ? $post['replace'] : '';
|
| 1770 |
$use_regex = !empty($post['regex']);
|
| 1771 |
$case_sensitive = !empty($post['case_sensitive']);
|
| 1772 |
+
|
| 1773 |
$delimiter = '`'; //Pick a char that's uncommon in URLs so that escaping won't usually be a problem
|
| 1774 |
if ( $use_regex ){
|
| 1775 |
$search = $delimiter . $this->escape_regex_delimiter($search, $delimiter) . $delimiter;
|
| 1782 |
$search = $delimiter . preg_quote($search, $delimiter) . $delimiter . 'i';
|
| 1783 |
$use_regex = true;
|
| 1784 |
}
|
| 1785 |
+
|
| 1786 |
+
if ( count($selected_links) > 0 ) {
|
| 1787 |
set_time_limit(300); //In case the user decides to edit hundreds of links at once
|
| 1788 |
+
|
| 1789 |
//Fetch all the selected links
|
| 1790 |
$links = blc_get_links(array(
|
| 1791 |
'link_ids' => $selected_links,
|
| 1792 |
'purpose' => BLC_FOR_EDITING,
|
| 1793 |
));
|
| 1794 |
+
|
| 1795 |
if ( count($links) > 0 ) {
|
| 1796 |
$processed_links = 0;
|
| 1797 |
$failed_links = 0;
|
| 1798 |
$skipped_links = 0;
|
| 1799 |
+
|
| 1800 |
//Edit the links
|
| 1801 |
foreach($links as $link){
|
| 1802 |
if ( $use_regex ){
|
| 1804 |
} else {
|
| 1805 |
$new_url = str_replace($search, $replace, $link->url);
|
| 1806 |
}
|
| 1807 |
+
|
| 1808 |
if ( $new_url == $link->url ){
|
| 1809 |
$skipped_links++;
|
| 1810 |
continue;
|
| 1811 |
}
|
| 1812 |
+
|
| 1813 |
$rez = $link->edit($new_url);
|
| 1814 |
if ( !is_wp_error($rez) && empty($rez['errors'] )){
|
| 1815 |
$processed_links++;
|
| 1816 |
} else {
|
| 1817 |
$failed_links++;
|
| 1818 |
}
|
| 1819 |
+
}
|
| 1820 |
+
|
| 1821 |
$message .= sprintf(
|
| 1822 |
_n(
|
| 1823 |
'%d link updated.',
|
| 1824 |
'%d links updated.',
|
| 1825 |
+
$processed_links,
|
| 1826 |
'broken-link-checker'
|
| 1827 |
),
|
| 1828 |
$processed_links
|
| 1829 |
);
|
| 1830 |
+
|
| 1831 |
if ( $failed_links > 0 ) {
|
| 1832 |
$message .= '<br>' . sprintf(
|
| 1833 |
_n(
|
| 1834 |
+
'Failed to update %d link.',
|
| 1835 |
'Failed to update %d links.',
|
| 1836 |
$failed_links,
|
| 1837 |
'broken-link-checker'
|
| 1842 |
}
|
| 1843 |
}
|
| 1844 |
}
|
| 1845 |
+
|
| 1846 |
return array($message, $msg_class);
|
| 1847 |
}
|
| 1848 |
|
| 1880 |
|
| 1881 |
return $output;
|
| 1882 |
}
|
| 1883 |
+
|
| 1884 |
/**
|
| 1885 |
* Unlink multiple links.
|
| 1886 |
*
|
| 1891 |
//Unlink all selected links.
|
| 1892 |
$message = '';
|
| 1893 |
$msg_class = 'updated';
|
| 1894 |
+
|
| 1895 |
check_admin_referer( 'bulk-action' );
|
| 1896 |
+
|
| 1897 |
+
if ( count($selected_links) > 0 ) {
|
| 1898 |
+
|
| 1899 |
//Fetch all the selected links
|
| 1900 |
$links = blc_get_links(array(
|
| 1901 |
'link_ids' => $selected_links,
|
| 1902 |
'purpose' => BLC_FOR_EDITING,
|
| 1903 |
));
|
| 1904 |
+
|
| 1905 |
if ( count($links) > 0 ) {
|
| 1906 |
$processed_links = 0;
|
| 1907 |
$failed_links = 0;
|
| 1908 |
+
|
| 1909 |
//Unlink (delete) each one
|
| 1910 |
foreach($links as $link){
|
| 1911 |
$rez = $link->unlink();
|
| 1914 |
} else {
|
| 1915 |
$processed_links++;
|
| 1916 |
}
|
| 1917 |
+
}
|
| 1918 |
+
|
| 1919 |
+
//This message is slightly misleading - it doesn't account for the fact that
|
| 1920 |
//a link can be present in more than one post.
|
| 1921 |
$message = sprintf(
|
| 1922 |
_n(
|
| 1923 |
'%d link removed',
|
| 1924 |
'%d links removed',
|
| 1925 |
+
$processed_links,
|
| 1926 |
'broken-link-checker'
|
| 1927 |
),
|
| 1928 |
$processed_links
|
| 1929 |
+
);
|
| 1930 |
+
|
| 1931 |
if ( $failed_links > 0 ) {
|
| 1932 |
$message .= '<br>' . sprintf(
|
| 1933 |
_n(
|
| 1934 |
+
'Failed to remove %d link',
|
| 1935 |
'Failed to remove %d links',
|
| 1936 |
$failed_links,
|
| 1937 |
'broken-link-checker'
|
| 1942 |
}
|
| 1943 |
}
|
| 1944 |
}
|
| 1945 |
+
|
| 1946 |
return array($message, $msg_class);
|
| 1947 |
}
|
| 1948 |
+
|
| 1949 |
/**
|
| 1950 |
* Delete or trash posts, bookmarks and other items that contain any of the specified links.
|
| 1951 |
+
*
|
| 1952 |
+
* Will prefer moving stuff to trash to permanent deletion. If it encounters an item that
|
| 1953 |
* can't be moved to the trash, it will skip that item by default.
|
| 1954 |
*
|
| 1955 |
* @param array $selected_links An array of link IDs
|
| 1959 |
function do_bulk_delete_sources($selected_links, $force_delete = false){
|
| 1960 |
$message = '';
|
| 1961 |
$msg_class = 'updated';
|
| 1962 |
+
|
| 1963 |
//Delete posts, blogroll entries and any other link containers that contain any of the selected links.
|
| 1964 |
//
|
| 1965 |
//Note that once all containers containing a particular link have been deleted,
|
| 1966 |
+
//there is no need to explicitly delete the link record itself. The hooks attached to
|
| 1967 |
+
//the actions that execute when something is deleted (e.g. "post_deleted") will
|
| 1968 |
+
//take care of that.
|
| 1969 |
+
|
| 1970 |
check_admin_referer( 'bulk-action' );
|
| 1971 |
+
|
| 1972 |
+
if ( count($selected_links) > 0 ) {
|
| 1973 |
$messages = array();
|
| 1974 |
+
|
| 1975 |
//Fetch all the selected links
|
| 1976 |
$links = blc_get_links(array(
|
| 1977 |
'link_ids' => $selected_links,
|
| 1978 |
'load_instances' => true,
|
| 1979 |
));
|
| 1980 |
+
|
| 1981 |
//Make a list of all containers associated with these links, with each container
|
| 1982 |
//listed only once.
|
| 1983 |
$containers = array();
|
| 1988 |
$containers[$key] = array($instance->container_type, $instance->container_id);
|
| 1989 |
}
|
| 1990 |
}
|
| 1991 |
+
|
| 1992 |
//Instantiate the containers
|
| 1993 |
$containers = blcContainerHelper::get_containers($containers);
|
| 1994 |
|
| 1999 |
if ( !$container->current_user_can_delete() ){
|
| 2000 |
continue;
|
| 2001 |
}
|
| 2002 |
+
|
| 2003 |
if ( $force_delete ){
|
| 2004 |
$rez = $container->delete_wrapped_object();
|
| 2005 |
} else {
|
| 2006 |
if ( $container->can_be_trashed() ){
|
| 2007 |
$rez = $container->trash_wrapped_object();
|
| 2008 |
} else {
|
| 2009 |
+
$skipped[] = $container;
|
| 2010 |
continue;
|
| 2011 |
}
|
| 2012 |
}
|
| 2013 |
+
|
| 2014 |
if ( is_wp_error($rez) ){ /* @var WP_Error $rez */
|
| 2015 |
//Record error messages for later display
|
| 2016 |
$messages[] = $rez->get_error_message();
|
| 2025 |
}
|
| 2026 |
}
|
| 2027 |
}
|
| 2028 |
+
|
| 2029 |
//Generate delete confirmation messages
|
| 2030 |
foreach($deleted as $container_type => $number){
|
| 2031 |
if ( $force_delete ){
|
| 2033 |
} else {
|
| 2034 |
$messages[] = blcContainerHelper::ui_bulk_trash_message($container_type, $number);
|
| 2035 |
}
|
| 2036 |
+
|
| 2037 |
}
|
| 2038 |
+
|
| 2039 |
//If some items couldn't be trashed, let the user know
|
| 2040 |
if ( count($skipped) > 0 ){
|
| 2041 |
$message = sprintf(
|
| 2054 |
);
|
| 2055 |
}
|
| 2056 |
$message .= '</ul>';
|
| 2057 |
+
|
| 2058 |
$messages[] = $message;
|
| 2059 |
}
|
| 2060 |
+
|
| 2061 |
if ( count($messages) > 0 ){
|
| 2062 |
$message = implode('<p>', $messages);
|
| 2063 |
} else {
|
| 2065 |
$msg_class = 'error';
|
| 2066 |
}
|
| 2067 |
}
|
| 2068 |
+
|
| 2069 |
return array($message, $msg_class);
|
| 2070 |
}
|
| 2071 |
+
|
| 2072 |
/**
|
| 2073 |
* Mark multiple links as unchecked.
|
| 2074 |
*
|
| 2078 |
function do_bulk_recheck($selected_links){
|
| 2079 |
/** @var wpdb $wpdb */
|
| 2080 |
global $wpdb;
|
| 2081 |
+
|
| 2082 |
$message = '';
|
| 2083 |
$msg_class = 'updated';
|
| 2084 |
|
| 2085 |
check_admin_referer('bulk-action');
|
| 2086 |
+
|
| 2087 |
if ( count($selected_links) > 0 ){
|
| 2088 |
+
$q = "UPDATE {$wpdb->prefix}blc_links
|
| 2089 |
+
SET last_check_attempt = '0000-00-00 00:00:00'
|
| 2090 |
WHERE link_id IN (".implode(', ', $selected_links).")";
|
| 2091 |
$changes = $wpdb->query($q);
|
| 2092 |
+
|
| 2093 |
$message = sprintf(
|
| 2094 |
_n(
|
| 2095 |
"%d link scheduled for rechecking",
|
| 2096 |
"%d links scheduled for rechecking",
|
| 2097 |
+
$changes,
|
| 2098 |
'broken-link-checker'
|
| 2099 |
),
|
| 2100 |
$changes
|
| 2101 |
);
|
| 2102 |
}
|
| 2103 |
+
|
| 2104 |
return array($message, $msg_class);
|
| 2105 |
}
|
| 2106 |
+
|
| 2107 |
+
|
| 2108 |
/**
|
| 2109 |
* Mark multiple links as not broken.
|
| 2110 |
+
*
|
| 2111 |
* @param array $selected_links An array of link IDs
|
| 2112 |
* @return array Confirmation nessage and the CSS class to use with that message.
|
| 2113 |
*/
|
| 2114 |
function do_bulk_discard($selected_links){
|
| 2115 |
check_admin_referer( 'bulk-action' );
|
| 2116 |
+
|
| 2117 |
$messages = array();
|
| 2118 |
$msg_class = 'updated';
|
| 2119 |
$processed_links = 0;
|
| 2120 |
+
|
| 2121 |
if ( count($selected_links) > 0 ){
|
| 2122 |
foreach($selected_links as $link_id){
|
| 2123 |
//Load the link
|
| 2124 |
$link = new blcLink( intval($link_id) );
|
| 2125 |
+
|
| 2126 |
//Skip links that don't actually exist
|
| 2127 |
if ( !$link->valid() ){
|
| 2128 |
continue;
|
| 2129 |
}
|
| 2130 |
+
|
| 2131 |
//Skip links that weren't actually detected as broken
|
| 2132 |
if ( !$link->broken && !$link->warning ){
|
| 2133 |
continue;
|
| 2134 |
}
|
| 2135 |
+
|
| 2136 |
//Make it appear "not broken"
|
| 2137 |
$link->broken = false;
|
| 2138 |
$link->warning = false;
|
| 2153 |
}
|
| 2154 |
}
|
| 2155 |
}
|
| 2156 |
+
|
| 2157 |
if ( $processed_links > 0 ){
|
| 2158 |
$messages[] = sprintf(
|
| 2159 |
_n(
|
| 2160 |
'%d link marked as not broken',
|
| 2161 |
'%d links marked as not broken',
|
| 2162 |
+
$processed_links,
|
| 2163 |
'broken-link-checker'
|
| 2164 |
),
|
| 2165 |
$processed_links
|
| 2166 |
);
|
| 2167 |
}
|
| 2168 |
+
|
| 2169 |
return array(implode('<br>', $messages), $msg_class);
|
| 2170 |
}
|
| 2171 |
|
| 2227 |
|
| 2228 |
return array(implode('<br>', $messages), $msg_class);
|
| 2229 |
}
|
| 2230 |
+
|
| 2231 |
+
|
| 2232 |
/**
|
| 2233 |
* Enqueue CSS files for the "Broken Links" page
|
| 2234 |
+
*
|
| 2235 |
* @return void
|
| 2236 |
*/
|
| 2237 |
function links_page_css(){
|
| 2290 |
)
|
| 2291 |
);
|
| 2292 |
}
|
| 2293 |
+
|
| 2294 |
/**
|
| 2295 |
* Generate the HTML for the plugin's Screen Options panel.
|
| 2296 |
+
*
|
| 2297 |
* @return string
|
| 2298 |
*/
|
| 2299 |
function screen_options_html(){
|
| 2306 |
$this->conf->save_options();
|
| 2307 |
}
|
| 2308 |
}
|
| 2309 |
+
|
| 2310 |
//Let the user show/hide individual table columns
|
| 2311 |
$html = '<h5>' . __('Table columns', 'broken-link-checker') . '</h5>';
|
| 2312 |
+
|
| 2313 |
include dirname($this->loader) . '/includes/admin/table-printer.php';
|
| 2314 |
$table = new blcTablePrinter($this);
|
| 2315 |
$available_columns = $table->get_layout_columns($this->conf->options['table_layout']);
|
| 2316 |
+
|
| 2317 |
$html .= '<div id="blc-column-selector" class="metabox-prefs">';
|
| 2318 |
+
|
| 2319 |
foreach( $available_columns as $column_id => $data ){
|
| 2320 |
$html .= sprintf(
|
| 2321 |
'<label><input type="checkbox" name="visible_columns[%s]"%s>%s</label>',
|
| 2323 |
in_array($column_id, $this->conf->options['table_visible_columns']) ? ' checked="checked"' : '',
|
| 2324 |
$data['heading']
|
| 2325 |
);
|
| 2326 |
+
}
|
| 2327 |
+
|
| 2328 |
$html .= '</div>';
|
| 2329 |
+
|
| 2330 |
+
$html .= '<h5>' . __('Show on screen', 'broken-link-checker') . '</h5>';
|
| 2331 |
$html .= '<div class="screen-options">';
|
| 2332 |
$html .= sprintf(
|
| 2333 |
'<input type="text" name="per_page" maxlength="3" value="%d" class="screen-per-page" id="blc_links_per_page" />
|
| 2338 |
__('Apply')
|
| 2339 |
);
|
| 2340 |
$html .= '</div>';
|
| 2341 |
+
|
| 2342 |
$html .= '<h5>' . __('Misc', 'broken-link-checker') . '</h5>';
|
| 2343 |
$html .= '<div class="screen-options">';
|
| 2344 |
/*
|
| 2345 |
+
Display a checkbox in "Screen Options" that lets the user highlight links that
|
| 2346 |
+
have been broken for at least X days.
|
| 2347 |
*/
|
| 2348 |
$html .= sprintf(
|
| 2349 |
'<label><input type="checkbox" id="highlight_permanent_failures" name="highlight_permanent_failures"%s> ',
|
| 2358 |
$input_box
|
| 2359 |
);
|
| 2360 |
$html .= '</label>';
|
| 2361 |
+
|
| 2362 |
//Display a checkbox for turning colourful link status messages on/off
|
| 2363 |
$html .= sprintf(
|
| 2364 |
'<br/><label><input type="checkbox" id="table_color_code_status" name="table_color_code_status"%s> %s</label>',
|
| 2365 |
$this->conf->options['table_color_code_status'] ? ' checked="checked"' : '',
|
| 2366 |
__('Color-code status codes', 'broken-link-checker')
|
| 2367 |
);
|
| 2368 |
+
|
| 2369 |
$html .= '</div>';
|
| 2370 |
+
|
| 2371 |
return $html;
|
| 2372 |
}
|
| 2373 |
+
|
| 2374 |
/**
|
| 2375 |
* AJAX callback for saving the "Screen Options" panel settings
|
| 2376 |
+
*
|
| 2377 |
* @param array $form
|
| 2378 |
* @return void
|
| 2379 |
*/
|
| 2380 |
function ajax_save_screen_options($form){
|
| 2381 |
if ( !current_user_can('edit_others_posts') ){
|
| 2382 |
die( json_encode( array(
|
| 2383 |
+
'error' => __("You're not allowed to do that!", 'broken-link-checker')
|
| 2384 |
)));
|
| 2385 |
}
|
| 2386 |
+
|
| 2387 |
$this->conf->options['highlight_permanent_failures'] = !empty($form['highlight_permanent_failures']);
|
| 2388 |
$this->conf->options['table_color_code_status'] = !empty($form['table_color_code_status']);
|
| 2389 |
+
|
| 2390 |
$failure_duration_threshold = intval($form['failure_duration_threshold']);
|
| 2391 |
if ( $failure_duration_threshold >=1 ){
|
| 2392 |
$this->conf->options['failure_duration_threshold'] = $failure_duration_threshold;
|
| 2393 |
}
|
| 2394 |
+
|
| 2395 |
if ( isset($form['visible_columns']) && is_array($form['visible_columns']) ){
|
| 2396 |
$this->conf->options['table_visible_columns'] = array_keys($form['visible_columns']);
|
| 2397 |
}
|
| 2398 |
+
|
| 2399 |
$this->conf->save_options();
|
| 2400 |
die('1');
|
| 2401 |
}
|
| 2402 |
+
|
| 2403 |
function start_timer(){
|
| 2404 |
$this->execution_start_time = microtime_float();
|
| 2405 |
}
|
| 2406 |
+
|
| 2407 |
function execution_time(){
|
| 2408 |
return microtime_float() - $this->execution_start_time;
|
| 2409 |
}
|
| 2410 |
+
|
| 2411 |
/**
|
| 2412 |
* The main worker function that does all kinds of things.
|
| 2413 |
*
|
| 2424 |
if ( session_id() != '' ) {
|
| 2425 |
session_write_close();
|
| 2426 |
}
|
| 2427 |
+
|
| 2428 |
if ( !$this->acquire_lock() ){
|
| 2429 |
//FB::warn("Another instance of BLC is already working. Stop.");
|
| 2430 |
$blclog->info('Another instance of BLC is already working. Stop.');
|
| 2431 |
return;
|
| 2432 |
}
|
| 2433 |
+
|
| 2434 |
if ( $this->server_too_busy() ){
|
| 2435 |
//FB::warn("Server is too busy. Stop.");
|
| 2436 |
$blclog->warn('Server load is too high, stopping.');
|
| 2437 |
return;
|
| 2438 |
}
|
| 2439 |
+
|
| 2440 |
$this->start_timer();
|
| 2441 |
$blclog->info('work() starts');
|
| 2442 |
|
| 2443 |
$max_execution_time = $this->conf->options['max_execution_time'];
|
| 2444 |
+
|
| 2445 |
/*****************************************
|
| 2446 |
Preparation
|
| 2447 |
******************************************/
|
| 2449 |
if( blcUtility::is_safe_mode() ){
|
| 2450 |
// Do it the safe mode way - obey the existing max_execution_time setting
|
| 2451 |
$t = ini_get('max_execution_time');
|
| 2452 |
+
if ($t && ($t < $max_execution_time))
|
| 2453 |
$max_execution_time = $t-1;
|
| 2454 |
} else {
|
| 2455 |
// Do it the regular way
|
| 2456 |
@set_time_limit( $max_execution_time * 2 ); //x2 should be plenty, running any longer would mean a glitch.
|
| 2457 |
}
|
| 2458 |
+
|
| 2459 |
//Don't stop the script when the connection is closed
|
| 2460 |
ignore_user_abort( true );
|
| 2461 |
|
| 2476 |
ob_end_flush(); // Strange behaviour, will not work
|
| 2477 |
flush(); // Unless both are called !
|
| 2478 |
}
|
| 2479 |
+
|
| 2480 |
//Load modules for this context
|
| 2481 |
$moduleManager = blcModuleManager::getInstance();
|
| 2482 |
$moduleManager->load_modules('work');
|
| 2484 |
$target_usage_fraction = $this->conf->get('target_resource_usage', 0.25);
|
| 2485 |
//Target usage must be between 1% and 100%.
|
| 2486 |
$target_usage_fraction = max(min($target_usage_fraction, 1), 0.01);
|
| 2487 |
+
|
| 2488 |
+
|
| 2489 |
/*****************************************
|
| 2490 |
Parse posts and bookmarks
|
| 2491 |
******************************************/
|
| 2492 |
+
|
| 2493 |
$orphans_possible = false;
|
| 2494 |
$still_need_resynch = $this->conf->options['need_resynch'];
|
| 2495 |
+
|
| 2496 |
if ( $still_need_resynch ) {
|
| 2497 |
|
| 2498 |
//FB::log("Looking for containers that need parsing...");
|
| 2505 |
while( !empty($containers) ){
|
| 2506 |
//FB::log($containers, 'Found containers');
|
| 2507 |
$this->sleep_to_maintain_ratio($get_containers_time, $target_usage_fraction);
|
| 2508 |
+
|
| 2509 |
foreach($containers as $container){
|
| 2510 |
$synch_start_time = microtime(true);
|
| 2511 |
|
| 2519 |
$container->container_id,
|
| 2520 |
$synch_elapsed_time * 1000
|
| 2521 |
));
|
| 2522 |
+
|
| 2523 |
//Check if we still have some execution time left
|
| 2524 |
if( $this->execution_time() > $max_execution_time ){
|
| 2525 |
//FB::log('The allotted execution time has run out');
|
| 2527 |
$this->release_lock();
|
| 2528 |
return;
|
| 2529 |
}
|
| 2530 |
+
|
| 2531 |
//Check if the server isn't overloaded
|
| 2532 |
if ( $this->server_too_busy() ){
|
| 2533 |
//FB::log('Server overloaded, bailing out.');
|
| 2546 |
$containers = blcContainerHelper::get_unsynched_containers($max_containers_per_query);
|
| 2547 |
$get_containers_time = microtime(true) - $start;
|
| 2548 |
}
|
| 2549 |
+
|
| 2550 |
//FB::log('No unparsed items found.');
|
| 2551 |
$still_need_resynch = false;
|
| 2552 |
+
|
| 2553 |
} else {
|
| 2554 |
//FB::log('Resynch not required.');
|
| 2555 |
}
|
| 2556 |
+
|
| 2557 |
/******************************************
|
| 2558 |
Resynch done?
|
| 2559 |
*******************************************/
|
| 2561 |
$this->conf->options['need_resynch'] = $still_need_resynch;
|
| 2562 |
$this->conf->save_options();
|
| 2563 |
}
|
| 2564 |
+
|
| 2565 |
/******************************************
|
| 2566 |
Remove orphaned links
|
| 2567 |
*******************************************/
|
| 2568 |
+
|
| 2569 |
if ( $orphans_possible ) {
|
| 2570 |
$start = microtime(true);
|
| 2571 |
|
| 2575 |
$get_links_time = microtime(true) - $start;
|
| 2576 |
$this->sleep_to_maintain_ratio($get_links_time, $target_usage_fraction);
|
| 2577 |
}
|
| 2578 |
+
|
| 2579 |
//Check if we still have some execution time left
|
| 2580 |
if( $this->execution_time() > $max_execution_time ){
|
| 2581 |
//FB::log('The allotted execution time has run out');
|
| 2583 |
$this->release_lock();
|
| 2584 |
return;
|
| 2585 |
}
|
| 2586 |
+
|
| 2587 |
if ( $this->server_too_busy() ){
|
| 2588 |
//FB::log('Server overloaded, bailing out.');
|
| 2589 |
$blclog->info('Server load too high, stopping.');
|
| 2590 |
$this->release_lock();
|
| 2591 |
return;
|
| 2592 |
}
|
| 2593 |
+
|
| 2594 |
/*****************************************
|
| 2595 |
Check links
|
| 2596 |
******************************************/
|
| 2602 |
|
| 2603 |
while ( $links ){
|
| 2604 |
$this->sleep_to_maintain_ratio($get_links_time, $target_usage_fraction);
|
| 2605 |
+
|
| 2606 |
//Some unchecked links found
|
| 2607 |
//FB::log("Checking ".count($links)." link(s)");
|
| 2608 |
$blclog->info("Checking ".count($links)." link(s)");
|
| 2625 |
$link->last_check_attempt = time();
|
| 2626 |
$link->save();
|
| 2627 |
}
|
| 2628 |
+
|
| 2629 |
//Check if we still have some execution time left
|
| 2630 |
if( $this->execution_time() > $max_execution_time ){
|
| 2631 |
//FB::log('The allotted execution time has run out');
|
| 2633 |
$this->release_lock();
|
| 2634 |
return;
|
| 2635 |
}
|
| 2636 |
+
|
| 2637 |
//Check if the server isn't overloaded
|
| 2638 |
if ( $this->server_too_busy() ){
|
| 2639 |
//FB::log('Server overloaded, bailing out.');
|
| 2649 |
$get_links_time = microtime(true) - $start;
|
| 2650 |
}
|
| 2651 |
//FB::log('No links need to be checked right now.');
|
| 2652 |
+
|
| 2653 |
$this->release_lock();
|
| 2654 |
$blclog->info('work(): All done.');
|
| 2655 |
//FB::log('All done.');
|
| 2679 |
usleep($sleep_time * 1000000);
|
| 2680 |
}
|
| 2681 |
}
|
| 2682 |
+
|
| 2683 |
/**
|
| 2684 |
* This function is called when the plugin's cron hook executes.
|
| 2685 |
* Its only purpose is to invoke the worker function.
|
| 2686 |
*
|
| 2687 |
+
* @uses wsBrokenLinkChecker::work()
|
| 2688 |
*
|
| 2689 |
* @return void
|
| 2690 |
*/
|
| 2691 |
function cron_check_links(){
|
| 2692 |
$this->work();
|
| 2693 |
}
|
| 2694 |
+
|
| 2695 |
/**
|
| 2696 |
* Retrieve links that need to be checked or re-checked.
|
| 2697 |
*
|
| 2698 |
* @param integer $max_results The maximum number of links to return. Defaults to 0 = no limit.
|
| 2699 |
+
* @param bool $count_only If true, only the number of found links will be returned, not the links themselves.
|
| 2700 |
* @return int|blcLink[]
|
| 2701 |
*/
|
| 2702 |
function get_links_to_check($max_results = 0, $count_only = false){
|
| 2703 |
global $wpdb; /* @var wpdb $wpdb */
|
| 2704 |
+
|
| 2705 |
$check_threshold = date('Y-m-d H:i:s', strtotime('-'.$this->conf->options['check_threshold'].' hours'));
|
| 2706 |
$recheck_threshold = date('Y-m-d H:i:s', time() - $this->conf->options['recheck_threshold']);
|
| 2707 |
+
|
| 2708 |
//FB::log('Looking for links to check (threshold : '.$check_threshold.', recheck_threshold : '.$recheck_threshold.')...');
|
| 2709 |
+
|
| 2710 |
//Select some links that haven't been checked for a long time or
|
| 2711 |
//that are broken and need to be re-checked again. Links that are
|
| 2712 |
//marked as "being checked" and have been that way for several minutes
|
| 2713 |
+
//can also be considered broken/buggy, so those will be selected
|
| 2714 |
//as well.
|
| 2715 |
+
|
| 2716 |
+
//Only check links that have at least one valid instance (i.e. an instance exists and
|
| 2717 |
//it corresponds to one of the currently loaded container/parser types).
|
| 2718 |
$manager = blcModuleManager::getInstance();
|
| 2719 |
$loaded_containers = $manager->get_escaped_ids('container');
|
| 2720 |
$loaded_parsers = $manager->get_escaped_ids('parser');
|
| 2721 |
+
|
| 2722 |
//Note : This is a slow query, but AFAIK there is no way to speed it up.
|
| 2723 |
+
//I could put an index on last_check_attempt, but that value is almost
|
| 2724 |
//certainly unique for each row so it wouldn't be much better than a full table scan.
|
| 2725 |
if ( $count_only ){
|
| 2726 |
$q = "SELECT COUNT(DISTINCT links.link_id)\n";
|
| 2752 |
$q .= "LIMIT " . intval($max_results);
|
| 2753 |
}
|
| 2754 |
}
|
| 2755 |
+
|
| 2756 |
$link_q = $wpdb->prepare(
|
| 2757 |
+
$q,
|
| 2758 |
+
$check_threshold,
|
| 2759 |
+
$this->conf->options['recheck_count'],
|
| 2760 |
$recheck_threshold
|
| 2761 |
);
|
| 2762 |
//FB::log($link_q, "Find links to check");
|
| 2763 |
//$blclog->debug("Find links to check: \n" . $link_q);
|
| 2764 |
+
|
| 2765 |
//If we just need the number of links, retrieve it and return
|
| 2766 |
if ( $count_only ){
|
| 2767 |
return $wpdb->get_var($link_q);
|
| 2768 |
}
|
| 2769 |
+
|
| 2770 |
//Fetch the link data
|
| 2771 |
$link_data = $wpdb->get_results($link_q, ARRAY_A);
|
| 2772 |
if ( empty($link_data) ){
|
| 2773 |
return array();
|
| 2774 |
}
|
| 2775 |
+
|
| 2776 |
//Instantiate blcLink objects for all fetched links
|
| 2777 |
$links = array();
|
| 2778 |
foreach($link_data as $data){
|
| 2779 |
$links[] = new blcLink($data);
|
| 2780 |
}
|
| 2781 |
+
|
| 2782 |
return $links;
|
| 2783 |
}
|
| 2784 |
+
|
| 2785 |
/**
|
| 2786 |
* Output the current link checker status in JSON format.
|
| 2787 |
* Ajax hook for the 'blc_full_status' action.
|
| 2791 |
function ajax_full_status( ){
|
| 2792 |
$status = $this->get_status();
|
| 2793 |
$text = $this->status_text( $status );
|
| 2794 |
+
|
| 2795 |
echo json_encode( array(
|
| 2796 |
'text' => $text,
|
| 2797 |
+
'status' => $status,
|
| 2798 |
) );
|
| 2799 |
+
|
| 2800 |
die();
|
| 2801 |
}
|
| 2802 |
+
|
| 2803 |
/**
|
| 2804 |
* Generates a status message based on the status info in $status
|
| 2805 |
*
|
| 2808 |
*/
|
| 2809 |
function status_text( $status ){
|
| 2810 |
$text = '';
|
| 2811 |
+
|
| 2812 |
if( $status['broken_links'] > 0 ){
|
| 2813 |
+
$text .= sprintf(
|
| 2814 |
+
"<a href='%s' title='" . __('View broken links', 'broken-link-checker') . "'><strong>".
|
| 2815 |
_n('Found %d broken link', 'Found %d broken links', $status['broken_links'], 'broken-link-checker') .
|
| 2816 |
"</strong></a>",
|
| 2817 |
esc_attr(admin_url('tools.php?page=view-broken-links')),
|
| 2820 |
} else {
|
| 2821 |
$text .= __("No broken links found.", 'broken-link-checker');
|
| 2822 |
}
|
| 2823 |
+
|
| 2824 |
$text .= "<br/>";
|
| 2825 |
+
|
| 2826 |
if( $status['unchecked_links'] > 0) {
|
| 2827 |
+
$text .= sprintf(
|
| 2828 |
+
_n('%d URL in the work queue', '%d URLs in the work queue', $status['unchecked_links'], 'broken-link-checker'),
|
| 2829 |
$status['unchecked_links'] );
|
| 2830 |
} else {
|
| 2831 |
$text .= __("No URLs in the work queue.", 'broken-link-checker');
|
| 2832 |
}
|
| 2833 |
+
|
| 2834 |
$text .= "<br/>";
|
| 2835 |
if ( $status['known_links'] > 0 ){
|
| 2836 |
$url_count = sprintf(
|
| 2862 |
$text .= __('No links detected.', 'broken-link-checker');
|
| 2863 |
}
|
| 2864 |
}
|
| 2865 |
+
|
| 2866 |
return $text;
|
| 2867 |
}
|
| 2868 |
+
|
| 2869 |
/**
|
| 2870 |
+
* @uses wsBrokenLinkChecker::ajax_full_status()
|
| 2871 |
*
|
| 2872 |
* @return void
|
| 2873 |
*/
|
| 2875 |
//Just display the full status.
|
| 2876 |
$this->ajax_full_status();
|
| 2877 |
}
|
| 2878 |
+
|
| 2879 |
/**
|
| 2880 |
* Output the current average server load (over the last one-minute period).
|
| 2881 |
* Called via AJAX.
|
| 2887 |
if ( empty($load) ){
|
| 2888 |
die( _x('Unknown', 'current load', 'broken-link-checker') );
|
| 2889 |
}
|
| 2890 |
+
|
| 2891 |
$one_minute = reset($load);
|
| 2892 |
printf('%.2f', $one_minute);
|
| 2893 |
die();
|
| 2894 |
}
|
| 2895 |
+
|
| 2896 |
/**
|
| 2897 |
+
* Returns an array with various status information about the plugin. Array key reference:
|
| 2898 |
* check_threshold - date/time; links checked before this threshold should be checked again.
|
| 2899 |
* recheck_threshold - date/time; broken links checked before this threshold should be re-checked.
|
| 2900 |
* known_links - the number of detected unique URLs (a misleading name, yes).
|
| 2901 |
* known_instances - the number of detected link instances, i.e. actual link elements in posts and other places.
|
| 2902 |
+
* broken_links - the number of detected broken links.
|
| 2903 |
* unchecked_links - the number of URLs that need to be checked ASAP; based on check_threshold and recheck_threshold.
|
| 2904 |
*
|
| 2905 |
* @return array
|
| 2906 |
*/
|
| 2907 |
function get_status(){
|
| 2908 |
$blc_link_query = blcLinkQuery::getInstance();
|
| 2909 |
+
|
| 2910 |
$check_threshold=date('Y-m-d H:i:s', strtotime('-'.$this->conf->options['check_threshold'].' hours'));
|
| 2911 |
$recheck_threshold=date('Y-m-d H:i:s', time() - $this->conf->options['recheck_threshold']);
|
| 2912 |
+
|
| 2913 |
$known_links = blc_get_links(array('count_only' => true));
|
| 2914 |
$known_instances = blc_get_usable_instance_count();
|
| 2915 |
+
|
| 2916 |
$broken_links = $blc_link_query->get_filter_links('broken', array('count_only' => true));
|
| 2917 |
+
|
| 2918 |
$unchecked_links = $this->get_links_to_check(0, true);
|
| 2919 |
+
|
| 2920 |
return array(
|
| 2921 |
'check_threshold' => $check_threshold,
|
| 2922 |
'recheck_threshold' => $recheck_threshold,
|
| 2926 |
'unchecked_links' => $unchecked_links,
|
| 2927 |
);
|
| 2928 |
}
|
| 2929 |
+
|
| 2930 |
function ajax_work(){
|
| 2931 |
check_ajax_referer('blc_work');
|
| 2932 |
|
| 2933 |
+
//Run the worker function
|
| 2934 |
$this->work();
|
| 2935 |
die();
|
| 2936 |
}
|
| 2937 |
+
|
| 2938 |
/**
|
| 2939 |
* AJAX hook for the "Not broken" button. Marks a link as broken and as a likely false positive.
|
| 2940 |
*
|
| 2944 |
if (!current_user_can('edit_others_posts') || !check_ajax_referer('blc_discard', false, false)){
|
| 2945 |
die( __("You're not allowed to do that!", 'broken-link-checker') );
|
| 2946 |
}
|
| 2947 |
+
|
| 2948 |
if ( isset($_POST['link_id']) ){
|
| 2949 |
//Load the link
|
| 2950 |
$link = new blcLink( intval($_POST['link_id']) );
|
| 2951 |
+
|
| 2952 |
if ( !$link->valid() ){
|
| 2953 |
printf( __("Oops, I can't find the link %d", 'broken-link-checker'), intval($_POST['link_id']) );
|
| 2954 |
die();
|
| 2955 |
}
|
| 2956 |
//Make it appear "not broken"
|
| 2957 |
+
$link->broken = false;
|
| 2958 |
$link->warning = false;
|
| 2959 |
$link->false_positive = true;
|
| 2960 |
$link->last_check_attempt = time();
|
| 3009 |
die( __("Error : link_id not specified", 'broken-link-checker') );
|
| 3010 |
}
|
| 3011 |
}
|
| 3012 |
+
|
| 3013 |
/**
|
| 3014 |
+
* AJAX hook for the inline link editor on Tools -> Broken Links.
|
| 3015 |
*
|
| 3016 |
* @return void
|
| 3017 |
*/
|
| 3018 |
function ajax_edit(){
|
| 3019 |
if (!current_user_can('edit_others_posts') || !check_ajax_referer('blc_edit', false, false)){
|
| 3020 |
die( json_encode( array(
|
| 3021 |
+
'error' => __("You're not allowed to do that!", 'broken-link-checker')
|
| 3022 |
)));
|
| 3023 |
}
|
| 3024 |
|
| 3109 |
die( json_encode($response) );
|
| 3110 |
}
|
| 3111 |
}
|
| 3112 |
+
|
| 3113 |
/**
|
| 3114 |
+
* AJAX hook for the "Unlink" action links in Tools -> Broken Links.
|
| 3115 |
* Removes the specified link from all posts and other supported items.
|
| 3116 |
*
|
| 3117 |
* @return void
|
| 3119 |
function ajax_unlink(){
|
| 3120 |
if (!current_user_can('edit_others_posts') || !check_ajax_referer('blc_unlink', false, false)){
|
| 3121 |
die( json_encode( array(
|
| 3122 |
+
'error' => __("You're not allowed to do that!", 'broken-link-checker')
|
| 3123 |
)));
|
| 3124 |
}
|
| 3125 |
+
|
| 3126 |
if ( isset($_POST['link_id']) ){
|
| 3127 |
//Load the link
|
| 3128 |
$link = new blcLink( intval($_POST['link_id']) );
|
| 3129 |
+
|
| 3130 |
if ( !$link->valid() ){
|
| 3131 |
die( json_encode( array(
|
| 3132 |
+
'error' => sprintf( __("Oops, I can't find the link %d", 'broken-link-checker'), intval($_POST['link_id']) )
|
| 3133 |
)));
|
| 3134 |
}
|
| 3135 |
+
|
| 3136 |
//Try and unlink it
|
| 3137 |
$rez = $link->unlink();
|
| 3138 |
+
|
| 3139 |
if ( $rez === false ){
|
| 3140 |
die( json_encode( array(
|
| 3141 |
'error' => __("An unexpected error occured!", 'broken-link-checker')
|
| 3149 |
foreach($rez['errors'] as $error){ /** @var WP_Error $error */
|
| 3150 |
array_push( $response['errors'], implode(', ', $error->get_error_messages()) );
|
| 3151 |
}
|
| 3152 |
+
|
| 3153 |
die( json_encode($response) );
|
| 3154 |
}
|
| 3155 |
+
|
| 3156 |
} else {
|
| 3157 |
die( json_encode( array(
|
| 3158 |
+
'error' => __("Error : link_id not specified", 'broken-link-checker')
|
| 3159 |
)));
|
| 3160 |
}
|
| 3161 |
}
|
| 3263 |
|
| 3264 |
die(json_encode($response));
|
| 3265 |
}
|
| 3266 |
+
|
| 3267 |
function ajax_link_details(){
|
| 3268 |
global $wpdb; /* @var wpdb $wpdb */
|
| 3269 |
+
|
| 3270 |
if (!current_user_can('edit_others_posts')){
|
| 3271 |
die( __("You don't have sufficient privileges to access this information!", 'broken-link-checker') );
|
| 3272 |
}
|
| 3273 |
+
|
| 3274 |
//FB::log("Loading link details via AJAX");
|
| 3275 |
+
|
| 3276 |
if ( isset($_GET['link_id']) ){
|
| 3277 |
//FB::info("Link ID found in GET");
|
| 3278 |
$link_id = intval($_GET['link_id']);
|
| 3283 |
//FB::error('Link ID not specified, you hacking bastard.');
|
| 3284 |
die( __('Error : link ID not specified', 'broken-link-checker') );
|
| 3285 |
}
|
| 3286 |
+
|
| 3287 |
+
//Load the link.
|
| 3288 |
$link = new blcLink($link_id);
|
| 3289 |
+
|
| 3290 |
if ( !$link->is_new ){
|
| 3291 |
//FB::info($link, 'Link loaded');
|
| 3292 |
if ( !class_exists('blcTablePrinter') ){
|
| 3299 |
die();
|
| 3300 |
}
|
| 3301 |
}
|
| 3302 |
+
|
| 3303 |
/**
|
| 3304 |
* Acquire an exclusive lock.
|
| 3305 |
* If we already hold a lock, it will be released and a new one will be acquired.
|
| 3309 |
function acquire_lock(){
|
| 3310 |
return WPMutex::acquire('blc_lock');
|
| 3311 |
}
|
| 3312 |
+
|
| 3313 |
/**
|
| 3314 |
+
* Relese our exclusive lock.
|
| 3315 |
* Does nothing if the lock has already been released.
|
| 3316 |
*
|
| 3317 |
* @return bool
|
| 3319 |
function release_lock(){
|
| 3320 |
return WPMutex::release('blc_lock');
|
| 3321 |
}
|
| 3322 |
+
|
| 3323 |
/**
|
| 3324 |
* Check if server is currently too overloaded to run the link checker.
|
| 3325 |
*
|
| 3329 |
if ( !$this->conf->options['enable_load_limit'] || !isset($this->conf->options['server_load_limit']) ){
|
| 3330 |
return false;
|
| 3331 |
}
|
| 3332 |
+
|
| 3333 |
$loads = blcUtility::get_server_load();
|
| 3334 |
if ( empty($loads) ){
|
| 3335 |
return false;
|
| 3336 |
}
|
| 3337 |
$one_minute = floatval(reset($loads));
|
| 3338 |
+
|
| 3339 |
return $one_minute > $this->conf->options['server_load_limit'];
|
| 3340 |
}
|
| 3341 |
+
|
| 3342 |
/**
|
| 3343 |
* Register BLC's Dashboard widget
|
| 3344 |
+
*
|
| 3345 |
* @return void
|
| 3346 |
*/
|
| 3347 |
function hook_wp_dashboard_setup(){
|
| 3348 |
$show_widget = current_user_can($this->conf->get('dashboard_widget_capability', 'edit_others_posts'));
|
| 3349 |
if ( function_exists( 'wp_add_dashboard_widget' ) && $show_widget ) {
|
| 3350 |
wp_add_dashboard_widget(
|
| 3351 |
+
'blc_dashboard_widget',
|
| 3352 |
+
__('Broken Link Checker', 'broken-link-checker'),
|
| 3353 |
array( $this, 'dashboard_widget' ),
|
| 3354 |
array( $this, 'dashboard_widget_control' )
|
| 3355 |
);
|
| 3356 |
}
|
| 3357 |
}
|
| 3358 |
+
|
| 3359 |
/**
|
| 3360 |
* Collect various debugging information and return it in an associative array
|
| 3361 |
*
|
| 3365 |
/** @var wpdb $wpdb */
|
| 3366 |
global $wpdb;
|
| 3367 |
|
| 3368 |
+
//Collect some information that's useful for debugging
|
| 3369 |
$debug = array();
|
| 3370 |
+
|
| 3371 |
//PHP version. Any one is fine as long as WP supports it.
|
| 3372 |
$debug[ __('PHP version', 'broken-link-checker') ] = array(
|
| 3373 |
'state' => 'ok',
|
| 3374 |
+
'value' => phpversion(),
|
| 3375 |
);
|
| 3376 |
+
|
| 3377 |
//MySQL version
|
| 3378 |
$debug[ __('MySQL version', 'broken-link-checker') ] = array(
|
| 3379 |
'state' => 'ok',
|
| 3380 |
'value' => $wpdb->db_version(),
|
| 3381 |
);
|
| 3382 |
+
|
| 3383 |
//CURL presence and version
|
| 3384 |
if ( function_exists('curl_version') ){
|
| 3385 |
$version = curl_version();
|
| 3386 |
+
|
| 3387 |
if ( version_compare( $version['version'], '7.16.0', '<=' ) ){
|
| 3388 |
$data = array(
|
| 3389 |
+
'state' => 'warning',
|
| 3390 |
'value' => $version['version'],
|
| 3391 |
'message' => __('You have an old version of CURL. Redirect detection may not work properly.', 'broken-link-checker'),
|
| 3392 |
);
|
| 3393 |
} else {
|
| 3394 |
$data = array(
|
| 3395 |
+
'state' => 'ok',
|
| 3396 |
'value' => $version['version'],
|
| 3397 |
);
|
| 3398 |
}
|
| 3399 |
+
|
| 3400 |
} else {
|
| 3401 |
$data = array(
|
| 3402 |
+
'state' => 'warning',
|
| 3403 |
'value' => __('Not installed', 'broken-link-checker'),
|
| 3404 |
);
|
| 3405 |
}
|
| 3406 |
$debug[ __('CURL version', 'broken-link-checker') ] = $data;
|
| 3407 |
+
|
| 3408 |
//Snoopy presence
|
| 3409 |
if ( class_exists('Snoopy') || file_exists(ABSPATH. WPINC . '/class-snoopy.php') ){
|
| 3410 |
$data = array(
|
| 3412 |
'value' => __('Installed', 'broken-link-checker'),
|
| 3413 |
);
|
| 3414 |
} else {
|
| 3415 |
+
//No Snoopy? This should never happen, but if it does we *must* have CURL.
|
| 3416 |
if ( function_exists('curl_init') ){
|
| 3417 |
$data = array(
|
| 3418 |
'state' => 'ok',
|
| 3425 |
'message' => __('You must have either CURL or Snoopy installed for the plugin to work!', 'broken-link-checker'),
|
| 3426 |
);
|
| 3427 |
}
|
| 3428 |
+
|
| 3429 |
}
|
| 3430 |
$debug['Snoopy'] = $data;
|
| 3431 |
+
|
| 3432 |
//Safe_mode status
|
| 3433 |
if ( blcUtility::is_safe_mode() ){
|
| 3434 |
$debug['Safe mode'] = array(
|
| 3442 |
'value' => __('Off', 'broken-link-checker'),
|
| 3443 |
);
|
| 3444 |
}
|
| 3445 |
+
|
| 3446 |
//Open_basedir status
|
| 3447 |
if ( blcUtility::is_open_basedir() ){
|
| 3448 |
$debug['open_basedir'] = array(
|
| 3456 |
'value' => __('Off', 'broken-link-checker'),
|
| 3457 |
);
|
| 3458 |
}
|
| 3459 |
+
|
| 3460 |
//Default PHP execution time limit
|
| 3461 |
$debug['Default PHP execution time limit'] = array(
|
| 3462 |
'state' => 'ok',
|
| 3476 |
'state' => 'ok',
|
| 3477 |
'value' => sprintf('%d', $this->conf->options['need_resynch'] ? '1 (resynch. required)' : '0 (resynch. not required)'),
|
| 3478 |
);
|
| 3479 |
+
|
| 3480 |
//Synch records
|
| 3481 |
$synch_records = intval($wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}blc_synch"));
|
| 3482 |
$data = array(
|
| 3488 |
$data['message'] = __('If this value is zero even after several page reloads you have probably encountered a bug.', 'broken-link-checker');
|
| 3489 |
}
|
| 3490 |
$debug['Synch. records'] = $data;
|
| 3491 |
+
|
| 3492 |
//Total links and instances (including invalid ones)
|
| 3493 |
$all_links = intval($wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}blc_links"));
|
| 3494 |
$all_instances = intval($wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}blc_instances"));
|
| 3495 |
+
|
| 3496 |
+
//Show the number of unparsed containers. Useful for debugging. For performance,
|
| 3497 |
//this is only shown when we have no links/instances yet.
|
| 3498 |
if( ($all_links == 0) && ($all_instances == 0) ){
|
| 3499 |
$unparsed_items = intval($wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}blc_synch WHERE synched=0"));
|
| 3500 |
$debug['Unparsed items'] = array(
|
| 3501 |
+
'state' => 'warning',
|
| 3502 |
'value' => $unparsed_items,
|
| 3503 |
);
|
| 3504 |
+
}
|
| 3505 |
+
|
| 3506 |
//Links & instances
|
| 3507 |
if ( ($all_links > 0) && ($all_instances > 0) ){
|
| 3508 |
$debug['Link records'] = array(
|
| 3514 |
'state' => 'warning',
|
| 3515 |
'value' => sprintf('%d (%d)', $all_links, $all_instances),
|
| 3516 |
);
|
| 3517 |
+
}
|
| 3518 |
|
| 3519 |
//Email notifications.
|
| 3520 |
if ( $this->conf->options['last_notification_sent'] ) {
|
| 3558 |
'value' => 'No installation log found found.',
|
| 3559 |
);
|
| 3560 |
}
|
| 3561 |
+
|
| 3562 |
return $debug;
|
| 3563 |
}
|
| 3564 |
|
| 3752 |
$this->send_html_email($author->user_email, $subject, $body);
|
| 3753 |
}
|
| 3754 |
}
|
| 3755 |
+
|
| 3756 |
function override_mail_content_type(/** @noinspection PhpUnusedParameterInspection */ $content_type){
|
| 3757 |
return 'text/html';
|
| 3758 |
}
|
| 3774 |
'%d'
|
| 3775 |
);
|
| 3776 |
}
|
| 3777 |
+
|
| 3778 |
/**
|
| 3779 |
* Install or uninstall the plugin's Cron events based on current settings.
|
| 3780 |
*
|
| 3781 |
+
* @uses wsBrokenLinkChecker::$conf Uses $conf->options to determine if events need to be (un)installed.
|
| 3782 |
*
|
| 3783 |
* @return void
|
| 3784 |
*/
|
| 3785 |
function setup_cron_events(){
|
| 3786 |
+
|
| 3787 |
+
//Link monitor
|
| 3788 |
if ( $this->conf->options['run_via_cron'] ){
|
| 3789 |
if (!wp_next_scheduled('blc_cron_check_links')) {
|
| 3790 |
+
wp_schedule_event( time(), '10min', 'blc_cron_check_links' );
|
| 3791 |
}
|
| 3792 |
} else {
|
| 3793 |
wp_clear_scheduled_hook('blc_cron_check_links');
|
| 3794 |
}
|
| 3795 |
+
|
| 3796 |
//Email notifications about broken links
|
| 3797 |
if ( $this->conf->options['send_email_notifications'] || $this->conf->options['send_authors_email_notifications'] ){
|
| 3798 |
if ( !wp_next_scheduled('blc_cron_email_notifications') ){
|
| 3801 |
} else {
|
| 3802 |
wp_clear_scheduled_hook('blc_cron_email_notifications');
|
| 3803 |
}
|
| 3804 |
+
|
| 3805 |
//Run database maintenance every two weeks or so
|
| 3806 |
if ( !wp_next_scheduled('blc_cron_database_maintenance') ){
|
| 3807 |
+
wp_schedule_event(time(), 'daily', 'blc_cron_database_maintenance');
|
| 3808 |
}
|
| 3809 |
}
|
| 3810 |
+
|
| 3811 |
/**
|
| 3812 |
* Load the plugin's textdomain.
|
| 3813 |
*
|
| 3816 |
function load_language(){
|
| 3817 |
$this->is_textdomain_loaded = load_plugin_textdomain( 'broken-link-checker', false, basename(dirname($this->loader)) . '/languages' );
|
| 3818 |
}
|
| 3819 |
+
|
| 3820 |
protected static function get_default_log_directory() {
|
| 3821 |
$uploads = wp_upload_dir();
|
| 3822 |
return $uploads['basedir'] . '/broken-link-checker';
|
core/init.php
CHANGED
|
@@ -95,6 +95,7 @@ $blc_config_manager = new blcConfigurationManager(
|
|
| 95 |
'enable_load_limit' => true, //Enable/disable load monitoring.
|
| 96 |
|
| 97 |
'custom_fields' => array(), //List of custom fields that can contain URLs and should be checked.
|
|
|
|
| 98 |
'enabled_post_statuses' => array('publish'), //Only check posts that match one of these statuses
|
| 99 |
|
| 100 |
'autoexpand_widget' => true, //Autoexpand the Dashboard widget if broken links are detected
|
| 95 |
'enable_load_limit' => true, //Enable/disable load monitoring.
|
| 96 |
|
| 97 |
'custom_fields' => array(), //List of custom fields that can contain URLs and should be checked.
|
| 98 |
+
'acf_fields' => array(), //List of custom fields that can contain URLs and should be checked.
|
| 99 |
'enabled_post_statuses' => array('publish'), //Only check posts that match one of these statuses
|
| 100 |
|
| 101 |
'autoexpand_widget' => true, //Autoexpand the Dashboard widget if broken links are detected
|
includes/activation.php
CHANGED
|
@@ -46,6 +46,9 @@ if ( isset($blc_config_manager->options['check_comment_links']) ){
|
|
| 46 |
if ( empty($blc_config_manager->options['custom_fields']) ){
|
| 47 |
$moduleManager->deactivate('custom_field');
|
| 48 |
}
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
//Prepare the database.
|
| 51 |
$blclog->info('Upgrading the database...');
|
| 46 |
if ( empty($blc_config_manager->options['custom_fields']) ){
|
| 47 |
$moduleManager->deactivate('custom_field');
|
| 48 |
}
|
| 49 |
+
if ( empty($blc_config_manager->options['acf_fields']) ){
|
| 50 |
+
$moduleManager->deactivate('acf_field');
|
| 51 |
+
}
|
| 52 |
|
| 53 |
//Prepare the database.
|
| 54 |
$blclog->info('Upgrading the database...');
|
includes/admin/links-page-js.php
CHANGED
|
@@ -436,7 +436,7 @@ jQuery(function($){
|
|
| 436 |
|
| 437 |
//Check the Wayback Machine for an archived version of the page.
|
| 438 |
$.getJSON(
|
| 439 |
-
'
|
| 440 |
{ url: url },
|
| 441 |
|
| 442 |
function(data) {
|
|
@@ -456,6 +456,9 @@ jQuery(function($){
|
|
| 456 |
'-' + snapshot.timestamp.substr(6, 2);
|
| 457 |
var name = sprintf(iaSuggestionName, readableTimestamp);
|
| 458 |
|
|
|
|
|
|
|
|
|
|
| 459 |
//Display the suggestion.
|
| 460 |
var item = suggestionTemplate.clone();
|
| 461 |
item.find('.blc-suggestion-name a').text(name).attr('href', snapshot.url);
|
| 436 |
|
| 437 |
//Check the Wayback Machine for an archived version of the page.
|
| 438 |
$.getJSON(
|
| 439 |
+
'https://archive.org/wayback/available?callback=?',
|
| 440 |
{ url: url },
|
| 441 |
|
| 442 |
function(data) {
|
| 456 |
'-' + snapshot.timestamp.substr(6, 2);
|
| 457 |
var name = sprintf(iaSuggestionName, readableTimestamp);
|
| 458 |
|
| 459 |
+
//Enforce HTTPS by default
|
| 460 |
+
snapshot.url = (snapshot.url).replace( new RegExp("^http:", "m"), "https:");
|
| 461 |
+
|
| 462 |
//Display the suggestion.
|
| 463 |
var item = suggestionTemplate.clone();
|
| 464 |
item.find('.blc-suggestion-name a').text(name).attr('href', snapshot.url);
|
includes/admin/options-page-js.php
CHANGED
|
@@ -111,6 +111,16 @@ jQuery(function($){
|
|
| 111 |
$('#module-extra-settings-custom_field').removeClass('hidden');
|
| 112 |
}
|
| 113 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
|
| 115 |
//Handle the "Recheck" button
|
| 116 |
$('#start-recheck').click(function(){
|
| 111 |
$('#module-extra-settings-custom_field').removeClass('hidden');
|
| 112 |
}
|
| 113 |
});
|
| 114 |
+
|
| 115 |
+
//When the user ticks the "Custom fields" box, display the field list input
|
| 116 |
+
//so that they notice that they need to enter the field names.
|
| 117 |
+
$('#module-checkbox-acf_field').click(function(){
|
| 118 |
+
var box = $(this);
|
| 119 |
+
var fieldList = $('#blc_acf_fields');
|
| 120 |
+
if ( box.is(':checked') && ( $.trim(fieldList.val()) == '' ) ){
|
| 121 |
+
$('#module-extra-settings-acf_field').removeClass('hidden');
|
| 122 |
+
}
|
| 123 |
+
});
|
| 124 |
|
| 125 |
//Handle the "Recheck" button
|
| 126 |
$('#start-recheck').click(function(){
|
includes/admin/table-printer.php
CHANGED
|
@@ -1,904 +1,907 @@
|
|
| 1 |
-
<?php
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
*
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
class blcTablePrinter {
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
$
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
<
|
| 345 |
-
|
| 346 |
-
<
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
|
| 350 |
-
<
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
|
| 355 |
-
<
|
| 356 |
-
|
| 357 |
-
<
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
<
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
<
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
$days_broken =
|
| 403 |
-
if ( $
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
$s_link_type
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
$
|
| 449 |
-
|
| 450 |
-
|
| 451 |
-
|
| 452 |
-
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
|
| 461 |
-
|
| 462 |
-
|
| 463 |
-
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
|
| 467 |
-
$
|
| 468 |
-
|
| 469 |
-
|
| 470 |
-
|
| 471 |
-
|
| 472 |
-
|
| 473 |
-
|
| 474 |
-
|
| 475 |
-
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
|
| 481 |
-
|
| 482 |
-
|
| 483 |
-
|
| 484 |
-
|
| 485 |
-
|
| 486 |
-
|
| 487 |
-
|
| 488 |
-
|
| 489 |
-
|
| 490 |
-
|
| 491 |
-
|
| 492 |
-
|
| 493 |
-
|
| 494 |
-
|
| 495 |
-
|
| 496 |
-
|
| 497 |
-
|
| 498 |
-
|
| 499 |
-
|
| 500 |
-
|
| 501 |
-
|
| 502 |
-
|
| 503 |
-
|
| 504 |
-
|
| 505 |
-
|
| 506 |
-
|
| 507 |
-
|
| 508 |
-
|
| 509 |
-
|
| 510 |
-
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
|
| 514 |
-
|
| 515 |
-
|
| 516 |
-
|
| 517 |
-
|
| 518 |
-
|
| 519 |
-
|
| 520 |
-
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
-
|
| 530 |
-
|
| 531 |
-
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
|
| 535 |
-
'
|
| 536 |
-
|
| 537 |
-
|
| 538 |
-
|
| 539 |
-
|
| 540 |
-
|
| 541 |
-
|
| 542 |
-
|
| 543 |
-
|
| 544 |
-
|
| 545 |
-
|
| 546 |
-
|
| 547 |
-
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
|
| 551 |
-
|
| 552 |
-
|
| 553 |
-
|
| 554 |
-
|
| 555 |
-
|
| 556 |
-
|
| 557 |
-
|
| 558 |
-
|
| 559 |
-
|
| 560 |
-
|
| 561 |
-
|
| 562 |
-
|
| 563 |
-
|
| 564 |
-
|
| 565 |
-
|
| 566 |
-
|
| 567 |
-
|
| 568 |
-
|
| 569 |
-
|
| 570 |
-
|
| 571 |
-
|
| 572 |
-
|
| 573 |
-
|
| 574 |
-
|
| 575 |
-
|
| 576 |
-
|
| 577 |
-
|
| 578 |
-
|
| 579 |
-
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
|
| 586 |
-
|
| 587 |
-
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
|
| 591 |
-
|
| 592 |
-
|
| 593 |
-
|
| 594 |
-
|
| 595 |
-
|
| 596 |
-
|
| 597 |
-
|
| 598 |
-
|
| 599 |
-
|
| 600 |
-
|
| 601 |
-
|
| 602 |
-
|
| 603 |
-
|
| 604 |
-
|
| 605 |
-
|
| 606 |
-
|
| 607 |
-
|
| 608 |
-
|
| 609 |
-
|
| 610 |
-
|
| 611 |
-
|
| 612 |
-
|
| 613 |
-
|
| 614 |
-
|
| 615 |
-
|
| 616 |
-
|
| 617 |
-
|
| 618 |
-
|
| 619 |
-
|
| 620 |
-
|
| 621 |
-
|
| 622 |
-
|
| 623 |
-
|
| 624 |
-
|
| 625 |
-
|
| 626 |
-
|
| 627 |
-
|
| 628 |
-
|
| 629 |
-
|
| 630 |
-
|
| 631 |
-
|
| 632 |
-
|
| 633 |
-
|
| 634 |
-
|
| 635 |
-
|
| 636 |
-
|
| 637 |
-
|
| 638 |
-
|
| 639 |
-
|
| 640 |
-
|
| 641 |
-
|
| 642 |
-
|
| 643 |
-
|
| 644 |
-
|
| 645 |
-
|
| 646 |
-
|
| 647 |
-
|
| 648 |
-
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
|
| 652 |
-
|
| 653 |
-
|
| 654 |
-
|
| 655 |
-
|
| 656 |
-
|
| 657 |
-
|
| 658 |
-
|
| 659 |
-
|
| 660 |
-
|
| 661 |
-
|
| 662 |
-
|
| 663 |
-
|
| 664 |
-
|
| 665 |
-
|
| 666 |
-
|
| 667 |
-
|
| 668 |
-
|
| 669 |
-
|
| 670 |
-
|
| 671 |
-
|
| 672 |
-
|
| 673 |
-
|
| 674 |
-
|
| 675 |
-
|
| 676 |
-
|
| 677 |
-
|
| 678 |
-
|
| 679 |
-
|
| 680 |
-
|
| 681 |
-
|
| 682 |
-
|
| 683 |
-
|
| 684 |
-
|
| 685 |
-
"href='javascript:void(0)
|
| 686 |
-
|
| 687 |
-
|
| 688 |
-
|
| 689 |
-
|
| 690 |
-
|
| 691 |
-
|
| 692 |
-
|
| 693 |
-
|
| 694 |
-
|
| 695 |
-
|
| 696 |
-
|
| 697 |
-
|
| 698 |
-
|
| 699 |
-
|
| 700 |
-
|
| 701 |
-
|
| 702 |
-
|
| 703 |
-
|
| 704 |
-
|
| 705 |
-
|
| 706 |
-
|
| 707 |
-
|
| 708 |
-
|
| 709 |
-
|
| 710 |
-
|
| 711 |
-
|
| 712 |
-
|
| 713 |
-
|
| 714 |
-
|
| 715 |
-
|
| 716 |
-
|
| 717 |
-
|
| 718 |
-
|
| 719 |
-
|
| 720 |
-
|
| 721 |
-
|
| 722 |
-
|
| 723 |
-
|
| 724 |
-
|
| 725 |
-
|
| 726 |
-
|
| 727 |
-
|
| 728 |
-
|
| 729 |
-
|
| 730 |
-
|
| 731 |
-
|
| 732 |
-
|
| 733 |
-
|
| 734 |
-
|
| 735 |
-
|
| 736 |
-
$spans
|
| 737 |
-
|
| 738 |
-
|
| 739 |
-
$
|
| 740 |
-
|
| 741 |
-
|
| 742 |
-
|
| 743 |
-
|
| 744 |
-
|
| 745 |
-
|
| 746 |
-
|
| 747 |
-
|
| 748 |
-
|
| 749 |
-
|
| 750 |
-
|
| 751 |
-
|
| 752 |
-
|
| 753 |
-
<
|
| 754 |
-
|
| 755 |
-
|
| 756 |
-
|
| 757 |
-
|
| 758 |
-
|
| 759 |
-
|
| 760 |
-
|
| 761 |
-
|
| 762 |
-
|
| 763 |
-
|
| 764 |
-
|
| 765 |
-
|
| 766 |
-
|
| 767 |
-
|
| 768 |
-
|
| 769 |
-
|
| 770 |
-
|
| 771 |
-
|
| 772 |
-
|
| 773 |
-
|
| 774 |
-
|
| 775 |
-
|
| 776 |
-
|
| 777 |
-
|
| 778 |
-
|
| 779 |
-
|
| 780 |
-
|
| 781 |
-
|
| 782 |
-
|
| 783 |
-
|
| 784 |
-
|
| 785 |
-
|
| 786 |
-
|
| 787 |
-
|
| 788 |
-
|
| 789 |
-
|
| 790 |
-
|
| 791 |
-
|
| 792 |
-
|
| 793 |
-
|
| 794 |
-
|
| 795 |
-
|
| 796 |
-
|
| 797 |
-
|
| 798 |
-
|
| 799 |
-
|
| 800 |
-
|
| 801 |
-
|
| 802 |
-
|
| 803 |
-
|
| 804 |
-
|
| 805 |
-
|
| 806 |
-
|
| 807 |
-
|
| 808 |
-
|
| 809 |
-
|
| 810 |
-
|
| 811 |
-
|
| 812 |
-
|
| 813 |
-
|
| 814 |
-
|
| 815 |
-
|
| 816 |
-
|
| 817 |
-
|
| 818 |
-
|
| 819 |
-
|
| 820 |
-
|
| 821 |
-
|
| 822 |
-
|
| 823 |
-
|
| 824 |
-
|
| 825 |
-
|
| 826 |
-
|
| 827 |
-
|
| 828 |
-
|
| 829 |
-
|
| 830 |
-
|
| 831 |
-
|
| 832 |
-
|
| 833 |
-
|
| 834 |
-
|
| 835 |
-
|
| 836 |
-
|
| 837 |
-
|
| 838 |
-
|
| 839 |
-
|
| 840 |
-
|
| 841 |
-
|
| 842 |
-
|
| 843 |
-
}
|
| 844 |
-
|
| 845 |
-
|
| 846 |
-
|
| 847 |
-
|
| 848 |
-
|
| 849 |
-
|
| 850 |
-
|
| 851 |
-
|
| 852 |
-
|
| 853 |
-
|
| 854 |
-
|
| 855 |
-
|
| 856 |
-
|
| 857 |
-
|
| 858 |
-
<
|
| 859 |
-
<
|
| 860 |
-
|
| 861 |
-
|
| 862 |
-
|
| 863 |
-
|
| 864 |
-
|
| 865 |
-
|
| 866 |
-
|
| 867 |
-
|
| 868 |
-
|
| 869 |
-
|
| 870 |
-
|
| 871 |
-
|
| 872 |
-
|
| 873 |
-
|
| 874 |
-
|
| 875 |
-
|
| 876 |
-
|
| 877 |
-
|
| 878 |
-
|
| 879 |
-
|
| 880 |
-
|
| 881 |
-
|
| 882 |
-
|
| 883 |
-
|
| 884 |
-
|
| 885 |
-
|
| 886 |
-
|
| 887 |
-
|
| 888 |
-
|
| 889 |
-
|
| 890 |
-
|
| 891 |
-
<
|
| 892 |
-
<
|
| 893 |
-
|
| 894 |
-
|
| 895 |
-
|
| 896 |
-
|
| 897 |
-
|
| 898 |
-
|
| 899 |
-
|
| 900 |
-
|
| 901 |
-
|
| 902 |
-
|
| 903 |
-
|
| 904 |
-
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
/**
|
| 3 |
+
* Utility class for printing the link listing table.
|
| 4 |
+
*
|
| 5 |
+
* @package Broken Link Checker
|
| 6 |
+
* @access public
|
| 7 |
+
*/
|
| 8 |
+
|
| 9 |
+
if ( ! class_exists( 'blcTablePrinter' ) ) {
|
| 10 |
+
|
| 11 |
+
class blcTablePrinter {
|
| 12 |
+
|
| 13 |
+
var $current_filter; //The current search filter. Also contains the list of links to display.
|
| 14 |
+
var $page; //The current page number
|
| 15 |
+
var $per_page; //Max links per page
|
| 16 |
+
/** @var wsBrokenLinkChecker */
|
| 17 |
+
var $core; //A reference to the main plugin object
|
| 18 |
+
var $neutral_current_url; //The "safe" version of the current URL, for use in the bulk action form.
|
| 19 |
+
|
| 20 |
+
var $bulk_actions_html = '';
|
| 21 |
+
var $pagination_html = '';
|
| 22 |
+
var $searched_link_type = '';
|
| 23 |
+
|
| 24 |
+
var $columns;
|
| 25 |
+
var $layouts;
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
function __construct( $core ) {
|
| 29 |
+
$this->core = $core;
|
| 30 |
+
|
| 31 |
+
// Initialize layout and column definitions,
|
| 32 |
+
$this->setup_columns();
|
| 33 |
+
$this->setup_layouts();
|
| 34 |
+
|
| 35 |
+
// Figure out what the "safe" URL to acccess the current page would be.
|
| 36 |
+
// This is used by the bulk action form.
|
| 37 |
+
$special_args = array( '_wpnonce', '_wp_http_referer', 'action', 'selected_links' );
|
| 38 |
+
$this->neutral_current_url = remove_query_arg( $special_args );
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
/**
|
| 43 |
+
* Print the entire link table and associated navigation elements.
|
| 44 |
+
*
|
| 45 |
+
* @param array $current_filter
|
| 46 |
+
* @param string $layout
|
| 47 |
+
* @param array $visible_columns
|
| 48 |
+
* @param bool $compact
|
| 49 |
+
* @return void
|
| 50 |
+
*/
|
| 51 |
+
function print_table( $current_filter, $layout = 'flexible', $visible_columns = null, $compact = false ) {
|
| 52 |
+
$this->current_filter = $current_filter;
|
| 53 |
+
$this->page = $current_filter['page'];
|
| 54 |
+
$this->per_page = $current_filter['per_page'];
|
| 55 |
+
|
| 56 |
+
$current_layout = $this->layouts[$layout];
|
| 57 |
+
if ( empty( $visible_columns ) ) {
|
| 58 |
+
$visible_columns = $current_layout;
|
| 59 |
+
}
|
| 60 |
+
// Only allow columns actually present in this layout.
|
| 61 |
+
$visible_columns = array_intersect( $visible_columns, $current_layout );
|
| 62 |
+
|
| 63 |
+
echo '<form id="blc-bulk-action-form" action="' . esc_attr( $this->neutral_current_url ) . '" method="post">';
|
| 64 |
+
wp_nonce_field( 'bulk-action' );
|
| 65 |
+
|
| 66 |
+
// Top navigation.
|
| 67 |
+
$this->prepare_nav_html();
|
| 68 |
+
$this->navigation( $compact );
|
| 69 |
+
|
| 70 |
+
// Table header.
|
| 71 |
+
$table_classes = array( 'widefat' );
|
| 72 |
+
if ( $compact ) {
|
| 73 |
+
$table_classes[] = 'compact';
|
| 74 |
+
};
|
| 75 |
+
if ( $this->core->conf->options['table_color_code_status'] ) {
|
| 76 |
+
$table_classes[] = 'color-code-link-status';
|
| 77 |
+
};
|
| 78 |
+
$table_classes[] = 'base-filter-' . $current_filter['base_filter'];
|
| 79 |
+
printf(
|
| 80 |
+
'<table class="%s" id="blc-links"><thead><tr>',
|
| 81 |
+
implode( ' ', $table_classes )
|
| 82 |
+
);
|
| 83 |
+
|
| 84 |
+
// The select-all checkbox.
|
| 85 |
+
echo '<th scope="col" class="column-checkbox check-column" id="cb"><input type="checkbox" /></th>';
|
| 86 |
+
|
| 87 |
+
// Column headers.
|
| 88 |
+
foreach ( $current_layout as $column_id ) {
|
| 89 |
+
$column = $this->columns[ $column_id ];
|
| 90 |
+
|
| 91 |
+
$column_classes = array( 'column-' . $column_id );
|
| 92 |
+
if ( isset( $column['class'] ) ) {
|
| 93 |
+
$column_classes[] = $column['class'];
|
| 94 |
+
}
|
| 95 |
+
if ( ! in_array( $column_id, $visible_columns ) ) {
|
| 96 |
+
$column_classes[] = 'hidden';
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
$heading = $column['heading'];
|
| 100 |
+
if ( isset( $column['sortable'] ) && $column['sortable'] ) {
|
| 101 |
+
$orderby = $column['orderby'];
|
| 102 |
+
$current_orderby = isset( $_GET['orderby'] ) ? $_GET['orderby'] : '';
|
| 103 |
+
$current_order = isset( $_GET['order'] ) ? $_GET['order'] : 'asc';
|
| 104 |
+
if ( ! in_array( $current_order, array( 'asc', 'desc') ) ) {
|
| 105 |
+
$current_order = 'asc';
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
if ( $orderby == $current_orderby ) {
|
| 109 |
+
$column_classes[] = 'sorted';
|
| 110 |
+
$column_classes[] = $current_order;
|
| 111 |
+
$order = ( 'asc' == $current_order ) ? 'desc' : 'asc'; //Reverse the sort direction
|
| 112 |
+
} else {
|
| 113 |
+
$order = 'asc';
|
| 114 |
+
$column_classes[] = 'desc';
|
| 115 |
+
$column_classes[] = 'sortable';
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
$heading = sprintf(
|
| 119 |
+
'<a href="%s"><span>%s</span><span class="sorting-indicator"></span></a>',
|
| 120 |
+
esc_attr(add_query_arg(array(
|
| 121 |
+
'orderby' => $orderby,
|
| 122 |
+
'order' => $order,
|
| 123 |
+
))),
|
| 124 |
+
$heading
|
| 125 |
+
);
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
printf(
|
| 129 |
+
'<th scope="col" class="%s"%s>%s</th>',
|
| 130 |
+
implode( ' ', $column_classes ),
|
| 131 |
+
isset ( $column['id'] ) ? ' id="' . $column['id'] . '"' : '',
|
| 132 |
+
$heading
|
| 133 |
+
);
|
| 134 |
+
}
|
| 135 |
+
echo '</tr></thead>';
|
| 136 |
+
|
| 137 |
+
// Table body.
|
| 138 |
+
echo '<tbody id="the-list">';
|
| 139 |
+
$this->bulk_edit_form( $visible_columns );
|
| 140 |
+
$rownum = 0;
|
| 141 |
+
foreach ( $this->current_filter['links'] as $link ) {
|
| 142 |
+
$rownum++;
|
| 143 |
+
$this->link_row( $link, $current_layout, $visible_columns, $rownum );
|
| 144 |
+
$this->link_details_row( $link, $visible_columns, $rownum );
|
| 145 |
+
}
|
| 146 |
+
echo '</tbody></table>';
|
| 147 |
+
|
| 148 |
+
// Bottom navigation.
|
| 149 |
+
$this->navigation( $compact, '2' );
|
| 150 |
+
echo '</form>';
|
| 151 |
+
|
| 152 |
+
// Inline editor (hidden by default, JS will move it to the right place).
|
| 153 |
+
$this->inline_editor( $visible_columns );
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
/**
|
| 157 |
+
* Print the "Bulk Actions" dropdown and navigation links
|
| 158 |
+
*
|
| 159 |
+
* @param bool $table_compact Whether to use the full or compact view.
|
| 160 |
+
* @param string $suffix Optional. Appended to ID and name attributes of the bulk action dropdown.
|
| 161 |
+
* @return void
|
| 162 |
+
*/
|
| 163 |
+
function navigation( $table_compact = false, $suffix = '' ) {
|
| 164 |
+
// Display the "Bulk Actions" dropdown.
|
| 165 |
+
echo '<div class="tablenav">
|
| 166 |
+
<div class="alignleft actions">
|
| 167 |
+
<select name="action' . $suffix . '" id="blc-bulk-action' . $suffix . '">' .
|
| 168 |
+
$this->bulk_actions_html .
|
| 169 |
+
'</select>
|
| 170 |
+
<input type="submit" name="doaction' . $suffix . '" id="doaction' . $suffix . '" value="',
|
| 171 |
+
esc_attr( __( 'Apply', 'broken-link-checker' ) ) .
|
| 172 |
+
'" class="button-secondary action">
|
| 173 |
+
</div>';
|
| 174 |
+
|
| 175 |
+
// Display pagination links.
|
| 176 |
+
if ( ! empty( $this->pagination_html ) ) {
|
| 177 |
+
echo $this->pagination_html;
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
// Display the view switch (only in the top nav. area).
|
| 181 |
+
if ( empty( $suffix ) ) {
|
| 182 |
+
?>
|
| 183 |
+
|
| 184 |
+
<div class="view-switch">
|
| 185 |
+
<a
|
| 186 |
+
href="<?php echo esc_url( add_query_arg( 'compact', '1', $_SERVER['REQUEST_URI'] ) ) ?>"
|
| 187 |
+
class="view-list <?php if ( $table_compact ) echo 'current'; ?>"
|
| 188 |
+
title="<?php echo esc_attr( __( 'Compact View', 'broken-link-checker' ) ); ?>">
|
| 189 |
+
</a>
|
| 190 |
+
<a
|
| 191 |
+
href="<?php echo esc_url( add_query_arg( 'compact', '0', $_SERVER['REQUEST_URI'] ) ) ?>"
|
| 192 |
+
class="view-excerpt <?php if ( ! $table_compact ) echo 'current'; ?>"
|
| 193 |
+
title="<?php echo esc_attr( __( 'Detailed View', 'broken-link-checker' ) ); ?>">
|
| 194 |
+
</a>
|
| 195 |
+
</div>
|
| 196 |
+
|
| 197 |
+
<?php
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
echo '</div>';
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
/**
|
| 204 |
+
* Initialize the internal list of available table columns.
|
| 205 |
+
*
|
| 206 |
+
* @return void
|
| 207 |
+
*/
|
| 208 |
+
function setup_columns(){
|
| 209 |
+
$this->columns = array(
|
| 210 |
+
'status' => array(
|
| 211 |
+
'heading' => __( 'Status', 'broken-link-checker' ),
|
| 212 |
+
'content' => array( $this, 'column_status' ),
|
| 213 |
+
),
|
| 214 |
+
|
| 215 |
+
'new-url' => array(
|
| 216 |
+
'heading' => __( 'URL', 'broken-link-checker' ),
|
| 217 |
+
'content' => array( $this, 'column_new_url' ),
|
| 218 |
+
'sortable' => true,
|
| 219 |
+
'orderby' => 'url',
|
| 220 |
+
),
|
| 221 |
+
|
| 222 |
+
'used-in' => array(
|
| 223 |
+
'heading' => __( 'Source', 'broken-link-checker' ),
|
| 224 |
+
'class' => 'column-title',
|
| 225 |
+
'content' => array( $this, 'column_used_in' ),
|
| 226 |
+
),
|
| 227 |
+
|
| 228 |
+
'new-link-text' => array(
|
| 229 |
+
'heading' => __( 'Link Text', 'broken-link-checker' ),
|
| 230 |
+
'content' => array( $this, 'column_new_link_text' ),
|
| 231 |
+
'sortable' => true,
|
| 232 |
+
'orderby' => 'link_text',
|
| 233 |
+
),
|
| 234 |
+
|
| 235 |
+
'redirect-url' => array(
|
| 236 |
+
'heading' => __( 'Redirect URL', 'broken-link-checker' ),
|
| 237 |
+
'content' => array( $this, 'column_redirect_url' ),
|
| 238 |
+
'sortable' => true,
|
| 239 |
+
'orderby' => 'redirect_url',
|
| 240 |
+
),
|
| 241 |
+
);
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
/**
|
| 245 |
+
* Initialize the list of available layouts
|
| 246 |
+
*
|
| 247 |
+
* @return void
|
| 248 |
+
*/
|
| 249 |
+
function setup_layouts() {
|
| 250 |
+
$this->layouts = array(
|
| 251 |
+
'classic' => array( 'used-in', 'new-link-text', 'new-url' ),
|
| 252 |
+
'flexible' => array( 'new-url', 'status', 'new-link-text', 'redirect-url', 'used-in' ),
|
| 253 |
+
);
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
/**
|
| 257 |
+
* Get a list of columns available in a specific table layout.
|
| 258 |
+
*
|
| 259 |
+
* @param string $layout Layout ID.
|
| 260 |
+
* @return array Associative array of column data indexed by column ID.
|
| 261 |
+
*/
|
| 262 |
+
function get_layout_columns( $layout ) {
|
| 263 |
+
if ( isset( $this->layouts[ $layout ] ) ) {
|
| 264 |
+
|
| 265 |
+
$result = array();
|
| 266 |
+
foreach ( $this->layouts[ $layout ] as $column_id ) {
|
| 267 |
+
if ( isset( $this->columns[ $column_id ] ) ) {
|
| 268 |
+
$result[ $column_id ] = $this->columns[ $column_id ];
|
| 269 |
+
}
|
| 270 |
+
}
|
| 271 |
+
return $result;
|
| 272 |
+
|
| 273 |
+
} else {
|
| 274 |
+
return null;
|
| 275 |
+
}
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
/**
|
| 279 |
+
* Pre-generate some HTML fragments used for both the top and bottom navigation/bulk action boxes.
|
| 280 |
+
*
|
| 281 |
+
* @return void
|
| 282 |
+
*/
|
| 283 |
+
function prepare_nav_html(){
|
| 284 |
+
//Generate an <option> element for each possible bulk action. The list doesn't change,
|
| 285 |
+
//so we can do it once and reuse the generated HTML.
|
| 286 |
+
$bulk_actions = array(
|
| 287 |
+
'-1' => __( 'Bulk Actions', 'broken-link-checker' ),
|
| 288 |
+
'bulk-edit' => __( 'Edit URL', 'broken-link-checker' ),
|
| 289 |
+
'bulk-recheck' => __( 'Recheck', 'broken-link-checker' ),
|
| 290 |
+
'bulk-deredirect' => __( 'Fix redirects', 'broken-link-checker' ),
|
| 291 |
+
'bulk-not-broken' => __( 'Mark as not broken', 'broken-link-checker' ),
|
| 292 |
+
'bulk-dismiss' => __( 'Dismiss', 'broken-link-checker' ),
|
| 293 |
+
'bulk-unlink' => __( 'Unlink', 'broken-link-checker' ),
|
| 294 |
+
);
|
| 295 |
+
if ( EMPTY_TRASH_DAYS ) {
|
| 296 |
+
$bulk_actions['bulk-trash-sources'] = __( 'Move sources to Trash', 'broken-link-checker' );
|
| 297 |
+
} else {
|
| 298 |
+
$bulk_actions['bulk-delete-sources'] = __( 'Delete sources', 'broken-link-checker' );
|
| 299 |
+
}
|
| 300 |
+
|
| 301 |
+
$bulk_actions_html = '';
|
| 302 |
+
foreach ( $bulk_actions as $value => $name ) {
|
| 303 |
+
$bulk_actions_html .= sprintf( '<option value="%s">%s</option>', $value, $name );
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
$this->bulk_actions_html = $bulk_actions_html;
|
| 307 |
+
|
| 308 |
+
// Pagination links can also be pre-generated.
|
| 309 |
+
// WP has a built-in function for pagination :).
|
| 310 |
+
$page_links = paginate_links( array(
|
| 311 |
+
'base' => add_query_arg( 'paged', '%#%' ),
|
| 312 |
+
'format' => '',
|
| 313 |
+
'prev_text' => __('«'),
|
| 314 |
+
'next_text' => __('»'),
|
| 315 |
+
'total' => $this->current_filter['max_pages'],
|
| 316 |
+
'current' => $this->page
|
| 317 |
+
));
|
| 318 |
+
|
| 319 |
+
if ( $page_links ) {
|
| 320 |
+
$this->pagination_html = '<div class="tablenav-pages">';
|
| 321 |
+
$this->pagination_html .= sprintf(
|
| 322 |
+
'<span class="displaying-num">' . __( 'Displaying %s–%s of <span class="current-link-count">%s</span>', 'broken-link-checker' ) . '</span>%s',
|
| 323 |
+
number_format_i18n( ( $this->page - 1 ) * $this->per_page + 1 ),
|
| 324 |
+
number_format_i18n( min( $this->page * $this->per_page, $this->current_filter['count'] ) ),
|
| 325 |
+
number_format_i18n( $this->current_filter['count'] ),
|
| 326 |
+
$page_links
|
| 327 |
+
);
|
| 328 |
+
$this->pagination_html .= '</div>';
|
| 329 |
+
} else {
|
| 330 |
+
$this->pagination_html = '';
|
| 331 |
+
}
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
/**
|
| 335 |
+
* Print the bulk edit form.
|
| 336 |
+
*
|
| 337 |
+
* @param array $visible_columns List of visible columns.
|
| 338 |
+
* @return void
|
| 339 |
+
*/
|
| 340 |
+
function bulk_edit_form( $visible_columns ) {
|
| 341 |
+
?>
|
| 342 |
+
<tr id="bulk-edit" class="inline-edit-rows"><td colspan="<?php echo count( $visible_columns ) + 1; ?>">
|
| 343 |
+
<div id="bulk-edit-wrap">
|
| 344 |
+
<fieldset>
|
| 345 |
+
<h4><?php _e( 'Bulk Edit URLs', 'broken-link-checker' ); ?></h4>
|
| 346 |
+
<label>
|
| 347 |
+
<span class="title"><?php _e( 'Find', 'broken-link-checker' ); ?></span>
|
| 348 |
+
<input type="text" name="search" class="text">
|
| 349 |
+
</label>
|
| 350 |
+
<label>
|
| 351 |
+
<span class="title"><?php _e( 'Replace with', 'broken-link-checker' ); ?></span>
|
| 352 |
+
<input type="text" name="replace" class="text">
|
| 353 |
+
</label>
|
| 354 |
+
|
| 355 |
+
<div id="bulk-edit-options">
|
| 356 |
+
<span class="title"> </span>
|
| 357 |
+
<label>
|
| 358 |
+
<input type="checkbox" name="case_sensitive">
|
| 359 |
+
<?php _e( 'Case sensitive', 'broken-link-checker' ); ?>
|
| 360 |
+
</label>
|
| 361 |
+
<label>
|
| 362 |
+
<input type="checkbox" name="regex">
|
| 363 |
+
<?php _e( 'Regular expression', 'broken-link-checker' ); ?>
|
| 364 |
+
</label>
|
| 365 |
+
</div>
|
| 366 |
+
</fieldset>
|
| 367 |
+
|
| 368 |
+
<p class="submit inline-edit-save">
|
| 369 |
+
<a href="#bulk-edit" class="button-secondary cancel alignleft" title="<?php echo esc_attr( __( 'Cancel', 'broken-link-checker' ) ); ?>" accesskey="c"><?php _e( 'Cancel', 'broken-link-checker' ); ?></a>
|
| 370 |
+
<input type="submit" name="bulk_edit" class="button-primary alignright" value="<?php
|
| 371 |
+
_e( 'Update', 'broken-link-checker' );
|
| 372 |
+
?>" accesskey="s">
|
| 373 |
+
</p>
|
| 374 |
+
</div>
|
| 375 |
+
</td></tr>
|
| 376 |
+
<?php
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
/**
|
| 380 |
+
* Print the link row.
|
| 381 |
+
*
|
| 382 |
+
* @param blcLink $link The link to display.
|
| 383 |
+
* @param array $layout List of columns to output.
|
| 384 |
+
* @param array $visible_columns List of visible columns.
|
| 385 |
+
* @param integer $rownum Table row number.
|
| 386 |
+
* @return void
|
| 387 |
+
*/
|
| 388 |
+
function link_row( $link, $layout, $visible_columns, $rownum = 0 ) {
|
| 389 |
+
|
| 390 |
+
//Figure out what CSS classes the link row should have
|
| 391 |
+
$rowclass = ($rownum % 2)? 'alternate' : '';
|
| 392 |
+
|
| 393 |
+
$excluded = $this->core->is_excluded( $link->url );
|
| 394 |
+
if ( $excluded ) {
|
| 395 |
+
$rowclass .= ' blc-excluded-link';
|
| 396 |
+
}
|
| 397 |
+
|
| 398 |
+
if ( $link->redirect_count > 0 ) {
|
| 399 |
+
$rowclass .= ' blc-redirect';
|
| 400 |
+
}
|
| 401 |
+
|
| 402 |
+
$days_broken = 0;
|
| 403 |
+
if ( $link->broken ) {
|
| 404 |
+
// Add a highlight to broken links that appear to be permanently broken.
|
| 405 |
+
$days_broken = intval( ( time() - $link->first_failure ) / ( 3600 * 24 ) );
|
| 406 |
+
if ( $days_broken >= $this->core->conf->options['failure_duration_threshold'] ) {
|
| 407 |
+
$rowclass .= ' blc-permanently-broken';
|
| 408 |
+
if ( $this->core->conf->options['highlight_permanent_failures'] ) {
|
| 409 |
+
$rowclass .= ' blc-permanently-broken-hl';
|
| 410 |
+
}
|
| 411 |
+
}
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
$status = $link->analyse_status();
|
| 415 |
+
$rowclass .= ' link-status-' . $status['code'];
|
| 416 |
+
|
| 417 |
+
// Retrieve link instances to display in the table.
|
| 418 |
+
$instances = $link->get_instances();
|
| 419 |
+
|
| 420 |
+
if ( ! empty( $instances ) ) {
|
| 421 |
+
// Put instances that match the selected link type at the top. Makes search results look better.
|
| 422 |
+
if ( ! empty( $this->current_filter['search_params']['s_link_type'] ) ) {
|
| 423 |
+
$s_link_type = $this->current_filter['search_params']['s_link_type'];
|
| 424 |
+
} else {
|
| 425 |
+
$s_link_type = '';
|
| 426 |
+
}
|
| 427 |
+
$instances = $this->sort_instances_for_display( $instances, $s_link_type );
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
// For inline editing, we'll need to know if any instances have editable link text, and what it is.
|
| 431 |
+
$can_edit_text = false;
|
| 432 |
+
$can_edit_url = false;
|
| 433 |
+
$editable_link_texts = $non_editable_link_texts = array();
|
| 434 |
+
foreach ( $instances as $instance ) {
|
| 435 |
+
if ( $instance->is_link_text_editable() ) {
|
| 436 |
+
$can_edit_text = true;
|
| 437 |
+
$editable_link_texts[ $instance->link_text ] = true;
|
| 438 |
+
} else {
|
| 439 |
+
$non_editable_link_texts[ $instance->link_text ] = true;
|
| 440 |
+
}
|
| 441 |
+
|
| 442 |
+
if ( $instance->is_url_editable() ) {
|
| 443 |
+
$can_edit_url = true;
|
| 444 |
+
}
|
| 445 |
+
}
|
| 446 |
+
|
| 447 |
+
$link_texts = $can_edit_text ? $editable_link_texts : $non_editable_link_texts;
|
| 448 |
+
$data_link_text = '';
|
| 449 |
+
if ( 1 === count( $link_texts ) ) {
|
| 450 |
+
// All instances have the same text - use it.
|
| 451 |
+
$link_text = key( $link_texts );
|
| 452 |
+
$data_link_text = ' data-link-text="' . esc_attr( $link_text ) . '"';
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
printf(
|
| 456 |
+
'<tr id="blc-row-%s" class="blc-row %s" data-days-broken="%d" data-can-edit-url="%d" data-can-edit-text="%d"%s>',
|
| 457 |
+
$link->link_id,
|
| 458 |
+
$rowclass,
|
| 459 |
+
$days_broken,
|
| 460 |
+
$can_edit_url ? 1 : 0,
|
| 461 |
+
$can_edit_text ? 1 : 0,
|
| 462 |
+
$data_link_text
|
| 463 |
+
);
|
| 464 |
+
|
| 465 |
+
// The checkbox used to select links is automatically printed in all layouts
|
| 466 |
+
// and can't be disabled. Without it, bulk actions wouldn't work.
|
| 467 |
+
$this->column_checkbox( $link );
|
| 468 |
+
|
| 469 |
+
foreach ( $layout as $column_id ) {
|
| 470 |
+
$column = $this->columns[ $column_id ];
|
| 471 |
+
|
| 472 |
+
printf(
|
| 473 |
+
'<td class="column-%s%s">',
|
| 474 |
+
$column_id,
|
| 475 |
+
in_array( $column_id, $visible_columns ) ? '' : ' hidden'
|
| 476 |
+
);
|
| 477 |
+
|
| 478 |
+
if ( isset( $column['content'] ) ) {
|
| 479 |
+
if ( is_callable( $column['content'] ) ) {
|
| 480 |
+
call_user_func( $column['content'], $link, $instances );
|
| 481 |
+
} else {
|
| 482 |
+
echo $column['content'];
|
| 483 |
+
}
|
| 484 |
+
} else {
|
| 485 |
+
echo '[', $column_id, ']';
|
| 486 |
+
}
|
| 487 |
+
|
| 488 |
+
echo '</td>';
|
| 489 |
+
}
|
| 490 |
+
|
| 491 |
+
echo '</tr>';
|
| 492 |
+
}
|
| 493 |
+
|
| 494 |
+
/**
|
| 495 |
+
* Print the details row for a specific link.
|
| 496 |
+
*
|
| 497 |
+
* @uses blcTablePrinter::details_row_contents()
|
| 498 |
+
*
|
| 499 |
+
* @param blcLink $link The link to display.
|
| 500 |
+
* @param array $visible_columns List of visible columns.
|
| 501 |
+
* @param integer $rownum Table row number.
|
| 502 |
+
* @return void
|
| 503 |
+
*/
|
| 504 |
+
function link_details_row( $link, $visible_columns, $rownum = 0 ) {
|
| 505 |
+
printf(
|
| 506 |
+
'<tr id="link-details-%d" class="blc-link-details"><td colspan="%d">',
|
| 507 |
+
$link->link_id,
|
| 508 |
+
count( $visible_columns ) + 1
|
| 509 |
+
);
|
| 510 |
+
$this->details_row_contents( $link );
|
| 511 |
+
echo '</td></tr>';
|
| 512 |
+
}
|
| 513 |
+
|
| 514 |
+
/**
|
| 515 |
+
* Print the contents of the details row for a specific link.
|
| 516 |
+
*
|
| 517 |
+
* @param blcLink $link
|
| 518 |
+
* @return void
|
| 519 |
+
*/
|
| 520 |
+
public static function details_row_contents( $link ) {
|
| 521 |
+
?>
|
| 522 |
+
<div class="blc-detail-container">
|
| 523 |
+
<div class="blc-detail-block" style="float: left; width: 49%;">
|
| 524 |
+
<ol style='list-style-type: none;'>
|
| 525 |
+
<?php if ( ! empty( $link->post_date ) ) { ?>
|
| 526 |
+
<li><strong><?php _e( 'Post published on', 'broken-link-checker' ); ?>:</strong>
|
| 527 |
+
<span class='post_date'><?php
|
| 528 |
+
echo date_i18n( get_option( 'date_format' ), strtotime( $link->post_date ) );
|
| 529 |
+
?></span></li>
|
| 530 |
+
<?php } ?>
|
| 531 |
+
<li><strong><?php _e( 'Link last checked', 'broken-link-checker' ); ?>:</strong>
|
| 532 |
+
<span class='check_date'><?php
|
| 533 |
+
$last_check = $link->last_check;
|
| 534 |
+
if ( $last_check < strtotime( '-10 years' ) ) {
|
| 535 |
+
_e( 'Never', 'broken-link-checker' );
|
| 536 |
+
} else {
|
| 537 |
+
printf(
|
| 538 |
+
'<time datetime="%s">%s</time>',
|
| 539 |
+
esc_attr( date( 'c', $last_check ) ),
|
| 540 |
+
date_i18n( get_option('date_format' ), $last_check )
|
| 541 |
+
);
|
| 542 |
+
}
|
| 543 |
+
?></span></li>
|
| 544 |
+
|
| 545 |
+
<li><strong><?php _e( 'HTTP code', 'broken-link-checker' ); ?>:</strong>
|
| 546 |
+
<span class='http_code'><?php
|
| 547 |
+
print $link->http_code;
|
| 548 |
+
?></span></li>
|
| 549 |
+
|
| 550 |
+
<li><strong><?php _e( 'Response time', 'broken-link-checker' ); ?>:</strong>
|
| 551 |
+
<span class='request_duration'><?php
|
| 552 |
+
printf( __( '%2.3f seconds', 'broken-link-checker' ), $link->request_duration );
|
| 553 |
+
?></span></li>
|
| 554 |
+
|
| 555 |
+
<li><strong><?php _e( 'Final URL', 'broken-link-checker' ); ?>:</strong>
|
| 556 |
+
<span class='final_url'><?php
|
| 557 |
+
print esc_html( $link->final_url );
|
| 558 |
+
?></span></li>
|
| 559 |
+
|
| 560 |
+
<li><strong><?php _e( 'Redirect count', 'broken-link-checker' ); ?>:</strong>
|
| 561 |
+
<span class='redirect_count'><?php
|
| 562 |
+
print $link->redirect_count;
|
| 563 |
+
?></span></li>
|
| 564 |
+
|
| 565 |
+
<li><strong><?php _e( 'Instance count', 'broken-link-checker' ); ?>:</strong>
|
| 566 |
+
<span class='instance_count'><?php
|
| 567 |
+
print count( $link->get_instances() );
|
| 568 |
+
?></span></li>
|
| 569 |
+
|
| 570 |
+
<?php if ( ( $link->broken || $link->warning ) && (intval( $link->check_count ) > 0) ) { ?>
|
| 571 |
+
<li><br/>
|
| 572 |
+
<?php
|
| 573 |
+
printf(
|
| 574 |
+
_n('This link has failed %d time.', 'This link has failed %d times.', $link->check_count, 'broken-link-checker'),
|
| 575 |
+
$link->check_count
|
| 576 |
+
);
|
| 577 |
+
|
| 578 |
+
echo '<br>';
|
| 579 |
+
|
| 580 |
+
$delta = time() - $link->first_failure;
|
| 581 |
+
printf(
|
| 582 |
+
__('This link has been broken for %s.', 'broken-link-checker'),
|
| 583 |
+
blcUtility::fuzzy_delta($delta)
|
| 584 |
+
);
|
| 585 |
+
?>
|
| 586 |
+
</li>
|
| 587 |
+
<?php } ?>
|
| 588 |
+
</ol>
|
| 589 |
+
</div>
|
| 590 |
+
|
| 591 |
+
<div class="blc-detail-block" style="float: right; width: 50%;">
|
| 592 |
+
<ol style='list-style-type: none;'>
|
| 593 |
+
<li><strong><?php _e('Log', 'broken-link-checker'); ?>:</strong>
|
| 594 |
+
<span class='blc_log'><?php
|
| 595 |
+
print nl2br( $link->log );
|
| 596 |
+
?></span></li>
|
| 597 |
+
</ol>
|
| 598 |
+
</div>
|
| 599 |
+
|
| 600 |
+
<div style="clear:both;"> </div>
|
| 601 |
+
</div>
|
| 602 |
+
<?php
|
| 603 |
+
}
|
| 604 |
+
|
| 605 |
+
function column_checkbox( $link ) {
|
| 606 |
+
?>
|
| 607 |
+
<th scope="row" class="check-column"><input type="checkbox" name="selected_links[]" value="<?php echo $link->link_id; ?>" /></th>
|
| 608 |
+
<?php
|
| 609 |
+
}
|
| 610 |
+
|
| 611 |
+
/**
|
| 612 |
+
* @param blcLink $link
|
| 613 |
+
* @param blcLinkInstance[] $instances
|
| 614 |
+
*/
|
| 615 |
+
function column_status( $link, $instances ) {
|
| 616 |
+
printf(
|
| 617 |
+
'<table class="mini-status" title="%s">',
|
| 618 |
+
esc_attr( __( 'Show more info about this link', 'broken-link-checker' ) )
|
| 619 |
+
);
|
| 620 |
+
|
| 621 |
+
$status = $link->analyse_status();
|
| 622 |
+
|
| 623 |
+
printf(
|
| 624 |
+
'<tr class="link-status-row link-status-%s">
|
| 625 |
+
<td>
|
| 626 |
+
<span class="http-code">%s</span> <span class="status-text">%s</span>
|
| 627 |
+
</td>
|
| 628 |
+
</tr>',
|
| 629 |
+
$status['code'],
|
| 630 |
+
empty( $link->http_code ) ? '' : $link->http_code,
|
| 631 |
+
$status['text']
|
| 632 |
+
);
|
| 633 |
+
|
| 634 |
+
// Last checked...
|
| 635 |
+
if ( $link->last_check != 0 ) {
|
| 636 |
+
$last_check = _x( 'Checked', 'checked how long ago', 'broken-link-checker' ) . ' ';
|
| 637 |
+
$last_check .= blcUtility::fuzzy_delta( time() - $link->last_check, 'ago' );
|
| 638 |
+
|
| 639 |
+
printf(
|
| 640 |
+
'<tr class="link-last-checked"><td>%s</td></tr>',
|
| 641 |
+
$last_check
|
| 642 |
+
);
|
| 643 |
+
}
|
| 644 |
+
|
| 645 |
+
|
| 646 |
+
// Broken for...
|
| 647 |
+
if ( $link->broken ) {
|
| 648 |
+
$delta = time() - $link->first_failure;
|
| 649 |
+
$broken_for = blcUtility::fuzzy_delta( $delta );
|
| 650 |
+
printf(
|
| 651 |
+
'<tr class="link-broken-for"><td>%s %s</td></tr>',
|
| 652 |
+
__( 'Broken for', 'broken-link-checker' ),
|
| 653 |
+
$broken_for
|
| 654 |
+
);
|
| 655 |
+
}
|
| 656 |
+
|
| 657 |
+
echo '</table>';
|
| 658 |
+
|
| 659 |
+
// "Details" link.
|
| 660 |
+
echo '<div class="row-actions">';
|
| 661 |
+
printf(
|
| 662 |
+
'<span><a href="#" class="blc-details-button" title="%s">%s</a></span>',
|
| 663 |
+
esc_attr( __( 'Show more info about this link', 'broken-link-checker' ) ),
|
| 664 |
+
_x( 'Details', 'link in the "Status" column', 'broken-link-checker' )
|
| 665 |
+
);
|
| 666 |
+
echo '</div>';
|
| 667 |
+
}
|
| 668 |
+
|
| 669 |
+
|
| 670 |
+
/**
|
| 671 |
+
* @param blcLink $link
|
| 672 |
+
*/
|
| 673 |
+
function column_new_url( $link ) {
|
| 674 |
+
?>
|
| 675 |
+
<a href="<?php print esc_url( $link->url ); ?>"
|
| 676 |
+
target='_blank'
|
| 677 |
+
class='blc-link-url'
|
| 678 |
+
title="<?php echo esc_attr( $link->url ); ?>"
|
| 679 |
+
data-editable-url="<?php echo esc_attr( $link->url ); ?>">
|
| 680 |
+
<?php print esc_html( $link->url ); ?></a>
|
| 681 |
+
<?php
|
| 682 |
+
// Output inline action links for the link/URL.
|
| 683 |
+
$actions = array();
|
| 684 |
+
|
| 685 |
+
$actions['edit'] = "<a href='javascript:void(0)' class='blc-edit-button' title='" . esc_attr( __('Edit this link' , 'broken-link-checker') ) . "'>". __( 'Edit URL' , 'broken-link-checker' ) . '</a>';
|
| 686 |
+
|
| 687 |
+
$actions['delete'] = "<a class='submitdelete blc-unlink-button' title='" . esc_attr( __( 'Remove this link from all posts', 'broken-link-checker') ). "' ".
|
| 688 |
+
"href='javascript:void(0);'>" . __( 'Unlink', 'broken-link-checker' ) . '</a>';
|
| 689 |
+
|
| 690 |
+
if ( $link->broken || $link->warning ) {
|
| 691 |
+
$actions['blc-discard-action'] = sprintf(
|
| 692 |
+
'<a href="#" title="%s" class="blc-discard-button">%s</a>',
|
| 693 |
+
esc_attr( __( 'Remove this link from the list of broken links and mark it as valid', 'broken-link-checker' ) ),
|
| 694 |
+
__( 'Not broken', 'broken-link-checker' )
|
| 695 |
+
);
|
| 696 |
+
}
|
| 697 |
+
|
| 698 |
+
if ( ! $link->dismissed && ( $link->broken || $link->warning || ( $link->redirect_count > 0 ) ) ) {
|
| 699 |
+
$actions['blc-dismiss-action'] = sprintf(
|
| 700 |
+
'<a href="#" title="%s" class="blc-dismiss-button">%s</a>',
|
| 701 |
+
esc_attr( __( 'Hide this link and do not report it again unless its status changes' , 'broken-link-checker' ) ),
|
| 702 |
+
__( 'Dismiss', 'broken-link-checker' )
|
| 703 |
+
);
|
| 704 |
+
} else if ( $link->dismissed ) {
|
| 705 |
+
$actions['blc-undismiss-action'] = sprintf(
|
| 706 |
+
'<a href="#" title="%s" class="blc-undismiss-button">%s</a>',
|
| 707 |
+
esc_attr( __( 'Undismiss this link', 'broken-link-checker' ) ),
|
| 708 |
+
__( 'Undismiss', 'broken-link-checker' )
|
| 709 |
+
);
|
| 710 |
+
}
|
| 711 |
+
|
| 712 |
+
$actions['blc-recheck-action'] = sprintf(
|
| 713 |
+
'<a href="#" class="blc-recheck-button">%s</a>',
|
| 714 |
+
__( 'Recheck', 'broken-link-checker' )
|
| 715 |
+
);
|
| 716 |
+
|
| 717 |
+
if ( $link->redirect_count > 0 && ! empty( $link->final_url ) && ( $link->url != $link->final_url ) ) {
|
| 718 |
+
//TODO: Check if at least one instance has an editable URL. Otherwise this won't work.
|
| 719 |
+
$actions['blc-deredirect-action'] = sprintf(
|
| 720 |
+
'<a href="#" class="blc-deredirect-button" title="%s">%s</a>',
|
| 721 |
+
__( 'Replace this redirect with a direct link', 'broken-link-checker' ),
|
| 722 |
+
_x( 'Fix redirect', 'link action; replace one redirect with a direct link', 'broken-link-checker' )
|
| 723 |
+
);
|
| 724 |
+
}
|
| 725 |
+
|
| 726 |
+
// Only show the enabled actions.
|
| 727 |
+
$conf = blc_get_configuration();
|
| 728 |
+
foreach ( $conf->get( 'show_link_actions', $actions ) as $name => $enabled) {
|
| 729 |
+
if ( ! $enabled ) {
|
| 730 |
+
unset( $actions[ $name ] );
|
| 731 |
+
}
|
| 732 |
+
}
|
| 733 |
+
|
| 734 |
+
// Wrap actions with <span></span> and separate them with | characters.
|
| 735 |
+
// Basically, this emulates the HTML structure that WP uses for post actions under Posts -> All Posts.
|
| 736 |
+
$spans = array();
|
| 737 |
+
$is_first_action = true;
|
| 738 |
+
foreach ( $actions as $name => $html ) {
|
| 739 |
+
$spans[] = sprintf(
|
| 740 |
+
'<span class="%s">%s%s</span>',
|
| 741 |
+
esc_attr($name),
|
| 742 |
+
$is_first_action ? '' : ' | ',
|
| 743 |
+
$html
|
| 744 |
+
);
|
| 745 |
+
$is_first_action = false;
|
| 746 |
+
}
|
| 747 |
+
|
| 748 |
+
echo '<div class="row-actions">';
|
| 749 |
+
echo implode( '', $spans );
|
| 750 |
+
echo '</div>';
|
| 751 |
+
|
| 752 |
+
?>
|
| 753 |
+
<div class="blc-url-editor-buttons">
|
| 754 |
+
<input type="button" class="button-secondary cancel alignleft blc-cancel-button" value="<?php echo esc_attr( __( 'Cancel', 'broken-link-checker' ) ); ?>" />
|
| 755 |
+
<input type="button" class="button-primary save alignright blc-update-url-button" value="<?php echo esc_attr( __( 'Update URL', 'broken-link-checker' ) ); ?>" />
|
| 756 |
+
<img class="waiting" style="display:none;" src="<?php echo esc_url( admin_url( 'images/wpspin_light.gif' ) ); ?>" alt="" />
|
| 757 |
+
</div>
|
| 758 |
+
<?php
|
| 759 |
+
}
|
| 760 |
+
|
| 761 |
+
/**
|
| 762 |
+
* @param blcLink $link
|
| 763 |
+
* @param blcLinkInstance[] $instances
|
| 764 |
+
*/
|
| 765 |
+
function column_used_in( $link, $instances ) {
|
| 766 |
+
echo '<span class="blc-link-id" style="display:none;">',
|
| 767 |
+
$link->link_id,
|
| 768 |
+
'</span>';
|
| 769 |
+
|
| 770 |
+
if ( ! empty( $instances ) ) {
|
| 771 |
+
/** @var $instance blcLinkInstance */
|
| 772 |
+
$instance = reset( $instances );
|
| 773 |
+
echo $instance->ui_get_source();
|
| 774 |
+
|
| 775 |
+
$actions = $instance->ui_get_action_links();
|
| 776 |
+
|
| 777 |
+
echo '<div class="row-actions">';
|
| 778 |
+
echo implode( ' | </span>', $actions );
|
| 779 |
+
echo '</div>';
|
| 780 |
+
|
| 781 |
+
} else {
|
| 782 |
+
_e( '[An orphaned link! This is a bug.]', 'broken-link-checker' );
|
| 783 |
+
}
|
| 784 |
+
}
|
| 785 |
+
|
| 786 |
+
/**
|
| 787 |
+
* @param blcLink $link
|
| 788 |
+
* @param blcLinkInstance[] $instances
|
| 789 |
+
*/
|
| 790 |
+
function column_new_link_text( $link, $instances ) {
|
| 791 |
+
if ( empty( $instances ) ) {
|
| 792 |
+
echo '<em>N/A</em>';
|
| 793 |
+
} else {
|
| 794 |
+
$instance = reset( $instances ); /** @var blcLinkInstance $instance */
|
| 795 |
+
echo $instance->ui_get_link_text();
|
| 796 |
+
}
|
| 797 |
+
}
|
| 798 |
+
|
| 799 |
+
function column_redirect_url( $link, $instances ) {
|
| 800 |
+
if ( $link->redirect_count > 0 ) {
|
| 801 |
+
printf(
|
| 802 |
+
'<a href="%1$s" target="_blank" class="blc-redirect-url" title="%1$s">%2$s</a>',
|
| 803 |
+
esc_attr( $link->final_url ),
|
| 804 |
+
esc_html( $link->final_url )
|
| 805 |
+
);
|
| 806 |
+
}
|
| 807 |
+
}
|
| 808 |
+
|
| 809 |
+
/**
|
| 810 |
+
* Sort a list of link instances to be displayed in the "Broken Links" page.
|
| 811 |
+
*
|
| 812 |
+
* Groups instances by container type and, if $search_link_type is specified,
|
| 813 |
+
* puts instances that have a matching container type or parser type at the
|
| 814 |
+
* beginning.
|
| 815 |
+
*
|
| 816 |
+
* @param array $instances An array of blcLinkInstance objects.
|
| 817 |
+
* @param string $searched_link_type Optional. The required container/parser type.
|
| 818 |
+
* @return array Sorted array.
|
| 819 |
+
*/
|
| 820 |
+
function sort_instances_for_display( $instances, $searched_link_type = '' ) {
|
| 821 |
+
$this->searched_link_type = $searched_link_type;
|
| 822 |
+
usort( $instances, array( $this, 'compare_link_instances' ) );
|
| 823 |
+
return $instances;
|
| 824 |
+
}
|
| 825 |
+
|
| 826 |
+
/**
|
| 827 |
+
* Callback function for sorting link instances.
|
| 828 |
+
*
|
| 829 |
+
* @see blcTablePrinter::sort_instances_for_display()
|
| 830 |
+
*
|
| 831 |
+
* @param blcLinkInstance $a
|
| 832 |
+
* @param blcLinkInstance $b
|
| 833 |
+
* @return int
|
| 834 |
+
*/
|
| 835 |
+
function compare_link_instances( $a, $b ) {
|
| 836 |
+
if ( ! empty( $this->searched_link_type ) ) {
|
| 837 |
+
if ( ( $a->container_type == $this->searched_link_type ) || ( $a->parser_type == $this->searched_link_type ) ) {
|
| 838 |
+
if ( ( $b->container_type == $this->searched_link_type ) || ( $b->parser_type == $this->searched_link_type ) ) {
|
| 839 |
+
return 0;
|
| 840 |
+
} else {
|
| 841 |
+
return -1;
|
| 842 |
+
}
|
| 843 |
+
} else {
|
| 844 |
+
if ( ( $b->container_type == $this->searched_link_type ) || ( $b->parser_type == $this->searched_link_type ) ) {
|
| 845 |
+
return 1;
|
| 846 |
+
}
|
| 847 |
+
}
|
| 848 |
+
}
|
| 849 |
+
|
| 850 |
+
return strcmp( $a->container_type, $b->container_type );
|
| 851 |
+
}
|
| 852 |
+
|
| 853 |
+
protected function inline_editor( $visible_columns ) {
|
| 854 |
+
?>
|
| 855 |
+
<table style="display: none;"><tbody>
|
| 856 |
+
<tr id="blc-inline-edit-row" class="blc-inline-editor">
|
| 857 |
+
<td class="blc-colspan-change" colspan="<?php echo count( $visible_columns ); ?>">
|
| 858 |
+
<div class="blc-inline-editor-content">
|
| 859 |
+
<h4><?php echo _x( 'Edit Link', 'inline editor title', 'broken-link-checker' ); ?></h4>
|
| 860 |
+
|
| 861 |
+
<label>
|
| 862 |
+
<span class="title"><?php echo _x( 'Text', 'inline link editor', 'broken-link-checker' ); ?></span>
|
| 863 |
+
<span class="blc-input-text-wrap"><input type="text" name="link_text" value="" class="blc-link-text-field" /></span>
|
| 864 |
+
</label>
|
| 865 |
+
|
| 866 |
+
<label>
|
| 867 |
+
<span class="title"><?php echo _x( 'URL', 'inline link editor', 'broken-link-checker' ); ?></span>
|
| 868 |
+
<span class="blc-input-text-wrap"><input type="text" name="link_url" value="" class="blc-link-url-field" /></span>
|
| 869 |
+
</label>
|
| 870 |
+
|
| 871 |
+
<div class="blc-url-replacement-suggestions" style="display: none;">
|
| 872 |
+
<h4><?php echo _x( 'Suggestions', 'inline link editor', 'broken-link-checker' ); ?></h4>
|
| 873 |
+
<ul class="blc-suggestion-list">
|
| 874 |
+
<li>...</li>
|
| 875 |
+
</ul>
|
| 876 |
+
</div>
|
| 877 |
+
|
| 878 |
+
<div class="submit blc-inline-editor-buttons">
|
| 879 |
+
<input type="button" class="button-secondary cancel alignleft blc-cancel-button" value="<?php echo esc_attr( __( 'Cancel', 'broken-link-checker' ) ); ?>" />
|
| 880 |
+
<input type="button" class="button-primary save alignright blc-update-link-button" value="<?php echo esc_attr( __( 'Update', 'broken-link-checker' ) ); ?>" />
|
| 881 |
+
|
| 882 |
+
<img class="waiting" style="display:none;" src="<?php echo esc_url( admin_url( 'images/wpspin_light.gif' ) ); ?>" alt="" />
|
| 883 |
+
<div class="clear"></div>
|
| 884 |
+
</div>
|
| 885 |
+
</div>
|
| 886 |
+
</td>
|
| 887 |
+
</tr>
|
| 888 |
+
</tbody></table>
|
| 889 |
+
|
| 890 |
+
<ul id="blc-suggestion-template" style="display: none;">
|
| 891 |
+
<li>
|
| 892 |
+
<input type="button" class="button-secondary blc-use-url-button" value="<?php echo esc_attr( __( 'Use this URL', 'broken-link-checker' ) ); ?>" />
|
| 893 |
+
|
| 894 |
+
<div class="blc-suggestion-details">
|
| 895 |
+
<span class="blc-suggestion-name">
|
| 896 |
+
<a href="http://example.com/" target="_blank">Suggestion name</a>
|
| 897 |
+
</span>
|
| 898 |
+
<code class="blc-suggestion-url">suggestion URL</code>
|
| 899 |
+
</div>
|
| 900 |
+
</li>
|
| 901 |
+
</ul>
|
| 902 |
+
<?php
|
| 903 |
+
}
|
| 904 |
+
|
| 905 |
+
}
|
| 906 |
+
|
| 907 |
+
} // class_exists.
|
includes/modules.php
CHANGED
|
@@ -20,6 +20,8 @@ $blc_module_manager = blcModuleManager::getInstance(array(
|
|
| 20 |
'url_field', //URL field parser
|
| 21 |
'comment', //Comment container
|
| 22 |
'custom_field', //Post metadata container (aka custom fields)
|
|
|
|
|
|
|
| 23 |
'post', //Post content container
|
| 24 |
'page', //Page content container
|
| 25 |
'youtube-checker', //Video checker using the YouTube API
|
| 20 |
'url_field', //URL field parser
|
| 21 |
'comment', //Comment container
|
| 22 |
'custom_field', //Post metadata container (aka custom fields)
|
| 23 |
+
'acf_field', //Post acf container (aka advanced custom fields)
|
| 24 |
+
'acf', //acf parser
|
| 25 |
'post', //Post content container
|
| 26 |
'page', //Page content container
|
| 27 |
'youtube-checker', //Video checker using the YouTube API
|
includes/utility-class.php
CHANGED
|
@@ -4,414 +4,414 @@
|
|
| 4 |
* @author W-Shadow
|
| 5 |
* @copyright 2010
|
| 6 |
*/
|
| 7 |
-
|
| 8 |
-
if ( !function_exists('sys_get_temp_dir')) {
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
}
|
| 21 |
|
| 22 |
//Include the internationalized domain name converter (requires PHP 5)
|
| 23 |
-
if ( version_compare(phpversion(), '5.0.0', '>=') && !class_exists('idna_convert') ){
|
| 24 |
include BLC_DIRECTORY . '/idn/idna_convert.class.php';
|
| 25 |
-
if ( !function_exists('encode_utf8') ){
|
| 26 |
include BLC_DIRECTORY . '/idn/transcode_wrapper.php';
|
| 27 |
}
|
| 28 |
}
|
| 29 |
|
| 30 |
|
| 31 |
-
if ( !class_exists('blcUtility') ){
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
case 'yes':
|
| 50 |
-
return true;
|
| 51 |
-
|
| 52 |
-
case 'off':
|
| 53 |
-
case 'false':
|
| 54 |
-
case 'no':
|
| 55 |
return false;
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
/**
|
| 74 |
-
* Truncate a string on a specified boundary character.
|
| 75 |
-
*
|
| 76 |
-
* @param string $text The text to truncate.
|
| 77 |
-
* @param integer $max_characters Return no more than $max_characters
|
| 78 |
-
* @param string $break Break on this character. Defaults to space.
|
| 79 |
-
* @param string $pad Pad the truncated string with this string. Defaults to an HTML ellipsis.
|
| 80 |
-
* @return string
|
| 81 |
-
*/
|
| 82 |
-
static function truncate($text, $max_characters = 0, $break = ' ', $pad = '…'){
|
| 83 |
-
if ( strlen($text) <= $max_characters ){
|
| 84 |
-
return $text;
|
| 85 |
-
}
|
| 86 |
-
|
| 87 |
-
$text = substr($text, 0, $max_characters);
|
| 88 |
-
$break_pos = strrpos($text, $break);
|
| 89 |
-
if ( $break_pos !== false ){
|
| 90 |
-
$text = substr($text, 0, $break_pos);
|
| 91 |
}
|
| 92 |
-
|
| 93 |
-
return $text.$pad;
|
| 94 |
-
}
|
| 95 |
-
|
| 96 |
/**
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
* with these keys :
|
| 106 |
-
* tag_name - the name of the extracted tag, e.g. "a" or "img".
|
| 107 |
-
* offset - the numberic offset of the first character of the tag within the HTML source.
|
| 108 |
-
* contents - the inner HTML of the tag. This is always empty for self-closing tags.
|
| 109 |
-
* attributes - a name -> value array of the tag's attributes, or an empty array if the tag has none.
|
| 110 |
-
* full_tag - the entire matched tag, e.g. '<a href="http://example.com">example.com</a>'. This key
|
| 111 |
-
* will only be present if you set $return_the_entire_tag to true.
|
| 112 |
-
*
|
| 113 |
-
* @param string $html The HTML code to search for tags.
|
| 114 |
-
* @param string|array $tag The tag(s) to extract.
|
| 115 |
-
* @param bool $selfclosing Whether the tag is self-closing or not. Setting it to null will force the script to try and make an educated guess.
|
| 116 |
-
* @param bool $return_the_entire_tag Return the entire matched tag in 'full_tag' key of the results array.
|
| 117 |
-
* @param string $charset The character set of the HTML code. Defaults to ISO-8859-1.
|
| 118 |
-
*
|
| 119 |
-
* @return array An array of extracted tags, or an empty array if no matching tags were found.
|
| 120 |
-
*/
|
| 121 |
-
static function extract_tags( $html, $tag, $selfclosing = null, $return_the_entire_tag = false, $charset = 'ISO-8859-1' ){
|
| 122 |
-
|
| 123 |
-
if ( is_array($tag) ){
|
| 124 |
-
$tag = implode('|', $tag);
|
| 125 |
}
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
}
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 149 |
@xsi';
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
$
|
| 181 |
-
} else if( !empty($attr['value_unquoted']) ){
|
| 182 |
-
$value = $attr['value_unquoted'];
|
| 183 |
-
} else {
|
| 184 |
-
$value = '';
|
| 185 |
}
|
| 186 |
-
|
| 187 |
-
//Passing the value through html_entity_decode is handy when you want
|
| 188 |
-
//to extract link URLs or something like that. You might want to remove
|
| 189 |
-
//or modify this call if it doesn't fit your situation.
|
| 190 |
-
$value = html_entity_decode( $value, ENT_QUOTES, $charset );
|
| 191 |
-
|
| 192 |
-
$attributes[$attr['name']] = $value;
|
| 193 |
}
|
|
|
|
| 194 |
}
|
| 195 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
}
|
| 197 |
-
|
| 198 |
-
$
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
}
|
| 207 |
-
|
| 208 |
-
$tags[] = $tag;
|
| 209 |
}
|
| 210 |
-
|
| 211 |
-
return $tags;
|
| 212 |
-
}
|
| 213 |
-
|
| 214 |
/**
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
)
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 268 |
}
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
$
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
$delta = intval($delta / $ONE_DAY);
|
| 280 |
-
$units = 'days';
|
| 281 |
-
} else {
|
| 282 |
-
$delta = intval( $delta / $ONE_MONTH );
|
| 283 |
-
$units = 'months';
|
| 284 |
}
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
)
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
static $cached_load = null;
|
| 318 |
-
static $cached_when = 0;
|
| 319 |
-
|
| 320 |
-
if ( !empty($cache) && ((time() - $cached_when) <= $cache) ){
|
| 321 |
-
return $cached_load;
|
| 322 |
}
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 334 |
}
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
* @return string
|
| 347 |
-
*/
|
| 348 |
-
static function idn_to_ascii($url, $charset = ''){
|
| 349 |
-
$idn = blcUtility::get_idna_converter();
|
| 350 |
-
if ( $idn != null ){
|
| 351 |
-
if ( empty($charset) ){
|
| 352 |
-
$charset = get_bloginfo('charset');
|
| 353 |
}
|
| 354 |
-
|
| 355 |
-
|
| 356 |
-
if ( preg_match('@(\w+:/*)?([^/:]+)(.*$)?@s', $url, $matches) ){
|
| 357 |
-
$host = $matches[2];
|
| 358 |
-
if ( (strtoupper($charset) != 'UTF-8') && (strtoupper($charset) != 'UTF8') ){
|
| 359 |
-
$host = encode_utf8($host, $charset, true);
|
| 360 |
-
}
|
| 361 |
-
$host = $idn->encode($host);
|
| 362 |
-
$url = $matches[1] . $host . $matches[3];
|
| 363 |
-
}
|
| 364 |
}
|
| 365 |
-
|
| 366 |
-
return $url;
|
| 367 |
-
}
|
| 368 |
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
|
|
|
| 379 |
}
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
static $
|
| 391 |
-
|
| 392 |
-
$
|
|
|
|
|
|
|
|
|
|
| 393 |
}
|
| 394 |
-
return $idn;
|
| 395 |
-
}
|
| 396 |
|
| 397 |
-
|
| 398 |
-
* Generate a numeric hash from a string. The result will be constrained to the specified interval.
|
| 399 |
-
*
|
| 400 |
-
* @static
|
| 401 |
-
* @param string $input
|
| 402 |
-
* @param int $min
|
| 403 |
-
* @param int $max
|
| 404 |
-
* @return float
|
| 405 |
-
*/
|
| 406 |
-
public static function constrained_hash($input, $min = 0, $max = 1) {
|
| 407 |
-
$bytes_to_use = 3;
|
| 408 |
-
$md5_char_count = 32;
|
| 409 |
-
$hash = substr(md5($input), $md5_char_count - $bytes_to_use*2);
|
| 410 |
-
$hash = intval(hexdec($hash));
|
| 411 |
-
return $min + (($max - $min) * ($hash / (pow(2, $bytes_to_use * 8) - 1)));
|
| 412 |
-
}
|
| 413 |
-
|
| 414 |
-
}//class
|
| 415 |
|
| 416 |
}//class_exists
|
| 417 |
-
|
| 4 |
* @author W-Shadow
|
| 5 |
* @copyright 2010
|
| 6 |
*/
|
| 7 |
+
|
| 8 |
+
if ( ! function_exists( 'sys_get_temp_dir' ) ) {
|
| 9 |
+
function sys_get_temp_dir() {
|
| 10 |
+
if ( ! empty( $_ENV['TMP'] ) ) { return realpath( $_ENV['TMP'] ); }
|
| 11 |
+
if ( ! empty( $_ENV['TMPDIR'] ) ) { return realpath( $_ENV['TMPDIR'] ); }
|
| 12 |
+
if ( ! empty( $_ENV['TEMP'] ) ) { return realpath( $_ENV['TEMP'] ); }
|
| 13 |
+
$tempfile = tempnam( uniqid( rand(),TRUE ),'' );
|
| 14 |
+
if ( @file_exists( $tempfile ) ) {
|
| 15 |
+
unlink( $tempfile );
|
| 16 |
+
return realpath( dirname( $tempfile ) );
|
| 17 |
+
}
|
| 18 |
+
return '';
|
| 19 |
+
}
|
| 20 |
}
|
| 21 |
|
| 22 |
//Include the internationalized domain name converter (requires PHP 5)
|
| 23 |
+
if ( version_compare( phpversion(), '5.0.0', '>=' ) && ! class_exists( 'idna_convert' ) ) {
|
| 24 |
include BLC_DIRECTORY . '/idn/idna_convert.class.php';
|
| 25 |
+
if ( ! function_exists( 'encode_utf8' ) ) {
|
| 26 |
include BLC_DIRECTORY . '/idn/transcode_wrapper.php';
|
| 27 |
}
|
| 28 |
}
|
| 29 |
|
| 30 |
|
| 31 |
+
if ( ! class_exists( 'blcUtility' ) ) {
|
| 32 |
+
class blcUtility {
|
| 33 |
+
/**
|
| 34 |
+
* Checks if PHP is running in safe mode
|
| 35 |
+
* blcUtility::is_safe_mode()
|
| 36 |
+
*
|
| 37 |
+
* @return bool
|
| 38 |
+
*/
|
| 39 |
+
static function is_safe_mode() {
|
| 40 |
+
// Check php.ini safe_mode only if PHP version is lower than 5.3.0, else set to false.
|
| 41 |
+
if ( version_compare( phpversion(), '5.3.0', '<' ) ) {
|
| 42 |
+
$safe_mode = ini_get( 'safe_mode' );
|
| 43 |
+
} else {
|
| 44 |
+
$safe_mode = false;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
// Null, 0, '', '0' and so on count as false.
|
| 48 |
+
if ( ! $safe_mode ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
return false;
|
| 50 |
+
}
|
| 51 |
+
// Test for some textual true/false variations.
|
| 52 |
+
switch ( strtolower( $safe_mode ) ) {
|
| 53 |
+
case 'on':
|
| 54 |
+
case 'true':
|
| 55 |
+
case 'yes':
|
| 56 |
+
return true;
|
| 57 |
+
|
| 58 |
+
case 'off':
|
| 59 |
+
case 'false':
|
| 60 |
+
case 'no':
|
| 61 |
+
return false;
|
| 62 |
+
|
| 63 |
+
default: // Let PHP handle anything else.
|
| 64 |
+
return (bool) (int) $safe_mode;
|
| 65 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
}
|
| 67 |
+
|
|
|
|
|
|
|
|
|
|
| 68 |
/**
|
| 69 |
+
* blcUtility::is_open_basedir()
|
| 70 |
+
* Checks if open_basedir is enabled
|
| 71 |
+
*
|
| 72 |
+
* @return bool
|
| 73 |
+
*/
|
| 74 |
+
static function is_open_basedir(){
|
| 75 |
+
$open_basedir = ini_get( 'open_basedir' );
|
| 76 |
+
return $open_basedir && ( strtolower( $open_basedir ) != 'none' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
}
|
| 78 |
+
|
| 79 |
+
/**
|
| 80 |
+
* Truncate a string on a specified boundary character.
|
| 81 |
+
*
|
| 82 |
+
* @param string $text The text to truncate.
|
| 83 |
+
* @param integer $max_characters Return no more than $max_characters
|
| 84 |
+
* @param string $break Break on this character. Defaults to space.
|
| 85 |
+
* @param string $pad Pad the truncated string with this string. Defaults to an HTML ellipsis.
|
| 86 |
+
* @return string
|
| 87 |
+
*/
|
| 88 |
+
static function truncate( $text, $max_characters = 0, $break = ' ', $pad = '…' ) {
|
| 89 |
+
if ( strlen( $text ) <= $max_characters ) {
|
| 90 |
+
return $text;
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
$text = substr( $text, 0, $max_characters );
|
| 94 |
+
$break_pos = strrpos( $text, $break );
|
| 95 |
+
if ( false !== $break_pos ) {
|
| 96 |
+
$text = substr( $text, 0, $break_pos );
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
return $text.$pad;
|
| 100 |
}
|
| 101 |
+
|
| 102 |
+
/**
|
| 103 |
+
* extract_tags()
|
| 104 |
+
* Extract specific HTML tags and their attributes from a string.
|
| 105 |
+
*
|
| 106 |
+
* You can either specify one tag, an array of tag names, or a regular expression that matches the tag name(s).
|
| 107 |
+
* If multiple tags are specified you must also set the $selfclosing parameter and it must be the same for
|
| 108 |
+
* all specified tags (so you can't extract both normal and self-closing tags in one go).
|
| 109 |
+
*
|
| 110 |
+
* The function returns a numerically indexed array of extracted tags. Each entry is an associative array
|
| 111 |
+
* with these keys :
|
| 112 |
+
* tag_name - the name of the extracted tag, e.g. "a" or "img".
|
| 113 |
+
* offset - the numberic offset of the first character of the tag within the HTML source.
|
| 114 |
+
* contents - the inner HTML of the tag. This is always empty for self-closing tags.
|
| 115 |
+
* attributes - a name -> value array of the tag's attributes, or an empty array if the tag has none.
|
| 116 |
+
* full_tag - the entire matched tag, e.g. '<a href="http://example.com">example.com</a>'. This key
|
| 117 |
+
* will only be present if you set $return_the_entire_tag to true.
|
| 118 |
+
*
|
| 119 |
+
* @param string $html The HTML code to search for tags.
|
| 120 |
+
* @param string|array $tag The tag(s) to extract.
|
| 121 |
+
* @param bool $selfclosing Whether the tag is self-closing or not. Setting it to null will force the script to try and make an educated guess.
|
| 122 |
+
* @param bool $return_the_entire_tag Return the entire matched tag in 'full_tag' key of the results array.
|
| 123 |
+
* @param string $charset The character set of the HTML code. Defaults to ISO-8859-1.
|
| 124 |
+
*
|
| 125 |
+
* @return array An array of extracted tags, or an empty array if no matching tags were found.
|
| 126 |
+
*/
|
| 127 |
+
static function extract_tags( $html, $tag, $selfclosing = null, $return_the_entire_tag = false, $charset = 'ISO-8859-1' ) {
|
| 128 |
+
|
| 129 |
+
if ( is_array( $tag ) ) {
|
| 130 |
+
$tag = implode( '|', $tag );
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
//If the user didn't specify if $tag is a self-closing tag we try to auto-detect it
|
| 134 |
+
//by checking against a list of known self-closing tags.
|
| 135 |
+
$selfclosing_tags = array( 'area', 'base', 'basefont', 'br', 'hr', 'input', 'img', 'link', 'meta', 'col', 'param' );
|
| 136 |
+
if ( is_null( $selfclosing ) ) {
|
| 137 |
+
$selfclosing = in_array( $tag, $selfclosing_tags );
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
//The regexp is different for normal and self-closing tags because I can't figure out
|
| 141 |
+
//how to make a sufficiently robust unified one.
|
| 142 |
+
if ( $selfclosing ) {
|
| 143 |
+
$tag_pattern =
|
| 144 |
+
'@<(?P<tag>' . $tag . ') # <tag
|
| 145 |
+
(?P<attributes>\s[^>]+)? # attributes, if any
|
| 146 |
+
\s*/?> # /> or just >, being lenient here
|
| 147 |
+
@xsi';
|
| 148 |
+
} else {
|
| 149 |
+
$tag_pattern =
|
| 150 |
+
'@<(?P<tag>' . $tag . ') # <tag
|
| 151 |
+
(?P<attributes>\s[^>]+)? # attributes, if any
|
| 152 |
+
\s*> # >
|
| 153 |
+
(?P<contents>.*?) # tag contents
|
| 154 |
+
</(?P=tag)> # the closing </tag>
|
| 155 |
+
@xsi';
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
$attribute_pattern =
|
| 159 |
+
'@
|
| 160 |
+
(?P<name>\w+) # attribute name
|
| 161 |
+
\s*=\s*
|
| 162 |
+
(
|
| 163 |
+
(?P<quote>[\"\'])(?P<value_quoted>.*?)(?P=quote) # a quoted value
|
| 164 |
+
| # or
|
| 165 |
+
(?P<value_unquoted>[^\s"\']+?)(?:\s+|$) # an unquoted value (terminated by whitespace or EOF)
|
| 166 |
+
)
|
| 167 |
@xsi';
|
| 168 |
+
|
| 169 |
+
//Find all tags
|
| 170 |
+
if ( ! preg_match_all( $tag_pattern, $html, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE ) ) {
|
| 171 |
+
//Return an empty array if we didn't find anything
|
| 172 |
+
return array();
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
$tags = array();
|
| 176 |
+
foreach ( $matches as $match ) {
|
| 177 |
+
|
| 178 |
+
// Parse tag attributes, if any.
|
| 179 |
+
$attributes = array();
|
| 180 |
+
if ( ! empty( $match['attributes'][0] ) ) {
|
| 181 |
+
|
| 182 |
+
if ( preg_match_all( $attribute_pattern, $match['attributes'][0], $attribute_data, PREG_SET_ORDER ) ) {
|
| 183 |
+
//Turn the attribute data into a name->value array
|
| 184 |
+
foreach ( $attribute_data as $attr ) {
|
| 185 |
+
if( ! empty( $attr['value_quoted'] ) ) {
|
| 186 |
+
$value = $attr['value_quoted'];
|
| 187 |
+
} else if( ! empty( $attr['value_unquoted'] ) ) {
|
| 188 |
+
$value = $attr['value_unquoted'];
|
| 189 |
+
} else {
|
| 190 |
+
$value = '';
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
// Passing the value through html_entity_decode is handy when you want
|
| 194 |
+
// to extract link URLs or something like that. You might want to remove
|
| 195 |
+
// or modify this call if it doesn't fit your situation.
|
| 196 |
+
$value = html_entity_decode( $value, ENT_QUOTES, $charset );
|
| 197 |
+
|
| 198 |
+
$attributes[ $attr['name'] ] = $value;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 199 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
}
|
| 201 |
+
|
| 202 |
}
|
| 203 |
+
|
| 204 |
+
$tag = array(
|
| 205 |
+
'tag_name' => $match['tag'][0],
|
| 206 |
+
'offset' => $match[0][1],
|
| 207 |
+
'contents' => ! empty( $match['contents'] ) ? $match['contents'][0] : '', // Empty for self-closing tags.
|
| 208 |
+
'attributes' => $attributes,
|
| 209 |
+
);
|
| 210 |
+
if ( $return_the_entire_tag ) {
|
| 211 |
+
$tag['full_tag'] = $match[0][0];
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
$tags[] = $tag;
|
| 215 |
}
|
| 216 |
+
|
| 217 |
+
return $tags;
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
/**
|
| 221 |
+
* Get the value of a cookie.
|
| 222 |
+
*
|
| 223 |
+
* @param string $cookie_name The name of the cookie to return.
|
| 224 |
+
* @param string $default_value Optional. If the cookie is not set, this value will be returned instead. Defaults to an empty string.
|
| 225 |
+
* @return mixed Either the value of the requested cookie, or $default_value.
|
| 226 |
+
*/
|
| 227 |
+
static function get_cookie( $cookie_name, $default_value = '' ) {
|
| 228 |
+
if ( isset( $_COOKIE[$cookie_name] ) ) {
|
| 229 |
+
return $_COOKIE[$cookie_name];
|
| 230 |
+
} else {
|
| 231 |
+
return $default_value;
|
| 232 |
}
|
|
|
|
|
|
|
| 233 |
}
|
| 234 |
+
|
|
|
|
|
|
|
|
|
|
| 235 |
/**
|
| 236 |
+
* Format a time delta using a fuzzy format, e.g. '2 minutes ago', '2 days', etc.
|
| 237 |
+
*
|
| 238 |
+
* @param int $delta Time period in seconds.
|
| 239 |
+
* @param string $type Optional. The output template to use.
|
| 240 |
+
* @return string
|
| 241 |
+
*/
|
| 242 |
+
static function fuzzy_delta( $delta, $template = 'default' ) {
|
| 243 |
+
|
| 244 |
+
$templates = array(
|
| 245 |
+
'seconds' => array(
|
| 246 |
+
'default' => _n_noop('%d second', '%d seconds'),
|
| 247 |
+
'ago' => _n_noop('%d second ago', '%d seconds ago'),
|
| 248 |
+
),
|
| 249 |
+
'minutes' => array(
|
| 250 |
+
'default' => _n_noop('%d minute', '%d minutes'),
|
| 251 |
+
'ago' => _n_noop('%d minute ago', '%d minutes ago'),
|
| 252 |
+
),
|
| 253 |
+
'hours' => array(
|
| 254 |
+
'default' => _n_noop('%d hour', '%d hours'),
|
| 255 |
+
'ago' => _n_noop('%d hour ago', '%d hours ago'),
|
| 256 |
+
),
|
| 257 |
+
'days' => array(
|
| 258 |
+
'default' => _n_noop('%d day', '%d days'),
|
| 259 |
+
'ago' => _n_noop('%d day ago', '%d days ago'),
|
| 260 |
+
),
|
| 261 |
+
'months' => array(
|
| 262 |
+
'default' => _n_noop('%d month', '%d months'),
|
| 263 |
+
'ago' => _n_noop('%d month ago', '%d months ago'),
|
| 264 |
+
),
|
| 265 |
+
);
|
| 266 |
+
|
| 267 |
+
if ( $delta < 1 ) {
|
| 268 |
+
$delta = 1;
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
if ( $delta < MINUTE_IN_SECONDS ) {
|
| 272 |
+
$units = 'seconds';
|
| 273 |
+
} elseif ( $delta < HOUR_IN_SECONDS ) {
|
| 274 |
+
$delta = intval( $delta / MINUTE_IN_SECONDS );
|
| 275 |
+
$units = 'minutes';
|
| 276 |
+
} elseif ( $delta < DAY_IN_SECONDS ) {
|
| 277 |
+
$delta = intval( $delta / HOUR_IN_SECONDS );
|
| 278 |
+
$units = 'hours';
|
| 279 |
+
} elseif ( $delta < MONTH_IN_SECONDS ) {
|
| 280 |
+
$delta = intval( $delta / DAY_IN_SECONDS );
|
| 281 |
+
$units = 'days';
|
| 282 |
+
} else {
|
| 283 |
+
$delta = intval( $delta / MONTH_IN_SECONDS );
|
| 284 |
+
$units = 'months';
|
| 285 |
+
}
|
| 286 |
+
|
| 287 |
+
return sprintf(
|
| 288 |
+
_n(
|
| 289 |
+
$templates[$units][$template][0],
|
| 290 |
+
$templates[$units][$template][1],
|
| 291 |
+
$delta,
|
| 292 |
+
'broken-link-checker'
|
| 293 |
+
),
|
| 294 |
+
$delta
|
| 295 |
+
);
|
| 296 |
}
|
| 297 |
+
|
| 298 |
+
/**
|
| 299 |
+
* Optimize the plugin's tables
|
| 300 |
+
*
|
| 301 |
+
* @return void
|
| 302 |
+
*/
|
| 303 |
+
static function optimize_database(){
|
| 304 |
+
global $wpdb; /** @var wpdb $wpdb */
|
| 305 |
+
|
| 306 |
+
$wpdb->query( "OPTIMIZE TABLE {$wpdb->prefix}blc_links, {$wpdb->prefix}blc_instances, {$wpdb->prefix}blc_synch" );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 307 |
}
|
| 308 |
+
|
| 309 |
+
/**
|
| 310 |
+
* Get the server's load averages.
|
| 311 |
+
*
|
| 312 |
+
* Returns an array with three samples - the 1 minute avg, the 5 minute avg, and the 15 minute avg.
|
| 313 |
+
*
|
| 314 |
+
* @param integer $cache How long the load averages may be cached, in seconds. Set to 0 to get maximally up-to-date data.
|
| 315 |
+
* @return array|null Array, or NULL if retrieving load data is impossible (e.g. when running on a Windows box).
|
| 316 |
+
*/
|
| 317 |
+
static function get_server_load( $cache = 5 ) {
|
| 318 |
+
static $cached_load = null;
|
| 319 |
+
static $cached_when = 0;
|
| 320 |
+
|
| 321 |
+
if ( ! empty( $cache ) && ((time() - $cached_when) <= $cache) ) {
|
| 322 |
+
return $cached_load;
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
$load = null;
|
| 326 |
+
|
| 327 |
+
if ( function_exists( 'sys_getloadavg' ) ) {
|
| 328 |
+
$load = sys_getloadavg();
|
| 329 |
+
} else {
|
| 330 |
+
$loadavg_file = '/proc/loadavg';
|
| 331 |
+
if ( @is_readable( $loadavg_file ) ) {
|
| 332 |
+
$load = explode( ' ', file_get_contents( $loadavg_file ) );
|
| 333 |
+
$load = array_map( 'floatval', $load );
|
| 334 |
+
}
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
$cached_load = $load;
|
| 338 |
+
$cached_when = time();
|
| 339 |
+
return $load;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 340 |
}
|
| 341 |
+
|
| 342 |
+
/**
|
| 343 |
+
* Convert an internationalized domain name or URL to ASCII-compatible encoding.
|
| 344 |
+
*
|
| 345 |
+
* @param string $url Either a domain name or a complete URL.
|
| 346 |
+
* @param string $charset The character encoding of the $url parameter. Defaults to the encoding set in Settings -> Reading.
|
| 347 |
+
* @return string
|
| 348 |
+
*/
|
| 349 |
+
static function idn_to_ascii( $url, $charset = '' ) {
|
| 350 |
+
$idn = blcUtility::get_idna_converter();
|
| 351 |
+
if ( $idn != null ) {
|
| 352 |
+
if ( empty( $charset ) ) {
|
| 353 |
+
$charset = get_bloginfo( 'charset' );
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
// Encode only the host.
|
| 357 |
+
if ( preg_match( '@(\w+:/*)?([^/:]+)(.*$)?@s', $url, $matches ) ) {
|
| 358 |
+
$host = $matches[2];
|
| 359 |
+
if ( ( strtoupper( $charset ) != 'UTF-8') && ( strtoupper( $charset ) != 'UTF8') ) {
|
| 360 |
+
$host = encode_utf8( $host, $charset, true );
|
| 361 |
+
}
|
| 362 |
+
$host = $idn->encode( $host );
|
| 363 |
+
$url = $matches[1] . $host . $matches[3];
|
| 364 |
+
}
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
return $url;
|
| 368 |
}
|
| 369 |
+
|
| 370 |
+
/**
|
| 371 |
+
* Convert an internationalized domain name (or URL) from ASCII-compatible encoding to UTF8.
|
| 372 |
+
*
|
| 373 |
+
* @param string $url
|
| 374 |
+
* @return string
|
| 375 |
+
*/
|
| 376 |
+
static function idn_to_utf8( $url ) {
|
| 377 |
+
$idn = blcUtility::get_idna_converter();
|
| 378 |
+
if ( null !== $idn ) {
|
| 379 |
+
$url = $idn->decode( $url );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 380 |
}
|
| 381 |
+
|
| 382 |
+
return $url;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 383 |
}
|
|
|
|
|
|
|
|
|
|
| 384 |
|
| 385 |
+
/**
|
| 386 |
+
* Get an instance of idna_converter
|
| 387 |
+
*
|
| 388 |
+
* @return idna_convert|null Either an instance of IDNA converter, or NULL if the converter class is not available
|
| 389 |
+
*/
|
| 390 |
+
static function get_idna_converter() {
|
| 391 |
+
static $idn = null;
|
| 392 |
+
if ( ( null === $idn ) && class_exists( 'idna_convert' ) ) {
|
| 393 |
+
$idn = new idna_convert();
|
| 394 |
+
}
|
| 395 |
+
return $idn;
|
| 396 |
}
|
| 397 |
+
|
| 398 |
+
/**
|
| 399 |
+
* Generate a numeric hash from a string. The result will be constrained to the specified interval.
|
| 400 |
+
*
|
| 401 |
+
* @static
|
| 402 |
+
* @param string $input
|
| 403 |
+
* @param int $min
|
| 404 |
+
* @param int $max
|
| 405 |
+
* @return float
|
| 406 |
+
*/
|
| 407 |
+
public static function constrained_hash( $input, $min = 0, $max = 1 ) {
|
| 408 |
+
$bytes_to_use = 3;
|
| 409 |
+
$md5_char_count = 32;
|
| 410 |
+
$hash = substr( md5( $input ), $md5_char_count - $bytes_to_use * 2 );
|
| 411 |
+
$hash = intval( hexdec( $hash ) );
|
| 412 |
+
return $min + ( ( $max - $min ) * ( $hash / ( pow( 2, $bytes_to_use * 8 ) - 1) ) );
|
| 413 |
}
|
|
|
|
|
|
|
| 414 |
|
| 415 |
+
}//class
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 416 |
|
| 417 |
}//class_exists
|
|
|
modules/checkers/http.php
CHANGED
|
@@ -254,6 +254,9 @@ class blcCurlHttp extends blcHttpCheckerBase {
|
|
| 254 |
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
|
| 255 |
}
|
| 256 |
|
|
|
|
|
|
|
|
|
|
| 257 |
//Execute the request
|
| 258 |
$start_time = microtime_float();
|
| 259 |
$content = curl_exec($ch);
|
|
@@ -316,6 +319,11 @@ class blcCurlHttp extends blcHttpCheckerBase {
|
|
| 316 |
} else {
|
| 317 |
$result['broken'] = $this->is_error_code($result['http_code']);
|
| 318 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 319 |
curl_close($ch);
|
| 320 |
|
| 321 |
$blclog->info(sprintf(
|
| 254 |
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
|
| 255 |
}
|
| 256 |
|
| 257 |
+
// Apply filter for additional options
|
| 258 |
+
curl_setopt_array($ch, apply_filters('broken-link-checker-curl-options', array()) );
|
| 259 |
+
|
| 260 |
//Execute the request
|
| 261 |
$start_time = microtime_float();
|
| 262 |
$content = curl_exec($ch);
|
| 319 |
} else {
|
| 320 |
$result['broken'] = $this->is_error_code($result['http_code']);
|
| 321 |
}
|
| 322 |
+
|
| 323 |
+
|
| 324 |
+
// Apply filter before curl closes
|
| 325 |
+
apply_filters('broken-link-checker-curl-before-close', $ch, $content, $this->last_headers);
|
| 326 |
+
|
| 327 |
curl_close($ch);
|
| 328 |
|
| 329 |
$blclog->info(sprintf(
|
modules/containers/acf_field.php
ADDED
|
@@ -0,0 +1,710 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
|
| 3 |
+
/*
|
| 4 |
+
Plugin Name: Acf fields
|
| 5 |
+
Description: Container module for acf fields.
|
| 6 |
+
Version: 1.0
|
| 7 |
+
Author: Janne Aalto
|
| 8 |
+
|
| 9 |
+
ModuleID: acf_field
|
| 10 |
+
ModuleCategory: container
|
| 11 |
+
ModuleClassName: blcAcfMetaManager
|
| 12 |
+
*/
|
| 13 |
+
|
| 14 |
+
//Note : If it ever becomes necessary to check metadata on objects other than posts, it will
|
| 15 |
+
//be fairly easy to extract a more general metadata container class from blcAcfMeta.
|
| 16 |
+
|
| 17 |
+
/**
|
| 18 |
+
* blcAcfMeta - A link container class for post metadata (AKA custom fields).
|
| 19 |
+
*
|
| 20 |
+
* Due to the way metadata works, this container differs significantly from other containers :
|
| 21 |
+
* - container_field is equal to meta name, and container_id holds the ID of the post.
|
| 22 |
+
* - There is one synch. record per post that determines the synch. state of all metadata fields of that post.
|
| 23 |
+
* - Unlinking simply deletes the meta entry in question without involving the parser.
|
| 24 |
+
* - The list of parse-able $fields is not fixed. Instead, it's initialized based on the
|
| 25 |
+
* custom field list defined in Settings -> Link Checker.
|
| 26 |
+
* - The $wrapped_object is an array (and isn't really used for anything).
|
| 27 |
+
* - update_wrapped_object() does nothing.
|
| 28 |
+
*
|
| 29 |
+
* @package Broken Link Checker
|
| 30 |
+
* @access public
|
| 31 |
+
*/
|
| 32 |
+
class blcAcfMeta extends blcContainer {
|
| 33 |
+
|
| 34 |
+
var $meta_type = 'post';
|
| 35 |
+
|
| 36 |
+
/**
|
| 37 |
+
* Retrieve all metadata fields of the post associated with this container.
|
| 38 |
+
* The results are cached in the internal $wrapped_object variable.
|
| 39 |
+
*
|
| 40 |
+
* @param bool $ensure_consistency
|
| 41 |
+
*
|
| 42 |
+
* @return object The wrapped object.
|
| 43 |
+
*/
|
| 44 |
+
function get_wrapped_object($ensure_consistency = false) {
|
| 45 |
+
if (is_null($this->wrapped_object) || $ensure_consistency) {
|
| 46 |
+
$this->wrapped_object = get_metadata($this->meta_type, $this->container_id);
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
return $this->wrapped_object;
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
function update_wrapped_object() {
|
| 53 |
+
trigger_error('Function blcAcfMeta::update_wrapped_object() does nothing and should not be used.', E_USER_WARNING);
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
/**
|
| 57 |
+
* Get the value of the specified metadata field of the object wrapped by this container.
|
| 58 |
+
*
|
| 59 |
+
* @access protected
|
| 60 |
+
*
|
| 61 |
+
* @param string $field Field name. If omitted, the value of the default field will be returned.
|
| 62 |
+
*
|
| 63 |
+
* @return array
|
| 64 |
+
*/
|
| 65 |
+
function get_field($field = '') {
|
| 66 |
+
global $wpdb;
|
| 67 |
+
|
| 68 |
+
$meta = get_metadata('post', $this->container_id, '_' . $field, true);
|
| 69 |
+
$key = explode('|', str_replace('_field', '|field', $meta));
|
| 70 |
+
|
| 71 |
+
if (is_array($key)) {
|
| 72 |
+
$key = $key[ count($key) - 1 ];
|
| 73 |
+
} else {
|
| 74 |
+
$key = $meta;
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
if (!isset($this->fields[ $key ])) {
|
| 78 |
+
$key = $field;
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
$get_only_first_field = ($this->fields[ $key ] !== 'acf_field');
|
| 82 |
+
|
| 83 |
+
return get_metadata($this->meta_type, $this->container_id, $field, $get_only_first_field);
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
/**
|
| 87 |
+
* Update the value of the specified metadata field of the object wrapped by this container.
|
| 88 |
+
*
|
| 89 |
+
* @access protected
|
| 90 |
+
*
|
| 91 |
+
* @param string $field Meta name.
|
| 92 |
+
* @param string $new_value New meta value.
|
| 93 |
+
* @param string $old_value old meta value.
|
| 94 |
+
*
|
| 95 |
+
* @return bool|WP_Error True on success, an error object if something went wrong.
|
| 96 |
+
*/
|
| 97 |
+
function update_field($field, $new_value, $old_value = '') {
|
| 98 |
+
$rez = update_metadata($this->meta_type, $this->container_id, $field, $new_value, $old_value);
|
| 99 |
+
if ($rez) {
|
| 100 |
+
return true;
|
| 101 |
+
} else {
|
| 102 |
+
return new WP_Error('metadata_update_failed', sprintf(__("Failed to update the meta field '%s' on %s [%d]", 'broken-link-checker'), $field, $this->meta_type, $this->container_id));
|
| 103 |
+
}
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
/**
|
| 107 |
+
* "Unlink"-ing a custom fields removes all metadata fields that contain the specified URL.
|
| 108 |
+
*
|
| 109 |
+
* @param string $field_name
|
| 110 |
+
* @param blcParser $parser
|
| 111 |
+
* @param string $url
|
| 112 |
+
* @param string $raw_url
|
| 113 |
+
*
|
| 114 |
+
* @return bool|WP_Error True on success, or an error object if something went wrong.
|
| 115 |
+
*/
|
| 116 |
+
function unlink($field_name, $parser, $url, $raw_url = '') {
|
| 117 |
+
// error_log(print_r('unlink', true));
|
| 118 |
+
$meta = get_metadata('post', $this->container_id, '_' . $field_name, true);
|
| 119 |
+
$key = explode('|', str_replace('_field', '|field', $meta));
|
| 120 |
+
|
| 121 |
+
if (is_array($key)) {
|
| 122 |
+
$key = $key[ count($key) - 1 ];
|
| 123 |
+
}
|
| 124 |
+
if ($this->fields[ $key ] !== 'acf_field') {
|
| 125 |
+
return parent::unlink($field_name, $parser, $url, $raw_url);
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
$rez = update_metadata($this->meta_type, $this->container_id, $field_name, '');
|
| 129 |
+
if ($rez) {
|
| 130 |
+
return true;
|
| 131 |
+
} else {
|
| 132 |
+
return new WP_Error('metadata_delete_failed', sprintf(__("Failed to delete the meta field '%s' on %s [%d]", 'broken-link-checker'), $field_name, $this->meta_type, $this->container_id));
|
| 133 |
+
}
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
/**
|
| 137 |
+
* Change a meta field containing the specified URL to a new URL.
|
| 138 |
+
*
|
| 139 |
+
* @param string $field_name Meta name
|
| 140 |
+
* @param blcParser $parser
|
| 141 |
+
* @param string $new_url New URL.
|
| 142 |
+
* @param string $old_url
|
| 143 |
+
* @param string $old_raw_url Old meta value.
|
| 144 |
+
* @param null $new_text
|
| 145 |
+
*
|
| 146 |
+
* @return string|WP_Error The new value of raw_url on success, or an error object if something went wrong.
|
| 147 |
+
*/
|
| 148 |
+
function edit_link($field_name, $parser, $new_url, $old_url = '', $old_raw_url = '', $new_text = null) {
|
| 149 |
+
// error_log(print_r('edit_link', true));
|
| 150 |
+
|
| 151 |
+
/*
|
| 152 |
+
FB::log(sprintf(
|
| 153 |
+
'Editing %s[%d]:%s - %s to %s',
|
| 154 |
+
$this->container_type,
|
| 155 |
+
$this->container_id,
|
| 156 |
+
$field_name,
|
| 157 |
+
$old_url,
|
| 158 |
+
$new_url
|
| 159 |
+
));
|
| 160 |
+
*/
|
| 161 |
+
|
| 162 |
+
$meta = get_metadata('post', $this->container_id, '_' . $field_name, true);
|
| 163 |
+
$key = explode('|', str_replace('_field', '|field', $meta));
|
| 164 |
+
|
| 165 |
+
if (is_array($key)) {
|
| 166 |
+
$key = $key[ count($key) - 1 ];
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
if ($this->fields[ $key ] !== 'acf_field') {
|
| 170 |
+
return parent::edit_link($field_name, $parser, $new_url, $old_url, $old_raw_url, $new_text);
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
if (empty($old_raw_url)) {
|
| 174 |
+
$old_raw_url = $old_url;
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
//Get the current values of the field that needs to be edited.
|
| 178 |
+
//The default metadata parser ignores them, but we're still going
|
| 179 |
+
//to set this argument to a valid value in case someone writes a
|
| 180 |
+
//custom meta parser that needs it.
|
| 181 |
+
$old_value = $this->get_field($field_name);
|
| 182 |
+
|
| 183 |
+
//Get the new field value (a string).
|
| 184 |
+
$edit_result = $parser->edit($old_value, $new_url, $old_url, $old_raw_url);
|
| 185 |
+
if (is_wp_error($edit_result)) {
|
| 186 |
+
return $edit_result;
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
//Update the field with the new value returned by the parser.
|
| 190 |
+
//Notice how $old_raw_url is used instead of $old_value. $old_raw_url contains the entire old
|
| 191 |
+
//value of the metadata field (see blcMetadataParser::parse()) and thus can be used to
|
| 192 |
+
//differentiate between multiple meta fields with identical names.
|
| 193 |
+
$update_result = $this->update_field($field_name, $edit_result['content'], $old_raw_url);
|
| 194 |
+
if (is_wp_error($update_result)) {
|
| 195 |
+
return $update_result;
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
//Return the new "raw" URL.
|
| 199 |
+
return $edit_result['raw_url'];
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
/**
|
| 203 |
+
* Get the default link text to use for links found in a specific container field.
|
| 204 |
+
*
|
| 205 |
+
* @param string $field
|
| 206 |
+
*
|
| 207 |
+
* @return string
|
| 208 |
+
*/
|
| 209 |
+
function default_link_text($field = '') {
|
| 210 |
+
// error_log(print_r('default_link_text', true));
|
| 211 |
+
|
| 212 |
+
//Just use the field name. There's no way to know how the links inside custom fields are
|
| 213 |
+
//used, so no way to know the "real" link text. Displaying the field name at least gives
|
| 214 |
+
//the user a clue where to look if they want to find/modify the field.
|
| 215 |
+
return $field;
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
function ui_get_source($container_field = '', $context = 'display') {
|
| 219 |
+
// error_log(print_r('ui_get_source', true));
|
| 220 |
+
|
| 221 |
+
if (!post_type_exists(get_post_type($this->container_id))) {
|
| 222 |
+
//Error: Invalid post type. The user probably removed a CPT without removing the actual posts.
|
| 223 |
+
$post_html = '';
|
| 224 |
+
|
| 225 |
+
$post = get_post($this->container_id);
|
| 226 |
+
if ($post) {
|
| 227 |
+
$post_html .= sprintf('<span class="row-title">%s</span><br>', get_the_title($post));
|
| 228 |
+
}
|
| 229 |
+
$post_html .= sprintf('Invalid post type "%s"', htmlentities($this->container_type));
|
| 230 |
+
|
| 231 |
+
return $post_html;
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
$post_html = sprintf('<a class="row-title" href="%s" title="%s">%s</a>', esc_url($this->get_edit_url()), esc_attr(__('Edit this post')), get_the_title($this->container_id));
|
| 235 |
+
|
| 236 |
+
return $post_html;
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
function ui_get_action_links($container_field) {
|
| 240 |
+
// error_log(print_r('ui_get_action_links', true));
|
| 241 |
+
|
| 242 |
+
$actions = [];
|
| 243 |
+
if (!post_type_exists(get_post_type($this->container_id))) {
|
| 244 |
+
return $actions;
|
| 245 |
+
}
|
| 246 |
+
|
| 247 |
+
if (current_user_can('edit_post', $this->container_id)) {
|
| 248 |
+
$actions['edit'] = '<span class="edit"><a href="' . $this->get_edit_url() . '" title="' . esc_attr(__('Edit this item')) . '">' . __('Edit') . '</a>';
|
| 249 |
+
|
| 250 |
+
if ($this->current_user_can_delete()) {
|
| 251 |
+
if ($this->can_be_trashed()) {
|
| 252 |
+
$actions['trash'] = sprintf("<span><a class='submitdelete' title='%s' href='%s'>%s</a>", esc_attr(__('Move this item to the Trash')), get_delete_post_link($this->container_id, '', false), __('Trash'));
|
| 253 |
+
} else {
|
| 254 |
+
$actions['delete'] = sprintf("<span><a class='submitdelete' title='%s' href='%s'>%s</a>", esc_attr(__('Delete this item permanently')), get_delete_post_link($this->container_id, '', true), __('Delete'));
|
| 255 |
+
}
|
| 256 |
+
}
|
| 257 |
+
}
|
| 258 |
+
$actions['view'] = '<span class="view"><a href="' . esc_url(get_permalink($this->container_id)) . '" title="' . esc_attr(sprintf(__('View "%s"', 'broken-link-checker'), get_the_title($this->container_id))) . '" rel="permalink">' . __('View') . '</a>';
|
| 259 |
+
|
| 260 |
+
return $actions;
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
/**
|
| 264 |
+
* Get edit URL for this container. Returns the URL of the Dashboard page where the item
|
| 265 |
+
* associated with this container can be edited.
|
| 266 |
+
*
|
| 267 |
+
* @access protected
|
| 268 |
+
*
|
| 269 |
+
* @return string
|
| 270 |
+
*/
|
| 271 |
+
function get_edit_url() {
|
| 272 |
+
// error_log(print_r('get_edit_url', true));
|
| 273 |
+
|
| 274 |
+
/*
|
| 275 |
+
The below is a near-exact copy of the get_post_edit_link() function.
|
| 276 |
+
Unfortunately we can't just call that function because it has a hardcoded
|
| 277 |
+
caps-check which fails when called from the email notification script
|
| 278 |
+
executed by Cron.
|
| 279 |
+
*/
|
| 280 |
+
|
| 281 |
+
if (!($post = get_post($this->container_id))) {
|
| 282 |
+
return '';
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
$context = 'display';
|
| 286 |
+
|
| 287 |
+
//WP 3.0
|
| 288 |
+
if ('display' == $context) {
|
| 289 |
+
$action = '&action=edit';
|
| 290 |
+
} else {
|
| 291 |
+
$action = '&action=edit';
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
$post_type_object = get_post_type_object($post->post_type);
|
| 295 |
+
if (!$post_type_object) {
|
| 296 |
+
return '';
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
return apply_filters('get_edit_post_link', admin_url(sprintf($post_type_object->_edit_link . $action, $post->ID)), $post->ID, $context);
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
/**
|
| 303 |
+
* Get the base URL of the container. For custom fields, the base URL is the permalink of
|
| 304 |
+
* the post that the field is attached to.
|
| 305 |
+
*
|
| 306 |
+
* @return string
|
| 307 |
+
*/
|
| 308 |
+
function base_url() {
|
| 309 |
+
return get_permalink($this->container_id);
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
/**
|
| 313 |
+
* Delete or trash the post corresponding to this container. If trash is enabled,
|
| 314 |
+
* will always move the post to the trash instead of deleting.
|
| 315 |
+
*
|
| 316 |
+
* @return bool|WP_error
|
| 317 |
+
*/
|
| 318 |
+
function delete_wrapped_object() {
|
| 319 |
+
// error_log(print_r('delete_wrapped_object', true));
|
| 320 |
+
|
| 321 |
+
if (EMPTY_TRASH_DAYS) {
|
| 322 |
+
return $this->trash_wrapped_object();
|
| 323 |
+
} else {
|
| 324 |
+
if (wp_delete_post($this->container_id)) {
|
| 325 |
+
return true;
|
| 326 |
+
} else {
|
| 327 |
+
return new WP_Error('delete_failed', sprintf(__('Failed to delete post "%s" (%d)', 'broken-link-checker'), get_the_title($this->container_id), $this->container_id));
|
| 328 |
+
}
|
| 329 |
+
}
|
| 330 |
+
}
|
| 331 |
+
|
| 332 |
+
/**
|
| 333 |
+
* Move the post corresponding to this custom field to the Trash.
|
| 334 |
+
*
|
| 335 |
+
* @return bool|WP_Error
|
| 336 |
+
*/
|
| 337 |
+
function trash_wrapped_object() {
|
| 338 |
+
// error_log(print_r('trash_wrapped_object', true));
|
| 339 |
+
|
| 340 |
+
if (!EMPTY_TRASH_DAYS) {
|
| 341 |
+
return new WP_Error('trash_disabled', sprintf(__('Can\'t move post "%s" (%d) to the trash because the trash feature is disabled', 'broken-link-checker'), get_the_title($this->container_id), $this->container_id));
|
| 342 |
+
}
|
| 343 |
+
|
| 344 |
+
$post = &get_post($this->container_id);
|
| 345 |
+
if ($post->post_status == 'trash') {
|
| 346 |
+
//Prevent conflicts between post and custom field containers trying to trash the same post.
|
| 347 |
+
return true;
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
if (wp_trash_post($this->container_id)) {
|
| 351 |
+
return true;
|
| 352 |
+
} else {
|
| 353 |
+
return new WP_Error('trash_failed', sprintf(__('Failed to move post "%s" (%d) to the trash', 'broken-link-checker'), get_the_title($this->container_id), $this->container_id));
|
| 354 |
+
}
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
function current_user_can_delete() {
|
| 358 |
+
$post = get_post($this->container_id);
|
| 359 |
+
$post_type_object = get_post_type_object($post->post_type);
|
| 360 |
+
|
| 361 |
+
return current_user_can($post_type_object->cap->delete_post, $this->container_id);
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
function can_be_trashed() {
|
| 365 |
+
return defined('EMPTY_TRASH_DAYS') && EMPTY_TRASH_DAYS;
|
| 366 |
+
}
|
| 367 |
+
}
|
| 368 |
+
|
| 369 |
+
class blcAcfMetaManager extends blcContainerManager {
|
| 370 |
+
|
| 371 |
+
var $container_class_name = 'blcAcfMeta';
|
| 372 |
+
|
| 373 |
+
protected $selected_fields = [];
|
| 374 |
+
|
| 375 |
+
function init() {
|
| 376 |
+
parent::init();
|
| 377 |
+
|
| 378 |
+
//Figure out which custom fields we're interested in.
|
| 379 |
+
if (is_array($this->plugin_conf->options['acf_fields'])) {
|
| 380 |
+
$prefix_formats = [
|
| 381 |
+
'html' => 'html',
|
| 382 |
+
'acf_field' => 'acf_field',
|
| 383 |
+
];
|
| 384 |
+
foreach ($this->plugin_conf->options['acf_fields'] as $meta_name) {
|
| 385 |
+
//The user can add an optional "format:" prefix to specify the format of the custom field.
|
| 386 |
+
$parts = explode(':', $meta_name, 2);
|
| 387 |
+
if ((count($parts) == 2) && in_array($parts[0], $prefix_formats)) {
|
| 388 |
+
$this->selected_fields[ $parts[1] ] = $prefix_formats[ $parts[0] ];
|
| 389 |
+
} else {
|
| 390 |
+
$this->selected_fields[ $meta_name ] = 'acf_field';
|
| 391 |
+
}
|
| 392 |
+
}
|
| 393 |
+
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
//Intercept 2.9+ style metadata modification actions
|
| 397 |
+
add_action("acf/save_post", [$this, 'acf_save'], 10, 4);
|
| 398 |
+
|
| 399 |
+
//When a post is deleted, also delete the custom field container associated with it.
|
| 400 |
+
add_action('delete_post', [$this, 'post_deleted']);
|
| 401 |
+
add_action('trash_post', [$this, 'post_deleted']);
|
| 402 |
+
|
| 403 |
+
//Re-parse custom fields when a post is restored from trash
|
| 404 |
+
add_action('untrashed_post', [$this, 'post_untrashed']);
|
| 405 |
+
|
| 406 |
+
}
|
| 407 |
+
|
| 408 |
+
/**
|
| 409 |
+
* Get a list of parseable fields.
|
| 410 |
+
*
|
| 411 |
+
* @return array
|
| 412 |
+
*/
|
| 413 |
+
function get_parseable_fields() {
|
| 414 |
+
return $this->selected_fields;
|
| 415 |
+
}
|
| 416 |
+
|
| 417 |
+
/**
|
| 418 |
+
* Instantiate multiple containers of the container type managed by this class.
|
| 419 |
+
*
|
| 420 |
+
* @param array $containers Array of assoc. arrays containing container data.
|
| 421 |
+
* @param string $purpose An optional code indicating how the retrieved containers will be used.
|
| 422 |
+
* @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
|
| 423 |
+
*
|
| 424 |
+
* @return array of blcAcfMeta indexed by "container_type|container_id"
|
| 425 |
+
*/
|
| 426 |
+
function get_containers($containers, $purpose = '', $load_wrapped_objects = false) {
|
| 427 |
+
|
| 428 |
+
$containers = $this->make_containers($containers);
|
| 429 |
+
|
| 430 |
+
/*
|
| 431 |
+
When links from custom fields are displayed in Tools -> Broken Links,
|
| 432 |
+
each one also shows the title of the post that the custom field(s)
|
| 433 |
+
belong to. Thus it makes sense to pre-cache the posts beforehand - it's
|
| 434 |
+
faster to load them all at once than to make a separate query for each
|
| 435 |
+
one later.
|
| 436 |
+
|
| 437 |
+
So make a list of involved post IDs and load them.
|
| 438 |
+
|
| 439 |
+
Calling get_posts() will automatically populate the post cache, so we
|
| 440 |
+
don't need to actually store the results anywhere in the container object().
|
| 441 |
+
*/
|
| 442 |
+
|
| 443 |
+
$preload = $load_wrapped_objects || in_array($purpose, [BLC_FOR_DISPLAY]);
|
| 444 |
+
if ($preload) {
|
| 445 |
+
$post_ids = [];
|
| 446 |
+
foreach ($containers as $container) {
|
| 447 |
+
$post_ids[] = $container->container_id;
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
+
$args = ['include' => implode(',', $post_ids)];
|
| 451 |
+
get_posts($args);
|
| 452 |
+
}
|
| 453 |
+
|
| 454 |
+
$selected_fields = $this->selected_fields;
|
| 455 |
+
|
| 456 |
+
$html_fields = array_filter($selected_fields, function ($value) {
|
| 457 |
+
if ($value == 'html') {
|
| 458 |
+
return true;
|
| 459 |
+
}
|
| 460 |
+
return false;
|
| 461 |
+
});
|
| 462 |
+
|
| 463 |
+
$url_fields = array_keys(array_diff($selected_fields, $html_fields));
|
| 464 |
+
$html_fields = array_keys($html_fields);
|
| 465 |
+
|
| 466 |
+
foreach ($containers as $key => $container) {
|
| 467 |
+
|
| 468 |
+
$meta = get_metadata('post', $container->container_id);
|
| 469 |
+
$fields = [];
|
| 470 |
+
|
| 471 |
+
foreach ($meta as $field => $value) {
|
| 472 |
+
|
| 473 |
+
$value = explode('|', str_replace('_field', '|field', $value[0]));
|
| 474 |
+
|
| 475 |
+
if (!is_array($value)) {
|
| 476 |
+
continue;
|
| 477 |
+
} else {
|
| 478 |
+
|
| 479 |
+
$value = $value[ count($value) - 1 ];
|
| 480 |
+
|
| 481 |
+
if (in_array($value, $url_fields)) {
|
| 482 |
+
$field = ltrim($field, '_');
|
| 483 |
+
if (!filter_var($meta[ $field ][0], FILTER_VALIDATE_URL) === false) {
|
| 484 |
+
$fields[ $field ] = 'acf_field';
|
| 485 |
+
}
|
| 486 |
+
}
|
| 487 |
+
|
| 488 |
+
if (in_array($value, $html_fields)) {
|
| 489 |
+
$field = ltrim($field, '_');
|
| 490 |
+
if ($meta[ $field ][0] != '') {
|
| 491 |
+
$fields[ $field ] = 'html';
|
| 492 |
+
}
|
| 493 |
+
}
|
| 494 |
+
|
| 495 |
+
}
|
| 496 |
+
}
|
| 497 |
+
|
| 498 |
+
$containers[ $key ]->fields = $fields;
|
| 499 |
+
|
| 500 |
+
}
|
| 501 |
+
|
| 502 |
+
return $containers;
|
| 503 |
+
}
|
| 504 |
+
|
| 505 |
+
/**
|
| 506 |
+
* Create or update synchronization records for all containers managed by this class.
|
| 507 |
+
*
|
| 508 |
+
* @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch.
|
| 509 |
+
*
|
| 510 |
+
* @return void
|
| 511 |
+
*/
|
| 512 |
+
function resynch($forced = false) {
|
| 513 |
+
// error_log(print_r('resynch', true));
|
| 514 |
+
|
| 515 |
+
global $wpdb;
|
| 516 |
+
/** @var wpdb $wpdb */
|
| 517 |
+
global $blclog;
|
| 518 |
+
|
| 519 |
+
//Only check custom fields on selected post types. By default, that's "post" and "page".
|
| 520 |
+
$post_types = ['post', 'page'];
|
| 521 |
+
if (class_exists('blcPostTypeOverlord')) {
|
| 522 |
+
$overlord = blcPostTypeOverlord::getInstance();
|
| 523 |
+
$post_types = array_merge($post_types, $overlord->enabled_post_types);
|
| 524 |
+
$post_types = array_unique($post_types);
|
| 525 |
+
}
|
| 526 |
+
|
| 527 |
+
$escaped_post_types = "'" . implode("', '", array_map('esc_sql', $post_types)) . "'";
|
| 528 |
+
|
| 529 |
+
if ($forced) {
|
| 530 |
+
//Create new synchronization records for all posts.
|
| 531 |
+
$blclog->log('...... Creating synch records for all custom fields on ' . $escaped_post_types);
|
| 532 |
+
$start = microtime(true);
|
| 533 |
+
$q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
|
| 534 |
+
SELECT id, '{$this->container_type}', 0
|
| 535 |
+
FROM {$wpdb->posts}
|
| 536 |
+
WHERE
|
| 537 |
+
{$wpdb->posts}.post_status = 'publish'
|
| 538 |
+
AND {$wpdb->posts}.post_type IN ({$escaped_post_types})";
|
| 539 |
+
$wpdb->query($q);
|
| 540 |
+
$blclog->log(sprintf('...... %d rows inserted in %.3f seconds', $wpdb->rows_affected, microtime(true) - $start));
|
| 541 |
+
} else {
|
| 542 |
+
//Delete synch records corresponding to posts that no longer exist.
|
| 543 |
+
$blclog->log('...... Deleting custom field synch records corresponding to deleted posts');
|
| 544 |
+
$start = microtime(true);
|
| 545 |
+
$q = "DELETE synch.*
|
| 546 |
+
FROM
|
| 547 |
+
{$wpdb->prefix}blc_synch AS synch LEFT JOIN {$wpdb->posts} AS posts
|
| 548 |
+
ON posts.ID = synch.container_id
|
| 549 |
+
WHERE
|
| 550 |
+
synch.container_type = '{$this->container_type}' AND posts.ID IS NULL";
|
| 551 |
+
$wpdb->query($q);
|
| 552 |
+
$blclog->log(sprintf('...... %d rows deleted in %.3f seconds', $wpdb->rows_affected, microtime(true) - $start));
|
| 553 |
+
|
| 554 |
+
//Remove the 'synched' flag from all posts that have been updated
|
| 555 |
+
//since the last time they were parsed/synchronized.
|
| 556 |
+
$blclog->log('...... Marking custom fields on changed posts as unsynched');
|
| 557 |
+
$start = microtime(true);
|
| 558 |
+
$q = "UPDATE
|
| 559 |
+
{$wpdb->prefix}blc_synch AS synch
|
| 560 |
+
JOIN {$wpdb->posts} AS posts ON (synch.container_id = posts.ID and synch.container_type='{$this->container_type}')
|
| 561 |
+
SET
|
| 562 |
+
synched = 0
|
| 563 |
+
WHERE
|
| 564 |
+
synch.last_synch < posts.post_modified";
|
| 565 |
+
$wpdb->query($q);
|
| 566 |
+
$blclog->log(sprintf('...... %d rows updated in %.3f seconds', $wpdb->rows_affected, microtime(true) - $start));
|
| 567 |
+
|
| 568 |
+
//Create synch. records for posts that don't have them.
|
| 569 |
+
$blclog->log('...... Creating custom field synch records for new ' . $escaped_post_types);
|
| 570 |
+
$start = microtime(true);
|
| 571 |
+
$q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
|
| 572 |
+
SELECT id, '{$this->container_type}', 0
|
| 573 |
+
FROM
|
| 574 |
+
{$wpdb->posts} AS posts LEFT JOIN {$wpdb->prefix}blc_synch AS synch
|
| 575 |
+
ON (synch.container_id = posts.ID and synch.container_type='{$this->container_type}')
|
| 576 |
+
WHERE
|
| 577 |
+
posts.post_status = 'publish'
|
| 578 |
+
AND posts.post_type IN ({$escaped_post_types})
|
| 579 |
+
AND synch.container_id IS NULL";
|
| 580 |
+
$wpdb->query($q);
|
| 581 |
+
$blclog->log(sprintf('...... %d rows inserted in %.3f seconds', $wpdb->rows_affected, microtime(true) - $start));
|
| 582 |
+
}
|
| 583 |
+
}
|
| 584 |
+
|
| 585 |
+
/**
|
| 586 |
+
* Mark custom fields as unsynched when they're modified or deleted.
|
| 587 |
+
*
|
| 588 |
+
* @param $post_id
|
| 589 |
+
*
|
| 590 |
+
* @return void
|
| 591 |
+
*
|
| 592 |
+
*/
|
| 593 |
+
function acf_save($post_id) {
|
| 594 |
+
global $wpdb;
|
| 595 |
+
/** @var wpdb $wpdb */
|
| 596 |
+
|
| 597 |
+
if (empty($this->selected_fields)) {
|
| 598 |
+
return;
|
| 599 |
+
}
|
| 600 |
+
|
| 601 |
+
if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id) || !is_int($post_id)) {
|
| 602 |
+
return;
|
| 603 |
+
}
|
| 604 |
+
|
| 605 |
+
$selected_fields = $this->selected_fields;
|
| 606 |
+
|
| 607 |
+
$html_fields = array_filter($selected_fields, function ($value) {
|
| 608 |
+
if ($value == 'html') {
|
| 609 |
+
return true;
|
| 610 |
+
}
|
| 611 |
+
|
| 612 |
+
return false;
|
| 613 |
+
});
|
| 614 |
+
|
| 615 |
+
$url_fields = array_keys(array_diff($selected_fields, $html_fields));
|
| 616 |
+
|
| 617 |
+
$html_fields = array_keys($html_fields);
|
| 618 |
+
$selected_fields = array_keys($selected_fields);
|
| 619 |
+
|
| 620 |
+
$keys = [];
|
| 621 |
+
$fields = $_POST['acf'];
|
| 622 |
+
|
| 623 |
+
array_walk_recursive($fields, function ($item, $key) use (&$keys, $selected_fields, $url_fields, $html_fields) {
|
| 624 |
+
|
| 625 |
+
$key = explode('|', str_replace('_field', '|field', $key));
|
| 626 |
+
|
| 627 |
+
if (is_array($key)) {
|
| 628 |
+
$key = $key[ count($key) - 1 ];
|
| 629 |
+
}
|
| 630 |
+
|
| 631 |
+
if (in_array($key, $url_fields)) {
|
| 632 |
+
if (!filter_var($item, FILTER_VALIDATE_URL) === false) {
|
| 633 |
+
$keys[] = $key;
|
| 634 |
+
}
|
| 635 |
+
}
|
| 636 |
+
|
| 637 |
+
if (in_array($key, $html_fields)) {
|
| 638 |
+
if ($item != '') {
|
| 639 |
+
$keys[] = $key;
|
| 640 |
+
}
|
| 641 |
+
}
|
| 642 |
+
});
|
| 643 |
+
|
| 644 |
+
if (empty($keys)) {
|
| 645 |
+
return;
|
| 646 |
+
}
|
| 647 |
+
|
| 648 |
+
$container = blcContainerHelper::get_container([$this->container_type, $post_id]);
|
| 649 |
+
$container->mark_as_unsynched();
|
| 650 |
+
|
| 651 |
+
}
|
| 652 |
+
|
| 653 |
+
/**
|
| 654 |
+
* Delete custom field synch. records when the post that they belong to is deleted.
|
| 655 |
+
*
|
| 656 |
+
* @param int $post_id
|
| 657 |
+
*
|
| 658 |
+
* @return void
|
| 659 |
+
*/
|
| 660 |
+
function post_deleted($post_id) {
|
| 661 |
+
//Get the associated container object
|
| 662 |
+
|
| 663 |
+
$container = blcContainerHelper::get_container([$this->container_type, intval($post_id) ]);
|
| 664 |
+
|
| 665 |
+
if ($container != null) {
|
| 666 |
+
//Delete it
|
| 667 |
+
$container->delete();
|
| 668 |
+
//Clean up any dangling links
|
| 669 |
+
blc_cleanup_links();
|
| 670 |
+
}
|
| 671 |
+
}
|
| 672 |
+
|
| 673 |
+
/**
|
| 674 |
+
* When a post is restored, mark all of its custom fields as unparsed.
|
| 675 |
+
* Called via the 'untrashed_post' action.
|
| 676 |
+
*
|
| 677 |
+
* @param int $post_id
|
| 678 |
+
*
|
| 679 |
+
* @return void
|
| 680 |
+
*/
|
| 681 |
+
function post_untrashed($post_id) {
|
| 682 |
+
//Get the associated container object
|
| 683 |
+
$container = blcContainerHelper::get_container([$this->container_type, intval($post_id)]);
|
| 684 |
+
$container->mark_as_unsynched();
|
| 685 |
+
}
|
| 686 |
+
|
| 687 |
+
/**
|
| 688 |
+
* Get the message to display after $n posts have been deleted.
|
| 689 |
+
*
|
| 690 |
+
* @uses blcAnyPostContainerManager::ui_bulk_delete_message()
|
| 691 |
+
*
|
| 692 |
+
* @param int $n Number of deleted posts.
|
| 693 |
+
*
|
| 694 |
+
* @return string A delete confirmation message, e.g. "5 posts were moved to the trash"
|
| 695 |
+
*/
|
| 696 |
+
function ui_bulk_delete_message($n) {
|
| 697 |
+
return blcAnyPostContainerManager::ui_bulk_delete_message($n);
|
| 698 |
+
}
|
| 699 |
+
|
| 700 |
+
/**
|
| 701 |
+
* Get the message to display after $n posts have been trashed.
|
| 702 |
+
*
|
| 703 |
+
* @param int $n Number of deleted posts.
|
| 704 |
+
*
|
| 705 |
+
* @return string A confirmation message, e.g. "5 posts were moved to trash"
|
| 706 |
+
*/
|
| 707 |
+
function ui_bulk_trash_message($n) {
|
| 708 |
+
return blcAnyPostContainerManager::ui_bulk_trash_message($n);
|
| 709 |
+
}
|
| 710 |
+
}
|
modules/containers/custom_field.php
CHANGED
|
@@ -12,32 +12,32 @@ ModuleClassName: blcPostMetaManager
|
|
| 12 |
*/
|
| 13 |
|
| 14 |
//Note : If it ever becomes necessary to check metadata on objects other than posts, it will
|
| 15 |
-
//be fairly easy to extract a more general metadata container class from blcPostMeta.
|
| 16 |
|
| 17 |
/**
|
| 18 |
* blcPostMeta - A link container class for post metadata (AKA custom fields).
|
| 19 |
*
|
| 20 |
* Due to the way metadata works, this container differs significantly from other containers :
|
| 21 |
* - container_field is equal to meta name, and container_id holds the ID of the post.
|
| 22 |
-
* - There is one synch. record per post that determines the synch. state of all metadata fields of that post.
|
| 23 |
* - Unlinking simply deletes the meta entry in question without involving the parser.
|
| 24 |
-
* - The list of parse-able $fields is not fixed. Instead, it's initialized based on the
|
| 25 |
-
* custom field list defined in Settings -> Link Checker.
|
| 26 |
* - The $wrapped_object is an array (and isn't really used for anything).
|
| 27 |
* - update_wrapped_object() does nothing.
|
| 28 |
-
*
|
| 29 |
* @package Broken Link Checker
|
| 30 |
* @access public
|
| 31 |
*/
|
| 32 |
class blcPostMeta extends blcContainer {
|
| 33 |
-
|
| 34 |
var $meta_type = 'post';
|
| 35 |
-
|
| 36 |
/**
|
| 37 |
* Retrieve all metadata fields of the post associated with this container.
|
| 38 |
* The results are cached in the internal $wrapped_object variable.
|
| 39 |
-
*
|
| 40 |
-
* @param bool $ensure_consistency
|
| 41 |
* @return object The wrapped object.
|
| 42 |
*/
|
| 43 |
function get_wrapped_object($ensure_consistency = false){
|
|
@@ -45,33 +45,33 @@ class blcPostMeta extends blcContainer {
|
|
| 45 |
$this->wrapped_object = get_metadata($this->meta_type, $this->container_id);
|
| 46 |
}
|
| 47 |
return $this->wrapped_object;
|
| 48 |
-
}
|
| 49 |
-
|
| 50 |
function update_wrapped_object(){
|
| 51 |
trigger_error('Function blcPostMeta::update_wrapped_object() does nothing and should not be used.', E_USER_WARNING);
|
| 52 |
}
|
| 53 |
-
|
| 54 |
/**
|
| 55 |
* Get the value of the specified metadata field of the object wrapped by this container.
|
| 56 |
-
*
|
| 57 |
* @access protected
|
| 58 |
*
|
| 59 |
-
* @param string $field Field name. If omitted, the value of the default field will be returned.
|
| 60 |
* @return array
|
| 61 |
*/
|
| 62 |
function get_field($field = ''){
|
| 63 |
$get_only_first_field = ($this->fields[$field] !== 'metadata');
|
| 64 |
return get_metadata($this->meta_type, $this->container_id, $field, $get_only_first_field);
|
| 65 |
}
|
| 66 |
-
|
| 67 |
/**
|
| 68 |
-
* Update the value of the specified metadata field of the object wrapped by this container.
|
| 69 |
*
|
| 70 |
* @access protected
|
| 71 |
*
|
| 72 |
* @param string $field Meta name.
|
| 73 |
-
* @param string $new_value New meta value.
|
| 74 |
-
* @param string $old_value old meta value.
|
| 75 |
* @return bool|WP_Error True on success, an error object if something went wrong.
|
| 76 |
*/
|
| 77 |
function update_field($field, $new_value, $old_value = ''){
|
|
@@ -82,9 +82,9 @@ class blcPostMeta extends blcContainer {
|
|
| 82 |
return new WP_Error(
|
| 83 |
'metadata_update_failed',
|
| 84 |
sprintf(
|
| 85 |
-
__("Failed to update the meta field '%s' on %s [%d]", 'broken-link-checker'),
|
| 86 |
-
$field,
|
| 87 |
-
$this->meta_type,
|
| 88 |
$this->container_id
|
| 89 |
)
|
| 90 |
);
|
|
@@ -112,9 +112,9 @@ class blcPostMeta extends blcContainer {
|
|
| 112 |
return new WP_Error(
|
| 113 |
'metadata_delete_failed',
|
| 114 |
sprintf(
|
| 115 |
-
__("Failed to delete the meta field '%s' on %s [%d]", 'broken-link-checker'),
|
| 116 |
$field_name,
|
| 117 |
-
$this->meta_type,
|
| 118 |
$this->container_id
|
| 119 |
)
|
| 120 |
);
|
|
@@ -138,7 +138,7 @@ class blcPostMeta extends blcContainer {
|
|
| 138 |
'Editing %s[%d]:%s - %s to %s',
|
| 139 |
$this->container_type,
|
| 140 |
$this->container_id,
|
| 141 |
-
$field_name,
|
| 142 |
$old_url,
|
| 143 |
$new_url
|
| 144 |
));
|
|
@@ -147,36 +147,36 @@ class blcPostMeta extends blcContainer {
|
|
| 147 |
if ( $this->fields[$field_name] !== 'metadata' ) {
|
| 148 |
return parent::edit_link($field_name, $parser, $new_url, $old_url, $old_raw_url, $new_text);
|
| 149 |
}
|
| 150 |
-
|
| 151 |
if ( empty($old_raw_url) ){
|
| 152 |
$old_raw_url = $old_url;
|
| 153 |
}
|
| 154 |
-
|
| 155 |
//Get the current values of the field that needs to be edited.
|
| 156 |
//The default metadata parser ignores them, but we're still going
|
| 157 |
-
//to set this argument to a valid value in case someone writes a
|
| 158 |
//custom meta parser that needs it.
|
| 159 |
$old_value = $this->get_field($field_name);
|
| 160 |
-
|
| 161 |
//Get the new field value (a string).
|
| 162 |
$edit_result = $parser->edit($old_value, $new_url, $old_url, $old_raw_url);
|
| 163 |
if ( is_wp_error($edit_result) ){
|
| 164 |
return $edit_result;
|
| 165 |
}
|
| 166 |
-
|
| 167 |
//Update the field with the new value returned by the parser.
|
| 168 |
//Notice how $old_raw_url is used instead of $old_value. $old_raw_url contains the entire old
|
| 169 |
//value of the metadata field (see blcMetadataParser::parse()) and thus can be used to
|
| 170 |
-
//differentiate between multiple meta fields with identical names.
|
| 171 |
$update_result = $this->update_field( $field_name, $edit_result['content'], $old_raw_url );
|
| 172 |
if ( is_wp_error($update_result) ){
|
| 173 |
return $update_result;
|
| 174 |
}
|
| 175 |
-
|
| 176 |
//Return the new "raw" URL.
|
| 177 |
return $edit_result['raw_url'];
|
| 178 |
}
|
| 179 |
-
|
| 180 |
/**
|
| 181 |
* Get the default link text to use for links found in a specific container field.
|
| 182 |
*
|
|
@@ -189,7 +189,7 @@ class blcPostMeta extends blcContainer {
|
|
| 189 |
//the user a clue where to look if they want to find/modify the field.
|
| 190 |
return $field;
|
| 191 |
}
|
| 192 |
-
|
| 193 |
function ui_get_source($container_field = '', $context = 'display'){
|
| 194 |
if ( !post_type_exists(get_post_type($this->container_id)) ) {
|
| 195 |
//Error: Invalid post type. The user probably removed a CPT without removing the actual posts.
|
|
@@ -216,10 +216,10 @@ class blcPostMeta extends blcContainer {
|
|
| 216 |
esc_attr(__('Edit this post')),
|
| 217 |
get_the_title($this->container_id)
|
| 218 |
);
|
| 219 |
-
|
| 220 |
return $post_html;
|
| 221 |
}
|
| 222 |
-
|
| 223 |
function ui_get_action_links($container_field){
|
| 224 |
$actions = array();
|
| 225 |
if ( !post_type_exists(get_post_type($this->container_id)) ) {
|
|
@@ -228,7 +228,7 @@ class blcPostMeta extends blcContainer {
|
|
| 228 |
|
| 229 |
if ( current_user_can('edit_post', $this->container_id) ) {
|
| 230 |
$actions['edit'] = '<span class="edit"><a href="' . $this->get_edit_url() . '" title="' . esc_attr(__('Edit this item')) . '">' . __('Edit') . '</a>';
|
| 231 |
-
|
| 232 |
if ( $this->current_user_can_delete() ){
|
| 233 |
if ( $this->can_be_trashed() ) {
|
| 234 |
$actions['trash'] = sprintf(
|
|
@@ -248,48 +248,48 @@ class blcPostMeta extends blcContainer {
|
|
| 248 |
}
|
| 249 |
}
|
| 250 |
$actions['view'] = '<span class="view"><a href="' . esc_url(get_permalink($this->container_id)) . '" title="' . esc_attr(sprintf(__('View "%s"', 'broken-link-checker'), get_the_title($this->container_id))) . '" rel="permalink">' . __('View') . '</a>';
|
| 251 |
-
|
| 252 |
return $actions;
|
| 253 |
}
|
| 254 |
-
|
| 255 |
/**
|
| 256 |
-
* Get edit URL for this container. Returns the URL of the Dashboard page where the item
|
| 257 |
* associated with this container can be edited.
|
| 258 |
*
|
| 259 |
-
* @access protected
|
| 260 |
*
|
| 261 |
* @return string
|
| 262 |
*/
|
| 263 |
function get_edit_url(){
|
| 264 |
/*
|
| 265 |
-
The below is a near-exact copy of the get_post_edit_link() function.
|
| 266 |
-
Unfortunately we can't just call that function because it has a hardcoded
|
| 267 |
-
caps-check which fails when called from the email notification script
|
| 268 |
executed by Cron.
|
| 269 |
-
*/
|
| 270 |
-
|
| 271 |
if ( !($post = get_post( $this->container_id )) ){
|
| 272 |
return '';
|
| 273 |
}
|
| 274 |
-
|
| 275 |
$context = 'display';
|
| 276 |
-
|
| 277 |
//WP 3.0
|
| 278 |
if ( 'display' == $context )
|
| 279 |
$action = '&action=edit';
|
| 280 |
else
|
| 281 |
$action = '&action=edit';
|
| 282 |
-
|
| 283 |
$post_type_object = get_post_type_object( $post->post_type );
|
| 284 |
if ( !$post_type_object ){
|
| 285 |
return '';
|
| 286 |
}
|
| 287 |
-
|
| 288 |
return apply_filters( 'get_edit_post_link', admin_url( sprintf($post_type_object->_edit_link . $action, $post->ID) ), $post->ID, $context );
|
| 289 |
}
|
| 290 |
-
|
| 291 |
/**
|
| 292 |
-
* Get the base URL of the container. For custom fields, the base URL is the permalink of
|
| 293 |
* the post that the field is attached to.
|
| 294 |
*
|
| 295 |
* @return string
|
|
@@ -297,7 +297,7 @@ class blcPostMeta extends blcContainer {
|
|
| 297 |
function base_url(){
|
| 298 |
return get_permalink($this->container_id);
|
| 299 |
}
|
| 300 |
-
|
| 301 |
/**
|
| 302 |
* Delete or trash the post corresponding to this container. If trash is enabled,
|
| 303 |
* will always move the post to the trash instead of deleting.
|
|
@@ -322,10 +322,10 @@ class blcPostMeta extends blcContainer {
|
|
| 322 |
}
|
| 323 |
}
|
| 324 |
}
|
| 325 |
-
|
| 326 |
/**
|
| 327 |
* Move the post corresponding to this custom field to the Trash.
|
| 328 |
-
*
|
| 329 |
* @return bool|WP_Error
|
| 330 |
*/
|
| 331 |
function trash_wrapped_object(){
|
|
@@ -339,13 +339,13 @@ class blcPostMeta extends blcContainer {
|
|
| 339 |
)
|
| 340 |
);
|
| 341 |
}
|
| 342 |
-
|
| 343 |
$post = &get_post($this->container_id);
|
| 344 |
if ( $post->post_status == 'trash' ){
|
| 345 |
//Prevent conflicts between post and custom field containers trying to trash the same post.
|
| 346 |
return true;
|
| 347 |
}
|
| 348 |
-
|
| 349 |
if ( wp_trash_post($this->container_id) ){
|
| 350 |
return true;
|
| 351 |
} else {
|
|
@@ -359,13 +359,13 @@ class blcPostMeta extends blcContainer {
|
|
| 359 |
);
|
| 360 |
}
|
| 361 |
}
|
| 362 |
-
|
| 363 |
function current_user_can_delete(){
|
| 364 |
$post = get_post($this->container_id);
|
| 365 |
$post_type_object = get_post_type_object($post->post_type);
|
| 366 |
return current_user_can( $post_type_object->cap->delete_post, $this->container_id );
|
| 367 |
}
|
| 368 |
-
|
| 369 |
function can_be_trashed(){
|
| 370 |
return defined('EMPTY_TRASH_DAYS') && EMPTY_TRASH_DAYS;
|
| 371 |
}
|
|
@@ -375,7 +375,7 @@ class blcPostMetaManager extends blcContainerManager {
|
|
| 375 |
var $container_class_name = 'blcPostMeta';
|
| 376 |
var $meta_type = 'post';
|
| 377 |
protected $selected_fields = array();
|
| 378 |
-
|
| 379 |
function init(){
|
| 380 |
parent::init();
|
| 381 |
|
|
@@ -395,7 +395,7 @@ class blcPostMetaManager extends blcContainerManager {
|
|
| 395 |
}
|
| 396 |
}
|
| 397 |
}
|
| 398 |
-
|
| 399 |
//Intercept 2.9+ style metadata modification actions
|
| 400 |
add_action( "added_{$this->meta_type}_meta", array($this, 'meta_modified'), 10, 4 );
|
| 401 |
add_action( "updated_{$this->meta_type}_meta", array($this, 'meta_modified'), 10, 4 );
|
|
@@ -404,63 +404,63 @@ class blcPostMetaManager extends blcContainerManager {
|
|
| 404 |
//When a post is deleted, also delete the custom field container associated with it.
|
| 405 |
add_action('delete_post', array($this,'post_deleted'));
|
| 406 |
add_action('trash_post', array($this,'post_deleted'));
|
| 407 |
-
|
| 408 |
//Re-parse custom fields when a post is restored from trash
|
| 409 |
add_action('untrashed_post', array($this,'post_untrashed'));
|
| 410 |
}
|
| 411 |
|
| 412 |
-
|
| 413 |
/**
|
| 414 |
* Get a list of parseable fields.
|
| 415 |
-
*
|
| 416 |
* @return array
|
| 417 |
*/
|
| 418 |
function get_parseable_fields(){
|
| 419 |
return $this->selected_fields;
|
| 420 |
}
|
| 421 |
-
|
| 422 |
/**
|
| 423 |
* Instantiate multiple containers of the container type managed by this class.
|
| 424 |
*
|
| 425 |
* @param array $containers Array of assoc. arrays containing container data.
|
| 426 |
* @param string $purpose An optional code indicating how the retrieved containers will be used.
|
| 427 |
-
* @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
|
| 428 |
-
*
|
| 429 |
* @return array of blcPostMeta indexed by "container_type|container_id"
|
| 430 |
*/
|
| 431 |
function get_containers($containers, $purpose = '', $load_wrapped_objects = false){
|
| 432 |
$containers = $this->make_containers($containers);
|
| 433 |
-
|
| 434 |
/*
|
| 435 |
When links from custom fields are displayed in Tools -> Broken Links,
|
| 436 |
each one also shows the title of the post that the custom field(s)
|
| 437 |
belong to. Thus it makes sense to pre-cache the posts beforehand - it's
|
| 438 |
faster to load them all at once than to make a separate query for each
|
| 439 |
one later.
|
| 440 |
-
|
| 441 |
So make a list of involved post IDs and load them.
|
| 442 |
-
|
| 443 |
-
Calling get_posts() will automatically populate the post cache, so we
|
| 444 |
don't need to actually store the results anywhere in the container object().
|
| 445 |
-
*/
|
| 446 |
$preload = $load_wrapped_objects || in_array($purpose, array(BLC_FOR_DISPLAY));
|
| 447 |
if ( $preload ){
|
| 448 |
$post_ids = array();
|
| 449 |
foreach($containers as $container){
|
| 450 |
$post_ids[] = $container->container_id;
|
| 451 |
}
|
| 452 |
-
|
| 453 |
$args = array('include' => implode(',', $post_ids));
|
| 454 |
get_posts($args);
|
| 455 |
}
|
| 456 |
-
|
| 457 |
return $containers;
|
| 458 |
}
|
| 459 |
-
|
| 460 |
/**
|
| 461 |
* Create or update synchronization records for all containers managed by this class.
|
| 462 |
*
|
| 463 |
-
* @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch.
|
| 464 |
* @return void
|
| 465 |
*/
|
| 466 |
function resynch($forced = false){
|
|
@@ -478,7 +478,7 @@ class blcPostMetaManager extends blcContainerManager {
|
|
| 478 |
$escaped_post_types = "'" . implode("', '", array_map('esc_sql', $post_types)) . "'";
|
| 479 |
|
| 480 |
if ( $forced ){
|
| 481 |
-
//Create new synchronization records for all posts.
|
| 482 |
$blclog->log('...... Creating synch records for all custom fields on ' . $escaped_post_types);
|
| 483 |
$start = microtime(true);
|
| 484 |
$q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
|
|
@@ -501,7 +501,7 @@ class blcPostMetaManager extends blcContainerManager {
|
|
| 501 |
synch.container_type = '{$this->container_type}' AND posts.ID IS NULL";
|
| 502 |
$wpdb->query( $q );
|
| 503 |
$blclog->log(sprintf('...... %d rows deleted in %.3f seconds', $wpdb->rows_affected, microtime(true) - $start));
|
| 504 |
-
|
| 505 |
//Remove the 'synched' flag from all posts that have been updated
|
| 506 |
//since the last time they were parsed/synchronized.
|
| 507 |
$blclog->log('...... Marking custom fields on changed posts as unsynched');
|
|
@@ -515,7 +515,7 @@ class blcPostMetaManager extends blcContainerManager {
|
|
| 515 |
synch.last_synch < posts.post_modified";
|
| 516 |
$wpdb->query( $q );
|
| 517 |
$blclog->log(sprintf('...... %d rows updated in %.3f seconds', $wpdb->rows_affected, microtime(true) - $start));
|
| 518 |
-
|
| 519 |
//Create synch. records for posts that don't have them.
|
| 520 |
$blclog->log('...... Creating custom field synch records for new ' . $escaped_post_types);
|
| 521 |
$start = microtime(true);
|
|
@@ -532,7 +532,7 @@ class blcPostMetaManager extends blcContainerManager {
|
|
| 532 |
$blclog->log(sprintf('...... %d rows inserted in %.3f seconds', $wpdb->rows_affected, microtime(true) - $start));
|
| 533 |
}
|
| 534 |
}
|
| 535 |
-
|
| 536 |
/**
|
| 537 |
* Mark custom fields as unsynched when they're modified or deleted.
|
| 538 |
*
|
|
@@ -544,27 +544,27 @@ class blcPostMetaManager extends blcContainerManager {
|
|
| 544 |
*/
|
| 545 |
function meta_modified($meta_id, $object_id = 0, $meta_key= '', $meta_value = ''){
|
| 546 |
global $wpdb; /** @var wpdb $wpdb */
|
| 547 |
-
|
| 548 |
-
//If object_id isn't specified then the hook was probably called from the
|
| 549 |
//stupidly inconsistent delete_meta() function in /wp-admin/includes/post.php.
|
| 550 |
if ( empty($object_id) ){
|
| 551 |
//We must manually retrieve object_id and meta_key from the DB.
|
| 552 |
if ( is_array($meta_id) ){
|
| 553 |
$meta_id = array_shift($meta_id);
|
| 554 |
}
|
| 555 |
-
|
| 556 |
$meta = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->postmeta WHERE meta_id = %d", $meta_id), ARRAY_A );
|
| 557 |
if ( empty($meta) ){
|
| 558 |
return;
|
| 559 |
}
|
| 560 |
-
|
| 561 |
$object_id = $meta['post_id'];
|
| 562 |
$meta_key = $meta['meta_key'];
|
| 563 |
}
|
| 564 |
-
|
| 565 |
-
|
| 566 |
-
//Metadata changes only matter to us if the modified key
|
| 567 |
-
//is one that the user wants checked.
|
| 568 |
if ( empty($this->selected_fields) ){
|
| 569 |
return;
|
| 570 |
}
|
|
@@ -581,7 +581,7 @@ class blcPostMetaManager extends blcContainerManager {
|
|
| 581 |
$container = blcContainerHelper::get_container( array($this->container_type, intval($object_id)) );
|
| 582 |
$container->mark_as_unsynched();
|
| 583 |
}
|
| 584 |
-
|
| 585 |
/**
|
| 586 |
* Delete custom field synch. records when the post that they belong to is deleted.
|
| 587 |
*
|
|
@@ -590,14 +590,17 @@ class blcPostMetaManager extends blcContainerManager {
|
|
| 590 |
*/
|
| 591 |
function post_deleted($post_id){
|
| 592 |
//Get the associated container object
|
| 593 |
-
|
| 594 |
-
|
| 595 |
-
|
| 596 |
-
|
| 597 |
-
|
| 598 |
-
|
| 599 |
-
|
| 600 |
-
|
|
|
|
|
|
|
|
|
|
| 601 |
* When a post is restored, mark all of its custom fields as unparsed.
|
| 602 |
* Called via the 'untrashed_post' action.
|
| 603 |
*
|
|
@@ -609,11 +612,11 @@ class blcPostMetaManager extends blcContainerManager {
|
|
| 609 |
$container = blcContainerHelper::get_container( array($this->container_type, intval($post_id)) );
|
| 610 |
$container->mark_as_unsynched();
|
| 611 |
}
|
| 612 |
-
|
| 613 |
/**
|
| 614 |
* Get the message to display after $n posts have been deleted.
|
| 615 |
*
|
| 616 |
-
* @uses blcAnyPostContainerManager::ui_bulk_delete_message()
|
| 617 |
*
|
| 618 |
* @param int $n Number of deleted posts.
|
| 619 |
* @return string A delete confirmation message, e.g. "5 posts were moved to the trash"
|
|
@@ -621,7 +624,7 @@ class blcPostMetaManager extends blcContainerManager {
|
|
| 621 |
function ui_bulk_delete_message($n){
|
| 622 |
return blcAnyPostContainerManager::ui_bulk_delete_message($n);
|
| 623 |
}
|
| 624 |
-
|
| 625 |
/**
|
| 626 |
* Get the message to display after $n posts have been trashed.
|
| 627 |
*
|
| 12 |
*/
|
| 13 |
|
| 14 |
//Note : If it ever becomes necessary to check metadata on objects other than posts, it will
|
| 15 |
+
//be fairly easy to extract a more general metadata container class from blcPostMeta.
|
| 16 |
|
| 17 |
/**
|
| 18 |
* blcPostMeta - A link container class for post metadata (AKA custom fields).
|
| 19 |
*
|
| 20 |
* Due to the way metadata works, this container differs significantly from other containers :
|
| 21 |
* - container_field is equal to meta name, and container_id holds the ID of the post.
|
| 22 |
+
* - There is one synch. record per post that determines the synch. state of all metadata fields of that post.
|
| 23 |
* - Unlinking simply deletes the meta entry in question without involving the parser.
|
| 24 |
+
* - The list of parse-able $fields is not fixed. Instead, it's initialized based on the
|
| 25 |
+
* custom field list defined in Settings -> Link Checker.
|
| 26 |
* - The $wrapped_object is an array (and isn't really used for anything).
|
| 27 |
* - update_wrapped_object() does nothing.
|
| 28 |
+
*
|
| 29 |
* @package Broken Link Checker
|
| 30 |
* @access public
|
| 31 |
*/
|
| 32 |
class blcPostMeta extends blcContainer {
|
| 33 |
+
|
| 34 |
var $meta_type = 'post';
|
| 35 |
+
|
| 36 |
/**
|
| 37 |
* Retrieve all metadata fields of the post associated with this container.
|
| 38 |
* The results are cached in the internal $wrapped_object variable.
|
| 39 |
+
*
|
| 40 |
+
* @param bool $ensure_consistency
|
| 41 |
* @return object The wrapped object.
|
| 42 |
*/
|
| 43 |
function get_wrapped_object($ensure_consistency = false){
|
| 45 |
$this->wrapped_object = get_metadata($this->meta_type, $this->container_id);
|
| 46 |
}
|
| 47 |
return $this->wrapped_object;
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
function update_wrapped_object(){
|
| 51 |
trigger_error('Function blcPostMeta::update_wrapped_object() does nothing and should not be used.', E_USER_WARNING);
|
| 52 |
}
|
| 53 |
+
|
| 54 |
/**
|
| 55 |
* Get the value of the specified metadata field of the object wrapped by this container.
|
| 56 |
+
*
|
| 57 |
* @access protected
|
| 58 |
*
|
| 59 |
+
* @param string $field Field name. If omitted, the value of the default field will be returned.
|
| 60 |
* @return array
|
| 61 |
*/
|
| 62 |
function get_field($field = ''){
|
| 63 |
$get_only_first_field = ($this->fields[$field] !== 'metadata');
|
| 64 |
return get_metadata($this->meta_type, $this->container_id, $field, $get_only_first_field);
|
| 65 |
}
|
| 66 |
+
|
| 67 |
/**
|
| 68 |
+
* Update the value of the specified metadata field of the object wrapped by this container.
|
| 69 |
*
|
| 70 |
* @access protected
|
| 71 |
*
|
| 72 |
* @param string $field Meta name.
|
| 73 |
+
* @param string $new_value New meta value.
|
| 74 |
+
* @param string $old_value old meta value.
|
| 75 |
* @return bool|WP_Error True on success, an error object if something went wrong.
|
| 76 |
*/
|
| 77 |
function update_field($field, $new_value, $old_value = ''){
|
| 82 |
return new WP_Error(
|
| 83 |
'metadata_update_failed',
|
| 84 |
sprintf(
|
| 85 |
+
__("Failed to update the meta field '%s' on %s [%d]", 'broken-link-checker'),
|
| 86 |
+
$field,
|
| 87 |
+
$this->meta_type,
|
| 88 |
$this->container_id
|
| 89 |
)
|
| 90 |
);
|
| 112 |
return new WP_Error(
|
| 113 |
'metadata_delete_failed',
|
| 114 |
sprintf(
|
| 115 |
+
__("Failed to delete the meta field '%s' on %s [%d]", 'broken-link-checker'),
|
| 116 |
$field_name,
|
| 117 |
+
$this->meta_type,
|
| 118 |
$this->container_id
|
| 119 |
)
|
| 120 |
);
|
| 138 |
'Editing %s[%d]:%s - %s to %s',
|
| 139 |
$this->container_type,
|
| 140 |
$this->container_id,
|
| 141 |
+
$field_name,
|
| 142 |
$old_url,
|
| 143 |
$new_url
|
| 144 |
));
|
| 147 |
if ( $this->fields[$field_name] !== 'metadata' ) {
|
| 148 |
return parent::edit_link($field_name, $parser, $new_url, $old_url, $old_raw_url, $new_text);
|
| 149 |
}
|
| 150 |
+
|
| 151 |
if ( empty($old_raw_url) ){
|
| 152 |
$old_raw_url = $old_url;
|
| 153 |
}
|
| 154 |
+
|
| 155 |
//Get the current values of the field that needs to be edited.
|
| 156 |
//The default metadata parser ignores them, but we're still going
|
| 157 |
+
//to set this argument to a valid value in case someone writes a
|
| 158 |
//custom meta parser that needs it.
|
| 159 |
$old_value = $this->get_field($field_name);
|
| 160 |
+
|
| 161 |
//Get the new field value (a string).
|
| 162 |
$edit_result = $parser->edit($old_value, $new_url, $old_url, $old_raw_url);
|
| 163 |
if ( is_wp_error($edit_result) ){
|
| 164 |
return $edit_result;
|
| 165 |
}
|
| 166 |
+
|
| 167 |
//Update the field with the new value returned by the parser.
|
| 168 |
//Notice how $old_raw_url is used instead of $old_value. $old_raw_url contains the entire old
|
| 169 |
//value of the metadata field (see blcMetadataParser::parse()) and thus can be used to
|
| 170 |
+
//differentiate between multiple meta fields with identical names.
|
| 171 |
$update_result = $this->update_field( $field_name, $edit_result['content'], $old_raw_url );
|
| 172 |
if ( is_wp_error($update_result) ){
|
| 173 |
return $update_result;
|
| 174 |
}
|
| 175 |
+
|
| 176 |
//Return the new "raw" URL.
|
| 177 |
return $edit_result['raw_url'];
|
| 178 |
}
|
| 179 |
+
|
| 180 |
/**
|
| 181 |
* Get the default link text to use for links found in a specific container field.
|
| 182 |
*
|
| 189 |
//the user a clue where to look if they want to find/modify the field.
|
| 190 |
return $field;
|
| 191 |
}
|
| 192 |
+
|
| 193 |
function ui_get_source($container_field = '', $context = 'display'){
|
| 194 |
if ( !post_type_exists(get_post_type($this->container_id)) ) {
|
| 195 |
//Error: Invalid post type. The user probably removed a CPT without removing the actual posts.
|
| 216 |
esc_attr(__('Edit this post')),
|
| 217 |
get_the_title($this->container_id)
|
| 218 |
);
|
| 219 |
+
|
| 220 |
return $post_html;
|
| 221 |
}
|
| 222 |
+
|
| 223 |
function ui_get_action_links($container_field){
|
| 224 |
$actions = array();
|
| 225 |
if ( !post_type_exists(get_post_type($this->container_id)) ) {
|
| 228 |
|
| 229 |
if ( current_user_can('edit_post', $this->container_id) ) {
|
| 230 |
$actions['edit'] = '<span class="edit"><a href="' . $this->get_edit_url() . '" title="' . esc_attr(__('Edit this item')) . '">' . __('Edit') . '</a>';
|
| 231 |
+
|
| 232 |
if ( $this->current_user_can_delete() ){
|
| 233 |
if ( $this->can_be_trashed() ) {
|
| 234 |
$actions['trash'] = sprintf(
|
| 248 |
}
|
| 249 |
}
|
| 250 |
$actions['view'] = '<span class="view"><a href="' . esc_url(get_permalink($this->container_id)) . '" title="' . esc_attr(sprintf(__('View "%s"', 'broken-link-checker'), get_the_title($this->container_id))) . '" rel="permalink">' . __('View') . '</a>';
|
| 251 |
+
|
| 252 |
return $actions;
|
| 253 |
}
|
| 254 |
+
|
| 255 |
/**
|
| 256 |
+
* Get edit URL for this container. Returns the URL of the Dashboard page where the item
|
| 257 |
* associated with this container can be edited.
|
| 258 |
*
|
| 259 |
+
* @access protected
|
| 260 |
*
|
| 261 |
* @return string
|
| 262 |
*/
|
| 263 |
function get_edit_url(){
|
| 264 |
/*
|
| 265 |
+
The below is a near-exact copy of the get_post_edit_link() function.
|
| 266 |
+
Unfortunately we can't just call that function because it has a hardcoded
|
| 267 |
+
caps-check which fails when called from the email notification script
|
| 268 |
executed by Cron.
|
| 269 |
+
*/
|
| 270 |
+
|
| 271 |
if ( !($post = get_post( $this->container_id )) ){
|
| 272 |
return '';
|
| 273 |
}
|
| 274 |
+
|
| 275 |
$context = 'display';
|
| 276 |
+
|
| 277 |
//WP 3.0
|
| 278 |
if ( 'display' == $context )
|
| 279 |
$action = '&action=edit';
|
| 280 |
else
|
| 281 |
$action = '&action=edit';
|
| 282 |
+
|
| 283 |
$post_type_object = get_post_type_object( $post->post_type );
|
| 284 |
if ( !$post_type_object ){
|
| 285 |
return '';
|
| 286 |
}
|
| 287 |
+
|
| 288 |
return apply_filters( 'get_edit_post_link', admin_url( sprintf($post_type_object->_edit_link . $action, $post->ID) ), $post->ID, $context );
|
| 289 |
}
|
| 290 |
+
|
| 291 |
/**
|
| 292 |
+
* Get the base URL of the container. For custom fields, the base URL is the permalink of
|
| 293 |
* the post that the field is attached to.
|
| 294 |
*
|
| 295 |
* @return string
|
| 297 |
function base_url(){
|
| 298 |
return get_permalink($this->container_id);
|
| 299 |
}
|
| 300 |
+
|
| 301 |
/**
|
| 302 |
* Delete or trash the post corresponding to this container. If trash is enabled,
|
| 303 |
* will always move the post to the trash instead of deleting.
|
| 322 |
}
|
| 323 |
}
|
| 324 |
}
|
| 325 |
+
|
| 326 |
/**
|
| 327 |
* Move the post corresponding to this custom field to the Trash.
|
| 328 |
+
*
|
| 329 |
* @return bool|WP_Error
|
| 330 |
*/
|
| 331 |
function trash_wrapped_object(){
|
| 339 |
)
|
| 340 |
);
|
| 341 |
}
|
| 342 |
+
|
| 343 |
$post = &get_post($this->container_id);
|
| 344 |
if ( $post->post_status == 'trash' ){
|
| 345 |
//Prevent conflicts between post and custom field containers trying to trash the same post.
|
| 346 |
return true;
|
| 347 |
}
|
| 348 |
+
|
| 349 |
if ( wp_trash_post($this->container_id) ){
|
| 350 |
return true;
|
| 351 |
} else {
|
| 359 |
);
|
| 360 |
}
|
| 361 |
}
|
| 362 |
+
|
| 363 |
function current_user_can_delete(){
|
| 364 |
$post = get_post($this->container_id);
|
| 365 |
$post_type_object = get_post_type_object($post->post_type);
|
| 366 |
return current_user_can( $post_type_object->cap->delete_post, $this->container_id );
|
| 367 |
}
|
| 368 |
+
|
| 369 |
function can_be_trashed(){
|
| 370 |
return defined('EMPTY_TRASH_DAYS') && EMPTY_TRASH_DAYS;
|
| 371 |
}
|
| 375 |
var $container_class_name = 'blcPostMeta';
|
| 376 |
var $meta_type = 'post';
|
| 377 |
protected $selected_fields = array();
|
| 378 |
+
|
| 379 |
function init(){
|
| 380 |
parent::init();
|
| 381 |
|
| 395 |
}
|
| 396 |
}
|
| 397 |
}
|
| 398 |
+
|
| 399 |
//Intercept 2.9+ style metadata modification actions
|
| 400 |
add_action( "added_{$this->meta_type}_meta", array($this, 'meta_modified'), 10, 4 );
|
| 401 |
add_action( "updated_{$this->meta_type}_meta", array($this, 'meta_modified'), 10, 4 );
|
| 404 |
//When a post is deleted, also delete the custom field container associated with it.
|
| 405 |
add_action('delete_post', array($this,'post_deleted'));
|
| 406 |
add_action('trash_post', array($this,'post_deleted'));
|
| 407 |
+
|
| 408 |
//Re-parse custom fields when a post is restored from trash
|
| 409 |
add_action('untrashed_post', array($this,'post_untrashed'));
|
| 410 |
}
|
| 411 |
|
| 412 |
+
|
| 413 |
/**
|
| 414 |
* Get a list of parseable fields.
|
| 415 |
+
*
|
| 416 |
* @return array
|
| 417 |
*/
|
| 418 |
function get_parseable_fields(){
|
| 419 |
return $this->selected_fields;
|
| 420 |
}
|
| 421 |
+
|
| 422 |
/**
|
| 423 |
* Instantiate multiple containers of the container type managed by this class.
|
| 424 |
*
|
| 425 |
* @param array $containers Array of assoc. arrays containing container data.
|
| 426 |
* @param string $purpose An optional code indicating how the retrieved containers will be used.
|
| 427 |
+
* @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
|
| 428 |
+
*
|
| 429 |
* @return array of blcPostMeta indexed by "container_type|container_id"
|
| 430 |
*/
|
| 431 |
function get_containers($containers, $purpose = '', $load_wrapped_objects = false){
|
| 432 |
$containers = $this->make_containers($containers);
|
| 433 |
+
|
| 434 |
/*
|
| 435 |
When links from custom fields are displayed in Tools -> Broken Links,
|
| 436 |
each one also shows the title of the post that the custom field(s)
|
| 437 |
belong to. Thus it makes sense to pre-cache the posts beforehand - it's
|
| 438 |
faster to load them all at once than to make a separate query for each
|
| 439 |
one later.
|
| 440 |
+
|
| 441 |
So make a list of involved post IDs and load them.
|
| 442 |
+
|
| 443 |
+
Calling get_posts() will automatically populate the post cache, so we
|
| 444 |
don't need to actually store the results anywhere in the container object().
|
| 445 |
+
*/
|
| 446 |
$preload = $load_wrapped_objects || in_array($purpose, array(BLC_FOR_DISPLAY));
|
| 447 |
if ( $preload ){
|
| 448 |
$post_ids = array();
|
| 449 |
foreach($containers as $container){
|
| 450 |
$post_ids[] = $container->container_id;
|
| 451 |
}
|
| 452 |
+
|
| 453 |
$args = array('include' => implode(',', $post_ids));
|
| 454 |
get_posts($args);
|
| 455 |
}
|
| 456 |
+
|
| 457 |
return $containers;
|
| 458 |
}
|
| 459 |
+
|
| 460 |
/**
|
| 461 |
* Create or update synchronization records for all containers managed by this class.
|
| 462 |
*
|
| 463 |
+
* @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch.
|
| 464 |
* @return void
|
| 465 |
*/
|
| 466 |
function resynch($forced = false){
|
| 478 |
$escaped_post_types = "'" . implode("', '", array_map('esc_sql', $post_types)) . "'";
|
| 479 |
|
| 480 |
if ( $forced ){
|
| 481 |
+
//Create new synchronization records for all posts.
|
| 482 |
$blclog->log('...... Creating synch records for all custom fields on ' . $escaped_post_types);
|
| 483 |
$start = microtime(true);
|
| 484 |
$q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
|
| 501 |
synch.container_type = '{$this->container_type}' AND posts.ID IS NULL";
|
| 502 |
$wpdb->query( $q );
|
| 503 |
$blclog->log(sprintf('...... %d rows deleted in %.3f seconds', $wpdb->rows_affected, microtime(true) - $start));
|
| 504 |
+
|
| 505 |
//Remove the 'synched' flag from all posts that have been updated
|
| 506 |
//since the last time they were parsed/synchronized.
|
| 507 |
$blclog->log('...... Marking custom fields on changed posts as unsynched');
|
| 515 |
synch.last_synch < posts.post_modified";
|
| 516 |
$wpdb->query( $q );
|
| 517 |
$blclog->log(sprintf('...... %d rows updated in %.3f seconds', $wpdb->rows_affected, microtime(true) - $start));
|
| 518 |
+
|
| 519 |
//Create synch. records for posts that don't have them.
|
| 520 |
$blclog->log('...... Creating custom field synch records for new ' . $escaped_post_types);
|
| 521 |
$start = microtime(true);
|
| 532 |
$blclog->log(sprintf('...... %d rows inserted in %.3f seconds', $wpdb->rows_affected, microtime(true) - $start));
|
| 533 |
}
|
| 534 |
}
|
| 535 |
+
|
| 536 |
/**
|
| 537 |
* Mark custom fields as unsynched when they're modified or deleted.
|
| 538 |
*
|
| 544 |
*/
|
| 545 |
function meta_modified($meta_id, $object_id = 0, $meta_key= '', $meta_value = ''){
|
| 546 |
global $wpdb; /** @var wpdb $wpdb */
|
| 547 |
+
|
| 548 |
+
//If object_id isn't specified then the hook was probably called from the
|
| 549 |
//stupidly inconsistent delete_meta() function in /wp-admin/includes/post.php.
|
| 550 |
if ( empty($object_id) ){
|
| 551 |
//We must manually retrieve object_id and meta_key from the DB.
|
| 552 |
if ( is_array($meta_id) ){
|
| 553 |
$meta_id = array_shift($meta_id);
|
| 554 |
}
|
| 555 |
+
|
| 556 |
$meta = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->postmeta WHERE meta_id = %d", $meta_id), ARRAY_A );
|
| 557 |
if ( empty($meta) ){
|
| 558 |
return;
|
| 559 |
}
|
| 560 |
+
|
| 561 |
$object_id = $meta['post_id'];
|
| 562 |
$meta_key = $meta['meta_key'];
|
| 563 |
}
|
| 564 |
+
|
| 565 |
+
|
| 566 |
+
//Metadata changes only matter to us if the modified key
|
| 567 |
+
//is one that the user wants checked.
|
| 568 |
if ( empty($this->selected_fields) ){
|
| 569 |
return;
|
| 570 |
}
|
| 581 |
$container = blcContainerHelper::get_container( array($this->container_type, intval($object_id)) );
|
| 582 |
$container->mark_as_unsynched();
|
| 583 |
}
|
| 584 |
+
|
| 585 |
/**
|
| 586 |
* Delete custom field synch. records when the post that they belong to is deleted.
|
| 587 |
*
|
| 590 |
*/
|
| 591 |
function post_deleted($post_id){
|
| 592 |
//Get the associated container object
|
| 593 |
+
|
| 594 |
+
$container = blcContainerHelper::get_container([$this->container_type, intval($post_id)]);
|
| 595 |
+
if ($container != null) {
|
| 596 |
+
//Delete it
|
| 597 |
+
$container->delete();
|
| 598 |
+
//Clean up any dangling links
|
| 599 |
+
blc_cleanup_links();
|
| 600 |
+
}
|
| 601 |
+
}
|
| 602 |
+
|
| 603 |
+
/**
|
| 604 |
* When a post is restored, mark all of its custom fields as unparsed.
|
| 605 |
* Called via the 'untrashed_post' action.
|
| 606 |
*
|
| 612 |
$container = blcContainerHelper::get_container( array($this->container_type, intval($post_id)) );
|
| 613 |
$container->mark_as_unsynched();
|
| 614 |
}
|
| 615 |
+
|
| 616 |
/**
|
| 617 |
* Get the message to display after $n posts have been deleted.
|
| 618 |
*
|
| 619 |
+
* @uses blcAnyPostContainerManager::ui_bulk_delete_message()
|
| 620 |
*
|
| 621 |
* @param int $n Number of deleted posts.
|
| 622 |
* @return string A delete confirmation message, e.g. "5 posts were moved to the trash"
|
| 624 |
function ui_bulk_delete_message($n){
|
| 625 |
return blcAnyPostContainerManager::ui_bulk_delete_message($n);
|
| 626 |
}
|
| 627 |
+
|
| 628 |
/**
|
| 629 |
* Get the message to display after $n posts have been trashed.
|
| 630 |
*
|
modules/parsers/acf_field.php
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
/*
|
| 3 |
+
Plugin Name: ACF
|
| 4 |
+
Description: Parses acf fields (AKA custom fields)
|
| 5 |
+
Version: 1.0
|
| 6 |
+
Author: Janne Aalto
|
| 7 |
+
|
| 8 |
+
ModuleID: acf
|
| 9 |
+
ModuleCategory: parser
|
| 10 |
+
ModuleClassName: blcACFParser
|
| 11 |
+
ModuleContext: on-demand
|
| 12 |
+
ModuleLazyInit: true
|
| 13 |
+
ModuleAlwaysActive: true
|
| 14 |
+
ModuleHidden: true
|
| 15 |
+
*/
|
| 16 |
+
|
| 17 |
+
class blcACFParser extends blcParser {
|
| 18 |
+
|
| 19 |
+
var $supported_formats = ['acf_field'];
|
| 20 |
+
var $supported_containers = [];
|
| 21 |
+
|
| 22 |
+
/**
|
| 23 |
+
* Parse a acf value.
|
| 24 |
+
*
|
| 25 |
+
* @param string|array $content ACF value(s).
|
| 26 |
+
* @param string $base_url The base URL to use for normalizing relative URLs. If ommitted, the blog's root URL will be used.
|
| 27 |
+
* @param string $default_link_text
|
| 28 |
+
* @return array An array of new blcLinkInstance objects.
|
| 29 |
+
*/
|
| 30 |
+
function parse($content, $base_url = '', $default_link_text = ''){
|
| 31 |
+
$instances = [];
|
| 32 |
+
|
| 33 |
+
if ( !is_array($content) ){
|
| 34 |
+
$content = [$content];
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
foreach($content as $value){
|
| 38 |
+
//The complete contents of the meta field are stored in raw_url.
|
| 39 |
+
//This is useful for editing/unlinking, when one may need to
|
| 40 |
+
//distinguish between multiple fields with the same name.
|
| 41 |
+
$raw_url = $value;
|
| 42 |
+
|
| 43 |
+
//If this is a multiline acf field take only the first line (workaround for the 'enclosure' field).
|
| 44 |
+
$lines = explode("\n", $value);
|
| 45 |
+
$url = trim(reset($lines));
|
| 46 |
+
|
| 47 |
+
//Attempt to parse the URL
|
| 48 |
+
$parts = @parse_url($url);
|
| 49 |
+
if(!$parts) {
|
| 50 |
+
return $instances; //Ignore invalid URLs
|
| 51 |
+
};
|
| 52 |
+
|
| 53 |
+
if ( !isset($parts['scheme']) ){
|
| 54 |
+
//No scheme - likely a relative URL. Turn it into an absolute one.
|
| 55 |
+
$url = $this->relative2absolute($url, $base_url);
|
| 56 |
+
|
| 57 |
+
//Skip invalid URLs (again)
|
| 58 |
+
if ( !$url || (strlen($url)<6) ) {
|
| 59 |
+
return $instances;
|
| 60 |
+
}
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
//The URL is okay, create and populate a new link instance.
|
| 64 |
+
$instance = new blcLinkInstance();
|
| 65 |
+
|
| 66 |
+
$instance->set_parser($this);
|
| 67 |
+
$instance->raw_url = $raw_url;
|
| 68 |
+
$instance->link_text = $default_link_text;
|
| 69 |
+
|
| 70 |
+
$link_obj = new blcLink($url); //Creates or loads the link
|
| 71 |
+
$instance->set_link($link_obj);
|
| 72 |
+
|
| 73 |
+
$instances[] = $instance;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
return $instances;
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
/**
|
| 80 |
+
* Change the URL in a acf field to another one.
|
| 81 |
+
*
|
| 82 |
+
* This is tricky because there can be multiple acf fields with the same name
|
| 83 |
+
* but different values. So we ignore $content (which might be an array of multiple
|
| 84 |
+
* acf values) and use the old raw_url that we stored when parsing the field(s)
|
| 85 |
+
* instead.
|
| 86 |
+
*
|
| 87 |
+
* @see blcACFParser::parse()
|
| 88 |
+
*
|
| 89 |
+
* @param string $content Ignored.
|
| 90 |
+
* @param string $new_url The new URL.
|
| 91 |
+
* @param string $old_url Ignored.
|
| 92 |
+
* @param string $old_raw_url The current meta value.
|
| 93 |
+
*
|
| 94 |
+
* @return array|WP_Error
|
| 95 |
+
*/
|
| 96 |
+
function edit($content, $new_url, $old_url, $old_raw_url){
|
| 97 |
+
//For multiline fields (like 'enclosure') we only want to change the first line.
|
| 98 |
+
$lines = explode("\n", $old_raw_url);
|
| 99 |
+
array_shift($lines); //Discard the old first line
|
| 100 |
+
array_unshift($lines, $new_url); //Insert the new URL in its place.
|
| 101 |
+
$content = implode("\n", $lines);
|
| 102 |
+
|
| 103 |
+
return array(
|
| 104 |
+
'content' => $content,
|
| 105 |
+
'raw_url' => $new_url,
|
| 106 |
+
);
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
/**
|
| 110 |
+
* Get the link text for printing in the "Broken Links" table.
|
| 111 |
+
*
|
| 112 |
+
* @param blcLinkInstance $instance
|
| 113 |
+
* @param string $context
|
| 114 |
+
* @return string HTML
|
| 115 |
+
*/
|
| 116 |
+
function ui_get_link_text($instance, $context = 'display'){
|
| 117 |
+
$image_html = sprintf(
|
| 118 |
+
'<img src="%s" class="blc-small-image" title="%2$s" alt="%2$s"> ',
|
| 119 |
+
esc_attr( plugins_url('/images/font-awesome/font-awesome-code.png', BLC_PLUGIN_FILE) ),
|
| 120 |
+
__('Custom field', 'broken-link-checker')
|
| 121 |
+
);
|
| 122 |
+
|
| 123 |
+
$field_html = sprintf(
|
| 124 |
+
'<code>%s</code>',
|
| 125 |
+
$instance->container_field
|
| 126 |
+
);
|
| 127 |
+
|
| 128 |
+
if ( $context != 'email' ){
|
| 129 |
+
$field_html = $image_html . $field_html;
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
return $field_html;
|
| 133 |
+
}
|
| 134 |
+
}
|
readme.txt
CHANGED
|
@@ -4,7 +4,7 @@ Donate link:
|
|
| 4 |
Tags: links, broken, maintenance, blogroll, custom fields, admin, comments, posts
|
| 5 |
Requires at least: 3.2
|
| 6 |
Tested up to: 4.8
|
| 7 |
-
Stable tag: 1.11.
|
| 8 |
|
| 9 |
This plugin will check your posts, comments and other content for broken links and missing images, and notify you if any are found.
|
| 10 |
|
|
@@ -101,6 +101,9 @@ To upgrade your installation
|
|
| 101 |
|
| 102 |
== Changelog ==
|
| 103 |
|
|
|
|
|
|
|
|
|
|
| 104 |
= 1.11.3 =
|
| 105 |
* Updated plugin information
|
| 106 |
|
| 4 |
Tags: links, broken, maintenance, blogroll, custom fields, admin, comments, posts
|
| 5 |
Requires at least: 3.2
|
| 6 |
Tested up to: 4.8
|
| 7 |
+
Stable tag: 1.11.4
|
| 8 |
|
| 9 |
This plugin will check your posts, comments and other content for broken links and missing images, and notify you if any are found.
|
| 10 |
|
| 101 |
|
| 102 |
== Changelog ==
|
| 103 |
|
| 104 |
+
= 1.11.4 =
|
| 105 |
+
* Fixed a few more PHP 7.x/5.6 compatibility issues
|
| 106 |
+
|
| 107 |
= 1.11.3 =
|
| 108 |
* Updated plugin information
|
| 109 |
|
uninstall.php
CHANGED
|
@@ -1,22 +1,21 @@
|
|
| 1 |
-
<?php
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
* @
|
| 5 |
-
*
|
| 6 |
-
*
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
delete_option('
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
$mywpdb
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
}
|
| 1 |
+
<?php
|
| 2 |
+
/**
|
| 3 |
+
* @author Janis Elsts
|
| 4 |
+
* @copyright 2010
|
| 5 |
+
*
|
| 6 |
+
* The terrifying uninstallation script.
|
| 7 |
+
*/
|
| 8 |
+
|
| 9 |
+
if ( defined( 'ABSPATH' ) && defined( 'WP_UNINSTALL_PLUGIN' ) ) {
|
| 10 |
+
|
| 11 |
+
// Remove the plugin's settings & installation log.
|
| 12 |
+
delete_option( 'wsblc_options' );
|
| 13 |
+
delete_option( 'blc_installation_log' );
|
| 14 |
+
|
| 15 |
+
// Remove the database tables.
|
| 16 |
+
$mywpdb = $GLOBALS['wpdb'];
|
| 17 |
+
if( isset( $mywpdb ) ) { /** @var wpdb $mywpdb */
|
| 18 |
+
// EXTERMINATE!
|
| 19 |
+
$mywpdb->query( "DROP TABLE IF EXISTS {$mywpdb->prefix}blc_linkdata, {$mywpdb->prefix}blc_postdata, {$mywpdb->prefix}blc_instances, {$mywpdb->prefix}blc_links, {$mywpdb->prefix}blc_synch, {$mywpdb->prefix}blc_filters" );
|
| 20 |
+
}
|
| 21 |
+
}
|
|
|
