Version Description
- Fixed a few more PHP 7.x/5.6 compatibility issues
Download this release
Release Info
Developer | freediver |
Plugin | Broken Link Checker |
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 |
+
}
|
|