Version Description
- Major performance improvement. Database queries reduced up to 10x in some cases.
- Feel free to contribute to the plugin on GitHub. Pull requests welcome!
Download this release
Release Info
Developer | freediver |
Plugin | Broken Link Checker |
Version | 1.11.1 |
Comparing to | |
See all releases |
Code changes from version 1.10.11 to 1.11.1
- broken-link-checker.php +1 -1
- core/core.php +37 -81
- images/embedplus_banner.jpg +0 -0
- images/mwp250_2.jpg +0 -0
- images/mwp250_2.png +0 -0
- includes/admin/sidebar.php +1 -79
- includes/config-manager.php +108 -108
- includes/containers.php +7 -1
- includes/links.php +8 -3
- includes/module-base.php +14 -13
- includes/screen-meta-links.php +239 -239
- includes/survey.php +0 -58
- includes/transactions-manager.php +41 -0
- readme.txt +5 -1
broken-link-checker.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
Plugin Name: Broken Link Checker
|
4 |
Plugin URI: http://w-shadow.com/blog/2007/08/05/broken-link-checker-for-wordpress/
|
5 |
Description: Checks your blog for broken links and missing images and notifies you on the dashboard if any are found.
|
6 |
-
Version: 1.
|
7 |
Author: Janis Elsts, Vladimir Prelovac
|
8 |
Author URI: http://w-shadow.com/
|
9 |
Text Domain: broken-link-checker
|
3 |
Plugin Name: Broken Link Checker
|
4 |
Plugin URI: http://w-shadow.com/blog/2007/08/05/broken-link-checker-for-wordpress/
|
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.1
|
7 |
Author: Janis Elsts, Vladimir Prelovac
|
8 |
Author URI: http://w-shadow.com/
|
9 |
Text Domain: broken-link-checker
|
core/core.php
CHANGED
@@ -14,6 +14,7 @@ if ( !function_exists( 'microtime_float' ) ) {
|
|
14 |
require BLC_DIRECTORY . '/includes/screen-options/screen-options.php';
|
15 |
require BLC_DIRECTORY . '/includes/screen-meta-links.php';
|
16 |
require BLC_DIRECTORY . '/includes/wp-mutex.php';
|
|
|
17 |
|
18 |
if (!class_exists('wsBrokenLinkChecker')) {
|
19 |
|
@@ -37,7 +38,7 @@ class wsBrokenLinkChecker {
|
|
37 |
* @param blcConfigurationManager $conf An instance of the configuration manager
|
38 |
* @return void
|
39 |
*/
|
40 |
-
|
41 |
$this->db_version = BLC_DATABASE_VERSION;
|
42 |
|
43 |
$this->conf = $conf;
|
@@ -81,8 +82,7 @@ class wsBrokenLinkChecker {
|
|
81 |
add_action('blc_cron_email_notifications', array( $this, 'maybe_send_email_notifications' ));
|
82 |
add_action('blc_cron_check_links', array($this, 'cron_check_links'));
|
83 |
add_action('blc_cron_database_maintenance', array($this, 'database_maintenance'));
|
84 |
-
|
85 |
-
|
86 |
//Set the footer hook that will call the worker function via AJAX.
|
87 |
add_action('admin_footer', array($this,'admin_footer'));
|
88 |
|
@@ -259,7 +259,7 @@ class wsBrokenLinkChecker {
|
|
259 |
wp_clear_scheduled_hook('blc_cron_check_links');
|
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');
|
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();
|
@@ -331,14 +331,6 @@ class wsBrokenLinkChecker {
|
|
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 |
-
//Add a "Feedback" button that links to the plugin's UserVoice forum
|
335 |
-
add_screen_meta_link(
|
336 |
-
'blc-feedback-widget',
|
337 |
-
__('Feedback', 'broken-link-checker'),
|
338 |
-
'http://whiteshadow.uservoice.com/forums/58400-broken-link-checker',
|
339 |
-
array($options_page_hook, $links_page_hook)
|
340 |
-
);
|
341 |
-
|
342 |
//Make the Settings page link to the link list
|
343 |
add_screen_meta_link(
|
344 |
'blc-links-page-link',
|
@@ -347,17 +339,6 @@ class wsBrokenLinkChecker {
|
|
347 |
$options_page_hook,
|
348 |
array('style' => 'font-weight: bold;')
|
349 |
);
|
350 |
-
|
351 |
-
//Add a link to the latest blog post/whatever about this plugin, if any.
|
352 |
-
if ( !$this->conf->get('user_has_donated') && isset($this->conf->options['plugin_news']) && !empty($this->conf->options['plugin_news']) ){
|
353 |
-
$news = $this->conf->options['plugin_news'];
|
354 |
-
add_screen_meta_link(
|
355 |
-
'blc-plugin-news-link',
|
356 |
-
$news[0],
|
357 |
-
$news[1],
|
358 |
-
array($options_page_hook, $links_page_hook)
|
359 |
-
);
|
360 |
-
}
|
361 |
}
|
362 |
|
363 |
/**
|
@@ -2113,7 +2094,8 @@ class wsBrokenLinkChecker {
|
|
2113 |
$link->false_positive = true;
|
2114 |
$link->last_check_attempt = time();
|
2115 |
$link->log = __("This link was manually marked as working by the user.", 'broken-link-checker');
|
2116 |
-
|
|
|
2117 |
//Save the changes
|
2118 |
if ( $link->save() ){
|
2119 |
$processed_links++;
|
@@ -2172,6 +2154,7 @@ class wsBrokenLinkChecker {
|
|
2172 |
|
2173 |
$link->dismissed = true;
|
2174 |
|
|
|
2175 |
//Save the changes
|
2176 |
if ( $link->save() ){
|
2177 |
$processed_links++;
|
@@ -2581,7 +2564,10 @@ class wsBrokenLinkChecker {
|
|
2581 |
|
2582 |
//Randomizing the array reduces the chances that we'll get several links to the same domain in a row.
|
2583 |
shuffle($links);
|
2584 |
-
|
|
|
|
|
|
|
2585 |
foreach ($links as $link) {
|
2586 |
//Does this link need to be checked? Excluded links aren't checked, but their URLs are still
|
2587 |
//tested periodically to see if they're still on the exclusion list.
|
@@ -2611,6 +2597,7 @@ class wsBrokenLinkChecker {
|
|
2611 |
return;
|
2612 |
}
|
2613 |
}
|
|
|
2614 |
|
2615 |
$start = microtime(true);
|
2616 |
$links = $this->get_links_to_check($max_links_per_query);
|
@@ -2691,30 +2678,29 @@ class wsBrokenLinkChecker {
|
|
2691 |
//I could put an index on last_check_attempt, but that value is almost
|
2692 |
//certainly unique for each row so it wouldn't be much better than a full table scan.
|
2693 |
if ( $count_only ){
|
2694 |
-
$q = "SELECT COUNT(links.link_id)\n";
|
2695 |
} else {
|
2696 |
-
$q = "SELECT links.*\n";
|
2697 |
}
|
2698 |
$q .= "FROM {$wpdb->prefix}blc_links AS links
|
2699 |
-
|
2700 |
-
|
2701 |
-
|
2702 |
-
|
2703 |
-
|
2704 |
-
|
2705 |
-
|
2706 |
-
|
2707 |
-
|
2708 |
-
|
2709 |
-
|
2710 |
-
|
2711 |
-
|
2712 |
-
|
2713 |
-
|
2714 |
-
|
2715 |
-
|
2716 |
-
|
2717 |
-
";
|
2718 |
if ( !$count_only ){
|
2719 |
$q .= "\nORDER BY last_check_attempt ASC\n";
|
2720 |
if ( !empty($max_results) ){
|
@@ -2928,7 +2914,8 @@ class wsBrokenLinkChecker {
|
|
2928 |
$link->false_positive = true;
|
2929 |
$link->last_check_attempt = time();
|
2930 |
$link->log = __("This link was manually marked as working by the user.", 'broken-link-checker');
|
2931 |
-
|
|
|
2932 |
//Save the changes
|
2933 |
if ( $link->save() ){
|
2934 |
die( "OK" );
|
@@ -2967,6 +2954,7 @@ class wsBrokenLinkChecker {
|
|
2967 |
$link->dismissed = $dismiss;
|
2968 |
|
2969 |
//Save the changes
|
|
|
2970 |
if ( $link->save() ){
|
2971 |
die( "OK" );
|
2972 |
} else {
|
@@ -3213,6 +3201,7 @@ class wsBrokenLinkChecker {
|
|
3213 |
|
3214 |
//In case the immediate check fails, this will ensure the link is checked during the next work() run.
|
3215 |
$link->last_check_attempt = 0;
|
|
|
3216 |
$link->save();
|
3217 |
|
3218 |
//Check the link and save the results.
|
@@ -3771,12 +3760,7 @@ class wsBrokenLinkChecker {
|
|
3771 |
if ( !wp_next_scheduled('blc_cron_database_maintenance') ){
|
3772 |
wp_schedule_event(time(), 'bimonthly', 'blc_cron_database_maintenance');
|
3773 |
}
|
3774 |
-
|
3775 |
-
//Check for news notices related to this plugin
|
3776 |
-
if ( !wp_next_scheduled('blc_cron_check_news') ){
|
3777 |
-
wp_schedule_event(time(), 'daily', 'blc_cron_check_news');
|
3778 |
-
}
|
3779 |
-
}
|
3780 |
|
3781 |
/**
|
3782 |
* Load the plugin's textdomain.
|
@@ -3787,34 +3771,6 @@ class wsBrokenLinkChecker {
|
|
3787 |
$this->is_textdomain_loaded = load_plugin_textdomain( 'broken-link-checker', false, basename(dirname($this->loader)) . '/languages' );
|
3788 |
}
|
3789 |
|
3790 |
-
/**
|
3791 |
-
* Check if there's a "news" link to display on the plugin's pages.
|
3792 |
-
*
|
3793 |
-
* @return void
|
3794 |
-
*/
|
3795 |
-
function check_news(){
|
3796 |
-
$url = 'http://w-shadow.com/plugin-news/broken-link-checker-news.txt';
|
3797 |
-
|
3798 |
-
//Retrieve the appropriate "news" file
|
3799 |
-
$res = wp_remote_get($url);
|
3800 |
-
if ( is_wp_error($res) ){
|
3801 |
-
return;
|
3802 |
-
}
|
3803 |
-
|
3804 |
-
//Anything there?
|
3805 |
-
if ( isset($res['response']['code']) && ($res['response']['code'] == 200) && isset($res['body']) ) {
|
3806 |
-
//The file should contain two lines - a title and an URL
|
3807 |
-
$news = explode("\n", trim($res['body']));
|
3808 |
-
if ( count($news) == 2 ){
|
3809 |
-
//Save for later.
|
3810 |
-
$this->conf->options['plugin_news'] = $news;
|
3811 |
-
} else {
|
3812 |
-
$this->conf->options['plugin_news'] = null;
|
3813 |
-
}
|
3814 |
-
$this->conf->save_options();
|
3815 |
-
}
|
3816 |
-
}
|
3817 |
-
|
3818 |
protected static function get_default_log_directory() {
|
3819 |
$uploads = wp_upload_dir();
|
3820 |
return $uploads['basedir'] . '/broken-link-checker';
|
14 |
require BLC_DIRECTORY . '/includes/screen-options/screen-options.php';
|
15 |
require BLC_DIRECTORY . '/includes/screen-meta-links.php';
|
16 |
require BLC_DIRECTORY . '/includes/wp-mutex.php';
|
17 |
+
require BLC_DIRECTORY . '/includes/transactions-manager.php';
|
18 |
|
19 |
if (!class_exists('wsBrokenLinkChecker')) {
|
20 |
|
38 |
* @param blcConfigurationManager $conf An instance of the configuration manager
|
39 |
* @return void
|
40 |
*/
|
41 |
+
function __construct ( $loader, $conf ) {
|
42 |
$this->db_version = BLC_DATABASE_VERSION;
|
43 |
|
44 |
$this->conf = $conf;
|
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 |
|
259 |
wp_clear_scheduled_hook('blc_cron_check_links');
|
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();
|
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',
|
339 |
$options_page_hook,
|
340 |
array('style' => 'font-weight: bold;')
|
341 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
342 |
}
|
343 |
|
344 |
/**
|
2094 |
$link->false_positive = true;
|
2095 |
$link->last_check_attempt = time();
|
2096 |
$link->log = __("This link was manually marked as working by the user.", 'broken-link-checker');
|
2097 |
+
|
2098 |
+
$link->isOptionLinkChanged = true;
|
2099 |
//Save the changes
|
2100 |
if ( $link->save() ){
|
2101 |
$processed_links++;
|
2154 |
|
2155 |
$link->dismissed = true;
|
2156 |
|
2157 |
+
$link->isOptionLinkChanged = true;
|
2158 |
//Save the changes
|
2159 |
if ( $link->save() ){
|
2160 |
$processed_links++;
|
2564 |
|
2565 |
//Randomizing the array reduces the chances that we'll get several links to the same domain in a row.
|
2566 |
shuffle($links);
|
2567 |
+
|
2568 |
+
$transactionManager = TransactionManager::getInstance();
|
2569 |
+
$transactionManager->start();
|
2570 |
+
|
2571 |
foreach ($links as $link) {
|
2572 |
//Does this link need to be checked? Excluded links aren't checked, but their URLs are still
|
2573 |
//tested periodically to see if they're still on the exclusion list.
|
2597 |
return;
|
2598 |
}
|
2599 |
}
|
2600 |
+
$transactionManager->commit();
|
2601 |
|
2602 |
$start = microtime(true);
|
2603 |
$links = $this->get_links_to_check($max_links_per_query);
|
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";
|
2682 |
} else {
|
2683 |
+
$q = "SELECT DISTINCT links.*\n";
|
2684 |
}
|
2685 |
$q .= "FROM {$wpdb->prefix}blc_links AS links
|
2686 |
+
INNER JOIN {$wpdb->prefix}blc_instances AS instances USING(link_id)
|
2687 |
+
WHERE
|
2688 |
+
(
|
2689 |
+
( last_check_attempt < %s )
|
2690 |
+
OR
|
2691 |
+
(
|
2692 |
+
(broken = 1 OR being_checked = 1)
|
2693 |
+
AND may_recheck = 1
|
2694 |
+
AND check_count < %d
|
2695 |
+
AND last_check_attempt < %s
|
2696 |
+
)
|
2697 |
+
)
|
2698 |
+
|
2699 |
+
AND
|
2700 |
+
( instances.container_type IN ({$loaded_containers}) )
|
2701 |
+
AND ( instances.parser_type IN ({$loaded_parsers}) )
|
2702 |
+
";
|
2703 |
+
|
|
|
2704 |
if ( !$count_only ){
|
2705 |
$q .= "\nORDER BY last_check_attempt ASC\n";
|
2706 |
if ( !empty($max_results) ){
|
2914 |
$link->false_positive = true;
|
2915 |
$link->last_check_attempt = time();
|
2916 |
$link->log = __("This link was manually marked as working by the user.", 'broken-link-checker');
|
2917 |
+
|
2918 |
+
$link->isOptionLinkChanged = true;
|
2919 |
//Save the changes
|
2920 |
if ( $link->save() ){
|
2921 |
die( "OK" );
|
2954 |
$link->dismissed = $dismiss;
|
2955 |
|
2956 |
//Save the changes
|
2957 |
+
$link->isOptionLinkChanged = true;
|
2958 |
if ( $link->save() ){
|
2959 |
die( "OK" );
|
2960 |
} else {
|
3201 |
|
3202 |
//In case the immediate check fails, this will ensure the link is checked during the next work() run.
|
3203 |
$link->last_check_attempt = 0;
|
3204 |
+
$link->isOptionLinkChanged = true;
|
3205 |
$link->save();
|
3206 |
|
3207 |
//Check the link and save the results.
|
3760 |
if ( !wp_next_scheduled('blc_cron_database_maintenance') ){
|
3761 |
wp_schedule_event(time(), 'bimonthly', 'blc_cron_database_maintenance');
|
3762 |
}
|
3763 |
+
}
|
|
|
|
|
|
|
|
|
|
|
3764 |
|
3765 |
/**
|
3766 |
* Load the plugin's textdomain.
|
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';
|
images/embedplus_banner.jpg
DELETED
Binary file
|
images/mwp250_2.jpg
DELETED
Binary file
|
images/mwp250_2.png
CHANGED
Binary file
|
includes/admin/sidebar.php
CHANGED
@@ -1,84 +1,6 @@
|
|
|
|
1 |
<?php
|
2 |
$configuration = blc_get_configuration();
|
3 |
-
|
4 |
-
if ( !function_exists('fetch_feed') ){
|
5 |
-
include_once(ABSPATH . WPINC . '/feed.php');
|
6 |
-
}
|
7 |
-
|
8 |
-
$show_plugin_feed = false;
|
9 |
-
if ( !$configuration->get('user_has_donated', false) ) {
|
10 |
-
$show_plugin_feed = true;
|
11 |
-
}
|
12 |
-
$show_plugin_feed = false; //Disabled for now to make room for the EmbedPlus banner.
|
13 |
-
?>
|
14 |
-
|
15 |
-
<!-- "More plugins" RSS feed -->
|
16 |
-
<?php
|
17 |
-
if ( $show_plugin_feed ):
|
18 |
-
$feed_url = 'http://w-shadow.com/files/blc-plugin-links.rss';
|
19 |
-
$num_items = 3;
|
20 |
-
|
21 |
-
$feed = fetch_feed($feed_url);
|
22 |
-
if ( !is_wp_error($feed) ):
|
23 |
-
?>
|
24 |
-
<div id="advertising" class="postbox">
|
25 |
-
<h3 class="hndle"><?php _e('More plugins by Janis Elsts', 'broken-link-checker'); ?></h3>
|
26 |
-
<div class="inside">
|
27 |
-
<ul>
|
28 |
-
<?php
|
29 |
-
foreach($feed->get_items(0, $num_items) as $item) { /** @var SimplePie_Item $item */
|
30 |
-
printf(
|
31 |
-
'<li><a href="%1$s" title="%2$s">%3$s</a></li>',
|
32 |
-
esc_url( $item->get_link() ),
|
33 |
-
esc_attr( strip_tags( $item->get_title() ) ),
|
34 |
-
esc_html( $item->get_title() )
|
35 |
-
);
|
36 |
-
}
|
37 |
-
?>
|
38 |
-
</ul>
|
39 |
-
</div>
|
40 |
-
</div>
|
41 |
-
<?php
|
42 |
-
endif;
|
43 |
-
endif;
|
44 |
-
?>
|
45 |
-
|
46 |
-
<!-- Donation button -->
|
47 |
-
<div id="donate" class="postbox">
|
48 |
-
<h3 class="hndle"><?php _e('Donate $10, $20 or $50!', 'broken-link-checker'); ?></h3>
|
49 |
-
<div class="inside">
|
50 |
-
<p><?php
|
51 |
-
_e('If you like this plugin, please donate to support development and maintenance!', 'broken-link-checker');
|
52 |
-
?></p>
|
53 |
-
|
54 |
-
<form style="text-align: center;" action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
55 |
-
<input type="hidden" name="cmd" value="_donations">
|
56 |
-
<input type="hidden" name="business" value="G3GGNXHBSHKYC">
|
57 |
-
<input type="hidden" name="lc" value="US">
|
58 |
-
<input type="hidden" name="item_name" value="Broken Link Checker">
|
59 |
-
<input type="hidden" name="no_note" value="1">
|
60 |
-
<input type="hidden" name="no_shipping" value="1">
|
61 |
-
<input type="hidden" name="currency_code" value="USD">
|
62 |
-
<input type="hidden" name="bn" value="PP-DonationsBF:btn_donateCC_LG.gif:NonHosted">
|
63 |
-
|
64 |
-
<input type="hidden" name="rm" value="2">
|
65 |
-
<input type="hidden" name="return" value="<?php
|
66 |
-
echo esc_attr(admin_url('options-general.php?page=link-checker-settings&donated=1'));
|
67 |
-
?>" />
|
68 |
-
<input type="hidden" name="cbt" value="<?php
|
69 |
-
echo esc_attr(__('Return to WordPress Dashboard', 'broken-link-checker'));
|
70 |
-
?>" />
|
71 |
-
<input type="hidden" name="cancel_return" value="<?php
|
72 |
-
echo esc_attr(admin_url('options-general.php?page=link-checker-settings&donation_canceled=1'));
|
73 |
-
?>" />
|
74 |
-
|
75 |
-
<input type="image" src="https://www.sandbox.paypal.com/en_US/GB/i/btn/btn_donateCC_LG.gif" name="submit" alt="PayPal - The safer, easier way to pay online." style="max-width:170px;height:47px;border:0;">
|
76 |
-
</form>
|
77 |
-
</div>
|
78 |
-
</div>
|
79 |
-
|
80 |
-
<!-- Other advertising -->
|
81 |
-
<?php
|
82 |
if ( !$configuration->get('user_has_donated') ):
|
83 |
?>
|
84 |
<div id="managewp-ad" class="postbox">
|
1 |
+
<!-- Advertising -->
|
2 |
<?php
|
3 |
$configuration = blc_get_configuration();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
if ( !$configuration->get('user_has_donated') ):
|
5 |
?>
|
6 |
<div id="managewp-ad" class="postbox">
|
includes/config-manager.php
CHANGED
@@ -7,121 +7,121 @@
|
|
7 |
|
8 |
if ( !class_exists('blcConfigurationManager') ){
|
9 |
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
}
|
31 |
-
$this->loaded_values = array();
|
32 |
-
|
33 |
-
$this->options = $this->defaults;
|
34 |
-
|
35 |
-
if ( !empty( $this->option_name ) ) {
|
36 |
-
$this->load_options();
|
37 |
-
}
|
38 |
}
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
}
|
46 |
-
$this->options = array_merge($this->defaults, $this->loaded_values);
|
47 |
}
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
* @return bool True if options were loaded, false otherwise.
|
56 |
-
*/
|
57 |
-
function load_options( $option_name = '' ){
|
58 |
-
$this->db_option_loaded = false;
|
59 |
-
|
60 |
-
if ( !empty($option_name) ){
|
61 |
-
$this->option_name = $option_name;
|
62 |
-
}
|
63 |
-
|
64 |
-
if ( empty($this->option_name) ) return false;
|
65 |
-
|
66 |
-
$new_options = get_option($this->option_name);
|
67 |
-
|
68 |
-
//Decode JSON (if applicable).
|
69 |
-
if ( is_string($new_options) && !empty($new_options) ) {
|
70 |
-
$new_options = json_decode($new_options, true);
|
71 |
-
}
|
72 |
-
|
73 |
-
if( !is_array( $new_options ) ){
|
74 |
-
return false;
|
75 |
-
} else {
|
76 |
-
$this->loaded_values = $new_options;
|
77 |
-
$this->options = array_merge( $this->defaults, $this->loaded_values );
|
78 |
-
$this->db_option_loaded = true;
|
79 |
-
return true;
|
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 |
}
|
|
|
|
7 |
|
8 |
if ( !class_exists('blcConfigurationManager') ){
|
9 |
|
10 |
+
class blcConfigurationManager {
|
11 |
+
|
12 |
+
var $option_name;
|
13 |
+
|
14 |
+
var $options;
|
15 |
+
var $defaults;
|
16 |
+
var $loaded_values;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @var bool Whether options have been successfully loaded from the database.
|
20 |
+
*/
|
21 |
+
public $db_option_loaded = false;
|
22 |
+
|
23 |
+
function __construct( $option_name = '', $default_settings = null ){
|
24 |
+
$this->option_name = $option_name;
|
25 |
+
|
26 |
+
if ( is_array($default_settings) ){
|
27 |
+
$this->defaults = $default_settings;
|
28 |
+
} else {
|
29 |
+
$this->defaults = array();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
}
|
31 |
+
$this->loaded_values = array();
|
32 |
+
|
33 |
+
$this->options = $this->defaults;
|
34 |
+
|
35 |
+
if ( !empty( $this->option_name ) ) {
|
36 |
+
$this->load_options();
|
|
|
|
|
37 |
}
|
38 |
+
}
|
39 |
+
|
40 |
+
function set_defaults( $default_settings = null ){
|
41 |
+
if ( is_array($default_settings) ){
|
42 |
+
$this->defaults = array();
|
43 |
+
} else {
|
44 |
+
$this->defaults = $default_settings;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
}
|
46 |
+
$this->options = array_merge($this->defaults, $this->loaded_values);
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* blcOptionManager::load_options()
|
51 |
+
* Load plugin options from the database. The current $options values are not affected
|
52 |
+
* if this function fails.
|
53 |
+
*
|
54 |
+
* @param string $option_name
|
55 |
+
* @return bool True if options were loaded, false otherwise.
|
56 |
+
*/
|
57 |
+
function load_options( $option_name = '' ){
|
58 |
+
$this->db_option_loaded = false;
|
59 |
+
|
60 |
+
if ( !empty($option_name) ){
|
61 |
+
$this->option_name = $option_name;
|
62 |
+
}
|
63 |
+
|
64 |
+
if ( empty($this->option_name) ) return false;
|
65 |
+
|
66 |
+
$new_options = get_option($this->option_name);
|
67 |
+
|
68 |
+
//Decode JSON (if applicable).
|
69 |
+
if ( is_string($new_options) && !empty($new_options) ) {
|
70 |
+
$new_options = json_decode($new_options, true);
|
71 |
}
|
72 |
|
73 |
+
if( !is_array( $new_options ) ){
|
74 |
+
return false;
|
75 |
+
} else {
|
76 |
+
$this->loaded_values = $new_options;
|
77 |
+
$this->options = array_merge( $this->defaults, $this->loaded_values );
|
78 |
+
$this->db_option_loaded = true;
|
79 |
+
return true;
|
80 |
+
}
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* blcOptionManager::save_options()
|
85 |
+
* Save plugin options to the database.
|
86 |
+
*
|
87 |
+
* @param string $option_name (Optional) Save the options under this name
|
88 |
+
* @return bool True if settings were saved, false if settings haven't been changed or if there was an error.
|
89 |
+
*/
|
90 |
+
function save_options( $option_name = '' ){
|
91 |
+
if ( !empty($option_name) ){
|
92 |
+
$this->option_name = $option_name;
|
93 |
}
|
94 |
+
|
95 |
+
if ( empty($this->option_name) ) return false;
|
96 |
|
97 |
+
return update_option( $this->option_name, json_encode($this->options) );
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* Retrieve a specific setting.
|
102 |
+
*
|
103 |
+
* @param string $key
|
104 |
+
* @param mixed $default
|
105 |
+
* @return mixed
|
106 |
+
*/
|
107 |
+
function get($key, $default = null){
|
108 |
+
if ( array_key_exists($key, $this->options) ){
|
109 |
+
return $this->options[$key];
|
110 |
+
} else {
|
111 |
+
return $default;
|
112 |
}
|
113 |
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* Update or add a setting.
|
117 |
+
*
|
118 |
+
* @param string $key
|
119 |
+
* @param mixed $value
|
120 |
+
* @return void
|
121 |
+
*/
|
122 |
+
function set($key, $value){
|
123 |
+
$this->options[$key] = $value;
|
124 |
+
}
|
125 |
}
|
126 |
+
|
127 |
+
}
|
includes/containers.php
CHANGED
@@ -274,12 +274,18 @@ class blcContainer {
|
|
274 |
//FB::log("Parsing $name with '{$parser->parser_type}' parser");
|
275 |
$found_instances = $parser->parse( $value, $base_url, $default_link_text );
|
276 |
//FB::log($found_instances, "Found instances");
|
277 |
-
|
|
|
|
|
|
|
278 |
//Complete the link instances by adding container info, then save them to the DB.
|
279 |
foreach($found_instances as $instance){
|
280 |
$instance->set_container($this, $name);
|
281 |
$instance->save();
|
282 |
}
|
|
|
|
|
|
|
283 |
}
|
284 |
}
|
285 |
|
274 |
//FB::log("Parsing $name with '{$parser->parser_type}' parser");
|
275 |
$found_instances = $parser->parse( $value, $base_url, $default_link_text );
|
276 |
//FB::log($found_instances, "Found instances");
|
277 |
+
|
278 |
+
$transactionManager = TransactionManager::getInstance();
|
279 |
+
$transactionManager->start();
|
280 |
+
|
281 |
//Complete the link instances by adding container info, then save them to the DB.
|
282 |
foreach($found_instances as $instance){
|
283 |
$instance->set_container($this, $name);
|
284 |
$instance->save();
|
285 |
}
|
286 |
+
|
287 |
+
$transactionManager->commit();
|
288 |
+
|
289 |
}
|
290 |
}
|
291 |
|
includes/links.php
CHANGED
@@ -105,7 +105,7 @@ class blcLink {
|
|
105 |
509=>'Bandwidth Limit Exceeded',
|
106 |
510=>'Not Extended',
|
107 |
);
|
108 |
-
|
109 |
function __construct($arg = null){
|
110 |
global $wpdb, $blclog; /** @var wpdb $wpdb */
|
111 |
|
@@ -529,7 +529,9 @@ class blcLink {
|
|
529 |
$values = $this->to_db_format($values);
|
530 |
|
531 |
if ( $this->is_new ){
|
532 |
-
|
|
|
|
|
533 |
//BUG: Technically, there should be a 'LOCK TABLES wp_blc_links WRITE' here. In fact,
|
534 |
//the plugin should probably lock all involved tables whenever it parses something, lest
|
535 |
//the user (ot another plugin) modify the thing being parsed while we're working.
|
@@ -575,7 +577,10 @@ class blcLink {
|
|
575 |
return $rez;
|
576 |
|
577 |
} else {
|
578 |
-
|
|
|
|
|
|
|
579 |
//Generate the field = dbvalue expressions
|
580 |
$set_exprs = array();
|
581 |
foreach($values as $name => $value){
|
105 |
509=>'Bandwidth Limit Exceeded',
|
106 |
510=>'Not Extended',
|
107 |
);
|
108 |
+
var $isOptionLinkChanged = false;
|
109 |
function __construct($arg = null){
|
110 |
global $wpdb, $blclog; /** @var wpdb $wpdb */
|
111 |
|
529 |
$values = $this->to_db_format($values);
|
530 |
|
531 |
if ( $this->is_new ){
|
532 |
+
|
533 |
+
TransactionManager::getInstance()->commit();
|
534 |
+
|
535 |
//BUG: Technically, there should be a 'LOCK TABLES wp_blc_links WRITE' here. In fact,
|
536 |
//the plugin should probably lock all involved tables whenever it parses something, lest
|
537 |
//the user (ot another plugin) modify the thing being parsed while we're working.
|
577 |
return $rez;
|
578 |
|
579 |
} else {
|
580 |
+
if ($this->isOptionLinkChanged !== true ) {
|
581 |
+
TransactionManager::getInstance()->start();
|
582 |
+
}
|
583 |
+
$this->isOptionLinkChanged = false;
|
584 |
//Generate the field = dbvalue expressions
|
585 |
$set_exprs = array();
|
586 |
foreach($values as $name => $value){
|
includes/module-base.php
CHANGED
@@ -7,22 +7,22 @@
|
|
7 |
|
8 |
/**
|
9 |
* Base class for BLC modules.
|
10 |
-
*
|
11 |
* @package Broken Link Checker
|
12 |
* @author Janis Elsts
|
13 |
* @access public
|
14 |
*/
|
15 |
class blcModule {
|
16 |
-
|
17 |
var $module_id; //The ID of this module. Usually a lowercase string.
|
18 |
var $cached_header; //An associative array containing the header data of the module file.
|
19 |
/** @var blcConfigurationManager $plugin__conf */
|
20 |
var $plugin_conf; //A reference to the plugin's global configuration object.
|
21 |
var $module_manager; //A reference to the module manager.
|
22 |
-
|
23 |
/**
|
24 |
* Class constructor
|
25 |
-
*
|
26 |
* @param string $module_id
|
27 |
* @param array $cached_header
|
28 |
* @param blcConfigurationManager $plugin_conf
|
@@ -34,25 +34,25 @@ class blcModule {
|
|
34 |
$this->cached_header = $cached_header;
|
35 |
$this->plugin_conf = &$plugin_conf;
|
36 |
$this->module_manager = &$module_manager;
|
37 |
-
|
38 |
$this->init();
|
39 |
-
}
|
40 |
-
|
41 |
/**
|
42 |
* Module initializer. Called when the module is first instantiated.
|
43 |
* The default implementation does nothing. Override it in a subclass to
|
44 |
-
* specify some sort of start-up behaviour.
|
45 |
-
*
|
46 |
* @return void
|
47 |
*/
|
48 |
function init(){
|
49 |
//Should be overridden in a sub-class.
|
50 |
}
|
51 |
-
|
52 |
/**
|
53 |
* Called when the module is activated.
|
54 |
* Should be overridden in a sub-class.
|
55 |
-
*
|
56 |
* @return void
|
57 |
*/
|
58 |
function activated(){
|
@@ -62,7 +62,7 @@ class blcModule {
|
|
62 |
/**
|
63 |
* Called when the module is deactivated.
|
64 |
* Should be overridden in a sub-class.
|
65 |
-
*
|
66 |
* @return void
|
67 |
*/
|
68 |
function deactivated(){
|
@@ -76,4 +76,5 @@ class blcModule {
|
|
76 |
function plugin_activated() {
|
77 |
$this->activated();
|
78 |
}
|
79 |
-
}
|
|
7 |
|
8 |
/**
|
9 |
* Base class for BLC modules.
|
10 |
+
*
|
11 |
* @package Broken Link Checker
|
12 |
* @author Janis Elsts
|
13 |
* @access public
|
14 |
*/
|
15 |
class blcModule {
|
16 |
+
|
17 |
var $module_id; //The ID of this module. Usually a lowercase string.
|
18 |
var $cached_header; //An associative array containing the header data of the module file.
|
19 |
/** @var blcConfigurationManager $plugin__conf */
|
20 |
var $plugin_conf; //A reference to the plugin's global configuration object.
|
21 |
var $module_manager; //A reference to the module manager.
|
22 |
+
|
23 |
/**
|
24 |
* Class constructor
|
25 |
+
*
|
26 |
* @param string $module_id
|
27 |
* @param array $cached_header
|
28 |
* @param blcConfigurationManager $plugin_conf
|
34 |
$this->cached_header = $cached_header;
|
35 |
$this->plugin_conf = &$plugin_conf;
|
36 |
$this->module_manager = &$module_manager;
|
37 |
+
|
38 |
$this->init();
|
39 |
+
}
|
40 |
+
|
41 |
/**
|
42 |
* Module initializer. Called when the module is first instantiated.
|
43 |
* The default implementation does nothing. Override it in a subclass to
|
44 |
+
* specify some sort of start-up behaviour.
|
45 |
+
*
|
46 |
* @return void
|
47 |
*/
|
48 |
function init(){
|
49 |
//Should be overridden in a sub-class.
|
50 |
}
|
51 |
+
|
52 |
/**
|
53 |
* Called when the module is activated.
|
54 |
* Should be overridden in a sub-class.
|
55 |
+
*
|
56 |
* @return void
|
57 |
*/
|
58 |
function activated(){
|
62 |
/**
|
63 |
* Called when the module is deactivated.
|
64 |
* Should be overridden in a sub-class.
|
65 |
+
*
|
66 |
* @return void
|
67 |
*/
|
68 |
function deactivated(){
|
76 |
function plugin_activated() {
|
77 |
$this->activated();
|
78 |
}
|
79 |
+
}
|
80 |
+
|
includes/screen-meta-links.php
CHANGED
@@ -9,89 +9,89 @@
|
|
9 |
if ( !class_exists('wsScreenMetaLinks11') ):
|
10 |
|
11 |
//Load JSON functions for PHP < 5.2
|
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 |
-
* Add a new link to the screen meta area.
|
40 |
-
*
|
41 |
-
* Do not call this method directly. Instead, use the global add_screen_meta_link() function.
|
42 |
-
*
|
43 |
-
* @param string $id Link ID. Should be unique and a valid value for a HTML ID attribute.
|
44 |
-
* @param string $text Link text.
|
45 |
-
* @param string $href Link URL.
|
46 |
-
* @param string|array $page The page(s) where you want to add the link.
|
47 |
-
* @param array $attributes Optional. Additional attributes for the link tag.
|
48 |
-
* @return void
|
49 |
-
*/
|
50 |
-
function add_screen_meta_link($id, $text, $href, $page, $attributes = null){
|
51 |
-
if ( !is_array($page) ){
|
52 |
-
$page = array($page);
|
53 |
-
}
|
54 |
-
if ( is_null($attributes) ){
|
55 |
-
$attributes = array();
|
56 |
-
}
|
57 |
-
|
58 |
-
//Basically a list of props for a jQuery() call
|
59 |
-
$link = compact('id', 'text', 'href');
|
60 |
-
$link = array_merge($link, $attributes);
|
61 |
-
|
62 |
-
//Add the CSS classes that will make the look like a proper meta link
|
63 |
-
if ( empty($link['class']) ){
|
64 |
-
$link['class'] = '';
|
65 |
-
}
|
66 |
-
$link['class'] = 'show-settings custom-screen-meta-link ' . $link['class'];
|
67 |
-
|
68 |
-
//Save the link in each relevant page's list
|
69 |
-
foreach($page as $page_id){
|
70 |
-
if ( !isset($this->registered_links[$page_id]) ){
|
71 |
-
$this->registered_links[$page_id] = array();
|
72 |
-
}
|
73 |
-
$this->registered_links[$page_id][] = $link;
|
74 |
-
}
|
75 |
}
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
if (
|
90 |
-
|
91 |
}
|
92 |
-
|
93 |
-
|
94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
(function($, links){
|
96 |
var container = $('#screen-meta-links');
|
97 |
if ( container.length == 0 ) {
|
@@ -109,185 +109,185 @@ if ( !class_exists('wsScreenMetaLinks11') ):
|
|
109 |
}
|
110 |
})(jQuery, <?php echo $this->json_encode($links); ?>);
|
111 |
</script>
|
112 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
}
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
*
|
118 |
-
* @param string $page
|
119 |
-
* @return array
|
120 |
-
*/
|
121 |
-
function get_links_for_page($page){
|
122 |
-
$links = array();
|
123 |
-
|
124 |
-
if ( isset($this->registered_links[$page]) ){
|
125 |
-
$links = array_merge($links, $this->registered_links[$page]);
|
126 |
-
}
|
127 |
-
$page_as_screen = $this->page_to_screen_id($page);
|
128 |
-
if ( ($page_as_screen != $page) && isset($this->registered_links[$page_as_screen]) ){
|
129 |
-
$links = array_merge($links, $this->registered_links[$page_as_screen]);
|
130 |
-
}
|
131 |
-
|
132 |
-
return $links;
|
133 |
}
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
$this->print_old_link_styles();
|
154 |
-
} else {
|
155 |
-
$this->print_link_styles();
|
156 |
-
}
|
157 |
}
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
?>
|
164 |
-
<style type="text/css">
|
165 |
-
.custom-screen-meta-link-wrap {
|
166 |
-
float: right;
|
167 |
-
height: 28px;
|
168 |
-
margin: 0 0 0 6px;
|
169 |
-
|
170 |
-
border: 1px solid #ddd;
|
171 |
-
border-top: none;
|
172 |
-
background: #fff;
|
173 |
-
-webkit-box-shadow: 0 1px 1px -1px rgba(0,0,0,0.1);
|
174 |
-
box-shadow: 0 1px 1px -1px rgba(0,0,0,0.1);
|
175 |
-
}
|
176 |
-
|
177 |
-
#screen-meta .custom-screen-meta-link-wrap a.custom-screen-meta-link,
|
178 |
-
#screen-meta-links .custom-screen-meta-link-wrap a.custom-screen-meta-link
|
179 |
-
{
|
180 |
-
padding: 3px 16px 3px 16px;
|
181 |
-
}
|
182 |
-
|
183 |
-
#screen-meta-links a.custom-screen-meta-link::after {
|
184 |
-
display: none;
|
185 |
-
}
|
186 |
-
</style>
|
187 |
-
<?php
|
188 |
}
|
|
|
189 |
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
border-bottom-right-radius: 3px;
|
208 |
-
|
209 |
-
background: #e3e3e3;
|
210 |
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
background-image: -o-linear-gradient(bottom, #dfdfdf, #f1f1f1); /* Opera */
|
217 |
-
background-image: -webkit-gradient(linear, left bottom, left top, from(#dfdfdf), to(#f1f1f1)); /* old Webkit */
|
218 |
-
background-image: -webkit-linear-gradient(bottom, #dfdfdf, #f1f1f1); /* new Webkit */
|
219 |
-
background-image: linear-gradient(bottom, #dfdfdf, #f1f1f1); /* proposed W3C Markup */
|
220 |
-
}
|
221 |
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
background-image: none;
|
226 |
-
padding-right: 6px;
|
227 |
-
color: #777;
|
228 |
-
}
|
229 |
</style>
|
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 |
-
function json_encode($data){
|
263 |
-
if ( function_exists('json_encode') ){
|
264 |
-
return json_encode($data);
|
265 |
}
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
272 |
} else {
|
273 |
-
|
274 |
-
return null;
|
275 |
}
|
|
|
|
|
276 |
}
|
277 |
-
|
278 |
}
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
283 |
}
|
284 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
285 |
|
286 |
endif;
|
287 |
|
288 |
/**
|
289 |
* Add a new link to the screen meta area.
|
290 |
-
*
|
291 |
* @param string $id Link ID. Should be unique and a valid value for a HTML ID attribute.
|
292 |
* @param string $text Link text.
|
293 |
* @param string $href Link URL.
|
@@ -297,7 +297,7 @@ endif;
|
|
297 |
*/
|
298 |
function add_screen_meta_link($id, $text, $href, $page, $attributes = null){
|
299 |
global $ws_screen_meta_links_versions;
|
300 |
-
|
301 |
static $instance = null;
|
302 |
if ( is_null($instance) ){
|
303 |
//Instantiate the latest version of the wsScreenMetaLinks class
|
@@ -305,8 +305,8 @@ function add_screen_meta_link($id, $text, $href, $page, $attributes = null){
|
|
305 |
$className = end($ws_screen_meta_links_versions);
|
306 |
$instance = new $className;
|
307 |
}
|
308 |
-
|
309 |
$instance->add_screen_meta_link($id, $text, $href, $page, $attributes);
|
310 |
}
|
311 |
|
312 |
-
?>
|
9 |
if ( !class_exists('wsScreenMetaLinks11') ):
|
10 |
|
11 |
//Load JSON functions for PHP < 5.2
|
12 |
+
if ( !(function_exists('json_encode') && function_exists('json_decode')) && !(class_exists('Services_JSON') || class_exists('Moxiecode_JSON')) ){
|
13 |
+
$class_json_path = ABSPATH.WPINC.'/class-json.php';
|
14 |
+
$class_moxiecode_json_path = ABSPATH.WPINC.'/js/tinymce/plugins/spellchecker/classes/utils/JSON.php';
|
15 |
+
if ( file_exists($class_json_path) ){
|
16 |
+
require $class_json_path;
|
17 |
+
|
18 |
+
} elseif ( file_exists($class_moxiecode_json_path) ) {
|
19 |
+
require $class_moxiecode_json_path;
|
|
|
20 |
}
|
21 |
+
}
|
22 |
+
|
23 |
+
class wsScreenMetaLinks11 {
|
24 |
+
var $registered_links; //List of meta links registered for each page.
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Class constructor.
|
28 |
+
*
|
29 |
+
* @return void
|
30 |
+
*/
|
31 |
+
function __construct(){
|
32 |
+
$this->registered_links = array();
|
33 |
+
|
34 |
+
add_action('admin_notices', array(&$this, 'append_meta_links'));
|
35 |
+
add_action('admin_print_styles', array(&$this, 'add_link_styles'));
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Add a new link to the screen meta area.
|
40 |
+
*
|
41 |
+
* Do not call this method directly. Instead, use the global add_screen_meta_link() function.
|
42 |
+
*
|
43 |
+
* @param string $id Link ID. Should be unique and a valid value for a HTML ID attribute.
|
44 |
+
* @param string $text Link text.
|
45 |
+
* @param string $href Link URL.
|
46 |
+
* @param string|array $page The page(s) where you want to add the link.
|
47 |
+
* @param array $attributes Optional. Additional attributes for the link tag.
|
48 |
+
* @return void
|
49 |
+
*/
|
50 |
+
function add_screen_meta_link($id, $text, $href, $page, $attributes = null){
|
51 |
+
if ( !is_array($page) ){
|
52 |
+
$page = array($page);
|
53 |
}
|
54 |
+
if ( is_null($attributes) ){
|
55 |
+
$attributes = array();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
}
|
57 |
+
|
58 |
+
//Basically a list of props for a jQuery() call
|
59 |
+
$link = compact('id', 'text', 'href');
|
60 |
+
$link = array_merge($link, $attributes);
|
61 |
+
|
62 |
+
//Add the CSS classes that will make the look like a proper meta link
|
63 |
+
if ( empty($link['class']) ){
|
64 |
+
$link['class'] = '';
|
65 |
+
}
|
66 |
+
$link['class'] = 'show-settings custom-screen-meta-link ' . $link['class'];
|
67 |
+
|
68 |
+
//Save the link in each relevant page's list
|
69 |
+
foreach($page as $page_id){
|
70 |
+
if ( !isset($this->registered_links[$page_id]) ){
|
71 |
+
$this->registered_links[$page_id] = array();
|
72 |
}
|
73 |
+
$this->registered_links[$page_id][] = $link;
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Output the JS that appends the custom meta links to the page.
|
79 |
+
* Callback for the 'admin_notices' action.
|
80 |
+
*
|
81 |
+
* @access private
|
82 |
+
* @return void
|
83 |
+
*/
|
84 |
+
function append_meta_links(){
|
85 |
+
global $hook_suffix;
|
86 |
+
|
87 |
+
//Find links registered for this page
|
88 |
+
$links = $this->get_links_for_page($hook_suffix);
|
89 |
+
if ( empty($links) ){
|
90 |
+
return;
|
91 |
+
}
|
92 |
+
|
93 |
+
?>
|
94 |
+
<script type="text/javascript">
|
95 |
(function($, links){
|
96 |
var container = $('#screen-meta-links');
|
97 |
if ( container.length == 0 ) {
|
109 |
}
|
110 |
})(jQuery, <?php echo $this->json_encode($links); ?>);
|
111 |
</script>
|
112 |
+
<?php
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* Get a list of custom screen meta links registered for a specific page.
|
117 |
+
*
|
118 |
+
* @param string $page
|
119 |
+
* @return array
|
120 |
+
*/
|
121 |
+
function get_links_for_page($page){
|
122 |
+
$links = array();
|
123 |
+
|
124 |
+
if ( isset($this->registered_links[$page]) ){
|
125 |
+
$links = array_merge($links, $this->registered_links[$page]);
|
126 |
}
|
127 |
+
$page_as_screen = $this->page_to_screen_id($page);
|
128 |
+
if ( ($page_as_screen != $page) && isset($this->registered_links[$page_as_screen]) ){
|
129 |
+
$links = array_merge($links, $this->registered_links[$page_as_screen]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
}
|
131 |
+
|
132 |
+
return $links;
|
133 |
+
}
|
134 |
+
|
135 |
+
/**
|
136 |
+
* Output the CSS code for custom screen meta links. Required because WP only
|
137 |
+
* has styles for specific meta links (by #id), not meta links in general.
|
138 |
+
*
|
139 |
+
* Callback for 'admin_print_styles'.
|
140 |
+
*
|
141 |
+
* @access private
|
142 |
+
* @return void
|
143 |
+
*/
|
144 |
+
function add_link_styles(){
|
145 |
+
global $hook_suffix;
|
146 |
+
//Don't output the CSS if there are no custom meta links for this page.
|
147 |
+
$links = $this->get_links_for_page($hook_suffix);
|
148 |
+
if ( empty($links) ){
|
149 |
+
return;
|
|
|
|
|
|
|
|
|
150 |
}
|
151 |
+
|
152 |
+
if ( !isset($GLOBALS['wp_version']) || version_compare($GLOBALS['wp_version'], '3.8-RC1', '<') ) {
|
153 |
+
$this->print_old_link_styles();
|
154 |
+
} else {
|
155 |
+
$this->print_link_styles();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
}
|
157 |
+
}
|
158 |
|
159 |
+
/**
|
160 |
+
* Print screen meta button styles (WP 3.8+).
|
161 |
+
*/
|
162 |
+
private function print_link_styles() {
|
163 |
+
?>
|
164 |
+
<style type="text/css">
|
165 |
+
.custom-screen-meta-link-wrap {
|
166 |
+
float: right;
|
167 |
+
height: 28px;
|
168 |
+
margin: 0 0 0 6px;
|
169 |
+
|
170 |
+
border: 1px solid #ddd;
|
171 |
+
border-top: none;
|
172 |
+
background: #fff;
|
173 |
+
-webkit-box-shadow: 0 1px 1px -1px rgba(0,0,0,0.1);
|
174 |
+
box-shadow: 0 1px 1px -1px rgba(0,0,0,0.1);
|
175 |
+
}
|
|
|
|
|
|
|
176 |
|
177 |
+
#screen-meta .custom-screen-meta-link-wrap a.custom-screen-meta-link,
|
178 |
+
#screen-meta-links .custom-screen-meta-link-wrap a.custom-screen-meta-link
|
179 |
+
{
|
180 |
+
padding: 3px 16px 3px 16px;
|
181 |
+
}
|
|
|
|
|
|
|
|
|
|
|
182 |
|
183 |
+
#screen-meta-links a.custom-screen-meta-link::after {
|
184 |
+
display: none;
|
185 |
+
}
|
|
|
|
|
|
|
|
|
186 |
</style>
|
187 |
+
<?php
|
188 |
+
}
|
189 |
|
190 |
+
/**
|
191 |
+
* Print old screen meta button styles (WP 3.7.x and older).
|
192 |
+
*/
|
193 |
+
private function print_old_link_styles() {
|
194 |
+
?>
|
195 |
+
<style type="text/css">
|
196 |
+
.custom-screen-meta-link-wrap {
|
197 |
+
float: right;
|
198 |
+
height: 22px;
|
199 |
+
padding: 0;
|
200 |
+
margin: 0 0 0 6px;
|
201 |
+
font-family: sans-serif;
|
202 |
+
-moz-border-radius-bottomleft: 3px;
|
203 |
+
-moz-border-radius-bottomright: 3px;
|
204 |
+
-webkit-border-bottom-left-radius: 3px;
|
205 |
+
-webkit-border-bottom-right-radius: 3px;
|
206 |
+
border-bottom-left-radius: 3px;
|
207 |
+
border-bottom-right-radius: 3px;
|
208 |
+
|
209 |
+
background: #e3e3e3;
|
210 |
+
|
211 |
+
border-right: 1px solid transparent;
|
212 |
+
border-left: 1px solid transparent;
|
213 |
+
border-bottom: 1px solid transparent;
|
214 |
+
background-image: -ms-linear-gradient(bottom, #dfdfdf, #f1f1f1); /* IE10 */
|
215 |
+
background-image: -moz-linear-gradient(bottom, #dfdfdf, #f1f1f1); /* Firefox */
|
216 |
+
background-image: -o-linear-gradient(bottom, #dfdfdf, #f1f1f1); /* Opera */
|
217 |
+
background-image: -webkit-gradient(linear, left bottom, left top, from(#dfdfdf), to(#f1f1f1)); /* old Webkit */
|
218 |
+
background-image: -webkit-linear-gradient(bottom, #dfdfdf, #f1f1f1); /* new Webkit */
|
219 |
+
background-image: linear-gradient(bottom, #dfdfdf, #f1f1f1); /* proposed W3C Markup */
|
220 |
}
|
|
|
221 |
|
222 |
+
#screen-meta .custom-screen-meta-link-wrap a.custom-screen-meta-link,
|
223 |
+
#screen-meta-links .custom-screen-meta-link-wrap a.custom-screen-meta-link
|
224 |
+
{
|
225 |
+
background-image: none;
|
226 |
+
padding-right: 6px;
|
227 |
+
color: #777;
|
|
|
|
|
|
|
|
|
228 |
}
|
229 |
+
</style>
|
230 |
+
<?php
|
231 |
+
}
|
232 |
+
|
233 |
+
/**
|
234 |
+
* Convert a page hook name to a screen ID.
|
235 |
+
*
|
236 |
+
* @uses convert_to_screen()
|
237 |
+
* @access private
|
238 |
+
*
|
239 |
+
* @param string $page
|
240 |
+
* @return string
|
241 |
+
*/
|
242 |
+
function page_to_screen_id($page){
|
243 |
+
if ( function_exists('convert_to_screen') ){
|
244 |
+
$screen = convert_to_screen($page);
|
245 |
+
if ( isset($screen->id) ){
|
246 |
+
return $screen->id;
|
247 |
} else {
|
248 |
+
return '';
|
|
|
249 |
}
|
250 |
+
} else {
|
251 |
+
return str_replace( array('.php', '-new', '-add' ), '', $page);
|
252 |
}
|
|
|
253 |
}
|
254 |
+
|
255 |
+
/**
|
256 |
+
* Back-wards compatible json_encode(). Used to encode link data before
|
257 |
+
* passing it to the JavaScript that actually creates the links.
|
258 |
+
*
|
259 |
+
* @param mixed $data
|
260 |
+
* @return string
|
261 |
+
*/
|
262 |
+
function json_encode($data){
|
263 |
+
if ( function_exists('json_encode') ){
|
264 |
+
return json_encode($data);
|
265 |
+
}
|
266 |
+
if ( class_exists('Services_JSON') ){
|
267 |
+
$json = new Services_JSON();
|
268 |
+
return( $json->encodeUnsafe($data) );
|
269 |
+
} elseif ( class_exists('Moxiecode_JSON') ){
|
270 |
+
$json = new Moxiecode_JSON();
|
271 |
+
return $json->encode($data);
|
272 |
+
} else {
|
273 |
+
trigger_error('No JSON parser available', E_USER_ERROR);
|
274 |
+
return null;
|
275 |
+
}
|
276 |
}
|
277 |
+
|
278 |
+
}
|
279 |
+
|
280 |
+
global $ws_screen_meta_links_versions;
|
281 |
+
if ( !isset($ws_screen_meta_links_versions) ){
|
282 |
+
$ws_screen_meta_links_versions = array();
|
283 |
+
}
|
284 |
+
$ws_screen_meta_links_versions['1.1'] = 'wsScreenMetaLinks11';
|
285 |
|
286 |
endif;
|
287 |
|
288 |
/**
|
289 |
* Add a new link to the screen meta area.
|
290 |
+
*
|
291 |
* @param string $id Link ID. Should be unique and a valid value for a HTML ID attribute.
|
292 |
* @param string $text Link text.
|
293 |
* @param string $href Link URL.
|
297 |
*/
|
298 |
function add_screen_meta_link($id, $text, $href, $page, $attributes = null){
|
299 |
global $ws_screen_meta_links_versions;
|
300 |
+
|
301 |
static $instance = null;
|
302 |
if ( is_null($instance) ){
|
303 |
//Instantiate the latest version of the wsScreenMetaLinks class
|
305 |
$className = end($ws_screen_meta_links_versions);
|
306 |
$instance = new $className;
|
307 |
}
|
308 |
+
|
309 |
$instance->add_screen_meta_link($id, $text, $href, $page, $attributes);
|
310 |
}
|
311 |
|
312 |
+
?>
|
includes/survey.php
DELETED
@@ -1,58 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* @author Janis Elsts
|
5 |
-
* @copyright 2010
|
6 |
-
*/
|
7 |
-
|
8 |
-
//Appearify the survey notice to people who have used BLC for at least 2 weeks (doesn't need to be very accurate)
|
9 |
-
$blc_config = blc_get_configuration();
|
10 |
-
$blc_show_survey = empty($blc_config->options['hide_surveyio_notice'])
|
11 |
-
&& !empty($blc_config->options['first_installation_timestamp'])
|
12 |
-
&& ( time() - $blc_config->options['first_installation_timestamp'] > 2*7*24*60*60 );
|
13 |
-
|
14 |
-
if ( $blc_show_survey ){
|
15 |
-
add_action('admin_notices', 'blc_display_survey_notice');
|
16 |
-
}
|
17 |
-
|
18 |
-
/**
|
19 |
-
* Display a notice asking the user to take the Broken Link Checker user survey.
|
20 |
-
*
|
21 |
-
* @return void
|
22 |
-
*/
|
23 |
-
function blc_display_survey_notice(){
|
24 |
-
//Only people who can actually use the plugin will see the notice
|
25 |
-
if ( !current_user_can('manage_links') ) return;
|
26 |
-
|
27 |
-
if ( !empty($_GET['dismiss-blc-survey']) ){
|
28 |
-
//The user has chosen to hide the survey notice
|
29 |
-
$blc_config = blc_get_configuration();
|
30 |
-
$blc_config->options['hide_surveyio_notice'] = true;
|
31 |
-
$blc_config->save_options();
|
32 |
-
return;
|
33 |
-
}
|
34 |
-
|
35 |
-
$survey_url = 'http://survey.io/survey/7fbf0';
|
36 |
-
|
37 |
-
$msg = sprintf(
|
38 |
-
'<strong>Help improve Broken Link Checker - <a href="%s" target="_blank" title="This link will open in a new window" id="blc-take-survey-link">take a user feedback survey!</a></strong>
|
39 |
-
<br><a href="%s" id="blc-dismiss-survey-notice">Hide this notice</a>',
|
40 |
-
$survey_url,
|
41 |
-
esc_attr(add_query_arg('dismiss-blc-survey', 1))
|
42 |
-
);
|
43 |
-
|
44 |
-
echo '<div id="update-nag" class="blc-survey-notice" style="text-align: left; padding-left: 10px;">'.$msg.'</div>';
|
45 |
-
|
46 |
-
//Auto-hide the notice after the user clicks the survey link
|
47 |
-
?>
|
48 |
-
<script type="text/javascript">
|
49 |
-
jQuery(function($){
|
50 |
-
$('#blc-take-survey-link').click(function(){
|
51 |
-
$('.blc-survey-notice').hide('fast');
|
52 |
-
$.get($('#blc-dismiss-survey-notice').attr('href'));
|
53 |
-
});
|
54 |
-
});
|
55 |
-
</script>
|
56 |
-
<?php
|
57 |
-
}
|
58 |
-
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
includes/transactions-manager.php
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class TransactionManager
|
4 |
+
{
|
5 |
+
private $isTransactionStarted = false;
|
6 |
+
static private $instance;
|
7 |
+
|
8 |
+
public function start()
|
9 |
+
{
|
10 |
+
global $wpdb;
|
11 |
+
|
12 |
+
if (!$this->isTransactionStarted) {
|
13 |
+
$wpdb->query('BEGIN');
|
14 |
+
$this->isTransactionStarted = true;
|
15 |
+
}
|
16 |
+
}
|
17 |
+
|
18 |
+
public function commit()
|
19 |
+
{
|
20 |
+
global $wpdb;
|
21 |
+
|
22 |
+
$this->start();
|
23 |
+
|
24 |
+
try {
|
25 |
+
$wpdb->query('COMMIT');
|
26 |
+
$this->isTransactionStarted = false;
|
27 |
+
} catch (Exception $e) {
|
28 |
+
$wpdb->query('ROLLBACK');
|
29 |
+
$this->isTransactionStarted = false;
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
static public function getInstance()
|
34 |
+
{
|
35 |
+
if (empty(static::$instance)) {
|
36 |
+
static::$instance = new static();
|
37 |
+
}
|
38 |
+
|
39 |
+
return static::$instance;
|
40 |
+
}
|
41 |
+
}
|
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.4.1
|
7 |
-
Stable tag: 1.
|
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,10 @@ To upgrade your installation
|
|
101 |
|
102 |
== Changelog ==
|
103 |
|
|
|
|
|
|
|
|
|
104 |
= 1.10.11 =
|
105 |
* Fixed the issue with HTTPS (Thanks to [gmcinnes](https://wordpress.org/support/profile/gmcinnes))
|
106 |
* Broken Link Checker is now on [GitHub](https://github.com/ManageWP/broken-link-checker). Pull Requests welcome.
|
4 |
Tags: links, broken, maintenance, blogroll, custom fields, admin, comments, posts
|
5 |
Requires at least: 3.2
|
6 |
Tested up to: 4.4.1
|
7 |
+
Stable tag: 1.11.1
|
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.1 =
|
105 |
+
* Major performance improvement. Database queries reduced up to 10x in some cases.
|
106 |
+
* Feel free to contribute to the plugin on [GitHub](https://github.com/ManageWP/broken-link-checker). Pull requests welcome!
|
107 |
+
|
108 |
= 1.10.11 =
|
109 |
* Fixed the issue with HTTPS (Thanks to [gmcinnes](https://wordpress.org/support/profile/gmcinnes))
|
110 |
* Broken Link Checker is now on [GitHub](https://github.com/ManageWP/broken-link-checker). Pull Requests welcome.
|