Version Description
- Masquerade as IE 7 when using the Snoopy library to check links. Should prevent some false positives.
- Fixed relative URL handling (yet again). It'll work this time, honest ;)
- Fixed post titles being displayed incorrectly on multilingual blogs (props Konstanin Zhilenko)
- Misc fixes/comments.
- "Unlink" works properly now.
- Additional source code comments.
- Don't try to display icons in email notifications. It didn't work anyway.
- Use AJAX nonces for additional security.
- General code cleanup.
- Email notifications about broken links.
- "Recheck" bulk action.
- Check comment links.
- Suspend checking if the server is overloaded (on by default).
- Icons for broken links and redirects.
- Fixed some UI glitches.
- "Discard" gone, replaced by "Not broken".
- "Exclude" gone from action links.
- Better handling of false positives.
- FTP, mailto:, javascript: and other links with unsupported protocols now show up in the All links list.
Download this release
Release Info
Developer | whiteshadow |
Plugin | Broken Link Checker |
Version | 0.9 |
Comparing to | |
See all releases |
Code changes from version 0.8.1 to 0.9
- broken-link-checker.php +256 -48
- core.php +1299 -1864
- css/links-page.css +124 -0
- css/options-page.css +38 -0
- highlighter-class.php +0 -93
- images/bullet_blue.png +0 -0
- images/bullet_error.png +0 -0
- images/comment.png +0 -0
- images/user_comment.png +0 -0
- includes/admin/links-page-js.php +383 -0
- includes/admin/search-form.php +91 -0
- includes/checkers.php +136 -0
- includes/checkers/http.php +312 -0
- includes/containers.php +886 -0
- includes/containers/blogroll.php +292 -0
- includes/containers/comment.php +336 -0
- includes/containers/custom_field.php +489 -0
- includes/containers/dummy.php +66 -0
- includes/containers/post.php +392 -0
- includes/instances.php +549 -0
- includes/links.php +1346 -0
- includes/parsers.php +356 -0
- includes/parsers/html_link.php +328 -0
- includes/parsers/image.php +161 -0
- includes/parsers/metadata.php +97 -0
- includes/parsers/url_field.php +87 -0
- instance-classes.php +0 -585
- js/sprintf.js +55 -0
- languages/broken-link-checker-cs_CZ.mo +0 -0
- languages/broken-link-checker-cs_CZ.po +872 -0
- languages/broken-link-checker.pot +644 -387
- link-classes.php +0 -622
- readme.txt +38 -19
- uninstall.php +1 -1
- utility-class.php +167 -17
broken-link-checker.php
CHANGED
@@ -3,8 +3,8 @@
|
|
3 |
/*
|
4 |
Plugin Name: Broken Link Checker
|
5 |
Plugin URI: http://w-shadow.com/blog/2007/08/05/broken-link-checker-for-wordpress/
|
6 |
-
Description: Checks your
|
7 |
-
Version: 0.
|
8 |
Author: Janis Elsts
|
9 |
Author URI: http://w-shadow.com/blog/
|
10 |
Text Domain: broken-link-checker
|
@@ -15,44 +15,67 @@ Created by Janis Elsts (email : whiteshadow@w-shadow.com)
|
|
15 |
MySQL 4.0 compatibility by Jeroen (www.yukka.eu)
|
16 |
*/
|
17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
/*
|
19 |
-
|
20 |
-
|
21 |
-
if ( !class_exists('FB') ) {
|
22 |
-
|
|
|
|
|
23 |
}
|
24 |
-
//FB::setEnabled(false);
|
25 |
-
|
26 |
//to comment out all calls : (^[^\/]*)(FB::) -> $1\/\/$2
|
27 |
//to uncomment : \/\/(\s*FB::) -> $1
|
28 |
//*/
|
29 |
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
|
46 |
//Load and initialize the plugin's configuration
|
|
|
47 |
$blc_directory = dirname(__FILE__);
|
48 |
require $blc_directory . '/config-manager.php';
|
|
|
|
|
49 |
$blc_config_manager = new blcConfigurationManager(
|
50 |
//Save the plugin's configuration into this DB option
|
51 |
'wsblc_options',
|
52 |
//Initialize default settings
|
53 |
array(
|
54 |
-
'max_execution_time' => 5*60, //How long the worker instance may run, at most.
|
55 |
-
'check_threshold' => 72, //Check each link every 72 hours.
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
|
57 |
'mark_broken_links' => true, //Whether to add the broken_link class to broken links in posts.
|
58 |
'broken_link_css' => ".broken_link, a.broken_link {\n\ttext-decoration: line-through;\n}",
|
@@ -60,37 +83,226 @@ $blc_config_manager = new blcConfigurationManager(
|
|
60 |
'mark_removed_links' => false, //Whether to add the removed_link class when un-linking a link.
|
61 |
'removed_link_css' => ".removed_link, a.removed_link {\n\ttext-decoration: line-through;\n}",
|
62 |
|
63 |
-
'exclusion_list' => array(), //Links that contain a substring listed in this array won't be checked.
|
64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
|
66 |
-
//These three are currently ignored. Everything is checked by default.
|
67 |
-
'check_posts' => true,
|
68 |
-
'check_custom_fields' => true,
|
69 |
-
'check_blogroll' => true,
|
70 |
-
|
71 |
'custom_fields' => array(), //List of custom fields that can contain URLs and should be checked.
|
72 |
|
73 |
'autoexpand_widget' => true, //Autoexpand the Dashboard widget if broken links are detected
|
74 |
|
75 |
-
'need_resynch' => false, //[Internal flag]
|
76 |
-
'current_db_version' => 0, //The
|
77 |
|
78 |
'custom_tmp_dir' => '', //The lockfile will be stored in this directory.
|
79 |
//If this option is not set, the plugin's own directory or the
|
80 |
//system-wide /tmp directory will be used instead.
|
81 |
|
82 |
-
'timeout' => 30, //Links that take longer than this to respond will be treated as broken.
|
83 |
)
|
84 |
);
|
85 |
|
86 |
-
|
87 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
if ( $blc_config_manager->options['mark_broken_links'] ){
|
89 |
-
//Load some utilities (used by the higlighter) and the highlighter itself
|
90 |
require $blc_directory . '/utility-class.php';
|
91 |
-
|
92 |
-
$blc_link_highlighter = new blcLinkHighlighter( $blc_config_manager->options['broken_link_css'] );
|
93 |
}
|
|
|
94 |
//And possibly inject the CSS for removed links
|
95 |
if ( $blc_config_manager->options['mark_removed_links'] && !empty($blc_config_manager->options['removed_link_css']) ){
|
96 |
function blc_print_remove_link_css(){
|
@@ -99,14 +311,10 @@ if ( !is_admin() ){
|
|
99 |
}
|
100 |
add_action('wp_head', 'blc_print_remove_link_css');
|
101 |
}
|
102 |
-
} else {
|
103 |
-
//Load everything
|
104 |
-
require $blc_directory . '/utility-class.php';
|
105 |
-
require $blc_directory . '/instance-classes.php';
|
106 |
-
require $blc_directory . '/link-classes.php';
|
107 |
-
require $blc_directory . '/core.php';
|
108 |
-
|
109 |
-
$ws_link_checker = new wsBrokenLinkChecker( __FILE__ , $blc_config_manager );
|
110 |
}
|
111 |
|
|
|
|
|
|
|
|
|
112 |
?>
|
3 |
/*
|
4 |
Plugin Name: Broken Link Checker
|
5 |
Plugin URI: http://w-shadow.com/blog/2007/08/05/broken-link-checker-for-wordpress/
|
6 |
+
Description: Checks your blog for broken links and missing images and notifies you on the dashboard if any are found.
|
7 |
+
Version: 0.9
|
8 |
Author: Janis Elsts
|
9 |
Author URI: http://w-shadow.com/blog/
|
10 |
Text Domain: broken-link-checker
|
15 |
MySQL 4.0 compatibility by Jeroen (www.yukka.eu)
|
16 |
*/
|
17 |
|
18 |
+
/***********************************************
|
19 |
+
Debugging stuff
|
20 |
+
************************************************/
|
21 |
+
|
22 |
+
define('BLC_DEBUG', false);
|
23 |
+
|
24 |
/*
|
25 |
+
if ( constant('BLC_DEBUG') ){
|
26 |
+
//Load FirePHP for debug logging
|
27 |
+
if ( !class_exists('FB') ) {
|
28 |
+
require_once 'FirePHPCore/fb.php4';
|
29 |
+
}
|
30 |
+
//FB::setEnabled(false);
|
31 |
}
|
|
|
|
|
32 |
//to comment out all calls : (^[^\/]*)(FB::) -> $1\/\/$2
|
33 |
//to uncomment : \/\/(\s*FB::) -> $1
|
34 |
//*/
|
35 |
|
36 |
+
/***********************************************
|
37 |
+
Constants
|
38 |
+
************************************************/
|
39 |
+
|
40 |
+
/*
|
41 |
+
For performance, some internal APIs used for retrieving multiple links, instances or containers
|
42 |
+
can take an optional "$purpose" argument. Those APIs will try to use this argument to pre-load
|
43 |
+
any DB data required for the specified purpose ahead of time.
|
44 |
+
|
45 |
+
For example, if you're loading a bunch of link containers for the purposes of parsing them and
|
46 |
+
thus set $purpose to BLC_FOR_PARSING, the relevant container managers will (if applicable) precache
|
47 |
+
the parse-able fields in each returned container object. Still, setting $purpose to any particular
|
48 |
+
value does not *guarantee* any data will be preloaded - it's only a suggestion that it should.
|
49 |
+
|
50 |
+
The currently supported values for the $purpose argument are :
|
51 |
+
*/
|
52 |
+
define('BLC_FOR_EDITING', 'edit');
|
53 |
+
define('BLC_FOR_PARSING', 'parse');
|
54 |
+
define('BLC_FOR_DISPLAY', 'display');
|
55 |
+
|
56 |
+
/***********************************************
|
57 |
+
Configuration
|
58 |
+
************************************************/
|
59 |
|
60 |
//Load and initialize the plugin's configuration
|
61 |
+
global $blc_directory;
|
62 |
$blc_directory = dirname(__FILE__);
|
63 |
require $blc_directory . '/config-manager.php';
|
64 |
+
|
65 |
+
global $blc_config_manager;
|
66 |
$blc_config_manager = new blcConfigurationManager(
|
67 |
//Save the plugin's configuration into this DB option
|
68 |
'wsblc_options',
|
69 |
//Initialize default settings
|
70 |
array(
|
71 |
+
'max_execution_time' => 5*60, //(in seconds) How long the worker instance may run, at most.
|
72 |
+
'check_threshold' => 72, //(in hours) Check each link every 72 hours.
|
73 |
+
|
74 |
+
'recheck_count' => 3, //How many times a broken link should be re-checked.
|
75 |
+
'recheck_threshold' => 20*60, //(in seconds) Re-check broken links after 20 minutes.
|
76 |
+
|
77 |
+
'run_in_dashboard' => true, //Run the link checker algo. continuously while the Dashboard is open.
|
78 |
+
'run_via_cron' => true, //Run it hourly via WordPress pseudo-cron.
|
79 |
|
80 |
'mark_broken_links' => true, //Whether to add the broken_link class to broken links in posts.
|
81 |
'broken_link_css' => ".broken_link, a.broken_link {\n\ttext-decoration: line-through;\n}",
|
83 |
'mark_removed_links' => false, //Whether to add the removed_link class when un-linking a link.
|
84 |
'removed_link_css' => ".removed_link, a.removed_link {\n\ttext-decoration: line-through;\n}",
|
85 |
|
86 |
+
'exclusion_list' => array(), //Links that contain a substring listed in this array won't be checked.
|
87 |
+
|
88 |
+
'send_email_notifications' => false,//Whether to send email notifications about broken links
|
89 |
+
'notification_schedule' => 'daily', //How often (at most) notifications will be sent. Possible values : 'daily', 'weekly'
|
90 |
+
'last_notification_sent' => 0, //When the last email notification was send (Unix timestamp)
|
91 |
+
|
92 |
+
'server_load_limit' => 2, //Stop parsing stuff & checking links if the 1-minute load average
|
93 |
+
//goes over this value. Only works on Linux servers. 0 = no limit.
|
94 |
+
'enable_load_limit' => true, //Enable/disable load monitoring.
|
95 |
|
|
|
|
|
|
|
|
|
|
|
96 |
'custom_fields' => array(), //List of custom fields that can contain URLs and should be checked.
|
97 |
|
98 |
'autoexpand_widget' => true, //Autoexpand the Dashboard widget if broken links are detected
|
99 |
|
100 |
+
'need_resynch' => false, //[Internal flag] True if there are unparsed items.
|
101 |
+
'current_db_version' => 0, //The currently set-up version of the plugin's tables
|
102 |
|
103 |
'custom_tmp_dir' => '', //The lockfile will be stored in this directory.
|
104 |
//If this option is not set, the plugin's own directory or the
|
105 |
//system-wide /tmp directory will be used instead.
|
106 |
|
107 |
+
'timeout' => 30, //(in seconds) Links that take longer than this to respond will be treated as broken.
|
108 |
)
|
109 |
);
|
110 |
|
111 |
+
/***********************************************
|
112 |
+
Global functions
|
113 |
+
************************************************/
|
114 |
+
|
115 |
+
/**
|
116 |
+
* Initialize link containers.
|
117 |
+
*
|
118 |
+
* @uses do_action() on 'blc_init_containers' after all built-in link containers have been loaded.
|
119 |
+
* @see blcContainer
|
120 |
+
*
|
121 |
+
* @return void
|
122 |
+
*/
|
123 |
+
function blc_init_containers(){
|
124 |
+
global $blc_directory;
|
125 |
+
|
126 |
+
//Only init once.
|
127 |
+
static $done = false;
|
128 |
+
if ( $done ) return;
|
129 |
+
|
130 |
+
//Load the base container classes
|
131 |
+
require $blc_directory . '/includes/containers.php';
|
132 |
+
|
133 |
+
//Load built-in link containers
|
134 |
+
require $blc_directory . '/includes/containers/post.php';
|
135 |
+
require $blc_directory . '/includes/containers/blogroll.php';
|
136 |
+
require $blc_directory . '/includes/containers/custom_field.php';
|
137 |
+
require $blc_directory . '/includes/containers/comment.php';
|
138 |
+
require $blc_directory . '/includes/containers/dummy.php';
|
139 |
+
|
140 |
+
//Notify other plugins that they may register their custom containers now.
|
141 |
+
do_action('blc_init_containers');
|
142 |
+
|
143 |
+
$done = true;
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* Initialize link parsers.
|
148 |
+
*
|
149 |
+
* @uses do_action() on 'blc_init_parsers' after all built-in parsers have been loaded.
|
150 |
+
*
|
151 |
+
* @return void
|
152 |
+
*/
|
153 |
+
function blc_init_parsers(){
|
154 |
+
global $blc_directory;
|
155 |
+
|
156 |
+
//Only init once.
|
157 |
+
static $done = false;
|
158 |
+
if ( $done ) return;
|
159 |
+
|
160 |
+
//Load the base parser classes
|
161 |
+
require $blc_directory . '/includes/parsers.php';
|
162 |
+
|
163 |
+
//Load built-in parsers
|
164 |
+
require $blc_directory . '/includes/parsers/html_link.php';
|
165 |
+
require $blc_directory . '/includes/parsers/image.php';
|
166 |
+
require $blc_directory . '/includes/parsers/metadata.php';
|
167 |
+
require $blc_directory . '/includes/parsers/url_field.php';
|
168 |
+
|
169 |
+
do_action('blc_init_parsers');
|
170 |
+
$done = true;
|
171 |
+
}
|
172 |
+
|
173 |
+
/**
|
174 |
+
* Initialize link checkers.
|
175 |
+
*
|
176 |
+
* @uses do_action() on 'blc_init_checkers' after all built-in checker implementations have been loaded.
|
177 |
+
*
|
178 |
+
* @return void
|
179 |
+
*/
|
180 |
+
function blc_init_checkers(){
|
181 |
+
global $blc_directory;
|
182 |
+
|
183 |
+
//Only init once.
|
184 |
+
static $done = false;
|
185 |
+
if ( $done ) return;
|
186 |
+
|
187 |
+
//Load the base classes for link checker algorithms
|
188 |
+
require $blc_directory . '/includes/checkers.php';
|
189 |
+
|
190 |
+
//Load built-in checker implementations (only HTTP at the time)
|
191 |
+
require $blc_directory . '/includes/checkers/http.php';
|
192 |
+
|
193 |
+
do_action('blc_init_checkers');
|
194 |
+
$done = true;
|
195 |
+
}
|
196 |
+
|
197 |
+
/**
|
198 |
+
* Load and register all containers, parsers and checkers.
|
199 |
+
*
|
200 |
+
* @return void
|
201 |
+
*/
|
202 |
+
function blc_init_all_components(){
|
203 |
+
blc_init_containers();
|
204 |
+
blc_init_parsers();
|
205 |
+
blc_init_checkers();
|
206 |
+
}
|
207 |
+
|
208 |
+
/**
|
209 |
+
* Get the configuration object used by Broken Link Checker.
|
210 |
+
*
|
211 |
+
* @return blcConfigurationManager
|
212 |
+
*/
|
213 |
+
function blc_get_configuration(){
|
214 |
+
return $GLOBALS['blc_config_manager'];
|
215 |
+
}
|
216 |
+
|
217 |
+
/**
|
218 |
+
* Notify the link checker that there are unsynched items
|
219 |
+
* that might contain links (e.g. a new or edited post).
|
220 |
+
*
|
221 |
+
* @return void
|
222 |
+
*/
|
223 |
+
function blc_got_unsynched_items(){
|
224 |
+
$conf = blc_get_configuration();
|
225 |
+
|
226 |
+
if ( !$conf->options['need_resynch'] ){
|
227 |
+
$conf->options['need_resynch'] = true;
|
228 |
+
$conf->save_options();
|
229 |
+
}
|
230 |
+
}
|
231 |
+
|
232 |
+
/**
|
233 |
+
* (Re)create synchronization records for all containers and mark them all as unparsed.
|
234 |
+
*
|
235 |
+
* @param bool $forced If true, the plugin will recreate all synch. records from scratch.
|
236 |
+
* @return void
|
237 |
+
*/
|
238 |
+
function blc_resynch( $forced = false ){
|
239 |
+
global $wpdb;
|
240 |
+
|
241 |
+
if ( $forced ){
|
242 |
+
//Drop all synchronization records
|
243 |
+
$wpdb->query("TRUNCATE {$wpdb->prefix}blc_synch");
|
244 |
+
}
|
245 |
+
|
246 |
+
//(Re)create and update synch. records for all container types.
|
247 |
+
blc_resynch_containers($forced);
|
248 |
+
|
249 |
+
//Delete invalid instances
|
250 |
+
blc_cleanup_instances();
|
251 |
+
//Delete orphaned links
|
252 |
+
blc_cleanup_links();
|
253 |
+
|
254 |
+
//All done.
|
255 |
+
blc_got_unsynched_items();
|
256 |
+
}
|
257 |
+
|
258 |
+
/**
|
259 |
+
* Add a weekly Cron schedule for email notifications
|
260 |
+
*
|
261 |
+
* @param array $schedules Existing Cron schedules.
|
262 |
+
* @return array
|
263 |
+
*/
|
264 |
+
function blc_cron_schedules($schedules){
|
265 |
+
if ( !isset($schedules['weekly']) ){
|
266 |
+
$schedules['weekly'] = array(
|
267 |
+
'interval' => 604800,
|
268 |
+
'display' => __('Once Weekly')
|
269 |
+
);
|
270 |
+
}
|
271 |
+
return $schedules;
|
272 |
+
}
|
273 |
+
add_filter('cron_schedules', 'blc_cron_schedules');
|
274 |
+
|
275 |
+
/***********************************************
|
276 |
+
Main functionality
|
277 |
+
************************************************/
|
278 |
+
|
279 |
+
if ( is_admin() || defined('DOING_CRON') ){
|
280 |
+
|
281 |
+
//It's an admin-side or Cron request. Load everything.
|
282 |
+
add_action('plugins_loaded', 'blc_init_all_components');
|
283 |
+
|
284 |
+
require $blc_directory . '/utility-class.php';
|
285 |
+
require $blc_directory . '/includes/links.php';
|
286 |
+
require $blc_directory . '/includes/instances.php';
|
287 |
+
|
288 |
+
require $blc_directory . '/core.php';
|
289 |
+
|
290 |
+
$ws_link_checker = new wsBrokenLinkChecker( __FILE__ , $blc_config_manager );
|
291 |
+
|
292 |
+
} else {
|
293 |
+
|
294 |
+
//This is user-side request, so we don't need to load the core.
|
295 |
+
//We do need to load containers (for the purposes of catching
|
296 |
+
//new comments and such).
|
297 |
+
add_action('plugins_loaded', 'blc_init_containers');
|
298 |
+
|
299 |
+
//If broken links need to be marked, we also need to load parsers
|
300 |
+
//(used to find & modify links) and utilities (used by some parsers).
|
301 |
if ( $blc_config_manager->options['mark_broken_links'] ){
|
|
|
302 |
require $blc_directory . '/utility-class.php';
|
303 |
+
add_action('plugins_loaded', 'blc_init_parsers');
|
|
|
304 |
}
|
305 |
+
|
306 |
//And possibly inject the CSS for removed links
|
307 |
if ( $blc_config_manager->options['mark_removed_links'] && !empty($blc_config_manager->options['removed_link_css']) ){
|
308 |
function blc_print_remove_link_css(){
|
311 |
}
|
312 |
add_action('wp_head', 'blc_print_remove_link_css');
|
313 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
314 |
}
|
315 |
|
316 |
+
|
317 |
+
|
318 |
+
|
319 |
+
|
320 |
?>
|
core.php
CHANGED
@@ -1,8 +1,5 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
//The plugin will use Snoopy in case CURL is not available
|
4 |
-
if (!class_exists('Snoopy')) require_once(ABSPATH. WPINC . '/class-snoopy.php');
|
5 |
-
|
6 |
/**
|
7 |
* Simple function to replicate PHP 5 behaviour
|
8 |
*/
|
@@ -22,13 +19,11 @@ class wsBrokenLinkChecker {
|
|
22 |
var $loader;
|
23 |
var $my_basename = '';
|
24 |
|
25 |
-
var $db_version =
|
26 |
|
27 |
var $execution_start_time; //Used for a simple internal execution timer in start_timer()/execution_time()
|
28 |
var $lockfile_handle = null;
|
29 |
|
30 |
-
var $native_filters = null;
|
31 |
-
|
32 |
/**
|
33 |
* wsBrokenLinkChecker::wsBrokenLinkChecker()
|
34 |
* Class constructor
|
@@ -40,30 +35,17 @@ class wsBrokenLinkChecker {
|
|
40 |
function wsBrokenLinkChecker ( $loader, $conf ) {
|
41 |
global $wpdb;
|
42 |
|
43 |
-
$this->loader = $loader;
|
44 |
$this->conf = $conf;
|
45 |
-
|
46 |
-
add_action('activate_' . plugin_basename( $this->loader ), array(&$this,'activation'));
|
47 |
$this->my_basename = plugin_basename( $this->loader );
|
|
|
|
|
|
|
48 |
|
49 |
add_action('init', array(&$this,'load_language'));
|
50 |
|
51 |
add_action('admin_menu', array(&$this,'admin_menu'));
|
52 |
|
53 |
-
//These hooks update the plugin's internal records when posts are added, deleted or modified.
|
54 |
-
add_action('delete_post', array(&$this,'post_deleted'));
|
55 |
-
add_action('save_post', array(&$this,'post_saved'));
|
56 |
-
//Treat post trashing/untrashing as delete/save.
|
57 |
-
add_action('trash_post', array(&$this,'post_deleted'));
|
58 |
-
add_action('untrash_post', array(&$this,'post_saved'));
|
59 |
-
|
60 |
-
//These do the same for (blogroll) links.
|
61 |
-
add_action('add_link', array(&$this,'hook_add_link'));
|
62 |
-
add_action('edit_link', array(&$this,'hook_edit_link'));
|
63 |
-
add_action('delete_link', array(&$this,'hook_delete_link'));
|
64 |
-
|
65 |
-
//TODO: Hook the delete_post_meta action to detect when custom fields are deleted directly
|
66 |
-
|
67 |
//Load jQuery on Dashboard pages (probably redundant as WP already does that)
|
68 |
add_action('admin_print_scripts', array(&$this,'admin_print_scripts'));
|
69 |
|
@@ -71,15 +53,14 @@ class wsBrokenLinkChecker {
|
|
71 |
add_action('wp_dashboard_setup', array(&$this, 'hook_wp_dashboard_setup'));
|
72 |
|
73 |
//AJAXy hooks
|
74 |
-
//TODO: Check nonces in AJAX hooks
|
75 |
add_action( 'wp_ajax_blc_full_status', array(&$this,'ajax_full_status') );
|
76 |
add_action( 'wp_ajax_blc_dashboard_status', array(&$this,'ajax_dashboard_status') );
|
77 |
add_action( 'wp_ajax_blc_work', array(&$this,'ajax_work') );
|
78 |
add_action( 'wp_ajax_blc_discard', array(&$this,'ajax_discard') );
|
79 |
add_action( 'wp_ajax_blc_edit', array(&$this,'ajax_edit') );
|
80 |
add_action( 'wp_ajax_blc_link_details', array(&$this,'ajax_link_details') );
|
81 |
-
add_action( 'wp_ajax_blc_exclude_link', array(&$this,'ajax_exclude_link') );
|
82 |
add_action( 'wp_ajax_blc_unlink', array(&$this,'ajax_unlink') );
|
|
|
83 |
|
84 |
//Check if it's possible to create a lockfile and nag the user about it if not.
|
85 |
if ( $this->lockfile_name() ){
|
@@ -91,14 +72,25 @@ class wsBrokenLinkChecker {
|
|
91 |
add_action( 'admin_notices', array( &$this, 'lockfile_warning' ) );
|
92 |
}
|
93 |
|
94 |
-
//
|
95 |
-
|
|
|
|
|
|
|
|
|
96 |
}
|
97 |
|
|
|
|
|
|
|
|
|
|
|
98 |
function admin_footer(){
|
|
|
|
|
|
|
99 |
?>
|
100 |
<!-- wsblc admin footer -->
|
101 |
-
<div id='wsblc_updater_div'></div>
|
102 |
<script type='text/javascript'>
|
103 |
(function($){
|
104 |
|
@@ -123,6 +115,12 @@ class wsBrokenLinkChecker {
|
|
123 |
<?php
|
124 |
}
|
125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
function is_excluded($url){
|
127 |
if (!is_array($this->conf->options['exclusion_list'])) return false;
|
128 |
foreach($this->conf->options['exclusion_list'] as $excluded_word){
|
@@ -193,55 +191,23 @@ class wsBrokenLinkChecker {
|
|
193 |
wp_enqueue_script('jquery');
|
194 |
}
|
195 |
|
196 |
-
function
|
197 |
-
//jQuery UI is used on the settings page
|
|
|
|
|
|
|
|
|
|
|
198 |
wp_enqueue_script('jquery-ui-core');
|
199 |
wp_enqueue_script('jquery-ui-dialog');
|
|
|
200 |
}
|
201 |
|
202 |
/**
|
203 |
-
*
|
204 |
-
* A hook for post_deleted. Remove link instances associated with that post.
|
205 |
*
|
206 |
-
* @param int $post_id
|
207 |
* @return void
|
208 |
*/
|
209 |
-
function post_deleted($post_id){
|
210 |
-
global $wpdb;
|
211 |
-
|
212 |
-
//FB::log($post_id, "Post deleted");
|
213 |
-
//Remove this post's instances
|
214 |
-
$q = "DELETE FROM {$wpdb->prefix}blc_instances
|
215 |
-
WHERE source_id = %d AND (source_type = 'post' OR source_type='custom_field')";
|
216 |
-
$q = $wpdb->prepare($q, intval($post_id) );
|
217 |
-
|
218 |
-
//FB::log($q, 'Executing query');
|
219 |
-
|
220 |
-
if ( $wpdb->query( $q ) === false ){
|
221 |
-
//FB::error($wpdb->last_error, "Database error");
|
222 |
-
}
|
223 |
-
|
224 |
-
//Remove the synch record
|
225 |
-
$q = "DELETE FROM {$wpdb->prefix}blc_synch
|
226 |
-
WHERE source_id = %d AND source_type = 'post'";
|
227 |
-
$wpdb->query( $wpdb->prepare($q, intval($post_id)) );
|
228 |
-
|
229 |
-
//Remove any dangling link records
|
230 |
-
$this->cleanup_links();
|
231 |
-
}
|
232 |
-
|
233 |
-
function post_saved($post_id){
|
234 |
-
global $wpdb;
|
235 |
-
|
236 |
-
$post = get_post($post_id);
|
237 |
-
//Only check links in posts, not revisions and attachments
|
238 |
-
if ( ($post->post_type != 'post') && ($post->post_type != 'page') ) return null;
|
239 |
-
//Only check published posts
|
240 |
-
if ( $post->post_status != 'publish' ) return null;
|
241 |
-
|
242 |
-
$this->mark_unsynched( $post_id, 'post' );
|
243 |
-
}
|
244 |
-
|
245 |
function initiate_recheck(){
|
246 |
global $wpdb;
|
247 |
|
@@ -252,69 +218,24 @@ class wsBrokenLinkChecker {
|
|
252 |
$wpdb->query("TRUNCATE {$wpdb->prefix}blc_links");
|
253 |
|
254 |
//Mark all posts, custom fields and bookmarks for processing.
|
255 |
-
|
256 |
}
|
257 |
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
$q = "INSERT INTO {$wpdb->prefix}blc_synch(source_id, source_type, synched)
|
266 |
-
SELECT id, 'post', 0
|
267 |
-
FROM {$wpdb->posts}
|
268 |
-
WHERE
|
269 |
-
{$wpdb->posts}.post_status = 'publish'
|
270 |
-
AND {$wpdb->posts}.post_type IN ('post', 'page')";
|
271 |
-
$wpdb->query( $q );
|
272 |
-
|
273 |
-
//Create new synchronization records for bookmarks (the blogroll)
|
274 |
-
$q = "INSERT INTO {$wpdb->prefix}blc_synch(source_id, source_type, synched)
|
275 |
-
SELECT link_id, 'blogroll', 0
|
276 |
-
FROM {$wpdb->links}
|
277 |
-
WHERE 1";
|
278 |
-
$wpdb->query( $q );
|
279 |
-
|
280 |
-
//Delete invalid instances
|
281 |
-
$this->cleanup_instances();
|
282 |
-
//Delete orphaned links
|
283 |
-
$this->cleanup_links();
|
284 |
-
|
285 |
-
$this->conf->options['need_resynch'] = true;
|
286 |
-
$this->conf->save_options();
|
287 |
-
}
|
288 |
-
|
289 |
-
function mark_unsynched( $source_id, $source_type ){
|
290 |
-
global $wpdb;
|
291 |
-
|
292 |
-
$q = "REPLACE INTO {$wpdb->prefix}blc_synch( source_id, source_type, synched, last_synch)
|
293 |
-
VALUES( %d, %s, %d, NOW() )";
|
294 |
-
$rez = $wpdb->query( $wpdb->prepare( $q, $source_id, $source_type, 0 ) );
|
295 |
-
|
296 |
-
if ( !$this->conf->options['need_resynch'] ){
|
297 |
-
$this->conf->options['need_resynch'] = true;
|
298 |
-
$this->conf->save_options();
|
299 |
-
}
|
300 |
-
|
301 |
-
return $rez;
|
302 |
-
}
|
303 |
-
|
304 |
-
function mark_synched( $source_id, $source_type ){
|
305 |
-
global $wpdb;
|
306 |
-
//FB::log("Marking $source_type $source_id as synched.");
|
307 |
-
$q = "REPLACE INTO {$wpdb->prefix}blc_synch( source_id, source_type, synched, last_synch)
|
308 |
-
VALUES( %d, %s, %d, NOW() )";
|
309 |
-
return $wpdb->query( $wpdb->prepare( $q, $source_id, $source_type, 1 ) );
|
310 |
-
}
|
311 |
-
|
312 |
function activation(){
|
|
|
|
|
313 |
//Prepare the database.
|
314 |
$this->upgrade_database();
|
315 |
|
316 |
-
//
|
317 |
-
|
318 |
|
319 |
//Save the default options.
|
320 |
$this->conf->save_options();
|
@@ -323,112 +244,216 @@ class wsBrokenLinkChecker {
|
|
323 |
$this->optimize_database();
|
324 |
}
|
325 |
|
|
|
326 |
/**
|
327 |
-
*
|
328 |
-
* Create and/or upgrade database tables
|
329 |
*
|
330 |
-
* @param bool $die_on_error Whether the function should stop the script and display an error message if a DB error is encountered.
|
331 |
* @return void
|
332 |
*/
|
333 |
-
function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
334 |
global $wpdb;
|
335 |
|
336 |
//Do we need to upgrade?
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
$rez = $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}blc_linkdata, {$wpdb->prefix}blc_postdata" );
|
342 |
-
if ( $rez === false ){
|
343 |
-
//FB::error($wpdb->last_error, "Database error");
|
344 |
-
return false;
|
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 |
-
MODIFY final_url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL";
|
377 |
-
if ( $wpdb->query( $q ) === false ){
|
378 |
-
if ( $die_on_error )
|
379 |
-
die( sprintf( __('Database error : %s', 'broken-link-checker'), $wpdb->last_error) );
|
380 |
-
};
|
381 |
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
KEY link_id (link_id),
|
393 |
-
KEY source_id (source_id,source_type),
|
394 |
-
FULLTEXT KEY link_text (link_text)
|
395 |
-
) ENGINE = MYISAM";
|
396 |
-
dbDelta($q);
|
397 |
-
|
398 |
-
//Create the synchronization table
|
399 |
-
$q = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}blc_synch (
|
400 |
-
source_id int(20) unsigned NOT NULL,
|
401 |
-
source_type enum('post','blogroll') NOT NULL,
|
402 |
-
synched tinyint(3) unsigned NOT NULL,
|
403 |
-
last_synch datetime NOT NULL,
|
404 |
-
PRIMARY KEY (source_id, source_type),
|
405 |
-
KEY synched (synched)
|
406 |
-
)";
|
407 |
-
if ( $wpdb->query( $q ) === false ){
|
408 |
-
if ( $die_on_error )
|
409 |
-
die( sprintf( __('Database error : %s', 'broken-link-checker'), $wpdb->last_error) );
|
410 |
-
};
|
411 |
|
412 |
-
//
|
413 |
-
$q =
|
414 |
-
|
|
|
415 |
`name` varchar(100) NOT NULL,
|
416 |
-
params text NOT NULL,
|
417 |
-
PRIMARY KEY (id)
|
418 |
-
)
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
423 |
|
424 |
-
|
425 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
426 |
|
|
|
427 |
return true;
|
428 |
}
|
429 |
|
430 |
/**
|
431 |
-
* wsBrokenLinkChecker::optimize_database()
|
432 |
* Optimize the plugin's tables
|
433 |
*
|
434 |
* @return void
|
@@ -458,14 +483,13 @@ class wsBrokenLinkChecker {
|
|
458 |
);
|
459 |
|
460 |
//Add plugin-specific scripts and CSS only to the it's own pages
|
461 |
-
//TODO: Use the admin_enqueue_scripts action to enqueue the scripts
|
462 |
add_action( 'admin_print_styles-' . $options_page_hook, array(&$this, 'options_page_css') );
|
463 |
add_action( 'admin_print_styles-' . $links_page_hook, array(&$this, 'links_page_css') );
|
464 |
-
|
465 |
-
add_action( 'admin_print_scripts-' . $links_page_hook, array(&$this, '
|
466 |
}
|
467 |
|
468 |
-
|
469 |
* plugin_action_links()
|
470 |
* Handler for the 'plugin_action_links' hook. Adds a "Settings" link to this plugin's entry
|
471 |
* on the plugin list.
|
@@ -480,15 +504,23 @@ class wsBrokenLinkChecker {
|
|
480 |
return $links;
|
481 |
}
|
482 |
|
483 |
-
function mytruncate($str, $max_length=50){
|
484 |
-
if(strlen($str)<=$max_length) return $str;
|
485 |
-
return (substr($str, 0, $max_length-3).'...');
|
486 |
-
}
|
487 |
-
|
488 |
function options_page(){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
489 |
if (isset($_GET['recheck']) && ($_GET['recheck'] == 'true')) {
|
490 |
$this->initiate_recheck();
|
491 |
}
|
|
|
492 |
if(isset($_POST['submit'])) {
|
493 |
check_admin_referer('link-checker-options');
|
494 |
|
@@ -512,7 +544,6 @@ class wsBrokenLinkChecker {
|
|
512 |
$new_removed_link_css = trim($_POST['removed_link_css']);
|
513 |
$this->conf->options['removed_link_css'] = $new_removed_link_css;
|
514 |
|
515 |
-
//TODO: Maybe update affected links when exclusion list changes (could be expensive resource-wise).
|
516 |
$this->conf->options['exclusion_list'] = array_filter(
|
517 |
preg_split(
|
518 |
'/[\s\r\n]+/', //split on newlines and whitespace
|
@@ -540,7 +571,36 @@ class wsBrokenLinkChecker {
|
|
540 |
if( $new_timeout > 0 ){
|
541 |
$this->conf->options['timeout'] = $new_timeout ;
|
542 |
}
|
543 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
544 |
$this->conf->save_options();
|
545 |
|
546 |
/*
|
@@ -549,15 +609,26 @@ class wsBrokenLinkChecker {
|
|
549 |
inefficient.
|
550 |
*/
|
551 |
if ( ( count($diff1) > 0 ) || ( count($diff2) > 0 ) ){
|
552 |
-
$
|
|
|
|
|
|
|
|
|
553 |
}
|
554 |
|
|
|
555 |
$base_url = remove_query_arg( array('_wpnonce', 'noheader', 'updated', 'error', 'action', 'message') );
|
556 |
-
wp_redirect( add_query_arg( array( 'updated' =>
|
|
|
|
|
|
|
|
|
|
|
|
|
557 |
}
|
558 |
|
559 |
$debug = $this->get_debug_info();
|
560 |
-
|
561 |
?>
|
562 |
|
563 |
<div class="wrap"><h2><?php _e('Broken Link Checker Options', 'broken-link-checker'); ?></h2>
|
@@ -579,7 +650,6 @@ class wsBrokenLinkChecker {
|
|
579 |
</th>
|
580 |
<td>
|
581 |
|
582 |
-
|
583 |
<div id='wsblc_full_status'>
|
584 |
<br/><br/><br/>
|
585 |
</div>
|
@@ -709,6 +779,19 @@ class wsBrokenLinkChecker {
|
|
709 |
</td>
|
710 |
</tr>
|
711 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
712 |
</table>
|
713 |
|
714 |
<h3><?php _e('Advanced','broken-link-checker'); ?></h3>
|
@@ -738,6 +821,53 @@ class wsBrokenLinkChecker {
|
|
738 |
</td>
|
739 |
</tr>
|
740 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
741 |
|
742 |
<tr valign="top">
|
743 |
<th scope="row">
|
@@ -771,33 +901,66 @@ class wsBrokenLinkChecker {
|
|
771 |
|
772 |
</td>
|
773 |
</tr>
|
774 |
-
|
775 |
-
|
776 |
-
<th scope="row"><?php _e('
|
777 |
<td>
|
778 |
-
|
779 |
<?php
|
780 |
|
781 |
-
|
782 |
-
|
783 |
-
sprintf(
|
784 |
-
'<input type="text" name="max_execution_time" id="max_execution_time" value="%d" size="5" maxlength="5" />',
|
785 |
-
$this->conf->options['max_execution_time']
|
786 |
-
)
|
787 |
-
);
|
788 |
|
789 |
-
|
790 |
-
|
791 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
792 |
|
793 |
-
|
794 |
-
|
|
|
|
|
|
|
|
|
795 |
?>
|
796 |
-
</span>
|
797 |
-
|
798 |
</td>
|
799 |
</tr>
|
800 |
-
|
801 |
</table>
|
802 |
|
803 |
<p class="submit"><input type="submit" name="submit" class='button-primary' value="<?php _e('Save Changes') ?>" /></p>
|
@@ -825,141 +988,22 @@ class wsBrokenLinkChecker {
|
|
825 |
}
|
826 |
|
827 |
function options_page_css(){
|
828 |
-
|
829 |
-
<style type='text/css'>
|
830 |
-
#blc-debug-info-toggle {
|
831 |
-
font-size: smaller;
|
832 |
-
}
|
833 |
-
|
834 |
-
.blc-debug-item-ok {
|
835 |
-
background-color: #d7ffa2;
|
836 |
-
}
|
837 |
-
.blc-debug-item-warning {
|
838 |
-
background-color: #fcffa2;
|
839 |
-
}
|
840 |
-
.blc-debug-item-error {
|
841 |
-
background-color: #ffc4c4;
|
842 |
-
}
|
843 |
-
|
844 |
-
#blc-debug-info {
|
845 |
-
display: none;
|
846 |
-
|
847 |
-
text-align: left;
|
848 |
-
|
849 |
-
border-width: 1px;
|
850 |
-
border-color: gray;
|
851 |
-
border-style: solid;
|
852 |
-
|
853 |
-
border-spacing: 0px;
|
854 |
-
border-collapse: collapse;
|
855 |
-
}
|
856 |
-
|
857 |
-
#blc-debug-info th, #blc-debug-info td {
|
858 |
-
padding: 6px;
|
859 |
-
font-weight: normal;
|
860 |
-
text-shadow: none;
|
861 |
-
|
862 |
-
border-width: 1px ;
|
863 |
-
border-color: silver;
|
864 |
-
border-style: solid;
|
865 |
-
|
866 |
-
border-collapse: collapse;
|
867 |
-
}
|
868 |
-
</style>
|
869 |
-
<?php
|
870 |
}
|
871 |
|
872 |
-
|
873 |
-
|
874 |
-
|
875 |
-
|
876 |
-
|
877 |
-
|
878 |
-
|
879 |
-
|
880 |
-
|
881 |
-
|
882 |
-
//Available filters by link type + the appropriate WHERE expressions
|
883 |
-
$this->native_filters = array(
|
884 |
-
'broken' => array(
|
885 |
-
'where_expr' => '( http_code < 200 OR http_code >= 400 OR timeout = 1 ) AND ( check_count > 0 ) AND ( http_code <> ' . BLC_CHECKING . ')',
|
886 |
-
'name' => __('Broken', 'broken-link-checker'),
|
887 |
-
'heading' => __('Broken Links', 'broken-link-checker'),
|
888 |
-
'heading_zero' => __('No broken links found', 'broken-link-checker')
|
889 |
-
),
|
890 |
-
'redirects' => array(
|
891 |
-
'where_expr' => '( redirect_count > 0 )',
|
892 |
-
'name' => __('Redirects', 'broken-link-checker'),
|
893 |
-
'heading' => __('Redirected Links', 'broken-link-checker'),
|
894 |
-
'heading_zero' => __('No redirects found', 'broken-link-checker')
|
895 |
-
),
|
896 |
-
|
897 |
-
'all' => array(
|
898 |
-
'where_expr' => '1',
|
899 |
-
'name' => __('All', 'broken-link-checker'),
|
900 |
-
'heading' => __('Detected Links', 'broken-link-checker'),
|
901 |
-
'heading_zero' => __('No links found (yet)', 'broken-link-checker')
|
902 |
-
),
|
903 |
);
|
904 |
-
|
905 |
-
return $this->native_filters;
|
906 |
}
|
907 |
-
}
|
908 |
-
|
909 |
-
/**
|
910 |
-
* wsBrokenLinkChecker::get_custom_filters()
|
911 |
-
* Returns a list of user-defined link filters.
|
912 |
-
*
|
913 |
-
* @return array An array of custom filter definitions. If there are no custom filters defined returns an empty array.
|
914 |
-
*/
|
915 |
-
function get_custom_filters(){
|
916 |
-
global $wpdb;
|
917 |
-
|
918 |
-
$filter_data = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}blc_filters ORDER BY name ASC", ARRAY_A);
|
919 |
-
$filters = array();
|
920 |
-
|
921 |
-
if ( !empty($filter_data) ) {
|
922 |
-
foreach($filter_data as $data){
|
923 |
-
$filters[ 'f'.$data['id'] ] = array(
|
924 |
-
'name' => $data['name'],
|
925 |
-
'params' => $data['params'],
|
926 |
-
'is_search' => true,
|
927 |
-
'heading' => ucwords($data['name']),
|
928 |
-
'heading_zero' => __('No links found for your query', 'broken-link-checker'),
|
929 |
-
);
|
930 |
-
}
|
931 |
-
}
|
932 |
-
|
933 |
-
return $filters;
|
934 |
-
}
|
935 |
-
|
936 |
-
function get_search_params( $filter = null ){
|
937 |
-
//If present, the filter's parameters may be saved either as an array or a string.
|
938 |
-
$params = array();
|
939 |
-
if ( !empty($filter) && !empty($filter['params']) ){
|
940 |
-
$params = $filter['params'];
|
941 |
-
if ( is_string( $params ) ){
|
942 |
-
wp_parse_str($params, $params);
|
943 |
-
}
|
944 |
-
} else {
|
945 |
-
//If the filter doesn't have it's own search query, use the URL parameters
|
946 |
-
$params = array_merge($params, $_GET);
|
947 |
-
}
|
948 |
-
|
949 |
-
//Only leave valid search query parameters
|
950 |
-
$search_param_names = array( 's_link_text', 's_link_url', 's_http_code', 's_filter', 's_link_type' );
|
951 |
-
$output = array();
|
952 |
-
foreach ( $params as $name => $value ){
|
953 |
-
if ( in_array($name, $search_param_names) ){
|
954 |
-
$output[$name] = $value;
|
955 |
-
}
|
956 |
-
}
|
957 |
-
|
958 |
-
return $output;
|
959 |
-
}
|
960 |
-
|
961 |
-
function links_page(){
|
962 |
-
global $wpdb;
|
963 |
|
964 |
$action = !empty($_POST['action'])?$_POST['action']:'';
|
965 |
if ( intval($action) == -1 ){
|
@@ -979,315 +1023,40 @@ class wsBrokenLinkChecker {
|
|
979 |
$message = '';
|
980 |
$msg_class = 'updated';
|
981 |
|
|
|
982 |
if ( $action == 'create-custom-filter' ){
|
983 |
-
|
984 |
-
|
985 |
-
check_admin_referer( $action );
|
986 |
-
|
987 |
-
//Filter name must be set
|
988 |
-
if ( empty($_POST['name']) ){
|
989 |
-
$message = __("You must enter a filter name!", 'broken-link-checker');
|
990 |
-
$msg_class = 'error';
|
991 |
-
//Filter parameters (a search query) must also be set
|
992 |
-
} elseif ( empty($_POST['params']) ){
|
993 |
-
$message = __("Invalid search query.", 'broken-link-checker');
|
994 |
-
$msg_class = 'error';
|
995 |
-
} else {
|
996 |
-
//Save the new filter
|
997 |
-
$q = $wpdb->prepare(
|
998 |
-
"INSERT INTO {$wpdb->prefix}blc_filters(name, params) VALUES (%s, %s)",
|
999 |
-
$_POST['name'], $_POST['params']
|
1000 |
-
);
|
1001 |
-
|
1002 |
-
if ( $wpdb->query($q) ){
|
1003 |
-
//Saved
|
1004 |
-
$message = sprintf( __('Filter "%s" created', 'broken-link-checker'), $_POST['name']);
|
1005 |
-
//A little hack to make the filter active immediately
|
1006 |
-
$_GET['filter_id'] = 'f' . $wpdb->insert_id;
|
1007 |
-
} else {
|
1008 |
-
//Error
|
1009 |
-
$message = sprintf( __("Database error : %s", 'broken-link-checker'), $wpdb->last_error);
|
1010 |
-
$msg_class = 'error';
|
1011 |
-
}
|
1012 |
-
}
|
1013 |
-
|
1014 |
} elseif ( $action == 'delete-custom-filter' ){
|
1015 |
-
|
1016 |
-
|
1017 |
-
check_admin_referer( $action );
|
1018 |
-
|
1019 |
-
//Filter ID must be set
|
1020 |
-
if ( empty($_POST['filter_id']) ){
|
1021 |
-
$message = __("Filter ID not specified.", 'broken-link-checker');
|
1022 |
-
$msg_class = 'error';
|
1023 |
-
} else {
|
1024 |
-
//Remove the "f" character from the filter ID to get its database key
|
1025 |
-
$filter_id = intval(ltrim($_POST['filter_id'], 'f'));
|
1026 |
-
//Try to delete the filter
|
1027 |
-
$q = $wpdb->prepare("DELETE FROM {$wpdb->prefix}blc_filters WHERE id = %d", $filter_id);
|
1028 |
-
if ( $wpdb->query($q) ){
|
1029 |
-
//Success
|
1030 |
-
$message = __('Filter deleted', 'broken-link-checker');
|
1031 |
-
} else {
|
1032 |
-
//Either the ID is wrong or there was some other error
|
1033 |
-
$message = __('Database error : %s', 'broken-link-checker');
|
1034 |
-
$msg_class = 'error';
|
1035 |
-
}
|
1036 |
-
}
|
1037 |
-
|
1038 |
} elseif ($action == 'bulk-delete-sources') {
|
1039 |
-
|
1040 |
-
//(links inside custom fields count as part of the post for the purposes of this action).
|
1041 |
-
//
|
1042 |
-
//Note that once all posts/bookmarks containing a particular link have been deleted,
|
1043 |
-
//there is no need to explicitly delete the link record itself. The hooks attached to
|
1044 |
-
//the post_deleted and delete_link actions will take care of that.
|
1045 |
-
|
1046 |
-
check_admin_referer( 'bulk-action' );
|
1047 |
-
|
1048 |
-
if ( count($selected_links) > 0 ) {
|
1049 |
-
$selected_links_sql = implode(', ', $selected_links);
|
1050 |
-
|
1051 |
-
$messages = array();
|
1052 |
-
|
1053 |
-
//First, fetch the posts that contain any of the selected links,
|
1054 |
-
//either in the content or in a custom field.
|
1055 |
-
$q = "
|
1056 |
-
SELECT posts.id, posts.post_title
|
1057 |
-
FROM
|
1058 |
-
{$wpdb->prefix}blc_links AS links,
|
1059 |
-
{$wpdb->prefix}blc_instances AS instances,
|
1060 |
-
{$wpdb->posts} AS posts
|
1061 |
-
WHERE
|
1062 |
-
links.link_id IN ($selected_links_sql)
|
1063 |
-
AND links.link_id = instances.link_id
|
1064 |
-
AND (instances.source_type = 'post' OR instances.source_type = 'custom_field')
|
1065 |
-
AND instances.source_id = posts.id
|
1066 |
-
AND posts.post_status <> \"trash\"
|
1067 |
-
GROUP BY posts.id
|
1068 |
-
";
|
1069 |
-
|
1070 |
-
$posts_to_delete = $wpdb->get_results($q);
|
1071 |
-
$deleted_posts = array();
|
1072 |
-
|
1073 |
-
//Delete the selected posts
|
1074 |
-
foreach($posts_to_delete as $post){
|
1075 |
-
if ( wp_delete_post($post->id) !== false) {
|
1076 |
-
$deleted_posts[] = $post;
|
1077 |
-
} else {
|
1078 |
-
$messages[] = sprintf(
|
1079 |
-
__('Failed to delete post "%s" (%d)', 'broken-link-checker'),
|
1080 |
-
$post->pots_title,
|
1081 |
-
$post->id
|
1082 |
-
);
|
1083 |
-
$msg_class = 'error';
|
1084 |
-
};
|
1085 |
-
}
|
1086 |
-
|
1087 |
-
if ( count($deleted_posts) > 0 ) {
|
1088 |
-
//Since the "Trash" feature has been introduced, calling wp_delete_post
|
1089 |
-
//doesn't actually delete the post (unless you set force_delete to True),
|
1090 |
-
//just moves it to the trash. So we pick the message accordingly.
|
1091 |
-
if ( function_exists('wp_trash_post') ){
|
1092 |
-
$delete_msg = _n("%d post moved to the trash", "%d posts moved to the trash", count($deleted_posts), 'broken-link-checker');
|
1093 |
-
} else {
|
1094 |
-
$delete_msg = _n("%d post deleted", "%d posts deleted", count($deleted_posts), 'broken-link-checker');
|
1095 |
-
}
|
1096 |
-
|
1097 |
-
$messages[] = sprintf(
|
1098 |
-
$delete_msg,
|
1099 |
-
count($deleted_posts)
|
1100 |
-
);
|
1101 |
-
}
|
1102 |
-
|
1103 |
-
//Fetch blogroll links (AKA bookmarks) that match any of the selected links
|
1104 |
-
$q = "
|
1105 |
-
SELECT bookmarks.link_id AS bookmark_id, bookmarks.link_name
|
1106 |
-
FROM
|
1107 |
-
{$wpdb->prefix}blc_links AS links,
|
1108 |
-
{$wpdb->prefix}blc_instances AS instances,
|
1109 |
-
{$wpdb->links} AS bookmarks
|
1110 |
-
WHERE
|
1111 |
-
links.link_id IN ($selected_links_sql)
|
1112 |
-
AND links.link_id = instances.link_id
|
1113 |
-
AND instances.source_type = 'blogroll'
|
1114 |
-
AND instances.source_id = bookmarks.link_id
|
1115 |
-
GROUP BY bookmarks.link_id
|
1116 |
-
";
|
1117 |
-
//echo "<pre>$q</pre>";
|
1118 |
-
|
1119 |
-
$bookmarks_to_delete = $wpdb->get_results($q);
|
1120 |
-
$deleted_bookmarks = array();
|
1121 |
-
|
1122 |
-
if ( count($bookmarks_to_delete) > 0 ){
|
1123 |
-
//Delete the matching blogroll links
|
1124 |
-
foreach($bookmarks_to_delete as $bookmark){
|
1125 |
-
if ( wp_delete_link($bookmark->bookmark_id) ){
|
1126 |
-
$deleted_bookmarks[] = $bookmark;
|
1127 |
-
} else {
|
1128 |
-
$messages[] = sprintf(
|
1129 |
-
__('Failed to delete blogroll link "%s" (%d)', 'broken-link-checker'),
|
1130 |
-
$bookmark->link_name,
|
1131 |
-
$bookmark->link_id
|
1132 |
-
);
|
1133 |
-
$msg_class = 'error';
|
1134 |
-
}
|
1135 |
-
}
|
1136 |
-
|
1137 |
-
if ( count($deleted_bookmarks) > 0 ) {
|
1138 |
-
$messages[] = sprintf(
|
1139 |
-
_n("%d blogroll link deleted", "%d blogroll links deleted", count($deleted_bookmarks), 'broken-link-checker'),
|
1140 |
-
count($deleted_bookmarks)
|
1141 |
-
);
|
1142 |
-
}
|
1143 |
-
}
|
1144 |
-
|
1145 |
-
if ( count($messages) > 0 ){
|
1146 |
-
$message = implode('<br>', $messages);
|
1147 |
-
} else {
|
1148 |
-
$message = __("Didn't find anything to delete!", 'broken-link-checker');
|
1149 |
-
$msg_class = 'error';
|
1150 |
-
}
|
1151 |
-
|
1152 |
-
|
1153 |
-
}
|
1154 |
-
|
1155 |
} elseif ($action == 'bulk-unlink') {
|
1156 |
-
|
1157 |
-
|
1158 |
-
check_admin_referer( 'bulk-action' );
|
1159 |
-
|
1160 |
-
if ( count($selected_links) > 0 ) {
|
1161 |
-
$selected_links_sql = implode(', ', $selected_links);
|
1162 |
-
|
1163 |
-
//Fetch the selected links
|
1164 |
-
$q = "SELECT * FROM {$wpdb->prefix}blc_links WHERE link_id IN ($selected_links_sql)";
|
1165 |
-
$links = $wpdb->get_results($q, ARRAY_A);
|
1166 |
-
|
1167 |
-
if ( count($links) > 0 ) {
|
1168 |
-
$processed_links = 0;
|
1169 |
-
$failed_links = 0;
|
1170 |
-
|
1171 |
-
//Unlink (delete) all selected links
|
1172 |
-
foreach($links as $link){
|
1173 |
-
$the_link = new blcLink($link);
|
1174 |
-
$rez = $the_link->unlink();
|
1175 |
-
if ( $rez !== false ){
|
1176 |
-
$processed_links++;
|
1177 |
-
} else {
|
1178 |
-
$failed_links++;
|
1179 |
-
}
|
1180 |
-
}
|
1181 |
-
|
1182 |
-
//This message is slightly misleading - it doesn't account for the fact that
|
1183 |
-
//a link can be present in more than one post.
|
1184 |
-
$message = sprintf(
|
1185 |
-
_n(
|
1186 |
-
'%d link removed',
|
1187 |
-
'%d links removed',
|
1188 |
-
$processed_links,
|
1189 |
-
'broken-link-checker'
|
1190 |
-
),
|
1191 |
-
$processed_links
|
1192 |
-
);
|
1193 |
-
|
1194 |
-
if ( $failed_links > 0 ) {
|
1195 |
-
$message .= '<br>' . sprintf(
|
1196 |
-
_n(
|
1197 |
-
'Failed to remove %d link',
|
1198 |
-
'Failed to remove %d links',
|
1199 |
-
$failed_links,
|
1200 |
-
'broken-link-checker'
|
1201 |
-
),
|
1202 |
-
$failed_links
|
1203 |
-
);
|
1204 |
-
$msg_class = 'error';
|
1205 |
-
}
|
1206 |
-
}
|
1207 |
-
}
|
1208 |
-
|
1209 |
} elseif ($action == 'bulk-deredirect') {
|
1210 |
-
|
1211 |
-
|
1212 |
-
|
1213 |
-
|
1214 |
-
if ( count($selected_links) > 0 ) {
|
1215 |
-
$selected_links_sql = implode(', ', $selected_links);
|
1216 |
-
|
1217 |
-
//Fetch the selected links
|
1218 |
-
$q = "SELECT * FROM {$wpdb->prefix}blc_links WHERE link_id IN ($selected_links_sql) AND redirect_count > 0";
|
1219 |
-
$links = $wpdb->get_results($q, ARRAY_A);
|
1220 |
-
|
1221 |
-
if ( count($links) > 0 ) {
|
1222 |
-
$processed_links = 0;
|
1223 |
-
$failed_links = 0;
|
1224 |
-
|
1225 |
-
//Deredirect all selected links
|
1226 |
-
foreach($links as $link){
|
1227 |
-
$the_link = new blcLink($link);
|
1228 |
-
$rez = $the_link->deredirect();
|
1229 |
-
if ( $rez !== false ){
|
1230 |
-
$processed_links++;
|
1231 |
-
} else {
|
1232 |
-
$failed_links++;
|
1233 |
-
}
|
1234 |
-
}
|
1235 |
-
|
1236 |
-
$message = sprintf(
|
1237 |
-
_n(
|
1238 |
-
'Replaced %d redirect with a direct link',
|
1239 |
-
'Replaced %d redirects with direct links',
|
1240 |
-
$processed_links,
|
1241 |
-
'broken-link-checker'
|
1242 |
-
),
|
1243 |
-
$processed_links
|
1244 |
-
);
|
1245 |
-
|
1246 |
-
if ( $failed_links > 0 ) {
|
1247 |
-
$message .= '<br>' . sprintf(
|
1248 |
-
_n(
|
1249 |
-
'Failed to fix %d redirect',
|
1250 |
-
'Failed to fix %d redirects',
|
1251 |
-
$failed_links,
|
1252 |
-
'broken-link-checker'
|
1253 |
-
),
|
1254 |
-
$failed_links
|
1255 |
-
);
|
1256 |
-
$msg_class = 'error';
|
1257 |
-
}
|
1258 |
-
} else {
|
1259 |
-
$message = __('None of the selected links are redirects!', 'broken-link-checker');
|
1260 |
-
}
|
1261 |
-
}
|
1262 |
-
|
1263 |
}
|
1264 |
|
1265 |
if ( !empty($message) ){
|
1266 |
-
echo '<div id="message" class="'.$msg_class.' fade"><p
|
1267 |
}
|
1268 |
|
1269 |
-
//
|
1270 |
-
|
1271 |
|
1272 |
-
//
|
1273 |
-
$
|
1274 |
-
'name' => __('Search', 'broken-link-checker'),
|
1275 |
-
'heading' => __('Search Results', 'broken-link-checker'),
|
1276 |
-
'heading_zero' => __('No links found for your query', 'broken-link-checker'),
|
1277 |
-
'is_search' => true,
|
1278 |
-
'where_expr' => 1,
|
1279 |
-
'hidden' => true,
|
1280 |
-
);
|
1281 |
|
1282 |
-
|
1283 |
-
foreach ($filters as $filter => $data){
|
1284 |
-
$filters[$filter]['count'] = $this->get_links($data, 0, 0, true);
|
1285 |
-
}
|
1286 |
|
1287 |
//Get the selected filter (defaults to displaying broken links)
|
1288 |
$filter_id = isset($_GET['filter_id'])?$_GET['filter_id']:'broken';
|
1289 |
-
|
|
|
1290 |
$filter_id = 'broken';
|
|
|
|
|
1291 |
}
|
1292 |
|
1293 |
//Get the desired page number (must be > 0)
|
@@ -1302,25 +1071,29 @@ class wsBrokenLinkChecker {
|
|
1302 |
$per_page = 200;
|
1303 |
}
|
1304 |
|
1305 |
-
|
1306 |
$max_pages = ceil($current_filter['count'] / $per_page);
|
1307 |
|
1308 |
-
//Select the required links
|
1309 |
-
$
|
1310 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1311 |
printf( __('Database error : %s', 'broken-link-checker'), $wpdb->last_error);
|
1312 |
}
|
1313 |
|
1314 |
-
//
|
1315 |
-
|
1316 |
-
|
1317 |
-
|
1318 |
-
$search_params =
|
1319 |
}
|
1320 |
|
1321 |
-
//Display the "Discard" button when listing broken links
|
1322 |
-
$show_discard_button = ('broken' == $filter_id) || (!empty($search_params['s_filter']) && ($search_params['s_filter'] == 'broken'));
|
1323 |
-
|
1324 |
//Figure out what the "safe" URL to acccess the current page would be.
|
1325 |
//This is used by the bulk action form.
|
1326 |
$special_args = array('_wpnonce', '_wp_http_referer', 'action', 'selected_links');
|
@@ -1330,6 +1103,13 @@ class wsBrokenLinkChecker {
|
|
1330 |
|
1331 |
<script type='text/javascript'>
|
1332 |
var blc_current_filter = '<?php echo $filter_id; ?>';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1333 |
</script>
|
1334 |
|
1335 |
<div class="wrap">
|
@@ -1364,98 +1144,12 @@ class wsBrokenLinkChecker {
|
|
1364 |
?>
|
1365 |
</ul>
|
1366 |
|
1367 |
-
|
1368 |
-
|
1369 |
-
|
1370 |
-
|
1371 |
-
//save the search query as a custom filter.
|
1372 |
-
if ( $filter_id == 'search' ){
|
1373 |
-
?>
|
1374 |
-
<form name="save-search-query" id="custom-filter-form" action="<?php echo admin_url("tools.php?page=view-broken-links"); ?>" method="post" class="blc-inline-form">
|
1375 |
-
<?php wp_nonce_field('create-custom-filter'); ?>
|
1376 |
-
<input type="hidden" name="name" id="blc-custom-filter-name" value="" />
|
1377 |
-
<input type="hidden" name="params" id="blc-custom-filter-params" value="<?php echo http_build_query($search_params, null, '&'); ?>" />
|
1378 |
-
<input type="hidden" name="action" value="create-custom-filter" />
|
1379 |
-
<input type="button" value="<?php esc_attr_e( 'Save This Search As a Filter', 'broken-link-checker' ); ?>" id="blc-create-filter" class="button" />
|
1380 |
-
</form>
|
1381 |
-
<?php
|
1382 |
-
} elseif ( !empty($current_filter['is_search']) ){
|
1383 |
-
//If we're displaying a custom filter give an option to delete it.
|
1384 |
-
?>
|
1385 |
-
<form name="save-search-query" id="custom-filter-form" action="<?php echo admin_url("tools.php?page=view-broken-links"); ?>" method="post" class="blc-inline-form">
|
1386 |
-
<?php wp_nonce_field('delete-custom-filter'); ?>
|
1387 |
-
<input type="hidden" name="filter_id" id="blc-custom-filter-id" value="<?php echo $filter_id; ?>" />
|
1388 |
-
<input type="hidden" name="action" value="delete-custom-filter" />
|
1389 |
-
<input type="submit" value="<?php esc_attr_e( 'Delete This Filter', 'broken-link-checker' ); ?>" id="blc-delete-filter" class="button" />
|
1390 |
-
</form>
|
1391 |
-
<?php
|
1392 |
-
}
|
1393 |
-
?>
|
1394 |
-
|
1395 |
-
<input type="button" value="<?php esc_attr_e( 'Search', 'broken-link-checker' ); ?> »" id="blc-open-search-box" class="button" />
|
1396 |
-
</div>
|
1397 |
|
1398 |
-
<!-- The search dialog -->
|
1399 |
-
<div id='search-links-dialog' title='Search'>
|
1400 |
-
<form class="search-form" action="<?php echo admin_url('tools.php?page=view-broken-links'); ?>" method="get">
|
1401 |
-
<input type="hidden" name="page" value="view-broken-links" />
|
1402 |
-
<input type="hidden" name="filter_id" value="search" />
|
1403 |
-
<fieldset>
|
1404 |
-
|
1405 |
-
<label for="s_link_text"><?php _e('Link text', 'broken-link-checker'); ?></label>
|
1406 |
-
<input type="text" name="s_link_text" value="<?php if(!empty($search_params['s_link_text'])) echo esc_attr($search_params['s_link_text']); ?>" id="s_link_text" class="text ui-widget-content" />
|
1407 |
-
|
1408 |
-
<label for="s_link_url"><?php _e('URL', 'broken-link-checker'); ?></label>
|
1409 |
-
<input type="text" name="s_link_url" id="s_link_url" value="<?php if(!empty($search_params['s_link_url'])) echo esc_attr($search_params['s_link_url']); ?>" class="text ui-widget-content" />
|
1410 |
-
|
1411 |
-
<label for="s_http_code"><?php _e('HTTP code', 'broken-link-checker'); ?></label>
|
1412 |
-
<input type="text" name="s_http_code" id="s_http_code" value="<?php if(!empty($search_params['s_http_code'])) echo esc_attr($search_params['s_http_code']); ?>" class="text ui-widget-content" />
|
1413 |
-
|
1414 |
-
<label for="s_filter"><?php _e('Link status', 'broken-link-checker'); ?></label>
|
1415 |
-
<select name="s_filter" id="s_filter">
|
1416 |
-
<?php
|
1417 |
-
if ( !empty($search_params['s_filter']) ){
|
1418 |
-
$search_subfilter = $search_params['s_filter'];
|
1419 |
-
} else {
|
1420 |
-
$search_subfilter = $filter_id;
|
1421 |
-
}
|
1422 |
-
|
1423 |
-
foreach ($this->native_filters as $filter => $data){
|
1424 |
-
$selected = ($search_subfilter == $filter)?' selected="selected"':'';
|
1425 |
-
printf('<option value="%s"%s>%s</option>', $filter, $selected, $data['name']);
|
1426 |
-
}
|
1427 |
-
?>
|
1428 |
-
</select>
|
1429 |
-
|
1430 |
-
<label for="s_link_type"><?php _e('Link type', 'broken-link-checker'); ?></label>
|
1431 |
-
<select name="s_link_type" id="s_link_type">
|
1432 |
-
<?php
|
1433 |
-
$link_types = array(
|
1434 |
-
__('Any', 'broken-link-checker') => '',
|
1435 |
-
__('Normal link', 'broken-link-checker') => 'link',
|
1436 |
-
__('Image', 'broken-link-checker') => 'image',
|
1437 |
-
__('Custom field', 'broken-link-checker') => 'custom_field',
|
1438 |
-
__('Bookmark', 'broken-link-checker') => 'blogroll',
|
1439 |
-
);
|
1440 |
-
|
1441 |
-
foreach ($link_types as $name => $value){
|
1442 |
-
$selected = ( isset($search_params['s_link_type']) && $search_params['s_link_type'] == $value )?' selected="selected"':'';
|
1443 |
-
printf('<option value="%s"%s>%s</option>', $value, $selected, $name);
|
1444 |
-
}
|
1445 |
-
?>
|
1446 |
-
</select>
|
1447 |
-
|
1448 |
-
</fieldset>
|
1449 |
-
|
1450 |
-
<div id="blc-search-button-row">
|
1451 |
-
<input type="submit" value="<?php esc_attr_e( 'Search Links', 'broken-link-checker' ); ?>" id="blc-search-button" name="search_button" class="button-primary" />
|
1452 |
-
<input type="button" value="<?php esc_attr_e( 'Cancel', 'broken-link-checker' ); ?>" id="blc-cancel-search" class="button" />
|
1453 |
-
</div>
|
1454 |
-
|
1455 |
-
</form>
|
1456 |
-
</div>
|
1457 |
|
1458 |
-
<?php
|
1459 |
//Do we have any links to display?
|
1460 |
if( $links && ( count($links) > 0 ) ) {
|
1461 |
?>
|
@@ -1466,8 +1160,9 @@ class wsBrokenLinkChecker {
|
|
1466 |
|
1467 |
$bulk_actions = array(
|
1468 |
'-1' => __('Bulk Actions', 'broken-link-checker'),
|
1469 |
-
"bulk-
|
1470 |
"bulk-deredirect" => __('Fix redirects', 'broken-link-checker'),
|
|
|
1471 |
"bulk-delete-sources" => __('Delete sources', 'broken-link-checker'),
|
1472 |
);
|
1473 |
|
@@ -1476,10 +1171,10 @@ class wsBrokenLinkChecker {
|
|
1476 |
$bulk_actions_html .= sprintf('<option value="%s">%s</option>', $value, $name);
|
1477 |
}
|
1478 |
?>
|
1479 |
-
|
1480 |
<div class='tablenav'>
|
1481 |
<div class="alignleft actions">
|
1482 |
-
<select name="action">
|
1483 |
<?php echo $bulk_actions_html; ?>
|
1484 |
</select>
|
1485 |
<input type="submit" name="doaction" id="doaction" value="<?php echo attribute_escape(__('Apply', 'broken-link-checker')); ?>" class="button-secondary action">
|
@@ -1516,14 +1211,9 @@ class wsBrokenLinkChecker {
|
|
1516 |
<th scope="col" id="cb" class="check-column">
|
1517 |
<input type="checkbox">
|
1518 |
</th>
|
1519 |
-
<th scope="col"><?php _e('Source', 'broken-link-checker'); ?></th>
|
1520 |
-
<th scope="col"><?php _e('Link Text', 'broken-link-checker'); ?></th>
|
1521 |
-
<th scope="col"><?php _e('URL', 'broken-link-checker'); ?></th>
|
1522 |
-
|
1523 |
-
<?php if ( $show_discard_button ) { ?>
|
1524 |
-
<th scope="col"> </th>
|
1525 |
-
<?php } ?>
|
1526 |
-
|
1527 |
</tr>
|
1528 |
</thead>
|
1529 |
<tbody id="the-list">
|
@@ -1532,97 +1222,81 @@ class wsBrokenLinkChecker {
|
|
1532 |
foreach ($links as $link) {
|
1533 |
$rownum++;
|
1534 |
|
1535 |
-
$rowclass =
|
1536 |
-
$excluded = $this->is_excluded( $link
|
1537 |
if ( $excluded ) $rowclass .= ' blc-excluded-link';
|
1538 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1539 |
?>
|
1540 |
-
<tr id='<?php echo "blc-row
|
1541 |
|
1542 |
<th class="check-column" scope="row">
|
1543 |
-
<input type="checkbox" name="selected_links[]" value="<?php echo $link
|
1544 |
</th>
|
1545 |
|
1546 |
<td class='post-title column-title'>
|
1547 |
-
<span class='blc-link-id' style='display:none;'><?php echo $link
|
1548 |
-
|
1549 |
-
if ( ('post' == $link['source_type']) || ('custom_field' == $link['source_type']) ){
|
1550 |
-
|
1551 |
-
echo "<a class='row-title' href='post.php?action=edit&post=$link[source_id]' title='",
|
1552 |
-
attribute_escape(__('Edit this post')),
|
1553 |
-
"'>{$link[post_title]}</a>";
|
1554 |
-
|
1555 |
-
//Output inline action links (copied from edit-post-rows.php)
|
1556 |
-
$actions = array();
|
1557 |
-
if ( current_user_can('edit_post', $link['source_id']) ) {
|
1558 |
-
$actions['edit'] = '<span class="edit"><a href="' . get_edit_post_link($link['source_id'], true) . '" title="' . attribute_escape(__('Edit this post')) . '">' . __('Edit') . '</a>';
|
1559 |
-
$actions['delete'] = "<span class='delete'><a class='submitdelete' title='" . attribute_escape(__('Delete this post')) . "' href='" . wp_nonce_url("post.php?action=delete&post=".$link['source_id'], 'delete-post_' . $link['source_id']) . "' onclick=\"if ( confirm('" . js_escape(sprintf( __("You are about to delete this post '%s'\n 'Cancel' to stop, 'OK' to delete."), $link['post_title'] )) . "') ) { return true;}return false;\">" . __('Delete') . "</a>";
|
1560 |
-
}
|
1561 |
-
$actions['view'] = '<span class="view"><a href="' . get_permalink($link['source_id']) . '" title="' . attribute_escape(sprintf(__('View "%s"', 'broken-link-checker'), $link['post_title'])) . '" rel="permalink">' . __('View') . '</a>';
|
1562 |
-
echo '<div class="row-actions">';
|
1563 |
-
echo implode(' | </span>', $actions);
|
1564 |
-
echo '</div>';
|
1565 |
|
1566 |
-
|
1567 |
-
|
1568 |
-
|
1569 |
-
|
1570 |
-
|
1571 |
-
|
1572 |
-
if
|
1573 |
-
$
|
1574 |
-
|
|
|
|
|
|
|
|
|
1575 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1576 |
|
1577 |
echo '<div class="row-actions">';
|
1578 |
echo implode(' | </span>', $actions);
|
1579 |
echo '</div>';
|
1580 |
-
|
1581 |
-
} elseif ( empty($link['source_type']) ){
|
1582 |
-
|
1583 |
-
_e("[An orphaned link! This is a bug.]", 'broken-link-checker');
|
1584 |
|
1585 |
-
|
|
|
|
|
|
|
1586 |
?>
|
1587 |
</td>
|
1588 |
<td class='blc-link-text'><?php
|
1589 |
-
|
1590 |
-
|
1591 |
-
|
1592 |
-
|
1593 |
-
|
1594 |
-
printf(
|
1595 |
-
'<img src="%s/broken-link-checker/images/image.png" class="blc-small-image" alt="%2$s" title="%2$s"> %2$s',
|
1596 |
-
WP_PLUGIN_URL,
|
1597 |
-
__('Image', 'broken-link-checker')
|
1598 |
-
);
|
1599 |
-
} else {
|
1600 |
-
echo '[ ??? ]';
|
1601 |
-
}
|
1602 |
-
|
1603 |
-
} elseif ( 'custom_field' == $link['source_type'] ){
|
1604 |
-
|
1605 |
-
printf(
|
1606 |
-
'<img src="%s/broken-link-checker/images/script_code.png" class="blc-small-image" title="%2$s" alt="%2$s"> ',
|
1607 |
-
WP_PLUGIN_URL,
|
1608 |
-
__('Custom field', 'broken-link-checker')
|
1609 |
-
);
|
1610 |
-
echo "<code>".$link['link_text']."</code>";
|
1611 |
-
|
1612 |
-
} elseif ( 'blogroll' == $link['source_type'] ){
|
1613 |
-
printf(
|
1614 |
-
'<img src="%s/broken-link-checker/images/link.png" class="blc-small-image" title="%2$s" alt="%2$s"> %2$s',
|
1615 |
-
WP_PLUGIN_URL,
|
1616 |
-
__('Bookmark', 'broken-link-checker')
|
1617 |
-
);
|
1618 |
}
|
1619 |
?>
|
1620 |
</td>
|
1621 |
<td class='column-url'>
|
1622 |
-
<a href=
|
1623 |
-
<?php print
|
1624 |
<input type='text' id='link-editor-<?php print $rownum; ?>'
|
1625 |
-
value=
|
1626 |
class='blc-link-editor' style='display:none' />
|
1627 |
<?php
|
1628 |
//Output inline action links for the link/URL
|
@@ -1633,49 +1307,37 @@ class wsBrokenLinkChecker {
|
|
1633 |
$actions['delete'] = "<span class='delete'><a class='submitdelete blc-unlink-button' title='" . attribute_escape( __('Remove this link from all posts', 'broken-link-checker') ). "' ".
|
1634 |
"id='unlink-button-$rownum' href='javascript:void(0);'>" . __('Unlink', 'broken-link-checker') . "</a>";
|
1635 |
|
1636 |
-
if ( $
|
1637 |
-
$actions['
|
1638 |
-
|
1639 |
-
|
1640 |
-
|
|
|
1641 |
}
|
1642 |
|
1643 |
$actions['edit'] = "<span class='edit'><a href='javascript:void(0)' class='blc-edit-button' title='" . attribute_escape( __('Edit link URL' , 'broken-link-checker') ) . "'>". __('Edit URL' , 'broken-link-checker') ."</a>";
|
1644 |
-
|
1645 |
echo '<div class="row-actions">';
|
1646 |
echo implode(' | </span>', $actions);
|
1647 |
|
1648 |
-
echo "<span style='display:none' class='blc-cancel-button-container'> "
|
1649 |
"| <a href='javascript:void(0)' class='blc-cancel-button' title='". attribute_escape(__('Cancel URL editing' , 'broken-link-checker')) ."'>". __('Cancel' , 'broken-link-checker') ."</a></span>";
|
1650 |
-
|
1651 |
echo '</div>';
|
1652 |
?>
|
1653 |
</td>
|
1654 |
-
|
1655 |
-
//Display the "Discard" button when listing broken links
|
1656 |
-
if ( $show_discard_button ) {
|
1657 |
-
?>
|
1658 |
-
<td><a href='javascript:void(0);'
|
1659 |
-
id='discard_button-<?php print $rownum; ?>'
|
1660 |
-
class='blc-discard-button'
|
1661 |
-
title='<?php
|
1662 |
-
echo attribute_escape(
|
1663 |
-
__('Remove this link from the list of broken links and mark it as valid', 'broken-link-checker')
|
1664 |
-
);
|
1665 |
-
?>'><?php _e('Discard', 'broken-link-checker'); ?></a>
|
1666 |
-
</td>
|
1667 |
-
<?php } ?>
|
1668 |
</tr>
|
1669 |
<!-- Link details -->
|
1670 |
<tr id='<?php print "link-details-$rownum"; ?>' style='display:none;' class='blc-link-details'>
|
1671 |
-
<td colspan='
|
1672 |
</tr><?php
|
1673 |
}
|
1674 |
?></tbody></table>
|
1675 |
|
1676 |
<div class="tablenav">
|
1677 |
<div class="alignleft actions">
|
1678 |
-
<select name="action2">
|
1679 |
<?php echo $bulk_actions_html; ?>
|
1680 |
</select>
|
1681 |
<input type="submit" name="doaction2" id="doaction2" value="<?php echo attribute_escape(__('Apply', 'broken-link-checker')); ?>" class="button-secondary action">
|
@@ -1703,634 +1365,406 @@ class wsBrokenLinkChecker {
|
|
1703 |
|
1704 |
?>
|
1705 |
|
1706 |
-
<?php
|
|
|
|
|
|
|
1707 |
</div>
|
1708 |
<?php
|
1709 |
} //Function ends
|
1710 |
|
1711 |
-
|
1712 |
-
|
1713 |
-
|
1714 |
-
|
1715 |
-
|
1716 |
-
|
1717 |
-
|
1718 |
-
|
1719 |
-
|
1720 |
-
|
1721 |
-
|
1722 |
-
|
1723 |
-
|
1724 |
-
$(".blc-discard-button").click(function () {
|
1725 |
-
var me = this;
|
1726 |
-
$(me).html('<?php echo js_escape(__('Wait...', 'broken-link-checker')); ?>');
|
1727 |
-
|
1728 |
-
var link_id = $(me).parents('.blc-row').find('.blc-link-id').html();
|
1729 |
-
|
1730 |
-
$.post(
|
1731 |
-
"<?php echo admin_url('admin-ajax.php'); ?>",
|
1732 |
-
{
|
1733 |
-
'action' : 'blc_discard',
|
1734 |
-
'link_id' : link_id
|
1735 |
-
},
|
1736 |
-
function (data, textStatus){
|
1737 |
-
if (data == 'OK'){
|
1738 |
-
var master = $(me).parents('.blc-row');
|
1739 |
-
var details = master.next('.blc-link-details');
|
1740 |
-
|
1741 |
-
details.hide();
|
1742 |
-
//Flash the main row green to indicate success, then hide it.
|
1743 |
-
var oldColor = master.css('background-color');
|
1744 |
-
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300, function(){
|
1745 |
-
master.hide();
|
1746 |
-
});
|
1747 |
-
|
1748 |
-
alterLinkCounter(-1);
|
1749 |
-
} else {
|
1750 |
-
$(me).html('<?php echo js_escape(__('Discard' , 'broken-link-checker')); ?>');
|
1751 |
-
alert(data);
|
1752 |
-
}
|
1753 |
-
}
|
1754 |
-
);
|
1755 |
-
});
|
1756 |
-
|
1757 |
-
//The details button - display/hide detailed info about a link
|
1758 |
-
$(".blc-details-button, .blc-link-text").click(function () {
|
1759 |
-
$(this).parents('.blc-row').next('.blc-link-details').toggle();
|
1760 |
-
});
|
1761 |
-
|
1762 |
-
//The edit button - edit/save the link's URL
|
1763 |
-
$(".blc-edit-button").click(function () {
|
1764 |
-
var edit_button = $(this);
|
1765 |
-
var master = $(edit_button).parents('.blc-row');
|
1766 |
-
var editor = $(master).find('.blc-link-editor');
|
1767 |
-
var url_el = $(master).find('.blc-link-url');
|
1768 |
-
var cancel_button_container = $(master).find('.blc-cancel-button-container');
|
1769 |
-
|
1770 |
-
//Find the current/original URL
|
1771 |
-
var orig_url = url_el.attr('href');
|
1772 |
-
//Find the link ID
|
1773 |
-
var link_id = $(master).find('.blc-link-id').html();
|
1774 |
|
1775 |
-
|
1776 |
-
|
1777 |
-
|
1778 |
-
|
1779 |
-
|
1780 |
-
|
1781 |
-
|
1782 |
-
|
1783 |
-
|
1784 |
-
|
1785 |
-
|
1786 |
-
editor.hide();
|
1787 |
-
cancel_button_container.hide();
|
1788 |
-
url_el.show();
|
1789 |
|
1790 |
-
|
1791 |
-
|
1792 |
-
|
1793 |
-
|
1794 |
-
|
1795 |
-
|
1796 |
-
|
1797 |
-
|
1798 |
-
|
1799 |
-
'action' : 'blc_edit',
|
1800 |
-
'link_id' : link_id,
|
1801 |
-
'new_url' : new_url
|
1802 |
-
},
|
1803 |
-
function (data, textStatus){
|
1804 |
-
var display_url = '';
|
1805 |
-
|
1806 |
-
if ( data && (typeof(data['error']) != 'undefined') ){
|
1807 |
-
//data.error is an error message
|
1808 |
-
alert(data.error);
|
1809 |
-
display_url = orig_url;
|
1810 |
-
} else {
|
1811 |
-
//data contains info about the performed edit
|
1812 |
-
if ( data.cnt_okay > 0 ){
|
1813 |
-
display_url = new_url;
|
1814 |
-
|
1815 |
-
url_el.attr('href', new_url);
|
1816 |
-
|
1817 |
-
if ( data.cnt_error > 0 ){
|
1818 |
-
//TODO: Internationalize this error message
|
1819 |
-
var msg = "The link was successfully modifed.";
|
1820 |
-
msg = msg + "\nHowever, "+data.cnt_error+" instances couldn't be edited and still point to the old URL."
|
1821 |
-
alert(msg);
|
1822 |
-
} else {
|
1823 |
-
//Flash the row green to indicate success
|
1824 |
-
var oldColor = master.css('background-color');
|
1825 |
-
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300);
|
1826 |
-
|
1827 |
-
//Save the new ID
|
1828 |
-
master.find('.blc-link-id').html(data.new_link_id);
|
1829 |
-
//Load up the new link info (so sue me)
|
1830 |
-
master.next('.blc-link-details').find('td').html('<center><?php echo js_escape(__('Loading...' , 'broken-link-checker')); ?></center>').load(
|
1831 |
-
"<?php echo admin_url('admin-ajax.php'); ?>",
|
1832 |
-
{
|
1833 |
-
'action' : 'blc_link_details',
|
1834 |
-
'link_id' : data.new_link_id
|
1835 |
-
}
|
1836 |
-
);
|
1837 |
-
}
|
1838 |
-
} else {
|
1839 |
-
//TODO: Internationalize this error message
|
1840 |
-
alert("Something went wrong. The plugin failed to edit "+
|
1841 |
-
data.cnt_error + ' instance(s) of this link.');
|
1842 |
-
|
1843 |
-
display_url = orig_url;
|
1844 |
-
}
|
1845 |
-
};
|
1846 |
-
|
1847 |
-
//Shorten the displayed URL if it's > 50 characters
|
1848 |
-
if ( display_url.length > 50 ){
|
1849 |
-
display_url = display_url.substr(0, 47) + '...';
|
1850 |
-
}
|
1851 |
-
url_el.html(display_url);
|
1852 |
-
}
|
1853 |
-
);
|
1854 |
-
|
1855 |
-
} else {
|
1856 |
-
//It's the same URL, so do nothing.
|
1857 |
}
|
1858 |
-
edit_button.html('<?php echo js_escape(__('Edit URL', 'broken-link-checker')); ?>');
|
1859 |
-
}
|
1860 |
-
});
|
1861 |
-
|
1862 |
-
//Let the user use Enter and Esc as shortcuts for "Save URL" and "Cancel"
|
1863 |
-
$('input.blc-link-editor').keypress(function (e) {
|
1864 |
-
if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
|
1865 |
-
$(this).parents('.blc-row').find('.blc-edit-button').click();
|
1866 |
-
return false;
|
1867 |
-
} else if ((e.which && e.which == 27) || (e.keyCode && e.keyCode == 27)) {
|
1868 |
-
$(this).parents('.blc-row').find('.blc-cancel-button').click();
|
1869 |
-
return false;
|
1870 |
-
} else {
|
1871 |
-
return true;
|
1872 |
}
|
1873 |
-
});
|
1874 |
-
|
1875 |
-
$(".blc-cancel-button").click(function () {
|
1876 |
-
var master = $(this).parents('.blc-row');
|
1877 |
-
var url_el = $(master).find('.blc-link-url');
|
1878 |
-
|
1879 |
-
//Hide the cancel button
|
1880 |
-
$(this).parent().hide();
|
1881 |
-
//Show the un-editable URL again
|
1882 |
-
url_el.show();
|
1883 |
-
//reset and hide the editor
|
1884 |
-
master.find('.blc-link-editor').hide().val(url_el.attr('href'));
|
1885 |
-
//Set the edit button to say "Edit URL"
|
1886 |
-
master.find('.blc-edit-button').html('<?php echo js_escape(__('Edit URL' , 'broken-link-checker')); ?>');
|
1887 |
-
});
|
1888 |
-
|
1889 |
-
//The unlink button - remove the link/image from all posts, custom fields, etc.
|
1890 |
-
$(".blc-unlink-button").click(function () {
|
1891 |
-
var me = this;
|
1892 |
-
var master = $(me).parents('.blc-row');
|
1893 |
-
$(me).html('<?php echo js_escape(__('Wait...' , 'broken-link-checker')); ?>');
|
1894 |
|
1895 |
-
|
1896 |
-
|
1897 |
-
$.post(
|
1898 |
-
"<?php echo admin_url('admin-ajax.php'); ?>",
|
1899 |
-
{
|
1900 |
-
'action' : 'blc_unlink',
|
1901 |
-
'link_id' : link_id
|
1902 |
-
},
|
1903 |
-
function (data, textStatus){
|
1904 |
-
eval('data = ' + data);
|
1905 |
-
|
1906 |
-
if ( data && ( typeof(data['ok']) != 'undefined') ){
|
1907 |
-
//Hide the details
|
1908 |
-
master.next('.blc-link-details').hide();
|
1909 |
-
//Flash the main row green to indicate success, then hide it.
|
1910 |
-
var oldColor = master.css('background-color');
|
1911 |
-
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300, function(){
|
1912 |
-
master.hide();
|
1913 |
-
});
|
1914 |
-
|
1915 |
-
alterLinkCounter(-1);
|
1916 |
-
} else {
|
1917 |
-
$(me).html('<?php echo js_escape(__('Unlink' , 'broken-link-checker')); ?>');
|
1918 |
-
//Show the error message
|
1919 |
-
alert(data.error);
|
1920 |
-
}
|
1921 |
-
}
|
1922 |
-
);
|
1923 |
-
});
|
1924 |
-
|
1925 |
-
//The exclude button - Add this link to the exclusion list
|
1926 |
-
$(".blc-exclude-button").click(function () {
|
1927 |
-
var me = this;
|
1928 |
-
var master = $(me).parents('.blc-row');
|
1929 |
-
var details = master.next('.blc-link-details');
|
1930 |
-
$(me).html('<?php echo js_escape(__('Wait...' , 'broken-link-checker')); ?>');
|
1931 |
-
|
1932 |
-
var link_id = $(me).parents('.blc-row').find('.blc-link-id').html();
|
1933 |
-
|
1934 |
-
$.post(
|
1935 |
-
"<?php echo admin_url('admin-ajax.php'); ?>",
|
1936 |
-
{
|
1937 |
-
'action' : 'blc_exclude_link',
|
1938 |
-
'link_id' : link_id
|
1939 |
-
},
|
1940 |
-
function (data, textStatus){
|
1941 |
-
eval('data = ' + data);
|
1942 |
-
|
1943 |
-
if ( data && ( typeof(data['ok']) != 'undefined' ) ){
|
1944 |
-
|
1945 |
-
if ( 'broken' == blc_current_filter ){
|
1946 |
-
//Flash the row green to indicate success, then hide it.
|
1947 |
-
$(me).replaceWith('<?php echo js_escape(__('Excluded' , 'broken-link-checker')); ?>');
|
1948 |
-
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: '#E2E2E2' }, 200, function(){
|
1949 |
-
details.hide();
|
1950 |
-
master.hide();
|
1951 |
-
alterLinkCounter(-1);
|
1952 |
-
});
|
1953 |
-
master.addClass('blc-excluded-link');
|
1954 |
-
} else {
|
1955 |
-
//Flash the row green to indicate success and fade to the "excluded link" color
|
1956 |
-
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: '#E2E2E2' }, 300);
|
1957 |
-
master.addClass('blc-excluded-link');
|
1958 |
-
$(me).replaceWith('<?php echo js_escape(__('Excluded' , 'broken-link-checker')); ?>');
|
1959 |
-
}
|
1960 |
-
} else {
|
1961 |
-
$(me).html('<?php echo js_escape(__('Exclude' , 'broken-link-checker')); ?>');
|
1962 |
-
alert(data.error);
|
1963 |
-
}
|
1964 |
-
}
|
1965 |
-
);
|
1966 |
-
});
|
1967 |
-
|
1968 |
-
//--------------------------------------------
|
1969 |
-
//The search box(es)
|
1970 |
-
//--------------------------------------------
|
1971 |
-
|
1972 |
-
var searchForm = $('#search-links-dialog');
|
1973 |
-
|
1974 |
-
searchForm.dialog({
|
1975 |
-
autoOpen : false,
|
1976 |
-
dialogClass : 'blc-search-container',
|
1977 |
-
resizable: false,
|
1978 |
-
});
|
1979 |
-
|
1980 |
-
$('#blc-open-search-box').click(function(){
|
1981 |
-
if ( searchForm.dialog('isOpen') ){
|
1982 |
-
searchForm.dialog('close');
|
1983 |
-
} else {
|
1984 |
-
var button_position = $('#blc-open-search-box').offset();
|
1985 |
-
var button_height = $('#blc-open-search-box').outerHeight(true);
|
1986 |
-
var button_width = $('#blc-open-search-box').outerWidth(true);
|
1987 |
-
|
1988 |
-
var dialog_width = searchForm.dialog('option', 'width');
|
1989 |
-
|
1990 |
-
searchForm.dialog('option', 'position',
|
1991 |
-
[
|
1992 |
-
button_position.left - dialog_width + button_width/2,
|
1993 |
-
button_position.top + button_height + 1 - $(document).scrollTop()
|
1994 |
-
]
|
1995 |
-
);
|
1996 |
-
searchForm.dialog('open');
|
1997 |
-
}
|
1998 |
-
});
|
1999 |
-
|
2000 |
-
$('#blc-cancel-search').click(function(){
|
2001 |
-
searchForm.dialog('close');
|
2002 |
-
});
|
2003 |
-
|
2004 |
-
//The "Save This Search Query" button creates a new custom filter based on the current search
|
2005 |
-
$('#blc-create-filter').click(function(){
|
2006 |
-
var filter_name = prompt("<?php echo js_escape(__("Enter a name for the new custom filter", 'broken-link-checker')); ?>", "");
|
2007 |
-
if ( filter_name ){
|
2008 |
-
$('#blc-custom-filter-name').val(filter_name);
|
2009 |
-
$('#custom-filter-form').submit();
|
2010 |
-
}
|
2011 |
-
});
|
2012 |
-
|
2013 |
-
//Display a confirmation dialog when the user clicks the "Delete This Filter" button
|
2014 |
-
$('#blc-delete-filter').click(function(){
|
2015 |
-
if ( confirm('<?php
|
2016 |
-
echo js_escape(
|
2017 |
-
__("You are about to delete the current filter.\n'Cancel' to stop, 'OK' to delete", 'broken-link-checker')
|
2018 |
-
);
|
2019 |
-
?>') ){
|
2020 |
-
return true;
|
2021 |
-
} else {
|
2022 |
-
return false;
|
2023 |
-
}
|
2024 |
-
});
|
2025 |
-
|
2026 |
-
//--------------------------------------------
|
2027 |
-
// Bulk actions
|
2028 |
-
//--------------------------------------------
|
2029 |
-
|
2030 |
-
//Not implemented yet
|
2031 |
-
});
|
2032 |
-
|
2033 |
-
</script>
|
2034 |
-
<?php
|
2035 |
-
}
|
2036 |
-
|
2037 |
-
function links_page_css(){
|
2038 |
-
?>
|
2039 |
-
<style type='text/css'>
|
2040 |
-
.blc-link-editor {
|
2041 |
-
font-size: 1em;
|
2042 |
-
width: 95%;
|
2043 |
-
}
|
2044 |
-
|
2045 |
-
.blc-excluded-link {
|
2046 |
-
background-color: #E2E2E2;
|
2047 |
-
}
|
2048 |
-
|
2049 |
-
.blc-small-image {
|
2050 |
-
display : block;
|
2051 |
-
float: left;
|
2052 |
-
padding-top: 2px;
|
2053 |
-
margin-right: 3px;
|
2054 |
-
}
|
2055 |
-
|
2056 |
-
.blc-search-container {
|
2057 |
-
background : white !important;
|
2058 |
-
border: 3px solid #EEEEEE;
|
2059 |
-
padding: 12px;
|
2060 |
-
}
|
2061 |
-
|
2062 |
-
.blc-search-container .ui-dialog-titlebar {
|
2063 |
-
display: none;
|
2064 |
-
margin: 0px;
|
2065 |
-
}
|
2066 |
-
|
2067 |
-
#search-links-dialog {
|
2068 |
-
display: none;
|
2069 |
-
}
|
2070 |
-
|
2071 |
-
#search-links-dialog label, #search-links-dialog input.text, #search-links-dialog select { display:block; }
|
2072 |
-
#search-links-dialog input.text { margin-bottom:12px; width:95%; padding: .4em; }
|
2073 |
-
#search-links-dialog select { margin-bottom:12px; padding: .4em; }
|
2074 |
-
#search-links-dialog fieldset { padding:0; border:0; margin-top:25px; }
|
2075 |
-
|
2076 |
-
#blc-search-button-row {
|
2077 |
-
text-align: center;
|
2078 |
-
}
|
2079 |
-
|
2080 |
-
#blc-search-button-row input {
|
2081 |
-
padding: 0.4em;
|
2082 |
-
margin-left: 8px;
|
2083 |
-
margin-right: 8px;
|
2084 |
-
margin-top: 8px;
|
2085 |
-
}
|
2086 |
-
|
2087 |
-
.blc-inline-form {
|
2088 |
-
display: inline;
|
2089 |
-
}
|
2090 |
-
|
2091 |
-
div.search-box{
|
2092 |
-
float: right;
|
2093 |
-
margin-top: -5px;
|
2094 |
-
margin-right: 0pt;
|
2095 |
-
margin-bottom: 0pt;
|
2096 |
-
margin-left: 0pt;
|
2097 |
-
}
|
2098 |
-
</style>
|
2099 |
-
<?php
|
2100 |
}
|
2101 |
|
2102 |
-
function link_details_row($link){
|
2103 |
-
?>
|
2104 |
-
<span id='post_date_full' style='display:none;'><?php
|
2105 |
-
|
2106 |
-
print $link['post_date'];
|
2107 |
-
|
2108 |
-
?></span>
|
2109 |
-
<span id='check_date_full' style='display:none;'><?php
|
2110 |
-
print $link['last_check'];
|
2111 |
-
?></span>
|
2112 |
-
<ol style='list-style-type: none; width: 50%; float: right;'>
|
2113 |
-
<li><strong><?php _e('Log', 'broken-link-checker'); ?> :</strong>
|
2114 |
-
<span class='blc_log'><?php
|
2115 |
-
print nl2br($link['log']);
|
2116 |
-
?></span></li>
|
2117 |
-
</ol>
|
2118 |
-
|
2119 |
-
<ol style='list-style-type: none; padding-left: 2px;'>
|
2120 |
-
<?php if ( !empty($link['post_date']) ) { ?>
|
2121 |
-
<li><strong><?php _e('Post published on', 'broken-link-checker'); ?> :</strong>
|
2122 |
-
<span class='post_date'><?php
|
2123 |
-
echo date_i18n(get_option('date_format'),strtotime($link['post_date']));
|
2124 |
-
?></span></li>
|
2125 |
-
<?php } ?>
|
2126 |
-
<li><strong><?php _e('Link last checked', 'broken-link-checker'); ?> :</strong>
|
2127 |
-
<span class='check_date'><?php
|
2128 |
-
$last_check = strtotime($link['last_check']);
|
2129 |
-
if ( $last_check < strtotime('-10 years') ){
|
2130 |
-
_e('Never', 'broken-link-checker');
|
2131 |
-
} else {
|
2132 |
-
echo date_i18n(get_option('date_format'), $last_check);
|
2133 |
-
}
|
2134 |
-
?></span></li>
|
2135 |
-
|
2136 |
-
<li><strong><?php _e('HTTP code', 'broken-link-checker'); ?> :</strong>
|
2137 |
-
<span class='http_code'><?php
|
2138 |
-
print $link['http_code'];
|
2139 |
-
?></span></li>
|
2140 |
-
|
2141 |
-
<li><strong><?php _e('Response time', 'broken-link-checker'); ?> :</strong>
|
2142 |
-
<span class='request_duration'><?php
|
2143 |
-
printf( __('%2.3f seconds', 'broken-link-checker'), $link['request_duration']);
|
2144 |
-
?></span></li>
|
2145 |
-
|
2146 |
-
<li><strong><?php _e('Final URL', 'broken-link-checker'); ?> :</strong>
|
2147 |
-
<span class='final_url'><?php
|
2148 |
-
print $link['final_url'];
|
2149 |
-
?></span></li>
|
2150 |
-
|
2151 |
-
<li><strong><?php _e('Redirect count', 'broken-link-checker'); ?> :</strong>
|
2152 |
-
<span class='redirect_count'><?php
|
2153 |
-
print $link['redirect_count'];
|
2154 |
-
?></span></li>
|
2155 |
-
|
2156 |
-
<li><strong><?php _e('Instance count', 'broken-link-checker'); ?> :</strong>
|
2157 |
-
<span class='instance_count'><?php
|
2158 |
-
print $link['instance_count'];
|
2159 |
-
?></span></li>
|
2160 |
-
|
2161 |
-
<?php if ( intval( $link['check_count'] ) > 0 ){ ?>
|
2162 |
-
<li><br/>
|
2163 |
-
<?php
|
2164 |
-
printf(
|
2165 |
-
_n('This link has failed %d time.', 'This link has failed %d times.', $link['check_count'], 'broken-link-checker'),
|
2166 |
-
$link['check_count']
|
2167 |
-
);
|
2168 |
-
?>
|
2169 |
-
</li>
|
2170 |
-
<?php } ?>
|
2171 |
-
</ol>
|
2172 |
-
<?php
|
2173 |
-
}
|
2174 |
-
|
2175 |
/**
|
2176 |
-
*
|
2177 |
-
* Remove orphaned links that have no corresponding instances
|
2178 |
*
|
2179 |
-
* @
|
2180 |
-
*
|
|
|
2181 |
*/
|
2182 |
-
|
2183 |
-
|
2184 |
-
|
2185 |
-
|
2186 |
-
|
2187 |
-
|
2188 |
-
|
2189 |
-
|
2190 |
-
|
2191 |
-
|
2192 |
-
|
2193 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2194 |
}
|
2195 |
-
$q .= " AND {$wpdb->prefix}blc_links.link_id IN (" . implode(', ', $link_id) . ')';
|
2196 |
}
|
2197 |
|
2198 |
-
return $
|
2199 |
}
|
2200 |
|
2201 |
/**
|
2202 |
-
*
|
2203 |
-
* Remove instances that reference invalid posts or bookmarks
|
2204 |
*
|
2205 |
-
* @
|
|
|
2206 |
*/
|
2207 |
-
function
|
2208 |
-
|
2209 |
|
2210 |
-
|
2211 |
-
$
|
2212 |
-
|
2213 |
-
|
2214 |
-
|
2215 |
-
|
2216 |
-
|
2217 |
-
|
2218 |
-
|
2219 |
-
|
2220 |
-
|
2221 |
-
|
2222 |
-
|
2223 |
-
|
2224 |
-
|
2225 |
-
|
2226 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2227 |
}
|
2228 |
|
2229 |
/**
|
2230 |
-
*
|
2231 |
-
* Parse a post for links and save them to the DB.
|
2232 |
*
|
2233 |
-
* @param
|
2234 |
-
* @
|
2235 |
-
* @return void
|
2236 |
*/
|
2237 |
-
function
|
2238 |
-
//
|
2239 |
-
$
|
2240 |
-
|
2241 |
-
|
2242 |
-
|
2243 |
-
//Find links
|
2244 |
-
if(preg_match_all(blcUtility::link_pattern(), $content, $matches, PREG_SET_ORDER)){
|
2245 |
-
foreach($matches as $link){
|
2246 |
-
$url = $link[3];
|
2247 |
-
$text = strip_tags( $link[5] );
|
2248 |
-
//FB::log($url, "Found link");
|
2249 |
-
|
2250 |
-
$url = blcUtility::normalize_url($url, $permalink);
|
2251 |
-
//Skip invalid links
|
2252 |
-
if ( !$url || (strlen($url)<6) ) continue;
|
2253 |
-
|
2254 |
-
//Create or load the link
|
2255 |
-
$link_obj = new blcLink($url);
|
2256 |
-
//Add & save a new instance
|
2257 |
-
$link_obj->add_instance($post_id, 'post', $text, 'link');
|
2258 |
-
}
|
2259 |
-
};
|
2260 |
|
2261 |
-
|
2262 |
-
|
2263 |
-
|
2264 |
-
|
2265 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
2266 |
|
2267 |
-
|
2268 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2269 |
|
2270 |
-
|
2271 |
-
|
2272 |
-
|
2273 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2274 |
}
|
2275 |
-
}
|
|
|
|
|
2276 |
}
|
2277 |
|
2278 |
/**
|
2279 |
-
*
|
2280 |
-
* Parse a post's custom fields for links and save them in the DB.
|
2281 |
*
|
2282 |
-
* @param
|
2283 |
-
* @return
|
2284 |
*/
|
2285 |
-
function
|
2286 |
-
|
2287 |
-
|
2288 |
-
|
2289 |
-
|
2290 |
-
|
2291 |
-
|
2292 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2293 |
|
2294 |
-
//
|
|
|
|
|
|
|
|
|
2295 |
|
2296 |
-
|
2297 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2298 |
|
2299 |
-
|
2300 |
-
|
2301 |
-
//If this is a multiline field take the first line (workaround for the enclosure field).
|
2302 |
-
$value = trim( array_shift( explode("\n", $value) ) );
|
2303 |
|
2304 |
-
|
2305 |
-
|
2306 |
-
|
2307 |
-
|
2308 |
-
continue;
|
2309 |
-
}
|
2310 |
|
2311 |
-
|
2312 |
-
|
2313 |
-
|
2314 |
-
|
2315 |
-
|
2316 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2317 |
}
|
2318 |
|
|
|
2319 |
}
|
2320 |
|
2321 |
-
|
2322 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
2323 |
|
2324 |
-
|
2325 |
-
$
|
2326 |
-
|
2327 |
-
|
2328 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2329 |
}
|
2330 |
|
2331 |
-
|
2332 |
-
|
2333 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2334 |
}
|
2335 |
|
2336 |
function start_timer(){
|
@@ -2342,7 +1776,6 @@ div.search-box{
|
|
2342 |
}
|
2343 |
|
2344 |
/**
|
2345 |
-
* ws_broken_link_checker::work()
|
2346 |
* The main worker function that does all kinds of things.
|
2347 |
*
|
2348 |
* @return void
|
@@ -2350,9 +1783,20 @@ div.search-box{
|
|
2350 |
function work(){
|
2351 |
global $wpdb;
|
2352 |
|
|
|
|
|
|
|
|
|
|
|
|
|
2353 |
if ( !$this->acquire_lock() ){
|
2354 |
//FB::warn("Another instance of BLC is already working. Stop.");
|
2355 |
-
return
|
|
|
|
|
|
|
|
|
|
|
2356 |
}
|
2357 |
|
2358 |
$this->start_timer();
|
@@ -2379,8 +1823,8 @@ div.search-box{
|
|
2379 |
//Close the connection as per http://www.php.net/manual/en/features.connection-handling.php#71172
|
2380 |
//This reduces resource usage and may solve the mysterious slowdowns certain users have
|
2381 |
//encountered when activating the plugin.
|
2382 |
-
//(
|
2383 |
-
if ( !
|
2384 |
ob_end_clean();
|
2385 |
header("Connection: close");
|
2386 |
ob_start();
|
@@ -2391,111 +1835,46 @@ div.search-box{
|
|
2391 |
flush(); // Unless both are called !
|
2392 |
}
|
2393 |
|
2394 |
-
$check_threshold = date('Y-m-d H:i:s', strtotime('-'.$this->conf->options['check_threshold'].' hours'));
|
2395 |
-
$recheck_threshold = date('Y-m-d H:i:s', strtotime('-20 minutes'));
|
2396 |
-
|
2397 |
$orphans_possible = false;
|
2398 |
-
|
2399 |
$still_need_resynch = $this->conf->options['need_resynch'];
|
2400 |
|
2401 |
/*****************************************
|
2402 |
Parse posts and bookmarks
|
2403 |
******************************************/
|
2404 |
|
2405 |
-
if ( $
|
2406 |
-
|
2407 |
-
//FB::log("Looking for posts and bookmarks that need parsing...");
|
2408 |
|
2409 |
-
|
2410 |
-
$tposts = $wpdb->posts;
|
2411 |
-
$tlinks = $wpdb->links;
|
2412 |
|
2413 |
-
$
|
2414 |
-
|
2415 |
-
|
2416 |
-
|
2417 |
-
|
2418 |
-
|
2419 |
-
ON ($tlinks.link_id = $tsynch.source_id AND $tsynch.source_type='blogroll')
|
2420 |
-
|
2421 |
-
WHERE
|
2422 |
-
$tsynch.synched = 0
|
2423 |
-
|
2424 |
-
LIMIT 50";
|
2425 |
-
|
2426 |
-
while ( $rows = $wpdb->get_results($synch_q, ARRAY_A) ) {
|
2427 |
-
|
2428 |
-
//FB::log("Found ".count($rows)." items to analyze.");
|
2429 |
-
|
2430 |
-
foreach ($rows as $row) {
|
2431 |
-
|
2432 |
-
if ( $row['source_type'] == 'post' ){
|
2433 |
-
|
2434 |
-
//FB::log("Parsing post ".$row['source_id']);
|
2435 |
-
|
2436 |
-
//Remove instances associated with this post
|
2437 |
-
$q = "DELETE FROM {$wpdb->prefix}blc_instances
|
2438 |
-
WHERE source_id = %d AND (source_type = 'post' OR source_type='custom_field')";
|
2439 |
-
$q = $wpdb->prepare($q, intval($row['source_id']));
|
2440 |
-
|
2441 |
-
//FB::log($q, "Executing query");
|
2442 |
-
|
2443 |
-
if ( $wpdb->query( $q ) === false ){
|
2444 |
-
//FB::error($wpdb->last_error, "Database error");
|
2445 |
-
}
|
2446 |
-
|
2447 |
-
//Gather links and images from the post
|
2448 |
-
$this->parse_post( $row['post_content'], $row['source_id'] );
|
2449 |
-
//Gather links from custom fields
|
2450 |
-
$this->parse_post_meta( $row['source_id'] );
|
2451 |
-
|
2452 |
-
//Some link records might be orhpaned now
|
2453 |
-
$orphans_possible = true;
|
2454 |
-
|
2455 |
-
} else {
|
2456 |
-
|
2457 |
-
//FB::log("Parsing bookmark ".$row['source_id']);
|
2458 |
-
|
2459 |
-
//Remove instances associated with this bookmark
|
2460 |
-
$q = "DELETE FROM {$wpdb->prefix}blc_instances
|
2461 |
-
WHERE source_id = %d AND source_type = 'blogroll'";
|
2462 |
-
$q = $wpdb->prepare($q, intval($row['source_id']));
|
2463 |
-
//FB::log($q, "Executing query");
|
2464 |
-
|
2465 |
-
if ( $wpdb->query( $q ) === false ){
|
2466 |
-
//FB::error($wpdb->last_error, "Database error");
|
2467 |
-
}
|
2468 |
-
|
2469 |
-
//(Re)add the instance and link
|
2470 |
-
$this->parse_blogroll_link( $row );
|
2471 |
-
|
2472 |
-
//Some link records might be orhpaned now
|
2473 |
-
$orphans_possible = true;
|
2474 |
-
|
2475 |
-
}
|
2476 |
|
2477 |
-
//
|
2478 |
-
$this->mark_synched( $row['source_id'], $row['source_type'] );
|
2479 |
-
|
2480 |
-
//Check if we still have some execution time left
|
2481 |
if( $this->execution_time() > $max_execution_time ){
|
2482 |
//FB::log('The alloted execution time has run out');
|
2483 |
-
|
2484 |
$this->release_lock();
|
2485 |
return;
|
2486 |
}
|
2487 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2488 |
}
|
2489 |
-
|
2490 |
}
|
2491 |
|
2492 |
//FB::log('No unparsed items found.');
|
2493 |
$still_need_resynch = false;
|
2494 |
|
2495 |
-
if ( $wpdb->last_error ){
|
2496 |
-
//FB::error($wpdb->last_error, "Database error");
|
2497 |
-
}
|
2498 |
-
|
2499 |
} else {
|
2500 |
//FB::log('Resynch not required.');
|
2501 |
}
|
@@ -2514,7 +1893,7 @@ div.search-box{
|
|
2514 |
|
2515 |
if ( $orphans_possible ) {
|
2516 |
//FB::log('Cleaning up the link table.');
|
2517 |
-
|
2518 |
}
|
2519 |
|
2520 |
//Check if we still have some execution time left
|
@@ -2524,56 +1903,31 @@ div.search-box{
|
|
2524 |
return;
|
2525 |
}
|
2526 |
|
|
|
|
|
|
|
|
|
|
|
|
|
2527 |
/*****************************************
|
2528 |
Check links
|
2529 |
******************************************/
|
2530 |
-
|
2531 |
-
|
2532 |
-
//Select some links that haven't been checked for a long time or
|
2533 |
-
//that are broken and need to be re-checked again.
|
2534 |
-
|
2535 |
-
//Note : This is a slow query, but AFAIK there is no way to speed it up.
|
2536 |
-
//I could put an index on last_check, but that value is almost certainly unique
|
2537 |
-
//for each row so it wouldn't be much better than a full table scan.
|
2538 |
-
$q = "SELECT *, ( last_check < %s ) AS meets_check_threshold
|
2539 |
-
FROM {$wpdb->prefix}blc_links
|
2540 |
-
WHERE
|
2541 |
-
( last_check < %s )
|
2542 |
-
OR
|
2543 |
-
(
|
2544 |
-
( http_code >= 400 OR http_code < 200 OR timeout = 1)
|
2545 |
-
AND check_count < %d
|
2546 |
-
AND check_count > 0
|
2547 |
-
AND last_check < %s
|
2548 |
-
)
|
2549 |
-
ORDER BY last_check ASC
|
2550 |
-
LIMIT 50";
|
2551 |
-
$link_q = $wpdb->prepare($q, $check_threshold, $check_threshold, $this->conf->options['recheck_count'], $recheck_threshold);
|
2552 |
-
//FB::log($link_q);
|
2553 |
|
2554 |
-
|
2555 |
-
|
2556 |
-
//some unchecked links found
|
2557 |
//FB::log("Checking ".count($links)." link(s)");
|
2558 |
|
2559 |
foreach ($links as $link) {
|
2560 |
-
|
2561 |
-
|
2562 |
-
|
2563 |
-
|
2564 |
-
//
|
2565 |
-
|
2566 |
-
$link_obj->check( $this->conf->options['timeout'] );
|
2567 |
-
$link_obj->save();
|
2568 |
} else {
|
2569 |
-
//
|
2570 |
-
|
2571 |
-
$
|
2572 |
-
$link_obj->http_code = 200; //Use a fake code so that the link doesn't show up in queries looking for broken links.
|
2573 |
-
$link_obj->timeout = false;
|
2574 |
-
$link_obj->request_duration = 0;
|
2575 |
-
$link_obj->log = __("This link wasn't checked because a matching keyword was found on your exclusion list.", 'broken-link-checker');
|
2576 |
-
$link_obj->save();
|
2577 |
}
|
2578 |
|
2579 |
//Check if we still have some execution time left
|
@@ -2582,7 +1936,15 @@ div.search-box{
|
|
2582 |
$this->release_lock();
|
2583 |
return;
|
2584 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2585 |
}
|
|
|
2586 |
}
|
2587 |
//FB::log('No links need to be checked right now.');
|
2588 |
|
@@ -2590,6 +1952,98 @@ div.search-box{
|
|
2590 |
//FB::log('All done.');
|
2591 |
}
|
2592 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2593 |
function ajax_full_status( ){
|
2594 |
$status = $this->get_status();
|
2595 |
$text = $this->status_text( $status );
|
@@ -2603,7 +2057,6 @@ div.search-box{
|
|
2603 |
}
|
2604 |
|
2605 |
/**
|
2606 |
-
* ws_broken_link_checker::status_text()
|
2607 |
* Generates a status message based on the status info in $status
|
2608 |
*
|
2609 |
* @param array $status
|
@@ -2658,9 +2111,31 @@ div.search-box{
|
|
2658 |
return $text;
|
2659 |
}
|
2660 |
|
|
|
|
|
|
|
|
|
|
|
2661 |
function ajax_dashboard_status(){
|
2662 |
//Just display the full status.
|
2663 |
-
$this->ajax_full_status(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2664 |
}
|
2665 |
|
2666 |
/**
|
@@ -2676,10 +2151,10 @@ div.search-box{
|
|
2676 |
* @return array
|
2677 |
*/
|
2678 |
function get_status(){
|
2679 |
-
global $wpdb;
|
2680 |
|
2681 |
$check_threshold=date('Y-m-d H:i:s', strtotime('-'.$this->conf->options['check_threshold'].' hours'));
|
2682 |
-
$recheck_threshold=date('Y-m-d H:i:s',
|
2683 |
|
2684 |
$q = "SELECT count(*) FROM {$wpdb->prefix}blc_links WHERE 1";
|
2685 |
$known_links = $wpdb->get_var($q);
|
@@ -2687,22 +2162,9 @@ div.search-box{
|
|
2687 |
$q = "SELECT count(*) FROM {$wpdb->prefix}blc_instances WHERE 1";
|
2688 |
$known_instances = $wpdb->get_var($q);
|
2689 |
|
2690 |
-
|
2691 |
-
$q = "SELECT count(*) FROM {$wpdb->prefix}blc_links
|
2692 |
-
WHERE check_count > 0 AND ( http_code < 200 OR http_code >= 400 OR timeout = 1 ) AND ( http_code <> ".BLC_CHECKING." )";
|
2693 |
-
$broken_links = $wpdb->get_var($q);
|
2694 |
-
*/
|
2695 |
-
$broken_links = $this->get_links( $this->native_filters['broken'], 0, 0, true );
|
2696 |
|
2697 |
-
$
|
2698 |
-
WHERE
|
2699 |
-
( ( last_check < '$check_threshold' ) OR
|
2700 |
-
(
|
2701 |
-
( http_code >= 400 OR http_code < 200 )
|
2702 |
-
AND check_count < 3
|
2703 |
-
AND last_check < '$recheck_threshold' )
|
2704 |
-
)";
|
2705 |
-
$unchecked_links = $wpdb->get_var($q);
|
2706 |
|
2707 |
return array(
|
2708 |
'check_threshold' => $check_threshold,
|
@@ -2720,9 +2182,13 @@ div.search-box{
|
|
2720 |
die();
|
2721 |
}
|
2722 |
|
|
|
|
|
|
|
|
|
|
|
2723 |
function ajax_discard(){
|
2724 |
-
|
2725 |
-
if (!current_user_can('edit_others_posts')){
|
2726 |
die( __("You're not allowed to do that!", 'broken-link-checker') );
|
2727 |
}
|
2728 |
|
@@ -2734,11 +2200,10 @@ div.search-box{
|
|
2734 |
printf( __("Oops, I can't find the link %d", 'broken-link-checker'), intval($_POST['link_id']) );
|
2735 |
die();
|
2736 |
}
|
2737 |
-
//Make it appear "not broken"
|
2738 |
-
$link->
|
2739 |
-
$link->
|
2740 |
-
$link->
|
2741 |
-
$link->check_count = 0;
|
2742 |
$link->log = __("This link was manually marked as working by the user.", 'broken-link-checker');
|
2743 |
|
2744 |
//Save the changes
|
@@ -2752,8 +2217,13 @@ div.search-box{
|
|
2752 |
}
|
2753 |
}
|
2754 |
|
|
|
|
|
|
|
|
|
|
|
2755 |
function ajax_edit(){
|
2756 |
-
if (!current_user_can('edit_others_posts')){
|
2757 |
die( json_encode( array(
|
2758 |
'error' => __("You're not allowed to do that!", 'broken-link-checker')
|
2759 |
)));
|
@@ -2769,23 +2239,37 @@ div.search-box{
|
|
2769 |
)));
|
2770 |
}
|
2771 |
|
2772 |
-
$new_url =
|
2773 |
-
|
|
|
|
|
|
|
2774 |
die( json_encode( array(
|
2775 |
'error' => __("Oops, the new URL is invalid!", 'broken-link-checker')
|
2776 |
)));
|
2777 |
}
|
2778 |
|
2779 |
//Try and edit the link
|
|
|
|
|
2780 |
$rez = $link->edit($new_url);
|
2781 |
|
2782 |
-
if ( $rez
|
2783 |
die( json_encode( array(
|
2784 |
'error' => __("An unexpected error occured!", 'broken-link-checker')
|
2785 |
)));
|
2786 |
} else {
|
2787 |
-
$
|
2788 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2789 |
}
|
2790 |
|
2791 |
} else {
|
@@ -2795,8 +2279,14 @@ div.search-box{
|
|
2795 |
}
|
2796 |
}
|
2797 |
|
|
|
|
|
|
|
|
|
|
|
|
|
2798 |
function ajax_unlink(){
|
2799 |
-
if (!current_user_can('edit_others_posts')){
|
2800 |
die( json_encode( array(
|
2801 |
'error' => __("You're not allowed to do that!", 'broken-link-checker')
|
2802 |
)));
|
@@ -2813,14 +2303,23 @@ div.search-box{
|
|
2813 |
}
|
2814 |
|
2815 |
//Try and unlink it
|
2816 |
-
|
|
|
|
|
2817 |
die( json_encode( array(
|
2818 |
-
'
|
2819 |
)));
|
2820 |
} else {
|
2821 |
-
|
2822 |
-
'
|
2823 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2824 |
}
|
2825 |
|
2826 |
} else {
|
@@ -2850,76 +2349,20 @@ div.search-box{
|
|
2850 |
die( __('Error : link ID not specified', 'broken-link-checker') );
|
2851 |
}
|
2852 |
|
2853 |
-
//Load the link.
|
2854 |
-
|
2855 |
-
$q = "SELECT
|
2856 |
-
links.*,
|
2857 |
-
COUNT(*) as instance_count
|
2858 |
-
|
2859 |
-
FROM
|
2860 |
-
{$wpdb->prefix}blc_links AS links,
|
2861 |
-
{$wpdb->prefix}blc_instances as instances
|
2862 |
-
|
2863 |
-
WHERE
|
2864 |
-
links.link_id = %d
|
2865 |
-
|
2866 |
-
GROUP BY links.link_id";
|
2867 |
|
2868 |
-
|
2869 |
-
if ( is_array($link) ){
|
2870 |
//FB::info($link, 'Link loaded');
|
2871 |
$this->link_details_row($link);
|
2872 |
die();
|
2873 |
} else {
|
2874 |
printf( __('Failed to load link details (%s)', 'broken-link-checker'), $wpdb->last_error );
|
2875 |
-
die
|
2876 |
-
}
|
2877 |
-
}
|
2878 |
-
|
2879 |
-
function ajax_exclude_link(){
|
2880 |
-
if ( !current_user_can('manage_options') ){
|
2881 |
-
die( json_encode( array(
|
2882 |
-
'error' => __("You're not allowed to do that!", 'broken-link-checker')
|
2883 |
-
)));
|
2884 |
-
}
|
2885 |
-
|
2886 |
-
if ( isset($_POST['link_id']) ){
|
2887 |
-
//Load the link
|
2888 |
-
$link = new blcLink( intval($_POST['link_id']) );
|
2889 |
-
|
2890 |
-
if ( !$link->valid() ){
|
2891 |
-
die( json_encode( array(
|
2892 |
-
'error' => sprintf( __("Oops, I can't find the link %d", 'broken-link-checker'), intval($_POST['link_id']) )
|
2893 |
-
)));
|
2894 |
-
}
|
2895 |
-
|
2896 |
-
//Add the URL to the exclusion list
|
2897 |
-
if ( !in_array( $link->url, $this->conf->options['exclusion_list'] ) ){
|
2898 |
-
$this->conf->options['exclusion_list'][] = $link->url;
|
2899 |
-
//Also mark it as already checked so that it doesn't show up with other broken links.
|
2900 |
-
//FB::info("The URL {$link->url} is excluded, marking link {$link->link_id} as already checked.");
|
2901 |
-
$link->last_check = date('Y-m-d H:i:s');
|
2902 |
-
$link->http_code = 200; //Use a fake code so that the link doesn't show up in queries looking for broken links.
|
2903 |
-
$link->timeout = false;
|
2904 |
-
$link->request_duration = 0;
|
2905 |
-
$link->log = __("This link wasn't checked because a matching keyword was found on your exclusion list.", 'broken-link-checker');
|
2906 |
-
$link->save();
|
2907 |
-
}
|
2908 |
-
|
2909 |
-
$this->conf->save_options();
|
2910 |
-
|
2911 |
-
die( json_encode( array(
|
2912 |
-
'ok' => sprintf( __('URL %s added to the exclusion list', 'broken-link-checker'), $link->url )
|
2913 |
-
)));
|
2914 |
-
} else {
|
2915 |
-
die( json_encode( array(
|
2916 |
-
'error' => __("Link ID not specified", 'broken-link-checker')
|
2917 |
-
)));
|
2918 |
}
|
2919 |
}
|
2920 |
|
2921 |
/**
|
2922 |
-
* ws_broken_link_checker::acquire_lock()
|
2923 |
* Create and lock a temporary file.
|
2924 |
*
|
2925 |
* @return bool
|
@@ -2957,7 +2400,6 @@ div.search-box{
|
|
2957 |
}
|
2958 |
|
2959 |
/**
|
2960 |
-
* ws_broken_link_checker::release_lock()
|
2961 |
* Unlock and delete the temporary file
|
2962 |
*
|
2963 |
* @return bool
|
@@ -2980,7 +2422,6 @@ div.search-box{
|
|
2980 |
}
|
2981 |
|
2982 |
/**
|
2983 |
-
* ws_broken_link_checker::lockfile_name()
|
2984 |
* Generate system-specific lockfile filename
|
2985 |
*
|
2986 |
* @return string A filename or FALSE on error
|
@@ -3017,32 +2458,53 @@ div.search-box{
|
|
3017 |
}
|
3018 |
}
|
3019 |
|
3020 |
-
|
3021 |
-
|
3022 |
-
|
3023 |
-
|
3024 |
-
|
3025 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3026 |
}
|
3027 |
|
3028 |
-
|
3029 |
-
|
3030 |
-
|
3031 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3032 |
|
3033 |
-
|
3034 |
-
|
|
|
3035 |
|
3036 |
-
|
3037 |
-
|
3038 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3039 |
}
|
3040 |
-
|
3041 |
-
|
3042 |
-
$
|
3043 |
-
|
3044 |
-
//Remove the link that was associated with this instance if it has no more related instances.
|
3045 |
-
$this->cleanup_links( $inst['link_id'] );
|
3046 |
}
|
3047 |
|
3048 |
function hook_wp_dashboard_setup(){
|
@@ -3088,7 +2550,6 @@ div.search-box{
|
|
3088 |
}
|
3089 |
|
3090 |
/**
|
3091 |
-
* wsBrokenLinkChecker::get_debug_info()
|
3092 |
* Collect various debugging information and return it in an associative array
|
3093 |
*
|
3094 |
* @return array
|
@@ -3137,7 +2598,7 @@ div.search-box{
|
|
3137 |
$debug[ __('CURL version', 'broken-link-checker') ] = $data;
|
3138 |
|
3139 |
//Snoopy presence
|
3140 |
-
if ( class_exists('Snoopy') ){
|
3141 |
$data = array(
|
3142 |
'state' => 'ok',
|
3143 |
'value' => __('Installed', 'broken-link-checker'),
|
@@ -3205,174 +2666,148 @@ div.search-box{
|
|
3205 |
return $debug;
|
3206 |
}
|
3207 |
|
3208 |
-
|
3209 |
-
|
3210 |
-
|
3211 |
-
|
3212 |
-
|
3213 |
-
|
3214 |
-
|
3215 |
-
|
3216 |
-
|
3217 |
-
|
3218 |
-
|
3219 |
-
|
3220 |
-
|
3221 |
-
|
3222 |
-
|
3223 |
-
|
3224 |
-
|
3225 |
-
|
3226 |
-
|
3227 |
-
|
3228 |
-
|
3229 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3230 |
|
3231 |
-
|
3232 |
-
$where_expr = '1'; //default = select all links
|
3233 |
|
3234 |
-
|
|
|
|
|
3235 |
|
3236 |
-
|
3237 |
-
|
3238 |
-
|
3239 |
-
|
3240 |
-
|
3241 |
-
|
3242 |
-
|
3243 |
-
|
3244 |
-
$params = $this->get_search_params($filter);
|
3245 |
-
|
3246 |
-
//Generate the individual clauses of the WHERE expression
|
3247 |
-
$pieces = array();
|
3248 |
-
|
3249 |
-
//Anchor text - use fulltext search
|
3250 |
-
if ( !empty($params['s_link_text']) ){
|
3251 |
-
$pieces[] = 'MATCH(instances.link_text) AGAINST("' . $wpdb->escape($params['s_link_text']) . '")';
|
3252 |
-
}
|
3253 |
-
|
3254 |
-
//URL - try to match both the initial URL and the final URL.
|
3255 |
-
//There is limited wildcard support, e.g. "google.*/search" will match both
|
3256 |
-
//"google.com/search" and "google.lv/search"
|
3257 |
-
if ( !empty($params['s_link_url']) ){
|
3258 |
-
$s_link_url = like_escape($wpdb->escape($params['s_link_url']));
|
3259 |
-
$s_link_url = str_replace('*', '%', $s_link_url);
|
3260 |
-
|
3261 |
-
$pieces[] = '(links.url LIKE "%'. $s_link_url .'%") OR '.
|
3262 |
-
'(links.final_url LIKE "%'. $s_link_url .'%")';
|
3263 |
-
}
|
3264 |
-
|
3265 |
-
//Link type should match either the instance_type or the source_type
|
3266 |
-
if ( !empty($params['s_link_type']) ){
|
3267 |
-
$s_link_type = $wpdb->escape($params['s_link_type']);
|
3268 |
-
$pieces[] = "instances.instance_type = '$s_link_type' OR instances.source_type='$s_link_type'";
|
3269 |
-
}
|
3270 |
-
|
3271 |
-
//HTTP code - the user can provide a list of HTTP response codes and code ranges.
|
3272 |
-
//Example : 201,400-410,500
|
3273 |
-
if ( !empty($params['s_http_code']) ){
|
3274 |
-
//Strip spaces.
|
3275 |
-
$params['s_http_code'] = str_replace(' ', '', $params['s_http_code']);
|
3276 |
-
//Split by comma
|
3277 |
-
$codes = explode(',', $params['s_http_code']);
|
3278 |
-
|
3279 |
-
$individual_codes = array();
|
3280 |
-
$ranges = array();
|
3281 |
-
|
3282 |
-
//Try to parse each response code or range. Invalid ones are simply ignored.
|
3283 |
-
foreach($codes as $code){
|
3284 |
-
if ( is_numeric($code) ){
|
3285 |
-
//It's a single number
|
3286 |
-
$individual_codes[] = abs(intval($code));
|
3287 |
-
} elseif ( strpos($code, '-') !== false ) {
|
3288 |
-
//Try to parse it as a range
|
3289 |
-
$range = explode( '-', $code, 2 );
|
3290 |
-
if ( (count($range) == 2) && is_numeric($range[0]) && is_numeric($range[0]) ){
|
3291 |
-
//Make sure the smaller code comes first
|
3292 |
-
$range = array( intval($range[0]), intval($range[1]) );
|
3293 |
-
$ranges[] = array( min($range), max($range) );
|
3294 |
-
}
|
3295 |
-
}
|
3296 |
-
}
|
3297 |
-
|
3298 |
-
$piece = array();
|
3299 |
-
|
3300 |
-
//All individual response codes get one "http_code IN (...)" clause
|
3301 |
-
if ( !empty($individual_codes) ){
|
3302 |
-
$piece[] = '(links.http_code IN ('. implode(', ', $individual_codes) .'))';
|
3303 |
-
}
|
3304 |
-
|
3305 |
-
//Ranges get a "http_code BETWEEN min AND max" clause each
|
3306 |
-
if ( !empty($ranges) ){
|
3307 |
-
$range_strings = array();
|
3308 |
-
foreach($ranges as $range){
|
3309 |
-
$range_strings[] = "(links.http_code BETWEEN $range[0] AND $range[1])";
|
3310 |
-
}
|
3311 |
-
$piece[] = '( ' . implode(' OR ', $range_strings) . ' )';
|
3312 |
-
}
|
3313 |
-
|
3314 |
-
//Finally, generate a composite WHERE clause for both types of response code queries
|
3315 |
-
if ( !empty($piece) ){
|
3316 |
-
$pieces[] = implode(' OR ', $piece);
|
3317 |
-
}
|
3318 |
-
|
3319 |
-
}
|
3320 |
|
3321 |
-
|
3322 |
-
|
3323 |
-
if ( !empty($params['s_filter']) && isset($this->native_filters[$params['s_filter']]) ){
|
3324 |
-
$pieces[] = $this->native_filters[$params['s_filter']]['where_expr'];
|
3325 |
-
}
|
3326 |
|
3327 |
-
|
3328 |
-
|
|
|
3329 |
}
|
3330 |
}
|
3331 |
-
|
3332 |
}
|
3333 |
|
3334 |
-
|
3335 |
-
|
3336 |
-
|
3337 |
-
|
3338 |
-
|
3339 |
-
|
3340 |
-
|
3341 |
-
|
3342 |
-
|
3343 |
-
|
3344 |
-
|
3345 |
-
|
3346 |
-
|
3347 |
-
|
3348 |
-
|
3349 |
-
|
3350 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3351 |
} else {
|
3352 |
-
|
3353 |
-
|
3354 |
-
|
3355 |
-
|
3356 |
-
|
3357 |
-
|
3358 |
-
|
3359 |
-
|
3360 |
-
|
3361 |
-
FROM
|
3362 |
-
{$wpdb->prefix}blc_links AS links,
|
3363 |
-
{$wpdb->prefix}blc_instances as instances LEFT JOIN {$wpdb->posts} as posts ON instances.source_id = posts.ID
|
3364 |
-
|
3365 |
-
WHERE
|
3366 |
-
links.link_id = instances.link_id
|
3367 |
-
AND ". $where_expr ."
|
3368 |
-
|
3369 |
-
GROUP BY links.link_id";
|
3370 |
-
if ( $max_results || $offset ){
|
3371 |
-
$q .= "\nLIMIT $offset, $max_results";
|
3372 |
}
|
3373 |
-
|
3374 |
-
|
3375 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3376 |
}
|
3377 |
|
3378 |
}//class ends here
|
1 |
<?php
|
2 |
|
|
|
|
|
|
|
3 |
/**
|
4 |
* Simple function to replicate PHP 5 behaviour
|
5 |
*/
|
19 |
var $loader;
|
20 |
var $my_basename = '';
|
21 |
|
22 |
+
var $db_version = 4; //The required version of the plugin's DB schema.
|
23 |
|
24 |
var $execution_start_time; //Used for a simple internal execution timer in start_timer()/execution_time()
|
25 |
var $lockfile_handle = null;
|
26 |
|
|
|
|
|
27 |
/**
|
28 |
* wsBrokenLinkChecker::wsBrokenLinkChecker()
|
29 |
* Class constructor
|
35 |
function wsBrokenLinkChecker ( $loader, $conf ) {
|
36 |
global $wpdb;
|
37 |
|
|
|
38 |
$this->conf = $conf;
|
39 |
+
$this->loader = $loader;
|
|
|
40 |
$this->my_basename = plugin_basename( $this->loader );
|
41 |
+
|
42 |
+
register_activation_hook($this->my_basename, array(&$this,'activation'));
|
43 |
+
register_deactivation_hook($this->my_basename, array(&$this, 'deactivation'));
|
44 |
|
45 |
add_action('init', array(&$this,'load_language'));
|
46 |
|
47 |
add_action('admin_menu', array(&$this,'admin_menu'));
|
48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
//Load jQuery on Dashboard pages (probably redundant as WP already does that)
|
50 |
add_action('admin_print_scripts', array(&$this,'admin_print_scripts'));
|
51 |
|
53 |
add_action('wp_dashboard_setup', array(&$this, 'hook_wp_dashboard_setup'));
|
54 |
|
55 |
//AJAXy hooks
|
|
|
56 |
add_action( 'wp_ajax_blc_full_status', array(&$this,'ajax_full_status') );
|
57 |
add_action( 'wp_ajax_blc_dashboard_status', array(&$this,'ajax_dashboard_status') );
|
58 |
add_action( 'wp_ajax_blc_work', array(&$this,'ajax_work') );
|
59 |
add_action( 'wp_ajax_blc_discard', array(&$this,'ajax_discard') );
|
60 |
add_action( 'wp_ajax_blc_edit', array(&$this,'ajax_edit') );
|
61 |
add_action( 'wp_ajax_blc_link_details', array(&$this,'ajax_link_details') );
|
|
|
62 |
add_action( 'wp_ajax_blc_unlink', array(&$this,'ajax_unlink') );
|
63 |
+
add_action( 'wp_ajax_blc_current_load', array(&$this,'ajax_current_load') );
|
64 |
|
65 |
//Check if it's possible to create a lockfile and nag the user about it if not.
|
66 |
if ( $this->lockfile_name() ){
|
72 |
add_action( 'admin_notices', array( &$this, 'lockfile_warning' ) );
|
73 |
}
|
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, 'send_email_notifications' ));
|
80 |
+
add_action('blc_cron_check_links', array(&$this, 'cron_check_links'));
|
81 |
}
|
82 |
|
83 |
+
/**
|
84 |
+
* Output the script that runs the link monitor while the Dashboard is open.
|
85 |
+
*
|
86 |
+
* @return void
|
87 |
+
*/
|
88 |
function admin_footer(){
|
89 |
+
if ( !$this->conf->options['run_in_dashboard'] ){
|
90 |
+
return;
|
91 |
+
}
|
92 |
?>
|
93 |
<!-- wsblc admin footer -->
|
|
|
94 |
<script type='text/javascript'>
|
95 |
(function($){
|
96 |
|
115 |
<?php
|
116 |
}
|
117 |
|
118 |
+
/**
|
119 |
+
* Check if an URL matches the exclusion list.
|
120 |
+
*
|
121 |
+
* @param string $url
|
122 |
+
* @return bool
|
123 |
+
*/
|
124 |
function is_excluded($url){
|
125 |
if (!is_array($this->conf->options['exclusion_list'])) return false;
|
126 |
foreach($this->conf->options['exclusion_list'] as $excluded_word){
|
191 |
wp_enqueue_script('jquery');
|
192 |
}
|
193 |
|
194 |
+
function enqueue_settings_scripts(){
|
195 |
+
//jQuery UI is used on the settings page
|
196 |
+
wp_enqueue_script('jquery-ui-core');
|
197 |
+
wp_enqueue_script('jquery-ui-dialog');
|
198 |
+
}
|
199 |
+
|
200 |
+
function enqueue_link_page_scripts(){
|
201 |
wp_enqueue_script('jquery-ui-core');
|
202 |
wp_enqueue_script('jquery-ui-dialog');
|
203 |
+
wp_enqueue_script('sprintf', WP_PLUGIN_URL . '/' . dirname($this->my_basename) . '/js/sprintf.js');
|
204 |
}
|
205 |
|
206 |
/**
|
207 |
+
* Initiate a full recheck - reparse everything and check all links anew.
|
|
|
208 |
*
|
|
|
209 |
* @return void
|
210 |
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
211 |
function initiate_recheck(){
|
212 |
global $wpdb;
|
213 |
|
218 |
$wpdb->query("TRUNCATE {$wpdb->prefix}blc_links");
|
219 |
|
220 |
//Mark all posts, custom fields and bookmarks for processing.
|
221 |
+
blc_resynch(true);
|
222 |
}
|
223 |
|
224 |
+
/**
|
225 |
+
* This is a hook that's executed when the plugin is activated.
|
226 |
+
* It set's up and populates the plugin's DB tables & performs
|
227 |
+
* other installation tasks.
|
228 |
+
*
|
229 |
+
* @return void
|
230 |
+
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
231 |
function activation(){
|
232 |
+
blc_init_all_components();
|
233 |
+
|
234 |
//Prepare the database.
|
235 |
$this->upgrade_database();
|
236 |
|
237 |
+
//Mark all new posts and other parse-able objects as unsynchronized.
|
238 |
+
blc_resynch();
|
239 |
|
240 |
//Save the default options.
|
241 |
$this->conf->save_options();
|
244 |
$this->optimize_database();
|
245 |
}
|
246 |
|
247 |
+
|
248 |
/**
|
249 |
+
* A hook executed when the plugin is deactivated.
|
|
|
250 |
*
|
|
|
251 |
* @return void
|
252 |
*/
|
253 |
+
function deactivation(){
|
254 |
+
//Remove our Cron events
|
255 |
+
wp_clear_scheduled_hook('blc_cron_check_links');
|
256 |
+
wp_clear_scheduled_hook('blc_cron_email_notifications');
|
257 |
+
}
|
258 |
+
|
259 |
+
/**
|
260 |
+
* Create and/or upgrade the plugin's database tables.
|
261 |
+
*
|
262 |
+
* @return void
|
263 |
+
*/
|
264 |
+
function upgrade_database(){
|
265 |
global $wpdb;
|
266 |
|
267 |
//Do we need to upgrade?
|
268 |
+
if ( $this->db_version == $this->conf->options['current_db_version'] ) {
|
269 |
+
//The DB is up to date, but lets make sure all the required tables are present
|
270 |
+
//in case the user has decided to delete some of them.
|
271 |
+
return $this->maybe_create_tables();
|
|
|
|
|
|
|
|
|
272 |
}
|
273 |
|
274 |
+
//Upgrade to DB version 4
|
275 |
+
if ( $this->db_version == 4 ){
|
276 |
+
//The 4th version makes a lot of backwards-incompatible changes to the main
|
277 |
+
//BLC tables (in particular, it adds several required fields to blc_instances).
|
278 |
+
//While it would be possible to import data from an older version of the DB,
|
279 |
+
//some things - like link editing - wouldn't work with the old data.
|
280 |
+
|
281 |
+
//So we just drop, recreate and repopulate most tables.
|
282 |
+
$tables = array(
|
283 |
+
$wpdb->prefix . 'blc_linkdata',
|
284 |
+
$wpdb->prefix . 'blc_postdata',
|
285 |
+
$wpdb->prefix . 'blc_instances',
|
286 |
+
$wpdb->prefix . 'blc_synch',
|
287 |
+
$wpdb->prefix . 'blc_links',
|
288 |
+
);
|
289 |
+
|
290 |
+
$q = "DROP TABLE IF EXISTS " . implode(', ', $tables);
|
291 |
+
$rez = $wpdb->query( $q );
|
292 |
+
if ( $rez === false ){
|
293 |
+
trigger_error(
|
294 |
+
sprintf(
|
295 |
+
__("Failed to delete old DB tables. Database error : %s", 'broken-link-checker'),
|
296 |
+
$wpdb->last_error
|
297 |
+
),
|
298 |
+
E_USER_ERROR
|
299 |
+
);
|
300 |
+
}
|
301 |
+
|
302 |
+
//Create new DB tables.
|
303 |
+
if ( !$this->maybe_create_tables() ){
|
304 |
+
return false;
|
305 |
+
};
|
306 |
+
|
307 |
+
} else {
|
308 |
+
//This should never happen.
|
309 |
+
trigger_error(
|
310 |
+
sprintf(
|
311 |
+
__(
|
312 |
+
"Unexpected error: The plugin doesn't know how to upgrade its database to version '%d'.",
|
313 |
+
'broken-link-checker'
|
314 |
+
),
|
315 |
+
$this->db_version
|
316 |
+
),
|
317 |
+
E_USER_ERROR
|
318 |
+
);
|
319 |
+
}
|
320 |
|
321 |
+
//Upgrade was successful.
|
322 |
+
$this->conf->options['current_db_version'] = $this->db_version;
|
323 |
+
$this->conf->save_options();
|
|
|
|
|
|
|
|
|
|
|
324 |
|
325 |
+
return true;
|
326 |
+
}
|
327 |
+
|
328 |
+
/**
|
329 |
+
* Create the plugin's DB tables, unless they already exist.
|
330 |
+
*
|
331 |
+
* @return bool
|
332 |
+
*/
|
333 |
+
function maybe_create_tables(){
|
334 |
+
global $wpdb;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
335 |
|
336 |
+
//Search filters
|
337 |
+
$q = <<<EOD
|
338 |
+
CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}blc_filters` (
|
339 |
+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
340 |
`name` varchar(100) NOT NULL,
|
341 |
+
`params` text NOT NULL,
|
342 |
+
PRIMARY KEY (`id`)
|
343 |
+
)
|
344 |
+
EOD;
|
345 |
+
if ( $wpdb->query($q) === false ){
|
346 |
+
trigger_error(
|
347 |
+
sprintf(
|
348 |
+
__("Failed to create table '%s'. Database error: %s", 'broken-link-checker'),
|
349 |
+
$wpdb->prefix . 'blc_filters',
|
350 |
+
$wpdb->last_error
|
351 |
+
),
|
352 |
+
E_USER_ERROR
|
353 |
+
);
|
354 |
+
}
|
355 |
|
356 |
+
//Link instances (i.e. link occurences inside posts and other items)
|
357 |
+
$q = <<<EOT
|
358 |
+
CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}blc_instances` (
|
359 |
+
`instance_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
360 |
+
`link_id` int(10) unsigned NOT NULL,
|
361 |
+
`container_id` int(10) unsigned NOT NULL,
|
362 |
+
`container_type` varchar(40) NOT NULL DEFAULT 'post',
|
363 |
+
`link_text` varchar(250) NOT NULL,
|
364 |
+
`parser_type` varchar(40) NOT NULL DEFAULT 'link',
|
365 |
+
`container_field` varchar(250) NOT NULL,
|
366 |
+
`link_context` varchar(250) NOT NULL,
|
367 |
+
`raw_url` text NOT NULL,
|
368 |
+
|
369 |
+
PRIMARY KEY (`instance_id`),
|
370 |
+
KEY `link_id` (`link_id`),
|
371 |
+
KEY `source_id` (`container_id`,`container_type`)
|
372 |
+
);
|
373 |
+
EOT;
|
374 |
+
if ( $wpdb->query($q) === false ){
|
375 |
+
trigger_error(
|
376 |
+
sprintf(
|
377 |
+
__("Failed to create table '%s'. Database error: %s", 'broken-link-checker'),
|
378 |
+
$wpdb->prefix . 'blc_instances',
|
379 |
+
$wpdb->last_error
|
380 |
+
),
|
381 |
+
E_USER_ERROR
|
382 |
+
);
|
383 |
+
}
|
384 |
+
|
385 |
+
//Links themselves. Note : The 'url' and 'final_url' columns must be collated
|
386 |
+
//in a case-sensitive manner. This is because "http://a.b/cde" may be a page
|
387 |
+
//very different from "http://a.b/CDe".
|
388 |
+
$q = <<<EOS
|
389 |
+
CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}blc_links` (
|
390 |
+
`link_id` int(20) unsigned NOT NULL AUTO_INCREMENT,
|
391 |
+
`url` text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
|
392 |
+
`first_failure` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
393 |
+
`last_check` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
394 |
+
`last_success` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
395 |
+
`last_check_attempt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
396 |
+
`check_count` int(4) unsigned NOT NULL DEFAULT '0',
|
397 |
+
`final_url` text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
|
398 |
+
`redirect_count` smallint(5) unsigned NOT NULL DEFAULT '0',
|
399 |
+
`log` text NOT NULL,
|
400 |
+
`http_code` smallint(6) NOT NULL,
|
401 |
+
`request_duration` float NOT NULL DEFAULT '0',
|
402 |
+
`timeout` tinyint(1) unsigned NOT NULL DEFAULT '0',
|
403 |
+
`broken` tinyint(1) NOT NULL DEFAULT '0',
|
404 |
+
`may_recheck` tinyint(1) NOT NULL DEFAULT '1',
|
405 |
+
`being_checked` tinyint(1) NOT NULL DEFAULT '0',
|
406 |
+
`result_hash` varchar(200) NOT NULL DEFAULT '',
|
407 |
+
`false_positive` tinyint(1) NOT NULL DEFAULT '0',
|
408 |
+
|
409 |
+
PRIMARY KEY (`link_id`),
|
410 |
+
KEY `url` (`url`(150)),
|
411 |
+
KEY `final_url` (`final_url`(150)),
|
412 |
+
KEY `http_code` (`http_code`),
|
413 |
+
KEY `broken` (`broken`)
|
414 |
+
);
|
415 |
+
EOS;
|
416 |
+
if ( $wpdb->query($q) === false ){
|
417 |
+
trigger_error(
|
418 |
+
sprintf(
|
419 |
+
__("Failed to create table '%s'. Database error: %s", 'broken-link-checker'),
|
420 |
+
$wpdb->prefix . 'blc_links',
|
421 |
+
$wpdb->last_error
|
422 |
+
),
|
423 |
+
E_USER_ERROR
|
424 |
+
);
|
425 |
+
}
|
426 |
+
|
427 |
+
//Synchronization records. This table is used to keep track of if and when various items
|
428 |
+
//(e.g. posts, comments, etc) were parsed.
|
429 |
+
$q = <<<EOZ
|
430 |
+
CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}blc_synch` (
|
431 |
+
`container_id` int(20) unsigned NOT NULL,
|
432 |
+
`container_type` varchar(40) NOT NULL,
|
433 |
+
`synched` tinyint(3) unsigned NOT NULL,
|
434 |
+
`last_synch` datetime NOT NULL,
|
435 |
+
|
436 |
+
PRIMARY KEY (`container_type`,`container_id`),
|
437 |
+
KEY `synched` (`synched`)
|
438 |
+
);
|
439 |
+
EOZ;
|
440 |
+
|
441 |
+
if ( $wpdb->query($q) === false ){
|
442 |
+
trigger_error(
|
443 |
+
sprintf(
|
444 |
+
__("Failed to create table '%s'. Database error: %s", 'broken-link-checker'),
|
445 |
+
$wpdb->prefix . 'blc_synch',
|
446 |
+
$wpdb->last_error
|
447 |
+
),
|
448 |
+
E_USER_ERROR
|
449 |
+
);
|
450 |
+
}
|
451 |
|
452 |
+
//All good.
|
453 |
return true;
|
454 |
}
|
455 |
|
456 |
/**
|
|
|
457 |
* Optimize the plugin's tables
|
458 |
*
|
459 |
* @return void
|
483 |
);
|
484 |
|
485 |
//Add plugin-specific scripts and CSS only to the it's own pages
|
|
|
486 |
add_action( 'admin_print_styles-' . $options_page_hook, array(&$this, 'options_page_css') );
|
487 |
add_action( 'admin_print_styles-' . $links_page_hook, array(&$this, 'links_page_css') );
|
488 |
+
add_action( 'admin_print_scripts-' . $options_page_hook, array(&$this, 'enqueue_settings_scripts') );
|
489 |
+
add_action( 'admin_print_scripts-' . $links_page_hook, array(&$this, 'enqueue_link_page_scripts') );
|
490 |
}
|
491 |
|
492 |
+
/**
|
493 |
* plugin_action_links()
|
494 |
* Handler for the 'plugin_action_links' hook. Adds a "Settings" link to this plugin's entry
|
495 |
* on the plugin list.
|
504 |
return $links;
|
505 |
}
|
506 |
|
|
|
|
|
|
|
|
|
|
|
507 |
function options_page(){
|
508 |
+
global $blc_container_registry;
|
509 |
+
|
510 |
+
//Sanity check : make sure the DB is all set up
|
511 |
+
if ( $this->db_version != $this->conf->options['current_db_version'] ) {
|
512 |
+
printf(
|
513 |
+
__("Error: The plugin's database tables are not up to date! (Current version : %d, expected : %d)", 'broken-link-checker'),
|
514 |
+
$this->conf->options['current_db_version'],
|
515 |
+
$this->db_version
|
516 |
+
);
|
517 |
+
return;
|
518 |
+
}
|
519 |
+
|
520 |
if (isset($_GET['recheck']) && ($_GET['recheck'] == 'true')) {
|
521 |
$this->initiate_recheck();
|
522 |
}
|
523 |
+
|
524 |
if(isset($_POST['submit'])) {
|
525 |
check_admin_referer('link-checker-options');
|
526 |
|
544 |
$new_removed_link_css = trim($_POST['removed_link_css']);
|
545 |
$this->conf->options['removed_link_css'] = $new_removed_link_css;
|
546 |
|
|
|
547 |
$this->conf->options['exclusion_list'] = array_filter(
|
548 |
preg_split(
|
549 |
'/[\s\r\n]+/', //split on newlines and whitespace
|
571 |
if( $new_timeout > 0 ){
|
572 |
$this->conf->options['timeout'] = $new_timeout ;
|
573 |
}
|
574 |
+
|
575 |
+
//Server load limit
|
576 |
+
if ( isset($_POST['server_load_limit']) ){
|
577 |
+
$this->conf->options['server_load_limit'] = floatval($_POST['server_load_limit']);
|
578 |
+
if ( $this->conf->options['server_load_limit'] < 0 ){
|
579 |
+
$this->conf->options['server_load_limit'] = 0;
|
580 |
+
}
|
581 |
+
}
|
582 |
+
$this->conf->options['enable_load_limit'] = $this->conf->options['server_load_limit'] > 0;
|
583 |
+
|
584 |
+
//When to run the checker
|
585 |
+
$this->conf->options['run_in_dashboard'] = !empty($_POST['run_in_dashboard']);
|
586 |
+
$this->conf->options['run_via_cron'] = !empty($_POST['run_via_cron']);
|
587 |
+
|
588 |
+
//Email notifications on/off
|
589 |
+
$email_notifications = !empty($_POST['send_email_notifications']);
|
590 |
+
if ( $email_notifications && ! $this->conf->options['send_email_notifications']){
|
591 |
+
/*
|
592 |
+
The plugin should only send notifications about links that have become broken
|
593 |
+
since the time when email notifications were turned on. If we don't do this,
|
594 |
+
the first email notification will be sent nigh-immediately and list *all* broken
|
595 |
+
links that the plugin currently knows about.
|
596 |
+
*/
|
597 |
+
$this->options['last_notification_sent'] = time();
|
598 |
+
}
|
599 |
+
$this->conf->options['send_email_notifications'] = $email_notifications;
|
600 |
+
|
601 |
+
//Make settings that affect our Cron events take effect immediately
|
602 |
+
$this->setup_cron_events();
|
603 |
+
|
604 |
$this->conf->save_options();
|
605 |
|
606 |
/*
|
609 |
inefficient.
|
610 |
*/
|
611 |
if ( ( count($diff1) > 0 ) || ( count($diff2) > 0 ) ){
|
612 |
+
$manager = $blc_container_registry->get_manager('custom_field');
|
613 |
+
if ( !is_null($manager) ){
|
614 |
+
$manager->resynch();
|
615 |
+
blc_got_unsynched_items();
|
616 |
+
}
|
617 |
}
|
618 |
|
619 |
+
//Redirect back to the settings page
|
620 |
$base_url = remove_query_arg( array('_wpnonce', 'noheader', 'updated', 'error', 'action', 'message') );
|
621 |
+
wp_redirect( add_query_arg( array( 'settings-updated' => true), $base_url ) );
|
622 |
+
}
|
623 |
+
|
624 |
+
//Show a confirmation message when settings are saved.
|
625 |
+
if ( !empty($_GET['settings-updated']) ){
|
626 |
+
echo '<div id="message" class="updated fade"><p><strong>',__('Settings saved.', 'broken-link-checker'), '</strong></p></div>';
|
627 |
+
|
628 |
}
|
629 |
|
630 |
$debug = $this->get_debug_info();
|
631 |
+
|
632 |
?>
|
633 |
|
634 |
<div class="wrap"><h2><?php _e('Broken Link Checker Options', 'broken-link-checker'); ?></h2>
|
650 |
</th>
|
651 |
<td>
|
652 |
|
|
|
653 |
<div id='wsblc_full_status'>
|
654 |
<br/><br/><br/>
|
655 |
</div>
|
779 |
</td>
|
780 |
</tr>
|
781 |
|
782 |
+
<tr valign="top">
|
783 |
+
<th scope="row"><?php _e('E-mail notifications', 'broken-link-checker'); ?></th>
|
784 |
+
<td>
|
785 |
+
<p>
|
786 |
+
<label for='send_email_notifications'>
|
787 |
+
<input type="checkbox" name="send_email_notifications" id="send_email_notifications"
|
788 |
+
<?php if ($this->conf->options['send_email_notifications']) echo ' checked="checked"'; ?>/>
|
789 |
+
<?php _e('Send me e-mail notifications about newly detected broken links', 'broken-link-checker'); ?>
|
790 |
+
</label><br>
|
791 |
+
</p>
|
792 |
+
</td>
|
793 |
+
</tr>
|
794 |
+
|
795 |
</table>
|
796 |
|
797 |
<h3><?php _e('Advanced','broken-link-checker'); ?></h3>
|
821 |
</td>
|
822 |
</tr>
|
823 |
|
824 |
+
<tr valign="top">
|
825 |
+
<th scope="row"><?php _e('Link monitor', 'broken-link-checker'); ?></th>
|
826 |
+
<td>
|
827 |
+
<label for='run_in_dashboard'>
|
828 |
+
<p>
|
829 |
+
<input type="checkbox" name="run_in_dashboard" id="run_in_dashboard"
|
830 |
+
<?php if ($this->conf->options['run_in_dashboard']) echo ' checked="checked"'; ?>/>
|
831 |
+
<?php _e('Run continuously while the Dashboard is open', 'broken-link-checker'); ?>
|
832 |
+
</p>
|
833 |
+
</label>
|
834 |
+
|
835 |
+
<label for='run_via_cron'>
|
836 |
+
<p>
|
837 |
+
<input type="checkbox" name="run_via_cron" id="run_via_cron"
|
838 |
+
<?php if ($this->conf->options['run_via_cron']) echo ' checked="checked"'; ?>/>
|
839 |
+
<?php _e('Run hourly in the background', 'broken-link-checker'); ?>
|
840 |
+
</p>
|
841 |
+
</label>
|
842 |
+
|
843 |
+
</td>
|
844 |
+
</tr>
|
845 |
+
|
846 |
+
<tr valign="top">
|
847 |
+
<th scope="row"><?php _e('Max. execution time', 'broken-link-checker'); ?></th>
|
848 |
+
<td>
|
849 |
+
|
850 |
+
<?php
|
851 |
+
|
852 |
+
printf(
|
853 |
+
__('%s seconds', 'broken-link-checker'),
|
854 |
+
sprintf(
|
855 |
+
'<input type="text" name="max_execution_time" id="max_execution_time" value="%d" size="5" maxlength="5" />',
|
856 |
+
$this->conf->options['max_execution_time']
|
857 |
+
)
|
858 |
+
);
|
859 |
+
|
860 |
+
?>
|
861 |
+
<br/><span class="description">
|
862 |
+
<?php
|
863 |
+
|
864 |
+
_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');
|
865 |
+
|
866 |
+
?>
|
867 |
+
</span>
|
868 |
+
|
869 |
+
</td>
|
870 |
+
</tr>
|
871 |
|
872 |
<tr valign="top">
|
873 |
<th scope="row">
|
901 |
|
902 |
</td>
|
903 |
</tr>
|
904 |
+
|
905 |
+
<tr valign="top">
|
906 |
+
<th scope="row"><?php _e('Server load limit', 'broken-link-checker'); ?></th>
|
907 |
<td>
|
|
|
908 |
<?php
|
909 |
|
910 |
+
$load = $this->get_server_load();
|
911 |
+
$available = !empty($load);
|
|
|
|
|
|
|
|
|
|
|
912 |
|
913 |
+
if ( $available ){
|
914 |
+
$value = !empty($this->conf->options['server_load_limit'])?sprintf('%.2f', $this->conf->options['server_load_limit']):'';
|
915 |
+
printf(
|
916 |
+
'<input type="text" name="server_load_limit" id="server_load_limit" value="%s" size="5" maxlength="5"/> ',
|
917 |
+
$value
|
918 |
+
);
|
919 |
+
|
920 |
+
?>
|
921 |
+
Current load : <span id='wsblc_current_load'>...</span>
|
922 |
+
<script type='text/javascript'>
|
923 |
+
(function($){
|
924 |
+
|
925 |
+
function blcUpdateLoad(){
|
926 |
+
$.get(
|
927 |
+
"<?php echo admin_url('admin-ajax.php'); ?>",
|
928 |
+
{
|
929 |
+
'action' : 'blc_current_load'
|
930 |
+
},
|
931 |
+
function (data, textStatus){
|
932 |
+
$('#wsblc_current_load').html(data);
|
933 |
+
|
934 |
+
setTimeout(blcUpdateLoad, 10000); //...update every 10 seconds
|
935 |
+
}
|
936 |
+
);
|
937 |
+
}
|
938 |
+
blcUpdateLoad();//Call it the first time
|
939 |
+
|
940 |
+
})(jQuery);
|
941 |
+
</script>
|
942 |
+
<?
|
943 |
+
|
944 |
+
echo '<br/><span class="description">';
|
945 |
+
printf(
|
946 |
+
__(
|
947 |
+
'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.',
|
948 |
+
'broken-link-checker'
|
949 |
+
),
|
950 |
+
'http://en.wikipedia.org/wiki/Load_(computing)'
|
951 |
+
);
|
952 |
+
echo '</span>';
|
953 |
|
954 |
+
} else {
|
955 |
+
echo '<input type="text" disabled="disabled" value="Not available" size="13"/><br>';
|
956 |
+
echo '<span class="description">';
|
957 |
+
_e('Load limiting only works on Linux-like systems where <code>/proc/loadavg</code> is present and accessible.', 'broken-link-checker');
|
958 |
+
echo '</span>';
|
959 |
+
}
|
960 |
?>
|
|
|
|
|
961 |
</td>
|
962 |
</tr>
|
963 |
+
|
964 |
</table>
|
965 |
|
966 |
<p class="submit"><input type="submit" name="submit" class='button-primary' value="<?php _e('Save Changes') ?>" /></p>
|
988 |
}
|
989 |
|
990 |
function options_page_css(){
|
991 |
+
wp_enqueue_style('blc-links-page', plugin_dir_url($this->loader) . 'css/options-page.css' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
992 |
}
|
993 |
|
994 |
+
|
995 |
+
function links_page(){
|
996 |
+
global $wpdb, $blc_link_query;
|
997 |
+
|
998 |
+
//Sanity check : Make sure the plugin's tables are all set up.
|
999 |
+
if ( $this->db_version != $this->conf->options['current_db_version'] ) {
|
1000 |
+
printf(
|
1001 |
+
__("Error: The plugin's database tables are not up to date! (Current version : %d, expected : %d)", 'broken-link-checker'),
|
1002 |
+
$this->conf->options['current_db_version'],
|
1003 |
+
$this->db_version
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1004 |
);
|
1005 |
+
return;
|
|
|
1006 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1007 |
|
1008 |
$action = !empty($_POST['action'])?$_POST['action']:'';
|
1009 |
if ( intval($action) == -1 ){
|
1023 |
$message = '';
|
1024 |
$msg_class = 'updated';
|
1025 |
|
1026 |
+
//Run the selected bulk action, if any
|
1027 |
if ( $action == 'create-custom-filter' ){
|
1028 |
+
list($message, $msg_class) = $this->do_create_custom_filter();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1029 |
} elseif ( $action == 'delete-custom-filter' ){
|
1030 |
+
list($message, $msg_class) = $this->do_delete_custom_filter();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1031 |
} elseif ($action == 'bulk-delete-sources') {
|
1032 |
+
list($message, $msg_class) = $this->do_bulk_delete_sources($selected_links);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1033 |
} elseif ($action == 'bulk-unlink') {
|
1034 |
+
list($message, $msg_class) = $this->do_bulk_unlink($selected_links);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1035 |
} elseif ($action == 'bulk-deredirect') {
|
1036 |
+
list($message, $msg_class) = $this->do_bulk_deredirect($selected_links);
|
1037 |
+
} elseif ($action == 'bulk-recheck') {
|
1038 |
+
list($message, $msg_class) = $this->do_bulk_recheck($selected_links);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1039 |
}
|
1040 |
|
1041 |
if ( !empty($message) ){
|
1042 |
+
echo '<div id="message" class="'.$msg_class.' fade"><p>'.$message.'</p></div>';
|
1043 |
}
|
1044 |
|
1045 |
+
//Load custom filters, if any
|
1046 |
+
$blc_link_query->load_custom_filters();
|
1047 |
|
1048 |
+
//Calculate the number of links matching each filter
|
1049 |
+
$blc_link_query->count_filter_results();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1050 |
|
1051 |
+
$filters = $blc_link_query->get_filters();
|
|
|
|
|
|
|
1052 |
|
1053 |
//Get the selected filter (defaults to displaying broken links)
|
1054 |
$filter_id = isset($_GET['filter_id'])?$_GET['filter_id']:'broken';
|
1055 |
+
$current_filter = $blc_link_query->get_filter($filter_id);
|
1056 |
+
if ( empty($current_filter) ){
|
1057 |
$filter_id = 'broken';
|
1058 |
+
$current_filter = $blc_link_query->get_filter('broken');
|
1059 |
+
|
1060 |
}
|
1061 |
|
1062 |
//Get the desired page number (must be > 0)
|
1071 |
$per_page = 200;
|
1072 |
}
|
1073 |
|
1074 |
+
//Calculate the maximum number of pages.
|
1075 |
$max_pages = ceil($current_filter['count'] / $per_page);
|
1076 |
|
1077 |
+
//Select the required links
|
1078 |
+
$extra_params = array(
|
1079 |
+
'offset' => ( ($page-1) * $per_page ),
|
1080 |
+
'max_results' => $per_page,
|
1081 |
+
'purpose' => BLC_FOR_DISPLAY,
|
1082 |
+
);
|
1083 |
+
$links = $blc_link_query->get_filter_links($current_filter, $extra_params);
|
1084 |
+
|
1085 |
+
//Error?
|
1086 |
+
if ( empty($links) && !empty($wpdb->last_error) ){
|
1087 |
printf( __('Database error : %s', 'broken-link-checker'), $wpdb->last_error);
|
1088 |
}
|
1089 |
|
1090 |
+
//If the current request is a user-initiated search query (either directly or
|
1091 |
+
//via a custom filter), save the search params. They can later be used to pre-fill
|
1092 |
+
//the search form or build a new/modified custom filter.
|
1093 |
+
if ( !empty($current_filter['custom']) || ($filter_id == 'search') ){
|
1094 |
+
$search_params = $blc_link_query->get_search_params($current_filter);
|
1095 |
}
|
1096 |
|
|
|
|
|
|
|
1097 |
//Figure out what the "safe" URL to acccess the current page would be.
|
1098 |
//This is used by the bulk action form.
|
1099 |
$special_args = array('_wpnonce', '_wp_http_referer', 'action', 'selected_links');
|
1103 |
|
1104 |
<script type='text/javascript'>
|
1105 |
var blc_current_filter = '<?php echo $filter_id; ?>';
|
1106 |
+
var blc_is_broken_filter = <?php
|
1107 |
+
if ( ($filter_id == 'broken') || ( isset($current_filter['params']['s_filter']) && ($current_filter['params']['s_filter'] = 'broken') ) ){
|
1108 |
+
echo 'true';
|
1109 |
+
} else {
|
1110 |
+
echo 'false';
|
1111 |
+
}
|
1112 |
+
?>;
|
1113 |
</script>
|
1114 |
|
1115 |
<div class="wrap">
|
1144 |
?>
|
1145 |
</ul>
|
1146 |
|
1147 |
+
<?php
|
1148 |
+
//Display the "Search" form and associated buttons.
|
1149 |
+
//The form requires the $filter_id and $search_params variables to be set.
|
1150 |
+
include dirname($this->loader) . '/includes/admin/search-form.php';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1151 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1152 |
|
|
|
1153 |
//Do we have any links to display?
|
1154 |
if( $links && ( count($links) > 0 ) ) {
|
1155 |
?>
|
1160 |
|
1161 |
$bulk_actions = array(
|
1162 |
'-1' => __('Bulk Actions', 'broken-link-checker'),
|
1163 |
+
"bulk-recheck" => __('Recheck', 'broken-link-checker'),
|
1164 |
"bulk-deredirect" => __('Fix redirects', 'broken-link-checker'),
|
1165 |
+
"bulk-unlink" => __('Unlink', 'broken-link-checker'),
|
1166 |
"bulk-delete-sources" => __('Delete sources', 'broken-link-checker'),
|
1167 |
);
|
1168 |
|
1171 |
$bulk_actions_html .= sprintf('<option value="%s">%s</option>', $value, $name);
|
1172 |
}
|
1173 |
?>
|
1174 |
+
|
1175 |
<div class='tablenav'>
|
1176 |
<div class="alignleft actions">
|
1177 |
+
<select name="action" id="blc-bulk-action">
|
1178 |
<?php echo $bulk_actions_html; ?>
|
1179 |
</select>
|
1180 |
<input type="submit" name="doaction" id="doaction" value="<?php echo attribute_escape(__('Apply', 'broken-link-checker')); ?>" class="button-secondary action">
|
1211 |
<th scope="col" id="cb" class="check-column">
|
1212 |
<input type="checkbox">
|
1213 |
</th>
|
1214 |
+
<th scope="col" class="column-title blc-column-source"><?php _e('Source', 'broken-link-checker'); ?></th>
|
1215 |
+
<th scope="col" class="blc-column-link-text"><?php _e('Link Text', 'broken-link-checker'); ?></th>
|
1216 |
+
<th scope="col" class="blc-column-url"><?php _e('URL', 'broken-link-checker'); ?></th>
|
|
|
|
|
|
|
|
|
|
|
1217 |
</tr>
|
1218 |
</thead>
|
1219 |
<tbody id="the-list">
|
1222 |
foreach ($links as $link) {
|
1223 |
$rownum++;
|
1224 |
|
1225 |
+
$rowclass = ($rownum % 2)? 'alternate' : '';
|
1226 |
+
$excluded = $this->is_excluded( $link->url );
|
1227 |
if ( $excluded ) $rowclass .= ' blc-excluded-link';
|
1228 |
|
1229 |
+
if ( $link->redirect_count > 0){
|
1230 |
+
$rowclass .= ' blc-redirect';
|
1231 |
+
}
|
1232 |
+
|
1233 |
+
if ( $link->broken ){
|
1234 |
+
$rowclass .= ' blc-broken-link';
|
1235 |
+
}
|
1236 |
+
|
1237 |
?>
|
1238 |
+
<tr id='<?php echo "blc-row-" . $link->link_id; ?>' class='blc-row <?php echo $rowclass; ?>'>
|
1239 |
|
1240 |
<th class="check-column" scope="row">
|
1241 |
+
<input type="checkbox" name="selected_links[]" value="<?php echo $link->link_id; ?>">
|
1242 |
</th>
|
1243 |
|
1244 |
<td class='post-title column-title'>
|
1245 |
+
<span class='blc-link-id' style='display:none;'><?php echo $link->link_id; ?></span>
|
1246 |
+
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1247 |
|
1248 |
+
//Pick one link instance to display in the table
|
1249 |
+
$instance = null;
|
1250 |
+
$instances = $link->get_instances();
|
1251 |
+
|
1252 |
+
if ( !empty($instances) ){
|
1253 |
+
//Try to find one that matches the selected link type, if any
|
1254 |
+
if( !empty($search_params['s_link_type']) ){
|
1255 |
+
foreach($instances as $candidate){
|
1256 |
+
if ( ($candidate->container_type == $search_params['s_link_type']) || ($candidate->parser_type == $search_params['s_link_type']) ){
|
1257 |
+
$instance = $candidate;
|
1258 |
+
break;
|
1259 |
+
}
|
1260 |
+
}
|
1261 |
}
|
1262 |
+
//If there's no specific link type set, or no suitable instances were found,
|
1263 |
+
//just use the first one.
|
1264 |
+
if ( is_null($instance) ){
|
1265 |
+
$instance = $instances[0];
|
1266 |
+
}
|
1267 |
+
|
1268 |
+
}
|
1269 |
+
|
1270 |
+
//Print the contents of the "Source" column
|
1271 |
+
if ( !is_null($instance) ){
|
1272 |
+
echo $instance->ui_get_source();
|
1273 |
+
|
1274 |
+
$actions = $instance->ui_get_action_links();
|
1275 |
|
1276 |
echo '<div class="row-actions">';
|
1277 |
echo implode(' | </span>', $actions);
|
1278 |
echo '</div>';
|
|
|
|
|
|
|
|
|
1279 |
|
1280 |
+
} else {
|
1281 |
+
_e("[An orphaned link! This is a bug.]", 'broken-link-checker');
|
1282 |
+
}
|
1283 |
+
|
1284 |
?>
|
1285 |
</td>
|
1286 |
<td class='blc-link-text'><?php
|
1287 |
+
//The "Link text" column
|
1288 |
+
if ( !is_null($instance) ){
|
1289 |
+
echo $instance->ui_get_link_text();
|
1290 |
+
} else {
|
1291 |
+
echo '<em>N/A</em>';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1292 |
}
|
1293 |
?>
|
1294 |
</td>
|
1295 |
<td class='column-url'>
|
1296 |
+
<a href="<?php print esc_attr($link->url); ?>" target='_blank' class='blc-link-url' title="<?php echo esc_attr($link->url); ?>">
|
1297 |
+
<?php print blcUtility::truncate($link->url, 50, ''); ?></a>
|
1298 |
<input type='text' id='link-editor-<?php print $rownum; ?>'
|
1299 |
+
value="<?php print esc_attr($link->url); ?>"
|
1300 |
class='blc-link-editor' style='display:none' />
|
1301 |
<?php
|
1302 |
//Output inline action links for the link/URL
|
1307 |
$actions['delete'] = "<span class='delete'><a class='submitdelete blc-unlink-button' title='" . attribute_escape( __('Remove this link from all posts', 'broken-link-checker') ). "' ".
|
1308 |
"id='unlink-button-$rownum' href='javascript:void(0);'>" . __('Unlink', 'broken-link-checker') . "</a>";
|
1309 |
|
1310 |
+
if ( $link->broken ){
|
1311 |
+
$actions['discard'] = sprintf(
|
1312 |
+
'<span><a href="#" title="%s" class="blc-discard-button">%s</a>',
|
1313 |
+
esc_attr(__('Remove this link from the list of broken links and mark it as valid', 'broken-link-checker')),
|
1314 |
+
__('Not broken', 'broken-link-checker')
|
1315 |
+
);
|
1316 |
}
|
1317 |
|
1318 |
$actions['edit'] = "<span class='edit'><a href='javascript:void(0)' class='blc-edit-button' title='" . attribute_escape( __('Edit link URL' , 'broken-link-checker') ) . "'>". __('Edit URL' , 'broken-link-checker') ."</a>";
|
1319 |
+
|
1320 |
echo '<div class="row-actions">';
|
1321 |
echo implode(' | </span>', $actions);
|
1322 |
|
1323 |
+
echo "<span style='display:none' class='blc-cancel-button-container'> " .
|
1324 |
"| <a href='javascript:void(0)' class='blc-cancel-button' title='". attribute_escape(__('Cancel URL editing' , 'broken-link-checker')) ."'>". __('Cancel' , 'broken-link-checker') ."</a></span>";
|
1325 |
+
|
1326 |
echo '</div>';
|
1327 |
?>
|
1328 |
</td>
|
1329 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1330 |
</tr>
|
1331 |
<!-- Link details -->
|
1332 |
<tr id='<?php print "link-details-$rownum"; ?>' style='display:none;' class='blc-link-details'>
|
1333 |
+
<td colspan='4'><?php $this->link_details_row($link); ?></td>
|
1334 |
</tr><?php
|
1335 |
}
|
1336 |
?></tbody></table>
|
1337 |
|
1338 |
<div class="tablenav">
|
1339 |
<div class="alignleft actions">
|
1340 |
+
<select name="action2" id="blc-bulk-action2">
|
1341 |
<?php echo $bulk_actions_html; ?>
|
1342 |
</select>
|
1343 |
<input type="submit" name="doaction2" id="doaction2" value="<?php echo attribute_escape(__('Apply', 'broken-link-checker')); ?>" class="button-secondary action">
|
1365 |
|
1366 |
?>
|
1367 |
|
1368 |
+
<?php
|
1369 |
+
//Load assorted JS event handlers and other shinies
|
1370 |
+
include dirname($this->loader) . '/includes/admin/links-page-js.php';
|
1371 |
+
?>
|
1372 |
</div>
|
1373 |
<?php
|
1374 |
} //Function ends
|
1375 |
|
1376 |
+
/**
|
1377 |
+
* Create a custom link filter using params passed in $_POST.
|
1378 |
+
*
|
1379 |
+
* @uses $_POST
|
1380 |
+
* @uses $_GET to replace the current filter ID (if any) with that of the newly created filter.
|
1381 |
+
*
|
1382 |
+
* @return array Message and the CSS class to apply to the message.
|
1383 |
+
*/
|
1384 |
+
function do_create_custom_filter(){
|
1385 |
+
//Create a custom filter!
|
1386 |
+
global $blc_link_query;
|
1387 |
+
check_admin_referer( 'create-custom-filter' );
|
1388 |
+
$msg_class = 'updated';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1389 |
|
1390 |
+
//Filter name must be set
|
1391 |
+
if ( empty($_POST['name']) ){
|
1392 |
+
$message = __("You must enter a filter name!", 'broken-link-checker');
|
1393 |
+
$msg_class = 'error';
|
1394 |
+
//Filter parameters (a search query) must also be set
|
1395 |
+
} elseif ( empty($_POST['params']) ){
|
1396 |
+
$message = __("Invalid search query.", 'broken-link-checker');
|
1397 |
+
$msg_class = 'error';
|
1398 |
+
} else {
|
1399 |
+
//Save the new filter
|
1400 |
+
$filter_id = $blc_link_query->create_custom_filter($_POST['name'], $_POST['params']);
|
|
|
|
|
|
|
1401 |
|
1402 |
+
if ( $filter_id ){
|
1403 |
+
//Saved
|
1404 |
+
$message = sprintf( __('Filter "%s" created', 'broken-link-checker'), $_POST['name']);
|
1405 |
+
//A little hack to make the filter active immediately
|
1406 |
+
$_GET['filter_id'] = $filter_id;
|
1407 |
+
} else {
|
1408 |
+
//Error
|
1409 |
+
$message = sprintf( __("Database error : %s", 'broken-link-checker'), $wpdb->last_error);
|
1410 |
+
$msg_class = 'error';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1411 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1412 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1413 |
|
1414 |
+
return array($message, $msg_class);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1415 |
}
|
1416 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1417 |
/**
|
1418 |
+
* Delete a custom link filter.
|
|
|
1419 |
*
|
1420 |
+
* @uses $_POST
|
1421 |
+
*
|
1422 |
+
* @return array Message and a CSS class to apply to the message.
|
1423 |
*/
|
1424 |
+
function do_delete_custom_filter(){
|
1425 |
+
//Delete an existing custom filter!
|
1426 |
+
global $blc_link_query;
|
1427 |
+
check_admin_referer( 'delete-custom-filter' );
|
1428 |
+
$msg_class = 'updated';
|
1429 |
+
|
1430 |
+
//Filter ID must be set
|
1431 |
+
if ( empty($_POST['filter_id']) ){
|
1432 |
+
$message = __("Filter ID not specified.", 'broken-link-checker');
|
1433 |
+
$msg_class = 'error';
|
1434 |
+
} else {
|
1435 |
+
//Try to delete the filter
|
1436 |
+
if ( $blc_link_query->delete_custom_filter($_POST['filter_id']) ){
|
1437 |
+
//Success
|
1438 |
+
$message = __('Filter deleted', 'broken-link-checker');
|
1439 |
+
} else {
|
1440 |
+
//Either the ID is wrong or there was some other error
|
1441 |
+
$message = __('Database error : %s', 'broken-link-checker');
|
1442 |
+
$msg_class = 'error';
|
1443 |
}
|
|
|
1444 |
}
|
1445 |
|
1446 |
+
return array($message, $msg_class);
|
1447 |
}
|
1448 |
|
1449 |
/**
|
1450 |
+
* Modify multiple links to point to their target URLs.
|
|
|
1451 |
*
|
1452 |
+
* @param array $selected_links
|
1453 |
+
* @return array The message to display and its CSS class.
|
1454 |
*/
|
1455 |
+
function do_bulk_deredirect($selected_links){
|
1456 |
+
//For all selected links, replace the URL with the final URL that it redirects to.
|
1457 |
|
1458 |
+
$message = '';
|
1459 |
+
$msg_class = 'updated';
|
1460 |
+
|
1461 |
+
check_admin_referer( 'bulk-action' );
|
1462 |
+
|
1463 |
+
if ( count($selected_links) > 0 ) {
|
1464 |
+
//Fetch all the selected links
|
1465 |
+
$links = blc_get_links(array(
|
1466 |
+
'link_ids' => $selected_links,
|
1467 |
+
'purpose' => BLC_FOR_EDITING,
|
1468 |
+
));
|
1469 |
+
|
1470 |
+
if ( count($links) > 0 ) {
|
1471 |
+
$processed_links = 0;
|
1472 |
+
$failed_links = 0;
|
1473 |
+
|
1474 |
+
//Deredirect all selected links
|
1475 |
+
foreach($links as $link){
|
1476 |
+
$rez = $link->deredirect();
|
1477 |
+
if ( !is_wp_error($rez) ){
|
1478 |
+
$processed_links++;
|
1479 |
+
} else {
|
1480 |
+
$failed_links++;
|
1481 |
+
}
|
1482 |
+
}
|
1483 |
+
|
1484 |
+
$message = sprintf(
|
1485 |
+
_n(
|
1486 |
+
'Replaced %d redirect with a direct link',
|
1487 |
+
'Replaced %d redirects with direct links',
|
1488 |
+
$processed_links,
|
1489 |
+
'broken-link-checker'
|
1490 |
+
),
|
1491 |
+
$processed_links
|
1492 |
+
);
|
1493 |
+
|
1494 |
+
if ( $failed_links > 0 ) {
|
1495 |
+
$message .= '<br>' . sprintf(
|
1496 |
+
_n(
|
1497 |
+
'Failed to fix %d redirect',
|
1498 |
+
'Failed to fix %d redirects',
|
1499 |
+
$failed_links,
|
1500 |
+
'broken-link-checker'
|
1501 |
+
),
|
1502 |
+
$failed_links
|
1503 |
+
);
|
1504 |
+
$msg_class = 'error';
|
1505 |
+
}
|
1506 |
+
} else {
|
1507 |
+
$message = __('None of the selected links are redirects!', 'broken-link-checker');
|
1508 |
+
}
|
1509 |
+
}
|
1510 |
+
|
1511 |
+
return array($message, $msg_class);
|
1512 |
}
|
1513 |
|
1514 |
/**
|
1515 |
+
* Unlink multiple links.
|
|
|
1516 |
*
|
1517 |
+
* @param array $selected_links
|
1518 |
+
* @return array Message and a CSS classname.
|
|
|
1519 |
*/
|
1520 |
+
function do_bulk_unlink($selected_links){
|
1521 |
+
//Unlink all selected links.
|
1522 |
+
$message = '';
|
1523 |
+
$msg_class = 'updated';
|
1524 |
+
|
1525 |
+
check_admin_referer( 'bulk-action' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1526 |
|
1527 |
+
if ( count($selected_links) > 0 ) {
|
1528 |
+
|
1529 |
+
//Fetch all the selected links
|
1530 |
+
$links = blc_get_links(array(
|
1531 |
+
'link_ids' => $selected_links,
|
1532 |
+
'purpose' => BLC_FOR_EDITING,
|
1533 |
+
));
|
1534 |
+
|
1535 |
+
if ( count($links) > 0 ) {
|
1536 |
+
$processed_links = 0;
|
1537 |
+
$failed_links = 0;
|
1538 |
|
1539 |
+
//Unlink (delete) each one
|
1540 |
+
foreach($links as $link){
|
1541 |
+
$rez = $link->unlink();
|
1542 |
+
if ( ($rez == false) || is_wp_error($rez) ){
|
1543 |
+
$failed_links++;
|
1544 |
+
} else {
|
1545 |
+
$processed_links++;
|
1546 |
+
}
|
1547 |
+
}
|
1548 |
|
1549 |
+
//This message is slightly misleading - it doesn't account for the fact that
|
1550 |
+
//a link can be present in more than one post.
|
1551 |
+
$message = sprintf(
|
1552 |
+
_n(
|
1553 |
+
'%d link removed',
|
1554 |
+
'%d links removed',
|
1555 |
+
$processed_links,
|
1556 |
+
'broken-link-checker'
|
1557 |
+
),
|
1558 |
+
$processed_links
|
1559 |
+
);
|
1560 |
+
|
1561 |
+
if ( $failed_links > 0 ) {
|
1562 |
+
$message .= '<br>' . sprintf(
|
1563 |
+
_n(
|
1564 |
+
'Failed to remove %d link',
|
1565 |
+
'Failed to remove %d links',
|
1566 |
+
$failed_links,
|
1567 |
+
'broken-link-checker'
|
1568 |
+
),
|
1569 |
+
$failed_links
|
1570 |
+
);
|
1571 |
+
$msg_class = 'error';
|
1572 |
+
}
|
1573 |
}
|
1574 |
+
}
|
1575 |
+
|
1576 |
+
return array($message, $msg_class);
|
1577 |
}
|
1578 |
|
1579 |
/**
|
1580 |
+
* Delete posts, bookmarks and other items that contain any of the specified links.
|
|
|
1581 |
*
|
1582 |
+
* @param array $selected_links An array of link IDs
|
1583 |
+
* @return array Confirmation message and its CSS class.
|
1584 |
*/
|
1585 |
+
function do_bulk_delete_sources($selected_links){
|
1586 |
+
global $blc_container_registry;
|
1587 |
+
|
1588 |
+
$message = '';
|
1589 |
+
$msg_class = 'updated';
|
1590 |
+
|
1591 |
+
//Delete posts, blogroll entries and any other link containers that contain any of the selected links.
|
1592 |
+
//
|
1593 |
+
//Note that once all cotnainers containing a particular link have been deleted,
|
1594 |
+
//there is no need to explicitly delete the link record itself. The hooks attached to
|
1595 |
+
//the actions that execute when something is deleted (e.g. "post_deleted") will
|
1596 |
+
//take care of that.
|
1597 |
+
|
1598 |
+
check_admin_referer( 'bulk-action' );
|
1599 |
+
|
1600 |
+
if ( count($selected_links) > 0 ) {
|
1601 |
+
$messages = array();
|
1602 |
|
1603 |
+
//Fetch all the selected links
|
1604 |
+
$links = blc_get_links(array(
|
1605 |
+
'link_ids' => $selected_links,
|
1606 |
+
'load_instances' => true,
|
1607 |
+
));
|
1608 |
|
1609 |
+
//Make a list of all containers associated with these links, with each container
|
1610 |
+
//listed only once.
|
1611 |
+
$containers = array();
|
1612 |
+
foreach($links as $link){
|
1613 |
+
$instances = $link->get_instances();
|
1614 |
+
foreach($instances as $instance){
|
1615 |
+
$key = $instance->container_type . '|' . $instance->container_id;
|
1616 |
+
$containers[$key] = array($instance->container_type, $instance->container_id);
|
1617 |
+
}
|
1618 |
+
}
|
1619 |
|
1620 |
+
//Instantiate the containers
|
1621 |
+
$containers = blc_get_containers($containers);
|
|
|
|
|
1622 |
|
1623 |
+
//Delete their associated entities
|
1624 |
+
$deleted = array();
|
1625 |
+
foreach($containers as $container){
|
1626 |
+
$container_type = $container->container_type;
|
|
|
|
|
1627 |
|
1628 |
+
$rez = $container->delete_wrapped_object();
|
1629 |
+
|
1630 |
+
if ( is_wp_error($rez) ){
|
1631 |
+
//Record error messages for later display
|
1632 |
+
$messages[] = $rez->get_error_message();
|
1633 |
+
$msg_class = 'error';
|
1634 |
+
} else {
|
1635 |
+
//Keep track of how many of each type were deleted.
|
1636 |
+
if ( isset($deleted[$container_type]) ){
|
1637 |
+
$deleted[$container_type]++;
|
1638 |
+
} else {
|
1639 |
+
$deleted[$container_type] = 1;
|
1640 |
+
}
|
1641 |
+
}
|
1642 |
+
}
|
1643 |
+
|
1644 |
+
//Generate delete confirmation messages
|
1645 |
+
foreach($deleted as $container_type => $number){
|
1646 |
+
$messages[] = $blc_container_registry->ui_bulk_delete_message($container_type, $number);
|
1647 |
+
}
|
1648 |
+
|
1649 |
+
if ( count($messages) > 0 ){
|
1650 |
+
$message = implode('<br>', $messages);
|
1651 |
+
} else {
|
1652 |
+
$message = __("Didn't find anything to delete!", 'broken-link-checker');
|
1653 |
+
$msg_class = 'error';
|
1654 |
+
}
|
1655 |
}
|
1656 |
|
1657 |
+
return array($message, $msg_class);
|
1658 |
}
|
1659 |
|
1660 |
+
/**
|
1661 |
+
* Mark multiple links as unchecked.
|
1662 |
+
*
|
1663 |
+
* @param array $selected_links An array of link IDs
|
1664 |
+
* @return array Confirmation nessage and the CSS class to use with that message.
|
1665 |
+
*/
|
1666 |
+
function do_bulk_recheck($selected_links){
|
1667 |
+
global $wpdb;
|
1668 |
|
1669 |
+
$message = '';
|
1670 |
+
$msg_class = 'updated';
|
1671 |
+
|
1672 |
+
if ( count($selected_links) > 0 ){
|
1673 |
+
$q = "UPDATE {$wpdb->prefix}blc_links
|
1674 |
+
SET last_check_attempt = '0000-00-00 00:00:00'
|
1675 |
+
WHERE link_id IN (".implode(', ', $selected_links).")";
|
1676 |
+
$changes = $wpdb->query($q);
|
1677 |
+
|
1678 |
+
$message = sprintf(
|
1679 |
+
_n(
|
1680 |
+
"%d link scheduled for rechecking",
|
1681 |
+
"%d links scheduled for rechecking",
|
1682 |
+
$changes,
|
1683 |
+
'broken-link-chekcer'
|
1684 |
+
),
|
1685 |
+
$changes
|
1686 |
+
);
|
1687 |
}
|
1688 |
|
1689 |
+
return array($message, $msg_class);
|
1690 |
+
}
|
1691 |
+
|
1692 |
+
|
1693 |
+
function links_page_css(){
|
1694 |
+
wp_enqueue_style('blc-links-page', plugin_dir_url($this->loader) . 'css/links-page.css' );
|
1695 |
+
}
|
1696 |
+
|
1697 |
+
function link_details_row($link){
|
1698 |
+
?>
|
1699 |
+
<div class="blc-detail-container">
|
1700 |
+
<div class="blc-detail-block" style="float: left; width: 49%;">
|
1701 |
+
<ol style='list-style-type: none;'>
|
1702 |
+
<?php if ( !empty($link->post_date) ) { ?>
|
1703 |
+
<li><strong><?php _e('Post published on', 'broken-link-checker'); ?> :</strong>
|
1704 |
+
<span class='post_date'><?php
|
1705 |
+
echo date_i18n(get_option('date_format'),strtotime($link->post_date));
|
1706 |
+
?></span></li>
|
1707 |
+
<?php } ?>
|
1708 |
+
<li><strong><?php _e('Link last checked', 'broken-link-checker'); ?> :</strong>
|
1709 |
+
<span class='check_date'><?php
|
1710 |
+
$last_check = $link->last_check;
|
1711 |
+
if ( $last_check < strtotime('-10 years') ){
|
1712 |
+
_e('Never', 'broken-link-checker');
|
1713 |
+
} else {
|
1714 |
+
echo date_i18n(get_option('date_format'), $last_check);
|
1715 |
+
}
|
1716 |
+
?></span></li>
|
1717 |
+
|
1718 |
+
<li><strong><?php _e('HTTP code', 'broken-link-checker'); ?> :</strong>
|
1719 |
+
<span class='http_code'><?php
|
1720 |
+
print $link->http_code;
|
1721 |
+
?></span></li>
|
1722 |
+
|
1723 |
+
<li><strong><?php _e('Response time', 'broken-link-checker'); ?> :</strong>
|
1724 |
+
<span class='request_duration'><?php
|
1725 |
+
printf( __('%2.3f seconds', 'broken-link-checker'), $link->request_duration);
|
1726 |
+
?></span></li>
|
1727 |
+
|
1728 |
+
<li><strong><?php _e('Final URL', 'broken-link-checker'); ?> :</strong>
|
1729 |
+
<span class='final_url'><?php
|
1730 |
+
print $link->final_url;
|
1731 |
+
?></span></li>
|
1732 |
+
|
1733 |
+
<li><strong><?php _e('Redirect count', 'broken-link-checker'); ?> :</strong>
|
1734 |
+
<span class='redirect_count'><?php
|
1735 |
+
print $link->redirect_count;
|
1736 |
+
?></span></li>
|
1737 |
+
|
1738 |
+
<li><strong><?php _e('Instance count', 'broken-link-checker'); ?> :</strong>
|
1739 |
+
<span class='instance_count'><?php
|
1740 |
+
print count($link->get_instances());
|
1741 |
+
?></span></li>
|
1742 |
+
|
1743 |
+
<?php if ( $link->broken && (intval( $link->check_count ) > 0) ){ ?>
|
1744 |
+
<li><br/>
|
1745 |
+
<?php
|
1746 |
+
printf(
|
1747 |
+
_n('This link has failed %d time.', 'This link has failed %d times.', $link->check_count, 'broken-link-checker'),
|
1748 |
+
$link->check_count
|
1749 |
+
);
|
1750 |
+
?>
|
1751 |
+
</li>
|
1752 |
+
<?php } ?>
|
1753 |
+
</ol>
|
1754 |
+
</div>
|
1755 |
+
|
1756 |
+
<div class="blc-detail-block" style="float: right; width: 50%;">
|
1757 |
+
<ol style='list-style-type: none;'>
|
1758 |
+
<li><strong><?php _e('Log', 'broken-link-checker'); ?> :</strong>
|
1759 |
+
<span class='blc_log'><?php
|
1760 |
+
print nl2br($link->log);
|
1761 |
+
?></span></li>
|
1762 |
+
</ol>
|
1763 |
+
</div>
|
1764 |
+
|
1765 |
+
<div style="clear:both;"> </div>
|
1766 |
+
</div>
|
1767 |
+
<?php
|
1768 |
}
|
1769 |
|
1770 |
function start_timer(){
|
1776 |
}
|
1777 |
|
1778 |
/**
|
|
|
1779 |
* The main worker function that does all kinds of things.
|
1780 |
*
|
1781 |
* @return void
|
1783 |
function work(){
|
1784 |
global $wpdb;
|
1785 |
|
1786 |
+
//Sanity check : make sure the DB is all set up
|
1787 |
+
if ( $this->db_version != $this->conf->options['current_db_version'] ) {
|
1788 |
+
//FB::error("The plugin's database tables are not up to date! Stop.");
|
1789 |
+
return;
|
1790 |
+
}
|
1791 |
+
|
1792 |
if ( !$this->acquire_lock() ){
|
1793 |
//FB::warn("Another instance of BLC is already working. Stop.");
|
1794 |
+
return;
|
1795 |
+
}
|
1796 |
+
|
1797 |
+
if ( $this->server_too_busy() ){
|
1798 |
+
//FB::warn("Server is too busy. Stop.");
|
1799 |
+
return;
|
1800 |
}
|
1801 |
|
1802 |
$this->start_timer();
|
1823 |
//Close the connection as per http://www.php.net/manual/en/features.connection-handling.php#71172
|
1824 |
//This reduces resource usage and may solve the mysterious slowdowns certain users have
|
1825 |
//encountered when activating the plugin.
|
1826 |
+
//(Disable when debugging or you won't get the FirePHP output)
|
1827 |
+
if ( !constant('BLC_DEBUG') ){
|
1828 |
ob_end_clean();
|
1829 |
header("Connection: close");
|
1830 |
ob_start();
|
1835 |
flush(); // Unless both are called !
|
1836 |
}
|
1837 |
|
|
|
|
|
|
|
1838 |
$orphans_possible = false;
|
|
|
1839 |
$still_need_resynch = $this->conf->options['need_resynch'];
|
1840 |
|
1841 |
/*****************************************
|
1842 |
Parse posts and bookmarks
|
1843 |
******************************************/
|
1844 |
|
1845 |
+
if ( $still_need_resynch ) {
|
|
|
|
|
1846 |
|
1847 |
+
//FB::log("Looking for containers that need parsing...");
|
|
|
|
|
1848 |
|
1849 |
+
while( $containers = blc_get_unsynched_containers(50) ){
|
1850 |
+
//FB::log($containers, 'Found containers');
|
1851 |
+
|
1852 |
+
foreach($containers as $container){
|
1853 |
+
//FB::log($container, "Parsing container");
|
1854 |
+
$container->synch();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1855 |
|
1856 |
+
//Check if we still have some execution time left
|
|
|
|
|
|
|
1857 |
if( $this->execution_time() > $max_execution_time ){
|
1858 |
//FB::log('The alloted execution time has run out');
|
1859 |
+
blc_cleanup_links();
|
1860 |
$this->release_lock();
|
1861 |
return;
|
1862 |
}
|
1863 |
|
1864 |
+
//Check if the server isn't overloaded
|
1865 |
+
if ( $this->server_too_busy() ){
|
1866 |
+
//FB::log('Server overloaded, bailing out.');
|
1867 |
+
blc_cleanup_links();
|
1868 |
+
$this->release_lock();
|
1869 |
+
return;
|
1870 |
+
}
|
1871 |
}
|
1872 |
+
$orphans_possible = true;
|
1873 |
}
|
1874 |
|
1875 |
//FB::log('No unparsed items found.');
|
1876 |
$still_need_resynch = false;
|
1877 |
|
|
|
|
|
|
|
|
|
1878 |
} else {
|
1879 |
//FB::log('Resynch not required.');
|
1880 |
}
|
1893 |
|
1894 |
if ( $orphans_possible ) {
|
1895 |
//FB::log('Cleaning up the link table.');
|
1896 |
+
blc_cleanup_links();
|
1897 |
}
|
1898 |
|
1899 |
//Check if we still have some execution time left
|
1903 |
return;
|
1904 |
}
|
1905 |
|
1906 |
+
if ( $this->server_too_busy() ){
|
1907 |
+
//FB::log('Server overloaded, bailing out.');
|
1908 |
+
$this->release_lock();
|
1909 |
+
return;
|
1910 |
+
}
|
1911 |
+
|
1912 |
/*****************************************
|
1913 |
Check links
|
1914 |
******************************************/
|
1915 |
+
while ( $links = $this->get_links_to_check(50) ){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1916 |
|
1917 |
+
//Some unchecked links found
|
|
|
|
|
1918 |
//FB::log("Checking ".count($links)." link(s)");
|
1919 |
|
1920 |
foreach ($links as $link) {
|
1921 |
+
//Does this link need to be checked? Excluded links aren't checked, but their URLs are still
|
1922 |
+
//tested periodically to see if they're still on the exlusion list.
|
1923 |
+
if ( !$this->is_excluded( $link->url ) ) {
|
1924 |
+
//Check the link.
|
1925 |
+
//FB::log($link->url, "Checking link {$link->link_id}");
|
1926 |
+
$link->check( true );
|
|
|
|
|
1927 |
} else {
|
1928 |
+
//FB::info("The URL {$link->url} is excluded, skipping link {$link->link_id}.");
|
1929 |
+
$link->last_check_attempt = time();
|
1930 |
+
$link->save();
|
|
|
|
|
|
|
|
|
|
|
1931 |
}
|
1932 |
|
1933 |
//Check if we still have some execution time left
|
1936 |
$this->release_lock();
|
1937 |
return;
|
1938 |
}
|
1939 |
+
|
1940 |
+
//Check if the server isn't overloaded
|
1941 |
+
if ( $this->server_too_busy() ){
|
1942 |
+
//FB::log('Server overloaded, bailing out.');
|
1943 |
+
$this->release_lock();
|
1944 |
+
return;
|
1945 |
+
}
|
1946 |
}
|
1947 |
+
|
1948 |
}
|
1949 |
//FB::log('No links need to be checked right now.');
|
1950 |
|
1952 |
//FB::log('All done.');
|
1953 |
}
|
1954 |
|
1955 |
+
/**
|
1956 |
+
* This function is called when the plugin's cron hook executes.
|
1957 |
+
* Its only purpose is to invoke the worker function.
|
1958 |
+
*
|
1959 |
+
* @uses wsBrokenLinkChecker::work()
|
1960 |
+
*
|
1961 |
+
* @return void
|
1962 |
+
*/
|
1963 |
+
function cron_check_links(){
|
1964 |
+
$this->work();
|
1965 |
+
}
|
1966 |
+
|
1967 |
+
/**
|
1968 |
+
* Retrieve links that need to be checked or re-checked.
|
1969 |
+
*
|
1970 |
+
* @param integer $max_results The maximum number of links to return. Defaults to 0 = no limit.
|
1971 |
+
* @param bool $count_only If true, only the number of found links will be returned, not the links themselves.
|
1972 |
+
* @return int|array
|
1973 |
+
*/
|
1974 |
+
function get_links_to_check($max_results = 0, $count_only = false){
|
1975 |
+
global $wpdb;
|
1976 |
+
|
1977 |
+
$check_threshold = date('Y-m-d H:i:s', strtotime('-'.$this->conf->options['check_threshold'].' hours'));
|
1978 |
+
$recheck_threshold = date('Y-m-d H:i:s', time() - $this->conf->options['recheck_threshold']);
|
1979 |
+
|
1980 |
+
//FB::log('Looking for links to check (threshold : '.$check_threshold.', recheck_threshold : '.$recheck_threshold.')...');
|
1981 |
+
|
1982 |
+
//Select some links that haven't been checked for a long time or
|
1983 |
+
//that are broken and need to be re-checked again. Links that are
|
1984 |
+
//marked as "being checked" and have been that way for several minutes
|
1985 |
+
//can also be considered broken/buggy, so those will be selected
|
1986 |
+
//as well.
|
1987 |
+
|
1988 |
+
//Note : This is a slow query, but AFAIK there is no way to speed it up.
|
1989 |
+
//I could put an index on last_check_attempt, but that value is almost
|
1990 |
+
//certainly unique for each row so it wouldn't be much better than a full table scan.
|
1991 |
+
if ( $count_only ){
|
1992 |
+
$q = "SELECT COUNT(*)\n";
|
1993 |
+
} else {
|
1994 |
+
$q = "SELECT *\n";
|
1995 |
+
}
|
1996 |
+
$q .= "FROM {$wpdb->prefix}blc_links
|
1997 |
+
WHERE
|
1998 |
+
( last_check_attempt < %s )
|
1999 |
+
OR
|
2000 |
+
(
|
2001 |
+
(broken = 1 OR being_checked = 1)
|
2002 |
+
AND may_recheck = 1
|
2003 |
+
AND check_count < %d
|
2004 |
+
AND last_check_attempt < %s
|
2005 |
+
)";
|
2006 |
+
if ( !$count_only ){
|
2007 |
+
$q .= "\nORDER BY last_check_attempt ASC\n";
|
2008 |
+
if ( !empty($max_results) ){
|
2009 |
+
$q .= "LIMIT " . intval($max_results);
|
2010 |
+
}
|
2011 |
+
}
|
2012 |
+
|
2013 |
+
$link_q = $wpdb->prepare(
|
2014 |
+
$q,
|
2015 |
+
$check_threshold,
|
2016 |
+
$this->conf->options['recheck_count'],
|
2017 |
+
$recheck_threshold
|
2018 |
+
);
|
2019 |
+
//FB::log($link_q, "Find links to check");
|
2020 |
+
|
2021 |
+
//If we just need the number of links, retrieve it and return
|
2022 |
+
if ( $count_only ){
|
2023 |
+
return $wpdb->get_var($link_q);
|
2024 |
+
}
|
2025 |
+
|
2026 |
+
//Fetch the link data
|
2027 |
+
$link_data = $wpdb->get_results($link_q, ARRAY_A);
|
2028 |
+
if ( empty($link_data) ){
|
2029 |
+
return array();
|
2030 |
+
}
|
2031 |
+
|
2032 |
+
//Instantiate blcLink objects for all fetched links
|
2033 |
+
$links = array();
|
2034 |
+
foreach($link_data as $data){
|
2035 |
+
$links[] = new blcLink($data);
|
2036 |
+
}
|
2037 |
+
|
2038 |
+
return $links;
|
2039 |
+
}
|
2040 |
+
|
2041 |
+
/**
|
2042 |
+
* Output the current link checker status in JSON format.
|
2043 |
+
* Ajax hook for the 'blc_full_status' action.
|
2044 |
+
*
|
2045 |
+
* @return void
|
2046 |
+
*/
|
2047 |
function ajax_full_status( ){
|
2048 |
$status = $this->get_status();
|
2049 |
$text = $this->status_text( $status );
|
2057 |
}
|
2058 |
|
2059 |
/**
|
|
|
2060 |
* Generates a status message based on the status info in $status
|
2061 |
*
|
2062 |
* @param array $status
|
2111 |
return $text;
|
2112 |
}
|
2113 |
|
2114 |
+
/**
|
2115 |
+
* @uses wsBrokenLinkChecker::ajax_full_status()
|
2116 |
+
*
|
2117 |
+
* @return void
|
2118 |
+
*/
|
2119 |
function ajax_dashboard_status(){
|
2120 |
//Just display the full status.
|
2121 |
+
$this->ajax_full_status();
|
2122 |
+
}
|
2123 |
+
|
2124 |
+
/**
|
2125 |
+
* Output the current average server load (over the last one-minute period).
|
2126 |
+
* Called via AJAX.
|
2127 |
+
*
|
2128 |
+
* @return void
|
2129 |
+
*/
|
2130 |
+
function ajax_current_load(){
|
2131 |
+
$load = $this->get_server_load();
|
2132 |
+
if ( empty($load) ){
|
2133 |
+
die('Unknown');
|
2134 |
+
}
|
2135 |
+
|
2136 |
+
$one_minute = reset($load);
|
2137 |
+
printf('%.2f', $one_minute);
|
2138 |
+
die();
|
2139 |
}
|
2140 |
|
2141 |
/**
|
2151 |
* @return array
|
2152 |
*/
|
2153 |
function get_status(){
|
2154 |
+
global $wpdb, $blc_link_query;
|
2155 |
|
2156 |
$check_threshold=date('Y-m-d H:i:s', strtotime('-'.$this->conf->options['check_threshold'].' hours'));
|
2157 |
+
$recheck_threshold=date('Y-m-d H:i:s', time() - $this->conf->options['recheck_threshold']);
|
2158 |
|
2159 |
$q = "SELECT count(*) FROM {$wpdb->prefix}blc_links WHERE 1";
|
2160 |
$known_links = $wpdb->get_var($q);
|
2162 |
$q = "SELECT count(*) FROM {$wpdb->prefix}blc_instances WHERE 1";
|
2163 |
$known_instances = $wpdb->get_var($q);
|
2164 |
|
2165 |
+
$broken_links = $blc_link_query->get_filter_links('broken', array('count_only' => true));
|
|
|
|
|
|
|
|
|
|
|
2166 |
|
2167 |
+
$unchecked_links = $this->get_links_to_check(0, true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2168 |
|
2169 |
return array(
|
2170 |
'check_threshold' => $check_threshold,
|
2182 |
die();
|
2183 |
}
|
2184 |
|
2185 |
+
/**
|
2186 |
+
* AJAX hook for the "Not broken" button. Marks a link as broken and as a likely false positive.
|
2187 |
+
*
|
2188 |
+
* @return void
|
2189 |
+
*/
|
2190 |
function ajax_discard(){
|
2191 |
+
if (!current_user_can('edit_others_posts') || !check_ajax_referer('blc_discard', false, false)){
|
|
|
2192 |
die( __("You're not allowed to do that!", 'broken-link-checker') );
|
2193 |
}
|
2194 |
|
2200 |
printf( __("Oops, I can't find the link %d", 'broken-link-checker'), intval($_POST['link_id']) );
|
2201 |
die();
|
2202 |
}
|
2203 |
+
//Make it appear "not broken"
|
2204 |
+
$link->broken = false;
|
2205 |
+
$link->false_positive = true;
|
2206 |
+
$link->last_check_attempt = time();
|
|
|
2207 |
$link->log = __("This link was manually marked as working by the user.", 'broken-link-checker');
|
2208 |
|
2209 |
//Save the changes
|
2217 |
}
|
2218 |
}
|
2219 |
|
2220 |
+
/**
|
2221 |
+
* AJAX hook for the inline link editor on Tools -> Broken Links.
|
2222 |
+
*
|
2223 |
+
* @return void
|
2224 |
+
*/
|
2225 |
function ajax_edit(){
|
2226 |
+
if (!current_user_can('edit_others_posts') || !check_ajax_referer('blc_edit', false, false)){
|
2227 |
die( json_encode( array(
|
2228 |
'error' => __("You're not allowed to do that!", 'broken-link-checker')
|
2229 |
)));
|
2239 |
)));
|
2240 |
}
|
2241 |
|
2242 |
+
$new_url = $_GET['new_url'];
|
2243 |
+
$new_url = stripslashes($new_url);
|
2244 |
+
|
2245 |
+
$parsed = @parse_url($parsed);
|
2246 |
+
if ( !$parsed ){
|
2247 |
die( json_encode( array(
|
2248 |
'error' => __("Oops, the new URL is invalid!", 'broken-link-checker')
|
2249 |
)));
|
2250 |
}
|
2251 |
|
2252 |
//Try and edit the link
|
2253 |
+
//FB::log($new_url, "Ajax edit");
|
2254 |
+
//FB::log($_GET, "Ajax edit");
|
2255 |
$rez = $link->edit($new_url);
|
2256 |
|
2257 |
+
if ( $rez === false ){
|
2258 |
die( json_encode( array(
|
2259 |
'error' => __("An unexpected error occured!", 'broken-link-checker')
|
2260 |
)));
|
2261 |
} else {
|
2262 |
+
$response = array(
|
2263 |
+
'new_link_id' => $rez['new_link_id'],
|
2264 |
+
'cnt_okay' => $rez['cnt_okay'],
|
2265 |
+
'cnt_error' => $rez['cnt_error'],
|
2266 |
+
'errors' => array(),
|
2267 |
+
);
|
2268 |
+
foreach($rez['errors'] as $error){
|
2269 |
+
array_push( $response['errors'], implode(', ', $error->get_error_messages()) );
|
2270 |
+
}
|
2271 |
+
|
2272 |
+
die( json_encode($response) );
|
2273 |
}
|
2274 |
|
2275 |
} else {
|
2279 |
}
|
2280 |
}
|
2281 |
|
2282 |
+
/**
|
2283 |
+
* AJAX hook for the "Unlink" action links in Tools -> Broken Links.
|
2284 |
+
* Removes the specified link from all posts and other supported items.
|
2285 |
+
*
|
2286 |
+
* @return void
|
2287 |
+
*/
|
2288 |
function ajax_unlink(){
|
2289 |
+
if (!current_user_can('edit_others_posts') || !check_ajax_referer('blc_unlink', false, false)){
|
2290 |
die( json_encode( array(
|
2291 |
'error' => __("You're not allowed to do that!", 'broken-link-checker')
|
2292 |
)));
|
2303 |
}
|
2304 |
|
2305 |
//Try and unlink it
|
2306 |
+
$rez = $link->unlink();
|
2307 |
+
|
2308 |
+
if ( $rez === false ){
|
2309 |
die( json_encode( array(
|
2310 |
+
'error' => __("An unexpected error occured!", 'broken-link-checker')
|
2311 |
)));
|
2312 |
} else {
|
2313 |
+
$response = array(
|
2314 |
+
'cnt_okay' => $rez['cnt_okay'],
|
2315 |
+
'cnt_error' => $rez['cnt_error'],
|
2316 |
+
'errors' => array(),
|
2317 |
+
);
|
2318 |
+
foreach($rez['errors'] as $error){
|
2319 |
+
array_push( $response['errors'], implode(', ', $error->get_error_messages()) );
|
2320 |
+
}
|
2321 |
+
|
2322 |
+
die( json_encode($response) );
|
2323 |
}
|
2324 |
|
2325 |
} else {
|
2349 |
die( __('Error : link ID not specified', 'broken-link-checker') );
|
2350 |
}
|
2351 |
|
2352 |
+
//Load the link.
|
2353 |
+
$link = new blcLink($link_id);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2354 |
|
2355 |
+
if ( !$link->is_new ){
|
|
|
2356 |
//FB::info($link, 'Link loaded');
|
2357 |
$this->link_details_row($link);
|
2358 |
die();
|
2359 |
} else {
|
2360 |
printf( __('Failed to load link details (%s)', 'broken-link-checker'), $wpdb->last_error );
|
2361 |
+
die();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2362 |
}
|
2363 |
}
|
2364 |
|
2365 |
/**
|
|
|
2366 |
* Create and lock a temporary file.
|
2367 |
*
|
2368 |
* @return bool
|
2400 |
}
|
2401 |
|
2402 |
/**
|
|
|
2403 |
* Unlock and delete the temporary file
|
2404 |
*
|
2405 |
* @return bool
|
2422 |
}
|
2423 |
|
2424 |
/**
|
|
|
2425 |
* Generate system-specific lockfile filename
|
2426 |
*
|
2427 |
* @return string A filename or FALSE on error
|
2458 |
}
|
2459 |
}
|
2460 |
|
2461 |
+
/**
|
2462 |
+
* Check if server is currently too overloaded to run the link checker.
|
2463 |
+
*
|
2464 |
+
* @return bool
|
2465 |
+
*/
|
2466 |
+
function server_too_busy(){
|
2467 |
+
if ( !$this->conf->options['enable_load_limit'] ){
|
2468 |
+
return false;
|
2469 |
+
}
|
2470 |
+
|
2471 |
+
$loads = $this->get_server_load();
|
2472 |
+
$one_minute = floatval(reset($loads));
|
2473 |
+
|
2474 |
+
return $one_minute > $this->conf->options['server_load_limit'];
|
2475 |
}
|
2476 |
|
2477 |
+
/**
|
2478 |
+
* Get the server's load averages.
|
2479 |
+
*
|
2480 |
+
* Returns an array with three samples - the 1 minute avg, the 5 minute avg, and the 15 minute avg.
|
2481 |
+
*
|
2482 |
+
* @param integer $cache How long the load averages may be cached, in seconds. Set to 0 to get maximally up-to-date data.
|
2483 |
+
* @return array|null Array, or NULL if retrieving load data is impossible (e.g. when running on a Windows box).
|
2484 |
+
*/
|
2485 |
+
function get_server_load($cache = 5){
|
2486 |
+
static $cached_load = null;
|
2487 |
+
static $cached_when = 0;
|
2488 |
|
2489 |
+
if ( !empty($cache) && ((time() - $cached_when) <= $cache) ){
|
2490 |
+
return $cached_load;
|
2491 |
+
}
|
2492 |
|
2493 |
+
$load = null;
|
2494 |
+
|
2495 |
+
if ( function_exists('sys_getloadavg') ){
|
2496 |
+
$load = sys_getloadavg();
|
2497 |
+
} else {
|
2498 |
+
$loadavg_file = '/proc/loadavg';
|
2499 |
+
if (@is_readable($loadavg_file)) {
|
2500 |
+
$load = explode(' ',file_get_contents($loadavg_file));
|
2501 |
+
$load = array_map('floatval', $load);
|
2502 |
+
}
|
2503 |
}
|
2504 |
+
|
2505 |
+
$cached_load = $load;
|
2506 |
+
$cached_when = time();
|
2507 |
+
return $load;
|
|
|
|
|
2508 |
}
|
2509 |
|
2510 |
function hook_wp_dashboard_setup(){
|
2550 |
}
|
2551 |
|
2552 |
/**
|
|
|
2553 |
* Collect various debugging information and return it in an associative array
|
2554 |
*
|
2555 |
* @return array
|
2598 |
$debug[ __('CURL version', 'broken-link-checker') ] = $data;
|
2599 |
|
2600 |
//Snoopy presence
|
2601 |
+
if ( class_exists('Snoopy') || file_exists(ABSPATH. WPINC . '/class-snoopy.php') ){
|
2602 |
$data = array(
|
2603 |
'state' => 'ok',
|
2604 |
'value' => __('Installed', 'broken-link-checker'),
|
2666 |
return $debug;
|
2667 |
}
|
2668 |
|
2669 |
+
function send_email_notifications(){
|
2670 |
+
global $wpdb;
|
2671 |
+
|
2672 |
+
//Find links that have been detected as broken since the last sent notification.
|
2673 |
+
$last_notification = date('Y-m-d H:i:s', $this->conf->options['last_notification_sent']);
|
2674 |
+
$where = $wpdb->prepare('( first_failure >= %s )', $last_notification);
|
2675 |
+
|
2676 |
+
$links = blc_get_links(array(
|
2677 |
+
's_filter' => 'broken',
|
2678 |
+
'where_expr' => $where,
|
2679 |
+
'load_instances' => true,
|
2680 |
+
'max_results' => 0,
|
2681 |
+
));
|
2682 |
+
|
2683 |
+
if ( empty($links) ){
|
2684 |
+
return;
|
2685 |
+
}
|
2686 |
+
|
2687 |
+
$cnt = count($links);
|
2688 |
+
|
2689 |
+
//Prepare email message
|
2690 |
+
$subject = sprintf(
|
2691 |
+
__("[%s] Broken links detected", 'broken-link-checker'),
|
2692 |
+
get_option('blogname')
|
2693 |
+
);
|
2694 |
+
|
2695 |
+
$body = sprintf(
|
2696 |
+
_n(
|
2697 |
+
"Broken Link Checker has detected %d new broken link on your site.",
|
2698 |
+
"Broken Link Checker has detected %d new broken links on your site.",
|
2699 |
+
$cnt,
|
2700 |
+
'broken-link-checker'
|
2701 |
+
),
|
2702 |
+
$cnt
|
2703 |
+
);
|
2704 |
+
|
2705 |
+
$body .= "<br>";
|
2706 |
+
|
2707 |
+
$max_displayed_links = 5;
|
2708 |
+
|
2709 |
+
if ( $cnt > $max_displayed_links ){
|
2710 |
+
$line = sprintf(
|
2711 |
+
_n(
|
2712 |
+
"Here's a list of the first %d broken links:",
|
2713 |
+
"Here's a list of the first %d broken links:",
|
2714 |
+
$max_displayed_links,
|
2715 |
+
'broken-link-checker'
|
2716 |
+
),
|
2717 |
+
$max_displayed_links
|
2718 |
+
);
|
2719 |
+
} else {
|
2720 |
+
$line = __("Here's a list of the new broken links: ", 'broken-link-checker');
|
2721 |
+
}
|
2722 |
|
2723 |
+
$body .= "<p>$line</p>";
|
|
|
2724 |
|
2725 |
+
//Show up to $max_displayed_links broken link instances right in the email.
|
2726 |
+
$displayed = 0;
|
2727 |
+
foreach($links as $link){
|
2728 |
|
2729 |
+
$instances = $link->get_instances();
|
2730 |
+
foreach($instances as $instance){
|
2731 |
+
$pieces = array(
|
2732 |
+
sprintf( __('Link text : %s', 'broken-link-checker'), $instance->ui_get_link_text('email') ),
|
2733 |
+
sprintf( __('Link URL : <a href="%s">%s</a>', 'broken-link-checker'), htmlentities($link->url), blcUtility::truncate($link->url, 70, '') ),
|
2734 |
+
sprintf( __('Source : %s', 'broken-link-checker'), $instance->ui_get_source('email') ),
|
2735 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2736 |
|
2737 |
+
$link_entry = implode("<br>", $pieces);
|
2738 |
+
$body .= "$link_entry<br><br>";
|
|
|
|
|
|
|
2739 |
|
2740 |
+
$displayed++;
|
2741 |
+
if ( $displayed >= $max_displayed_links ){
|
2742 |
+
break 2; //Exit both foreach loops
|
2743 |
}
|
2744 |
}
|
|
|
2745 |
}
|
2746 |
|
2747 |
+
//Add a link to the "Broken Links" tab.
|
2748 |
+
$body .= __("You can see all broken links here:", 'brokenk-link-checker') . "<br>";
|
2749 |
+
$link_page = admin_url('tools.php?page=view-broken-links');
|
2750 |
+
$body .= sprintf('<a href="%1$s">%1$s</a>', $link_page);
|
2751 |
+
|
2752 |
+
//Need to override the default 'text/plain' content type to send a HTML email.
|
2753 |
+
add_filter('wp_mail_content_type', array(&$this, 'override_mail_content_type'));
|
2754 |
+
|
2755 |
+
//Send the notification
|
2756 |
+
$rez = wp_mail(
|
2757 |
+
get_option('admin_email'),
|
2758 |
+
$subject,
|
2759 |
+
$body
|
2760 |
+
);
|
2761 |
+
if ( $rez ){
|
2762 |
+
$this->conf->options['last_notification_sent'] = time();
|
2763 |
+
$this->conf->save_options();
|
2764 |
+
}
|
2765 |
+
|
2766 |
+
//Remove the override so that it doesn't interfere with other plugins that might
|
2767 |
+
//want to send normal plaintext emails.
|
2768 |
+
remove_filter('wp_mail_content_type', array(&$this, 'override_mail_content_type'));
|
2769 |
+
|
2770 |
+
}
|
2771 |
+
|
2772 |
+
function override_mail_content_type($content_type){
|
2773 |
+
return 'text/html';
|
2774 |
+
}
|
2775 |
+
|
2776 |
+
/**
|
2777 |
+
* Install or uninstall the plugin's Cron events based on current settings.
|
2778 |
+
*
|
2779 |
+
* @uses wsBrokenLinkChecker::$conf Uses $conf->options to determine if events need to be (un)installed.
|
2780 |
+
*
|
2781 |
+
* @return void
|
2782 |
+
*/
|
2783 |
+
function setup_cron_events(){
|
2784 |
+
//Link monitor
|
2785 |
+
if ( $this->conf->options['run_via_cron'] ){
|
2786 |
+
if (!wp_next_scheduled('blc_cron_check_links')) {
|
2787 |
+
wp_schedule_event( time(), 'hourly', 'blc_cron_check_links' );
|
2788 |
+
}
|
2789 |
} else {
|
2790 |
+
wp_clear_scheduled_hook('blc_cron_check_links');
|
2791 |
+
}
|
2792 |
+
|
2793 |
+
//Email notifications about broken links
|
2794 |
+
$notification_email = get_option('admin_email');
|
2795 |
+
if ( $this->conf->options['send_email_notifications'] && !empty($notification_email) ){
|
2796 |
+
if ( !wp_next_scheduled('blc_cron_email_notifications') ){
|
2797 |
+
wp_schedule_event(time(), $this->conf->options['notification_schedule'], 'blc_cron_email_notifications');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2798 |
}
|
2799 |
+
} else {
|
2800 |
+
wp_clear_scheduled_hook('blc_cron_email_notifications');
|
2801 |
}
|
2802 |
+
}
|
2803 |
+
|
2804 |
+
/**
|
2805 |
+
* Load the plugin's textdomain
|
2806 |
+
*
|
2807 |
+
* @return void
|
2808 |
+
*/
|
2809 |
+
function load_language(){
|
2810 |
+
load_plugin_textdomain( 'broken-link-checker', false, basename(dirname($this->loader)) . '/languages' );
|
2811 |
}
|
2812 |
|
2813 |
}//class ends here
|
css/links-page.css
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* Link table layout */
|
2 |
+
|
3 |
+
table#blc-links {
|
4 |
+
width: 100%;
|
5 |
+
table-layout: fixed;
|
6 |
+
}
|
7 |
+
|
8 |
+
td.blc-link-details {
|
9 |
+
width: 100%;
|
10 |
+
}
|
11 |
+
|
12 |
+
.blc-detail-container {
|
13 |
+
display: block;
|
14 |
+
width: 100%;
|
15 |
+
}
|
16 |
+
|
17 |
+
.blc-detail-block {
|
18 |
+
width: 50%;
|
19 |
+
}
|
20 |
+
|
21 |
+
.blc-column-source {
|
22 |
+
width: 33%;
|
23 |
+
}
|
24 |
+
|
25 |
+
.blc-column-link-text {
|
26 |
+
width: 24%;
|
27 |
+
}
|
28 |
+
|
29 |
+
.blc-column-url {
|
30 |
+
/*width: 35%;*/
|
31 |
+
}
|
32 |
+
|
33 |
+
/* Styles for broken links, redirects and excluded links */
|
34 |
+
|
35 |
+
.blc-redirect { }
|
36 |
+
|
37 |
+
.blc-redirect .blc-link-url {
|
38 |
+
background-image: url("../images/bullet_blue.png");
|
39 |
+
background-position: left center;
|
40 |
+
background-repeat: no-repeat;
|
41 |
+
}
|
42 |
+
|
43 |
+
.blc-broken-link { }
|
44 |
+
|
45 |
+
.blc-broken-link .blc-link-url {
|
46 |
+
background-image: url("../images/bullet_error.png");
|
47 |
+
background-position: left center;
|
48 |
+
background-repeat: no-repeat;
|
49 |
+
}
|
50 |
+
|
51 |
+
.blc-excluded-link {
|
52 |
+
background-color: #E2E2E2;
|
53 |
+
}
|
54 |
+
|
55 |
+
|
56 |
+
/* Misc table styles */
|
57 |
+
|
58 |
+
.blc-link-url {
|
59 |
+
padding-left: 16px;
|
60 |
+
}
|
61 |
+
|
62 |
+
.blc-link-editor {
|
63 |
+
font-size: 1em;
|
64 |
+
width: 95%;
|
65 |
+
margin-left: 12px;
|
66 |
+
}
|
67 |
+
|
68 |
+
.column-url .row-actions {
|
69 |
+
margin-left: 16px;
|
70 |
+
}
|
71 |
+
|
72 |
+
.blc-link-text {
|
73 |
+
cursor: pointer;
|
74 |
+
}
|
75 |
+
|
76 |
+
|
77 |
+
.blc-small-image {
|
78 |
+
vertical-align: middle;
|
79 |
+
}
|
80 |
+
|
81 |
+
/* Search form */
|
82 |
+
|
83 |
+
.blc-search-container {
|
84 |
+
background : white !important;
|
85 |
+
border: 3px solid #EEEEEE;
|
86 |
+
padding: 12px;
|
87 |
+
}
|
88 |
+
|
89 |
+
.blc-search-container .ui-dialog-titlebar {
|
90 |
+
display: none;
|
91 |
+
margin: 0px;
|
92 |
+
}
|
93 |
+
|
94 |
+
#search-links-dialog {
|
95 |
+
display: none;
|
96 |
+
}
|
97 |
+
|
98 |
+
#search-links-dialog label, #search-links-dialog input.text, #search-links-dialog select { display:block; }
|
99 |
+
#search-links-dialog input.text { margin-bottom:12px; width:95%; padding: .4em; }
|
100 |
+
#search-links-dialog select { margin-bottom:12px; padding: .4em; }
|
101 |
+
#search-links-dialog fieldset { padding:0; border:0; margin-top:25px; }
|
102 |
+
|
103 |
+
#blc-search-button-row {
|
104 |
+
text-align: center;
|
105 |
+
}
|
106 |
+
|
107 |
+
#blc-search-button-row input {
|
108 |
+
padding: 0.4em;
|
109 |
+
margin-left: 8px;
|
110 |
+
margin-right: 8px;
|
111 |
+
margin-top: 8px;
|
112 |
+
}
|
113 |
+
|
114 |
+
.blc-inline-form {
|
115 |
+
display: inline;
|
116 |
+
}
|
117 |
+
|
118 |
+
div.search-box{
|
119 |
+
float: right;
|
120 |
+
margin-top: -5px;
|
121 |
+
margin-right: 0pt;
|
122 |
+
margin-bottom: 0pt;
|
123 |
+
margin-left: 0pt;
|
124 |
+
}
|
css/options-page.css
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#blc-debug-info-toggle {
|
2 |
+
font-size: smaller;
|
3 |
+
}
|
4 |
+
|
5 |
+
.blc-debug-item-ok {
|
6 |
+
background-color: #d7ffa2;
|
7 |
+
}
|
8 |
+
.blc-debug-item-warning {
|
9 |
+
background-color: #fcffa2;
|
10 |
+
}
|
11 |
+
.blc-debug-item-error {
|
12 |
+
background-color: #ffc4c4;
|
13 |
+
}
|
14 |
+
|
15 |
+
#blc-debug-info {
|
16 |
+
display: none;
|
17 |
+
|
18 |
+
text-align: left;
|
19 |
+
|
20 |
+
border-width: 1px;
|
21 |
+
border-color: gray;
|
22 |
+
border-style: solid;
|
23 |
+
|
24 |
+
border-spacing: 0px;
|
25 |
+
border-collapse: collapse;
|
26 |
+
}
|
27 |
+
|
28 |
+
#blc-debug-info th, #blc-debug-info td {
|
29 |
+
padding: 6px;
|
30 |
+
font-weight: normal;
|
31 |
+
text-shadow: none;
|
32 |
+
|
33 |
+
border-width: 1px ;
|
34 |
+
border-color: silver;
|
35 |
+
border-style: solid;
|
36 |
+
|
37 |
+
border-collapse: collapse;
|
38 |
+
}
|
highlighter-class.php
DELETED
@@ -1,93 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* @author W-Shadow
|
5 |
-
* @copyright 2009
|
6 |
-
*
|
7 |
-
* @requires blcUtility
|
8 |
-
*/
|
9 |
-
|
10 |
-
if ( !class_exists('blcLinkHighlighter') ){
|
11 |
-
|
12 |
-
class blcLinkHighlighter {
|
13 |
-
|
14 |
-
var $links_to_remove;
|
15 |
-
var $broken_link_css;
|
16 |
-
var $current_permalink;
|
17 |
-
|
18 |
-
function blcLinkHighlighter( $broken_link_css = '' ) {
|
19 |
-
if ( !empty( $broken_link_css ) ){
|
20 |
-
$this->broken_link_css = $broken_link_css;
|
21 |
-
add_action( 'wp_head', array(&$this,'hook_wp_head') );
|
22 |
-
}
|
23 |
-
|
24 |
-
add_filter( 'the_content', array(&$this,'hook_the_content') );
|
25 |
-
$this->current_permalink = '';
|
26 |
-
}
|
27 |
-
|
28 |
-
function hook_the_content($content){
|
29 |
-
global $post, $wpdb;
|
30 |
-
if ( empty($post) ) return $content;
|
31 |
-
|
32 |
-
//Get the post permalink - it's used to resolve relative URLs
|
33 |
-
$this->current_permalink = get_permalink( $post->ID );
|
34 |
-
|
35 |
-
$q = "
|
36 |
-
SELECT instances.link_text, links.*
|
37 |
-
|
38 |
-
FROM {$wpdb->prefix}blc_instances AS instances, {$wpdb->prefix}blc_links AS links
|
39 |
-
|
40 |
-
WHERE
|
41 |
-
instances.source_id = %d
|
42 |
-
AND instances.source_type = 'post'
|
43 |
-
AND instances.instance_type = 'link'
|
44 |
-
|
45 |
-
AND instances.link_id = links.link_id
|
46 |
-
AND links.check_count > 0
|
47 |
-
AND ( links.http_code < 200 OR links.http_code >= 400 OR links.timeout = 1 )
|
48 |
-
AND links.http_code <> " . BLC_CHECKING;
|
49 |
-
|
50 |
-
$rows = $wpdb->get_results( $wpdb->prepare( $q, $post->ID ), ARRAY_A );
|
51 |
-
if( $rows ){
|
52 |
-
$this->links_to_remove = array();
|
53 |
-
foreach($rows as $row){
|
54 |
-
$this->links_to_remove[$row['url']] = $row;
|
55 |
-
}
|
56 |
-
$content = preg_replace_callback( blcUtility::link_pattern(), array(&$this,'mark_broken_links'), $content );
|
57 |
-
|
58 |
-
/*
|
59 |
-
if ( BLC_DEBUG ){
|
60 |
-
$content .= '<p><strong>Broken links in this post : </strong></p><ul>';
|
61 |
-
$content .= '<li>' . implode('</li><li>', array_keys($this->links_to_remove)) . '</li></ul>';
|
62 |
-
}
|
63 |
-
//*/
|
64 |
-
} else {
|
65 |
-
/*
|
66 |
-
if ( BLC_DEBUG ){
|
67 |
-
$content .= '<p><strong>This post contains no broken links.</strong></p>';
|
68 |
-
}
|
69 |
-
//*/
|
70 |
-
};
|
71 |
-
|
72 |
-
return $content;
|
73 |
-
}
|
74 |
-
|
75 |
-
function mark_broken_links($matches){
|
76 |
-
//TODO: Tooltip-style popups with more info
|
77 |
-
$url = blcUtility::normalize_url( html_entity_decode( $matches[3] ), $this->current_permalink );
|
78 |
-
|
79 |
-
if( isset( $this->links_to_remove[$url] ) ){
|
80 |
-
return $matches[1].$matches[2].$matches[3].$matches[2].' class="broken_link" '.$matches[4].
|
81 |
-
$matches[5].$matches[6];
|
82 |
-
} else {
|
83 |
-
return $matches[0];
|
84 |
-
}
|
85 |
-
}
|
86 |
-
|
87 |
-
function hook_wp_head(){
|
88 |
-
echo '<style type="text/css">',$this->broken_link_css,'</style>';
|
89 |
-
}
|
90 |
-
}
|
91 |
-
|
92 |
-
}
|
93 |
-
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
images/bullet_blue.png
ADDED
Binary file
|
images/bullet_error.png
ADDED
Binary file
|
images/comment.png
ADDED
Binary file
|
images/user_comment.png
ADDED
Binary file
|
includes/admin/links-page-js.php
ADDED
@@ -0,0 +1,383 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script type='text/javascript'>
|
2 |
+
|
3 |
+
function alterLinkCounter(factor){
|
4 |
+
cnt = parseInt(jQuery('.current-link-count').eq(0).html());
|
5 |
+
cnt = cnt + factor;
|
6 |
+
jQuery('.current-link-count').html(cnt);
|
7 |
+
}
|
8 |
+
|
9 |
+
function replaceLinkId(old_id, new_id){
|
10 |
+
var master = jQuery('#blc-row-'+old_id);
|
11 |
+
|
12 |
+
//Save the new ID
|
13 |
+
master.attr('id', 'blc-row-'+new_id);
|
14 |
+
master.find('.blc-link-id').html(new_id);
|
15 |
+
}
|
16 |
+
|
17 |
+
function reloadDetailsRow(link_id){
|
18 |
+
var master = jQuery('#blc-row-'+link_id);
|
19 |
+
|
20 |
+
//Load up the new link info (so sue me)
|
21 |
+
master.next('.blc-link-details').find('td').html('<center><?php echo esc_js(__('Loading...' , 'broken-link-checker')); ?></center>').load(
|
22 |
+
"<?php echo admin_url('admin-ajax.php'); ?>",
|
23 |
+
{
|
24 |
+
'action' : 'blc_link_details',
|
25 |
+
'link_id' : link_id
|
26 |
+
}
|
27 |
+
);
|
28 |
+
}
|
29 |
+
|
30 |
+
jQuery(function($){
|
31 |
+
|
32 |
+
//The details button - display/hide detailed info about a link
|
33 |
+
$(".blc-details-button, .blc-link-text").click(function () {
|
34 |
+
$(this).parents('.blc-row').next('.blc-link-details').toggle();
|
35 |
+
});
|
36 |
+
|
37 |
+
//The discard button - manually mark the link as valid. The link will be checked again later.
|
38 |
+
$(".blc-discard-button").click(function () {
|
39 |
+
var me = $(this);
|
40 |
+
me.html('<?php echo esc_js(__('Wait...', 'broken-link-checker')); ?>');
|
41 |
+
|
42 |
+
var link_id = $(me).parents('.blc-row').find('.blc-link-id').html();
|
43 |
+
|
44 |
+
$.post(
|
45 |
+
"<?php echo admin_url('admin-ajax.php'); ?>",
|
46 |
+
{
|
47 |
+
'action' : 'blc_discard',
|
48 |
+
'link_id' : link_id,
|
49 |
+
'_ajax_nonce' : '<?php echo esc_js(wp_create_nonce('blc_discard')); ?>'
|
50 |
+
},
|
51 |
+
function (data, textStatus){
|
52 |
+
if (data == 'OK'){
|
53 |
+
var master = $(me).parents('.blc-row');
|
54 |
+
var details = master.next('.blc-link-details');
|
55 |
+
|
56 |
+
//Remove the "Not broken" link
|
57 |
+
me.parent().remove();
|
58 |
+
|
59 |
+
master.removeClass('blc-broken-link');
|
60 |
+
|
61 |
+
//Flash the main row green to indicate success, then remove it if the current view
|
62 |
+
//is supposed to show only broken links.
|
63 |
+
var oldColor = master.css('background-color');
|
64 |
+
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300, function(){
|
65 |
+
if ( blc_is_broken_filter ){
|
66 |
+
details.remove();
|
67 |
+
master.remove();
|
68 |
+
} else {
|
69 |
+
reloadDetailsRow(link_id);
|
70 |
+
}
|
71 |
+
});
|
72 |
+
|
73 |
+
//Update the elements displaying the number of results for the current filter.
|
74 |
+
if( blc_is_broken_filter ){
|
75 |
+
alterLinkCounter(-1);
|
76 |
+
}
|
77 |
+
} else {
|
78 |
+
$(me).html('<?php echo esc_js(__('Not broken' , 'broken-link-checker')); ?>');
|
79 |
+
alert(data);
|
80 |
+
}
|
81 |
+
}
|
82 |
+
);
|
83 |
+
|
84 |
+
return false;
|
85 |
+
});
|
86 |
+
|
87 |
+
//The edit button - edit/save the link's URL
|
88 |
+
$(".blc-edit-button").click(function () {
|
89 |
+
var edit_button = $(this);
|
90 |
+
var master = $(edit_button).parents('.blc-row');
|
91 |
+
var editor = $(master).find('.blc-link-editor');
|
92 |
+
var url_el = $(master).find('.blc-link-url');
|
93 |
+
var cancel_button_container = $(master).find('.blc-cancel-button-container');
|
94 |
+
|
95 |
+
//Find the current/original URL
|
96 |
+
var orig_url = url_el.attr('href');
|
97 |
+
//Find the link ID
|
98 |
+
var link_id = $(master).find('.blc-link-id').html();
|
99 |
+
|
100 |
+
if ( !$(editor).is(':visible') ){
|
101 |
+
//Dislay the editing UI
|
102 |
+
url_el.hide();
|
103 |
+
//Reset the edit box to the actual URL value in case the user has already tried and failed to edit this link.
|
104 |
+
editor.val( url_el.attr('href') );
|
105 |
+
editor.show();
|
106 |
+
cancel_button_container.show();
|
107 |
+
editor.focus();
|
108 |
+
editor.select();
|
109 |
+
edit_button.html('<?php echo esc_js(__('Save URL' , 'broken-link-checker')); ?>');
|
110 |
+
} else {
|
111 |
+
//"Save" clicked.
|
112 |
+
editor.hide();
|
113 |
+
cancel_button_container.hide();
|
114 |
+
url_el.show();
|
115 |
+
|
116 |
+
new_url = editor.val();
|
117 |
+
|
118 |
+
if (new_url != orig_url){
|
119 |
+
//Save the changed link
|
120 |
+
url_el.html('<?php echo esc_js(__('Saving changes...' , 'broken-link-checker')); ?>');
|
121 |
+
|
122 |
+
$.getJSON(
|
123 |
+
"<?php echo admin_url('admin-ajax.php'); ?>",
|
124 |
+
{
|
125 |
+
'action' : 'blc_edit',
|
126 |
+
'link_id' : link_id,
|
127 |
+
'new_url' : new_url,
|
128 |
+
'_ajax_nonce' : '<?php echo esc_js(wp_create_nonce('blc_edit')); ?>'
|
129 |
+
},
|
130 |
+
function (data, textStatus){
|
131 |
+
var display_url = '';
|
132 |
+
|
133 |
+
if ( data && (typeof(data['error']) != 'undefined') ){
|
134 |
+
//An internal error occured before the link could be edited.
|
135 |
+
//data.error is an error message.
|
136 |
+
alert(data.error);
|
137 |
+
display_url = orig_url;
|
138 |
+
} else {
|
139 |
+
//data contains info about the performed edit
|
140 |
+
if ( data.errors.length == 0 ){
|
141 |
+
//Everything went well.
|
142 |
+
|
143 |
+
//Replace the displayed link URL with the new one.
|
144 |
+
display_url = new_url;
|
145 |
+
url_el.attr('href', new_url);
|
146 |
+
|
147 |
+
//Save the new ID
|
148 |
+
replaceLinkId(link_id, data.new_link_id);
|
149 |
+
//Load up the new link info
|
150 |
+
reloadDetailsRow(data.new_link_id);
|
151 |
+
//Remove classes indicating link state - they're probably wrong by now
|
152 |
+
master.removeClass('blc-broken-link').removeClass('blc-redirect');
|
153 |
+
|
154 |
+
//Flash the row green to indicate success
|
155 |
+
var oldColor = master.css('background-color');
|
156 |
+
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300);
|
157 |
+
|
158 |
+
} else {
|
159 |
+
display_url = orig_url;
|
160 |
+
|
161 |
+
//Build and display an error message.
|
162 |
+
var msg = '';
|
163 |
+
|
164 |
+
if ( data.cnt_okay > 0 ){
|
165 |
+
var msgpiece = sprintf(
|
166 |
+
'<?php echo esc_js(__('%d instances of the link were successfully modified.', 'broken-link-checker')); ?>',
|
167 |
+
data.cnt_okay
|
168 |
+
);
|
169 |
+
msg = msg + msgpiece + '\n';
|
170 |
+
if ( data.cnt_error > 0 ){
|
171 |
+
msgpiece = sprintf(
|
172 |
+
'<?php echo esc_js(__("However, %d instances couldn't be edited and still point to the old URL.", 'broken-link-checker')); ?>',
|
173 |
+
data.cnt_error
|
174 |
+
);
|
175 |
+
msg = msg + msgpiece + "\n";
|
176 |
+
}
|
177 |
+
} else {
|
178 |
+
msg = msg + '<?php echo esc_js(__('The link could not be modified.', 'broken-link-checker')); ?>\n';
|
179 |
+
}
|
180 |
+
|
181 |
+
msg = msg + '\n<?php echo esc_js(__("The following error(s) occured :", 'broken-link-checker')); ?>\n* ';
|
182 |
+
msg = msg + data.errors.join('\n* ');
|
183 |
+
|
184 |
+
alert(msg);
|
185 |
+
}
|
186 |
+
};
|
187 |
+
|
188 |
+
//Shorten the displayed URL if it's > 50 characters
|
189 |
+
if ( display_url.length > 50 ){
|
190 |
+
display_url = display_url.substr(0, 47) + '...';
|
191 |
+
}
|
192 |
+
url_el.html(display_url);
|
193 |
+
}
|
194 |
+
);
|
195 |
+
|
196 |
+
} else {
|
197 |
+
//It's the same URL, so do nothing.
|
198 |
+
}
|
199 |
+
edit_button.html('<?php echo esc_js(__('Edit URL', 'broken-link-checker')); ?>');
|
200 |
+
}
|
201 |
+
});
|
202 |
+
|
203 |
+
//Let the user use Enter and Esc as shortcuts for "Save URL" and "Cancel"
|
204 |
+
$('input.blc-link-editor').keypress(function (e) {
|
205 |
+
if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
|
206 |
+
$(this).parents('.blc-row').find('.blc-edit-button').click();
|
207 |
+
return false;
|
208 |
+
} else if ((e.which && e.which == 27) || (e.keyCode && e.keyCode == 27)) {
|
209 |
+
$(this).parents('.blc-row').find('.blc-cancel-button').click();
|
210 |
+
return false;
|
211 |
+
} else {
|
212 |
+
return true;
|
213 |
+
}
|
214 |
+
});
|
215 |
+
|
216 |
+
$(".blc-cancel-button").click(function () {
|
217 |
+
var master = $(this).parents('.blc-row');
|
218 |
+
var url_el = $(master).find('.blc-link-url');
|
219 |
+
|
220 |
+
//Hide the cancel button
|
221 |
+
$(this).parent().hide();
|
222 |
+
//Show the un-editable URL again
|
223 |
+
url_el.show();
|
224 |
+
//reset and hide the editor
|
225 |
+
master.find('.blc-link-editor').hide().val(url_el.attr('href'));
|
226 |
+
//Set the edit button to say "Edit URL"
|
227 |
+
master.find('.blc-edit-button').html('<?php echo esc_js(__('Edit URL' , 'broken-link-checker')); ?>');
|
228 |
+
});
|
229 |
+
|
230 |
+
//The unlink button - remove the link/image from all posts, custom fields, etc.
|
231 |
+
$(".blc-unlink-button").click(function () {
|
232 |
+
var me = this;
|
233 |
+
var master = $(me).parents('.blc-row');
|
234 |
+
$(me).html('<?php echo esc_js(__('Wait...' , 'broken-link-checker')); ?>');
|
235 |
+
|
236 |
+
var link_id = $(me).parents('.blc-row').find('.blc-link-id').html();
|
237 |
+
|
238 |
+
$.post(
|
239 |
+
"<?php echo admin_url('admin-ajax.php'); ?>",
|
240 |
+
{
|
241 |
+
'action' : 'blc_unlink',
|
242 |
+
'link_id' : link_id,
|
243 |
+
'_ajax_nonce' : '<?php echo esc_js(wp_create_nonce('blc_unlink')); ?>'
|
244 |
+
},
|
245 |
+
function (data, textStatus){
|
246 |
+
eval('data = ' + data);
|
247 |
+
|
248 |
+
if ( data && (typeof(data['error']) != 'undefined') ){
|
249 |
+
//An internal error occured before the link could be edited.
|
250 |
+
//data.error is an error message.
|
251 |
+
alert(data.error);
|
252 |
+
} else {
|
253 |
+
if ( data.errors.length == 0 ){
|
254 |
+
//The link was successfully removed. Hide its details.
|
255 |
+
master.next('.blc-link-details').hide();
|
256 |
+
//Flash the main row green to indicate success, then hide it.
|
257 |
+
var oldColor = master.css('background-color');
|
258 |
+
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300, function(){
|
259 |
+
master.hide();
|
260 |
+
});
|
261 |
+
|
262 |
+
alterLinkCounter(-1);
|
263 |
+
|
264 |
+
return;
|
265 |
+
} else {
|
266 |
+
//Build and display an error message.
|
267 |
+
var msg = '';
|
268 |
+
|
269 |
+
if ( data.cnt_okay > 0 ){
|
270 |
+
msg = msg + sprintf(
|
271 |
+
'<?php echo esc_js(__("%d instances of the link were successfully unlinked.", 'broken-link-checker')); ?>\n',
|
272 |
+
data.cnt_okay
|
273 |
+
);
|
274 |
+
|
275 |
+
if ( data.cnt_error > 0 ){
|
276 |
+
msg = msg + sprintf(
|
277 |
+
'<?php echo esc_js(__("However, %d instances couldn't be removed.", 'broken-link-checker')); ?>\n',
|
278 |
+
data.cnt_error
|
279 |
+
);
|
280 |
+
}
|
281 |
+
} else {
|
282 |
+
msg = msg + '<?php echo esc_js(__("The plugin failed to remove the link.", 'broken-link-checker')); ?>\n';
|
283 |
+
}
|
284 |
+
|
285 |
+
msg = msg + '\n<?php echo esc_js(__("The following error(s) occured :", 'broken-link-checker')); ?>\n* ';
|
286 |
+
msg = msg + data.errors.join('\n* ');
|
287 |
+
|
288 |
+
//Show the error message
|
289 |
+
alert(msg);
|
290 |
+
}
|
291 |
+
}
|
292 |
+
|
293 |
+
$(me).html('<?php echo esc_js(__('Unlink' , 'broken-link-checker')); ?>');
|
294 |
+
}
|
295 |
+
);
|
296 |
+
});
|
297 |
+
|
298 |
+
//--------------------------------------------
|
299 |
+
//The search box(es)
|
300 |
+
//--------------------------------------------
|
301 |
+
|
302 |
+
var searchForm = $('#search-links-dialog');
|
303 |
+
|
304 |
+
searchForm.dialog({
|
305 |
+
autoOpen : false,
|
306 |
+
dialogClass : 'blc-search-container',
|
307 |
+
resizable: false,
|
308 |
+
});
|
309 |
+
|
310 |
+
$('#blc-open-search-box').click(function(){
|
311 |
+
if ( searchForm.dialog('isOpen') ){
|
312 |
+
searchForm.dialog('close');
|
313 |
+
} else {
|
314 |
+
//Display the search form under the "Search" button
|
315 |
+
var button_position = $('#blc-open-search-box').offset();
|
316 |
+
var button_height = $('#blc-open-search-box').outerHeight(true);
|
317 |
+
var button_width = $('#blc-open-search-box').outerWidth(true);
|
318 |
+
|
319 |
+
var dialog_width = searchForm.dialog('option', 'width');
|
320 |
+
|
321 |
+
searchForm.dialog('option', 'position',
|
322 |
+
[
|
323 |
+
button_position.left - dialog_width + button_width/2,
|
324 |
+
button_position.top + button_height + 1 - $(document).scrollTop()
|
325 |
+
]
|
326 |
+
);
|
327 |
+
searchForm.dialog('open');
|
328 |
+
}
|
329 |
+
});
|
330 |
+
|
331 |
+
$('#blc-cancel-search').click(function(){
|
332 |
+
searchForm.dialog('close');
|
333 |
+
});
|
334 |
+
|
335 |
+
//The "Save This Search Query" button creates a new custom filter based on the current search
|
336 |
+
$('#blc-create-filter').click(function(){
|
337 |
+
var filter_name = prompt("<?php echo esc_js(__("Enter a name for the new custom filter", 'broken-link-checker')); ?>", "");
|
338 |
+
if ( filter_name ){
|
339 |
+
$('#blc-custom-filter-name').val(filter_name);
|
340 |
+
$('#custom-filter-form').submit();
|
341 |
+
}
|
342 |
+
});
|
343 |
+
|
344 |
+
//Display a confirmation dialog when the user clicks the "Delete This Filter" button
|
345 |
+
$('#blc-delete-filter').click(function(){
|
346 |
+
if ( confirm('<?php
|
347 |
+
echo esc_js(
|
348 |
+
__("You are about to delete the current filter.\n'Cancel' to stop, 'OK' to delete", 'broken-link-checker')
|
349 |
+
);
|
350 |
+
?>') ){
|
351 |
+
return true;
|
352 |
+
} else {
|
353 |
+
return false;
|
354 |
+
}
|
355 |
+
});
|
356 |
+
|
357 |
+
//--------------------------------------------
|
358 |
+
// Bulk actions
|
359 |
+
//--------------------------------------------
|
360 |
+
|
361 |
+
$('#blc-bulk-action-form').submit(function(){
|
362 |
+
var action = $('#blc-bulk-action').val();
|
363 |
+
if ( action == '-1' ){
|
364 |
+
var action = $('#blc-bulk-action2').val();
|
365 |
+
}
|
366 |
+
|
367 |
+
//Convey the gravitas of deleting link sources.
|
368 |
+
if ( action == 'bulk-delete-sources' ){
|
369 |
+
var message = '<?php
|
370 |
+
echo esc_js(
|
371 |
+
__("Are you sure you want to delete all posts, bookmarks or other items that contain any of the selected links? This action can't be undone.\n'Cancel' to stop, 'OK' to delete", 'broken-link-checker')
|
372 |
+
);
|
373 |
+
?>';
|
374 |
+
if ( !confirm(message) ){
|
375 |
+
return false;
|
376 |
+
}
|
377 |
+
}
|
378 |
+
});
|
379 |
+
|
380 |
+
//Not implemented yet
|
381 |
+
});
|
382 |
+
|
383 |
+
</script>
|
includes/admin/search-form.php
ADDED
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="search-box">
|
2 |
+
|
3 |
+
<?php
|
4 |
+
//If we're currently displaying search results offer the user the option to s
|
5 |
+
//save the search query as a custom filter.
|
6 |
+
if ( $filter_id == 'search' ){
|
7 |
+
?>
|
8 |
+
<form name="save-search-query" id="custom-filter-form" action="<?php echo admin_url("tools.php?page=view-broken-links"); ?>" method="post" class="blc-inline-form">
|
9 |
+
<?php wp_nonce_field('create-custom-filter'); ?>
|
10 |
+
<input type="hidden" name="name" id="blc-custom-filter-name" value="" />
|
11 |
+
<input type="hidden" name="params" id="blc-custom-filter-params" value="<?php echo http_build_query($search_params, null, '&'); ?>" />
|
12 |
+
<input type="hidden" name="action" value="create-custom-filter" />
|
13 |
+
<input type="button" value="<?php esc_attr_e( 'Save This Search As a Filter', 'broken-link-checker' ); ?>" id="blc-create-filter" class="button" />
|
14 |
+
</form>
|
15 |
+
<?php
|
16 |
+
} elseif ( !empty($current_filter['custom']) ){
|
17 |
+
//If we're displaying a custom filter give an option to delete it.
|
18 |
+
?>
|
19 |
+
<form name="save-search-query" id="custom-filter-form" action="<?php echo admin_url("tools.php?page=view-broken-links"); ?>" method="post" class="blc-inline-form">
|
20 |
+
<?php wp_nonce_field('delete-custom-filter'); ?>
|
21 |
+
<input type="hidden" name="filter_id" id="blc-custom-filter-id" value="<?php echo $filter_id; ?>" />
|
22 |
+
<input type="hidden" name="action" value="delete-custom-filter" />
|
23 |
+
<input type="submit" value="<?php esc_attr_e( 'Delete This Filter', 'broken-link-checker' ); ?>" id="blc-delete-filter" class="button" />
|
24 |
+
</form>
|
25 |
+
<?php
|
26 |
+
}
|
27 |
+
?>
|
28 |
+
|
29 |
+
<input type="button" value="<?php esc_attr_e( 'Search', 'broken-link-checker' ); ?> »" id="blc-open-search-box" class="button" />
|
30 |
+
</div>
|
31 |
+
|
32 |
+
<!-- The search dialog -->
|
33 |
+
<div id='search-links-dialog' title='Search'>
|
34 |
+
<form class="search-form" action="<?php echo admin_url('tools.php?page=view-broken-links'); ?>" method="get">
|
35 |
+
<input type="hidden" name="page" value="view-broken-links" />
|
36 |
+
<input type="hidden" name="filter_id" value="search" />
|
37 |
+
<fieldset>
|
38 |
+
|
39 |
+
<label for="s_link_text"><?php _e('Link text', 'broken-link-checker'); ?></label>
|
40 |
+
<input type="text" name="s_link_text" value="<?php if(!empty($search_params['s_link_text'])) echo esc_attr($search_params['s_link_text']); ?>" id="s_link_text" class="text ui-widget-content" />
|
41 |
+
|
42 |
+
<label for="s_link_url"><?php _e('URL', 'broken-link-checker'); ?></label>
|
43 |
+
<input type="text" name="s_link_url" id="s_link_url" value="<?php if(!empty($search_params['s_link_url'])) echo esc_attr($search_params['s_link_url']); ?>" class="text ui-widget-content" />
|
44 |
+
|
45 |
+
<label for="s_http_code"><?php _e('HTTP code', 'broken-link-checker'); ?></label>
|
46 |
+
<input type="text" name="s_http_code" id="s_http_code" value="<?php if(!empty($search_params['s_http_code'])) echo esc_attr($search_params['s_http_code']); ?>" class="text ui-widget-content" />
|
47 |
+
|
48 |
+
<label for="s_filter"><?php _e('Link status', 'broken-link-checker'); ?></label>
|
49 |
+
<select name="s_filter" id="s_filter">
|
50 |
+
<?php
|
51 |
+
if ( !empty($search_params['s_filter']) ){
|
52 |
+
$search_subfilter = $search_params['s_filter'];
|
53 |
+
} else {
|
54 |
+
$search_subfilter = $filter_id;
|
55 |
+
}
|
56 |
+
|
57 |
+
foreach ($blc_link_query->native_filters as $filter => $data){
|
58 |
+
$selected = ($search_subfilter == $filter)?' selected="selected"':'';
|
59 |
+
printf('<option value="%s"%s>%s</option>', $filter, $selected, $data['name']);
|
60 |
+
}
|
61 |
+
?>
|
62 |
+
</select>
|
63 |
+
|
64 |
+
<label for="s_link_type"><?php _e('Link type', 'broken-link-checker'); ?></label>
|
65 |
+
<select name="s_link_type" id="s_link_type">
|
66 |
+
<?php
|
67 |
+
$link_types = array(
|
68 |
+
__('Any', 'broken-link-checker') => '',
|
69 |
+
__('Normal link', 'broken-link-checker') => 'link',
|
70 |
+
__('Image', 'broken-link-checker') => 'image',
|
71 |
+
__('Custom field', 'broken-link-checker') => 'custom_field',
|
72 |
+
__('Bookmark', 'broken-link-checker') => 'blogroll',
|
73 |
+
__('Comment', 'broken-link-checker') => 'comment',
|
74 |
+
);
|
75 |
+
|
76 |
+
foreach ($link_types as $name => $value){
|
77 |
+
$selected = ( isset($search_params['s_link_type']) && $search_params['s_link_type'] == $value )?' selected="selected"':'';
|
78 |
+
printf('<option value="%s"%s>%s</option>', $value, $selected, $name);
|
79 |
+
}
|
80 |
+
?>
|
81 |
+
</select>
|
82 |
+
|
83 |
+
</fieldset>
|
84 |
+
|
85 |
+
<div id="blc-search-button-row">
|
86 |
+
<input type="submit" value="<?php esc_attr_e( 'Search Links', 'broken-link-checker' ); ?>" id="blc-search-button" name="search_button" class="button-primary" />
|
87 |
+
<input type="button" value="<?php esc_attr_e( 'Cancel', 'broken-link-checker' ); ?>" id="blc-cancel-search" class="button" />
|
88 |
+
</div>
|
89 |
+
|
90 |
+
</form>
|
91 |
+
</div>
|
includes/checkers.php
ADDED
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Base class for link checking algorithms.
|
5 |
+
*
|
6 |
+
* All link checkering algorithms should extend this class.
|
7 |
+
*
|
8 |
+
* @package Broken Link Checker
|
9 |
+
* @access public
|
10 |
+
*/
|
11 |
+
class blcChecker {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Priority determines the order in which the plugin will try all registered checkers
|
15 |
+
* when looking for one that can check a particular URL. Registered checkers will be
|
16 |
+
* tried in order, from highest to lowest priority, and the first one that returns
|
17 |
+
* true when its can_check() method is called will be used.
|
18 |
+
*
|
19 |
+
* Checker implementations should set their priority depending on how specific they are
|
20 |
+
* in choosing the URLs that they check.
|
21 |
+
*
|
22 |
+
* -10 .. 10 : checks all URLs that have a certain protocol, e.g. all HTTP URLs.
|
23 |
+
* 11 .. 100 : checks only URLs from a restricted number of domains, e.g. video site URLs.
|
24 |
+
* 100+ : checks only certain URLs from a certain domain, e.g. YouTube video links.
|
25 |
+
*
|
26 |
+
*/
|
27 |
+
var $priority = -100;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Check if this checker knows how to check a particular URL.
|
31 |
+
*
|
32 |
+
* @param string $url
|
33 |
+
* @param array|false $parsed_url The result of parsing $url with parse_url(). See PHP docs for details.
|
34 |
+
* @return bool
|
35 |
+
*/
|
36 |
+
function can_check($url, $parsed_url){
|
37 |
+
return false;
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Check an URL.
|
42 |
+
*
|
43 |
+
* This method returns an associative array containing results of
|
44 |
+
* the check. The following array keys are recognized by the plugin and
|
45 |
+
* their values will be stored in the link's DB record :
|
46 |
+
* 'broken' (bool) - True if the URL points to a missing/broken page. Required.
|
47 |
+
* 'http_code' (int) - HTTP code returned when requesting the URL. Defaults to 0.
|
48 |
+
* 'redirect_count' (int) - The number of redirects. Defaults to 0.
|
49 |
+
* 'final_url' (string) - The redirected-to URL. Assumed to be equal to the checked URL by default.
|
50 |
+
* 'request_duration' (float) - How long it took for the server to respond. Defaults to 0 seconds.
|
51 |
+
* 'timeout' (bool) - True if checking the URL resulted in a timeout. Defaults to false.
|
52 |
+
* 'may_recheck' (bool) - Allow the plugin to re-check the URL after 'recheck_threshold' seconds (see broken-link-checker.php).
|
53 |
+
* 'log' (string) - Free-form log of the performed check. It will be displayed in the "Details" section of the checked link.
|
54 |
+
* 'result_hash' (string) - A free-form hash or code uniquely identifying the detected link status. See sub-classes for examples. Max 200 characters.
|
55 |
+
*
|
56 |
+
* @see blcLink:check()
|
57 |
+
*
|
58 |
+
* @param string $url
|
59 |
+
* @return array
|
60 |
+
*/
|
61 |
+
function check($url){
|
62 |
+
trigger_error('Function blcChecker::check() must be over-ridden in a subclass', E_USER_ERROR);
|
63 |
+
}
|
64 |
+
}
|
65 |
+
|
66 |
+
class blcCheckerRegistry {
|
67 |
+
var $registered_checkers = array();
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Register a link checker.
|
71 |
+
*
|
72 |
+
* @param string $class_name Class name of the checker.
|
73 |
+
* @return void
|
74 |
+
*/
|
75 |
+
function register_checker($class_name){
|
76 |
+
$checker = new $class_name;
|
77 |
+
$this->registered_checkers[] = $checker;
|
78 |
+
|
79 |
+
usort($this->registered_checkers, array(&$this, 'compare_checkers'));
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Callback for sorting checkers by priority.
|
84 |
+
*
|
85 |
+
* @access private
|
86 |
+
*
|
87 |
+
* @param blcChecker $a
|
88 |
+
* @param blcChecker $b
|
89 |
+
* @return int
|
90 |
+
*/
|
91 |
+
function compare_checkers($a, $b){
|
92 |
+
return $b->priority - $a->priority;
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Get a checker object that can check the specified URL.
|
97 |
+
*
|
98 |
+
* @param string $url
|
99 |
+
* @return blcChecker|null
|
100 |
+
*/
|
101 |
+
function get_checker_for($url){
|
102 |
+
$parsed = @parse_url($url);
|
103 |
+
|
104 |
+
foreach($this->registered_checkers as $checker){
|
105 |
+
if ( $checker->can_check($url, $parsed) ){
|
106 |
+
return $checker;
|
107 |
+
}
|
108 |
+
}
|
109 |
+
|
110 |
+
return null;
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
$GLOBALS['blc_checker_registry'] = new blcCheckerRegistry();
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Register a new link checker.
|
118 |
+
*
|
119 |
+
* @param string $class_name
|
120 |
+
* @return void
|
121 |
+
*/
|
122 |
+
function blc_register_checker($class_name){
|
123 |
+
return $GLOBALS['blc_checker_registry']->register_checker($class_name);
|
124 |
+
}
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Get the checker algo. implementation that knows how to check a specific URL.
|
128 |
+
*
|
129 |
+
* @param string $url The URL that needs to be checked.
|
130 |
+
* @return blcChecker|null
|
131 |
+
*/
|
132 |
+
function blc_get_checker_for($url){
|
133 |
+
return $GLOBALS['blc_checker_registry']->get_checker_for($url);
|
134 |
+
}
|
135 |
+
|
136 |
+
?>
|
includes/checkers/http.php
ADDED
@@ -0,0 +1,312 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Base class for checkers that deal with HTTP(S) URLs.
|
5 |
+
*
|
6 |
+
* @package Broken Link Checker
|
7 |
+
* @access public
|
8 |
+
*/
|
9 |
+
class blcHttpChecker extends blcChecker{
|
10 |
+
|
11 |
+
var $priority = -1;
|
12 |
+
|
13 |
+
function clean_url($url){
|
14 |
+
$url = html_entity_decode($url);
|
15 |
+
$url = preg_replace(
|
16 |
+
array(
|
17 |
+
'/([\?&]PHPSESSID=\w+)$/i', //remove session ID
|
18 |
+
'/(#[^\/]*)$/', //and anchors/fragments
|
19 |
+
'/&/', //convert improper HTML entities
|
20 |
+
'/([\?&]sid=\w+)$/i' //remove another flavour of session ID
|
21 |
+
),
|
22 |
+
array('','','&','',''),
|
23 |
+
$url
|
24 |
+
);
|
25 |
+
$url = trim($url);
|
26 |
+
|
27 |
+
return $url;
|
28 |
+
}
|
29 |
+
|
30 |
+
function is_error_code($http_code){
|
31 |
+
/*"Good" response codes are anything in the 2XX range (e.g "200 OK") and redirects - the 3XX range.
|
32 |
+
HTTP 401 Unauthorized is a special case that is considered OK as well. Other errors - the 4XX range -
|
33 |
+
are treated as "page doesn't exist'". */
|
34 |
+
$good_code = ( ($http_code >= 200) && ($http_code < 400) ) || ( $http_code == 401 );
|
35 |
+
return !$good_code;
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* This checker only accepts HTTP(s) links.
|
40 |
+
*
|
41 |
+
* @param string $url
|
42 |
+
* @param array|false $parsed
|
43 |
+
* @return bool
|
44 |
+
*/
|
45 |
+
function can_check($url, $parsed){
|
46 |
+
if ( !isset($parsed['scheme']) ) return false;
|
47 |
+
|
48 |
+
return in_array( strtolower($parsed['scheme']), array('http', 'https') );
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Takes an URL and replaces spaces and some other non-alphanumeric characters with their urlencoded equivalents.
|
53 |
+
*
|
54 |
+
* @param string $str
|
55 |
+
* @return string
|
56 |
+
*/
|
57 |
+
function urlencodefix($url){
|
58 |
+
return preg_replace_callback(
|
59 |
+
'|[^a-z0-9\+\-\/\\#:.=?&%@]|i',
|
60 |
+
create_function('$str','return rawurlencode($str[0]);'),
|
61 |
+
$url
|
62 |
+
);
|
63 |
+
}
|
64 |
+
|
65 |
+
}
|
66 |
+
|
67 |
+
//TODO: Rewrite sub-classes as transports, not stand-alone checkers
|
68 |
+
class blcCurlHttp extends blcHttpChecker {
|
69 |
+
|
70 |
+
var $last_headers = '';
|
71 |
+
|
72 |
+
function check($url, $use_get = false){
|
73 |
+
$this->last_headers = '';
|
74 |
+
|
75 |
+
$url = $this->clean_url($url);
|
76 |
+
|
77 |
+
$result = array(
|
78 |
+
'broken' => false,
|
79 |
+
);
|
80 |
+
$log = '';
|
81 |
+
|
82 |
+
//Get the BLC configuration. It's used below to set the right timeout values and such.
|
83 |
+
$conf = blc_get_configuration();
|
84 |
+
|
85 |
+
//Init curl.
|
86 |
+
$ch = curl_init();
|
87 |
+
curl_setopt($ch, CURLOPT_URL, $this->urlencodefix($url));
|
88 |
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
89 |
+
|
90 |
+
//Masquerade as Internet explorer
|
91 |
+
//$ua = 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)';
|
92 |
+
$ua = 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)';
|
93 |
+
curl_setopt($ch, CURLOPT_USERAGENT, $ua);
|
94 |
+
|
95 |
+
//Add a semi-plausible referer header to avoid tripping up some bot traps
|
96 |
+
curl_setopt($ch, CURLOPT_REFERER, get_option('home'));
|
97 |
+
|
98 |
+
//Redirects don't work when safe mode or open_basedir is enabled.
|
99 |
+
if ( !blcUtility::is_safe_mode() && !blcUtility::is_open_basedir() ) {
|
100 |
+
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
101 |
+
}
|
102 |
+
//Set maximum redirects
|
103 |
+
curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
|
104 |
+
|
105 |
+
//Set the timeout
|
106 |
+
curl_setopt($ch, CURLOPT_TIMEOUT, $conf->options['timeout']);
|
107 |
+
|
108 |
+
//Set the proxy configuration. The user can provide this in wp-config.php
|
109 |
+
if (defined('WP_PROXY_HOST')) {
|
110 |
+
curl_setopt($ch, CURLOPT_PROXY, WP_PROXY_HOST);
|
111 |
+
}
|
112 |
+
if (defined('WP_PROXY_PORT')) {
|
113 |
+
curl_setopt($ch, CURLOPT_PROXYPORT, WP_PROXY_PORT);
|
114 |
+
}
|
115 |
+
if (defined('WP_PROXY_USERNAME')){
|
116 |
+
$auth = WP_PROXY_USERNAME;
|
117 |
+
if (defined('WP_PROXY_PASSWORD')){
|
118 |
+
$auth .= ':' . WP_PROXY_PASSWORD;
|
119 |
+
}
|
120 |
+
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $auth);
|
121 |
+
}
|
122 |
+
|
123 |
+
//Make CURL return a valid result even if it gets a 404 or other error.
|
124 |
+
curl_setopt($ch, CURLOPT_FAILONERROR, false);
|
125 |
+
|
126 |
+
|
127 |
+
$nobody = !$use_get; //Whether to send a HEAD request (the default) or a GET request
|
128 |
+
|
129 |
+
$parts = @parse_url($url);
|
130 |
+
if( $parts['scheme'] == 'https' ){
|
131 |
+
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); //Required to make HTTPS URLs work.
|
132 |
+
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); //Likewise.
|
133 |
+
$nobody = false; //Can't use HEAD with HTTPS.
|
134 |
+
}
|
135 |
+
|
136 |
+
if ( $nobody ){
|
137 |
+
//If possible, use HEAD requests for speed.
|
138 |
+
curl_setopt($ch, CURLOPT_NOBODY, true);
|
139 |
+
} else {
|
140 |
+
//If we must use GET at least limit the amount of downloaded data.
|
141 |
+
curl_setopt($ch, HTTP_HEADER, array('Range: bytes=0-2048')); //2 KB
|
142 |
+
}
|
143 |
+
|
144 |
+
//Register a callback function which will process the HTTP header(s).
|
145 |
+
//It can be called multiple times if the remote server performs a redirect.
|
146 |
+
curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$this,'read_header'));
|
147 |
+
|
148 |
+
//Execute the request
|
149 |
+
curl_exec($ch);
|
150 |
+
|
151 |
+
$info = curl_getinfo($ch);
|
152 |
+
curl_close($ch);
|
153 |
+
|
154 |
+
//Store the results
|
155 |
+
$result['http_code'] = intval( $info['http_code'] );
|
156 |
+
$result['timeout'] = ($result['http_code'] == 0); //If the code is 0 then it's probably a timeout
|
157 |
+
$result['final_url'] = $info['url'];
|
158 |
+
$result['request_duration'] = $info['total_time'];
|
159 |
+
$result['redirect_count'] = $info['redirect_count'];
|
160 |
+
|
161 |
+
if ( $nobody && ($result['http_code'] == 405) ){
|
162 |
+
//405 = Method not allowed. The site in question is probably expecting
|
163 |
+
//GET instead of HEAD. So lets retry the request using the GET verb.
|
164 |
+
return $this->check($url, true);
|
165 |
+
}
|
166 |
+
|
167 |
+
//When safe_mode or open_basedir is enabled CURL will be forbidden from following redirects,
|
168 |
+
//so redirect_count will be 0 for all URLs. As a workaround, set it to 1 when the HTTP
|
169 |
+
//response codes indicates a redirect but redirect_count is zero.
|
170 |
+
//Note to self : Extracting the Location header might also be helpful.
|
171 |
+
if ( ($result['redirect_count'] == 0) && ( in_array( $result['http_code'], array(301, 302, 303, 307) ) ) ){
|
172 |
+
$result['redirect_count'] = 1;
|
173 |
+
}
|
174 |
+
|
175 |
+
//Determine if the link counts as "broken"
|
176 |
+
$result['broken'] = $this->is_error_code($result['http_code']) || $result['timeout'];
|
177 |
+
|
178 |
+
//Build the log from HTTP code and headers.
|
179 |
+
//TODO: Put some kind of a color-coded error explanation at the top of the log, not a cryptic HTTP code.
|
180 |
+
$log .= '=== ';
|
181 |
+
if ( $result['http_code'] ){
|
182 |
+
$log .= sprintf( __('HTTP code : %d', 'broken-link-checker'), $result['http_code']);
|
183 |
+
} else {
|
184 |
+
$log .= __('(No response)', 'broken-link-checker');
|
185 |
+
}
|
186 |
+
$log .= " ===\n\n";
|
187 |
+
$log .= $this->last_headers;
|
188 |
+
|
189 |
+
if ( $result['broken'] && $result['timeout'] ) {
|
190 |
+
$log .= "\n(" . __("Most likely the connection timed out or the domain doesn't exist.", 'broken-link-checker') . ')';
|
191 |
+
}
|
192 |
+
|
193 |
+
$result['log'] = $log;
|
194 |
+
|
195 |
+
//The hash should contain info about all pieces of data that pertain to determining if the
|
196 |
+
//link is working.
|
197 |
+
$result['result_hash'] = implode('|', array(
|
198 |
+
$result['http_code'],
|
199 |
+
$result['broken']?'broken':'0',
|
200 |
+
$result['timeout']?'timeout':'0',
|
201 |
+
md5($result['final_url']),
|
202 |
+
));
|
203 |
+
|
204 |
+
return $result;
|
205 |
+
}
|
206 |
+
|
207 |
+
function read_header($ch, $header){
|
208 |
+
$this->last_headers .= $header;
|
209 |
+
return strlen($header);
|
210 |
+
}
|
211 |
+
|
212 |
+
}
|
213 |
+
|
214 |
+
class blcSnoopyHttp extends blcHttpChecker {
|
215 |
+
|
216 |
+
function check($url){
|
217 |
+
$url = $this->clean_url($url); //Note : Snoopy doesn't work too well with HTTPS URLs.
|
218 |
+
|
219 |
+
$result = array(
|
220 |
+
'broken' => false,
|
221 |
+
);
|
222 |
+
$log = '';
|
223 |
+
|
224 |
+
//Get the timeout setting from the BLC configuration.
|
225 |
+
$conf = blc_get_configuration();
|
226 |
+
$timeout = $conf->options['timeout'];
|
227 |
+
|
228 |
+
$start_time = microtime_float(true);
|
229 |
+
|
230 |
+
//Fetch the URL with Snoopy
|
231 |
+
$snoopy = new Snoopy;
|
232 |
+
$snoopy->read_timeout = $timeout; //read timeout in seconds
|
233 |
+
$snoopy->agent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"; //masquerade as IE 7
|
234 |
+
$snoopy->maxlength = 1024*5; //load up to 5 kilobytes
|
235 |
+
$snoopy->fetch($url);
|
236 |
+
|
237 |
+
$result['request_duration'] = microtime_float(true) - $start_time;
|
238 |
+
|
239 |
+
$result['http_code'] = $snoopy->status; //HTTP status code
|
240 |
+
//Snoopy returns -100 on timeout
|
241 |
+
if ( $result['http_code'] == -100 ){
|
242 |
+
$result['http_code'] = 0;
|
243 |
+
$result['timeout'] = true;
|
244 |
+
}
|
245 |
+
|
246 |
+
//Build the log
|
247 |
+
$log .= '=== ';
|
248 |
+
if ( $result['http_code'] ){
|
249 |
+
$log .= sprintf( __('HTTP code : %d', 'broken-link-checker'), $result['http_code']);
|
250 |
+
} else {
|
251 |
+
$log .= __('(No response)', 'broken-link-checker');
|
252 |
+
}
|
253 |
+
$log .= " ===\n\n";
|
254 |
+
|
255 |
+
if ($snoopy->error)
|
256 |
+
$log .= $snoopy->error."\n";
|
257 |
+
if ($snoopy->timed_out) {
|
258 |
+
$log .= __("Request timed out.", 'broken-link-checker') . "\n";
|
259 |
+
$result['timeout'] = true;
|
260 |
+
}
|
261 |
+
|
262 |
+
if ( is_array($snoopy->headers) )
|
263 |
+
$log .= implode("", $snoopy->headers)."\n"; //those headers already contain newlines
|
264 |
+
|
265 |
+
//Redirected?
|
266 |
+
if ( $snoopy->lastredirectaddr ) {
|
267 |
+
$result['final_url'] = $snoopy->lastredirectaddr;
|
268 |
+
$result['redirect_count'] = $snoopy->_redirectdepth;
|
269 |
+
} else {
|
270 |
+
$result['final_url'] = $url;
|
271 |
+
}
|
272 |
+
|
273 |
+
//Determine if the link counts as "broken"
|
274 |
+
$result['broken'] = $this->is_error_code($result['http_code']) || $result['timeout'];
|
275 |
+
|
276 |
+
$log .= "<em>(" . __('Using Snoopy', 'broken-link-checker') . ")</em>";
|
277 |
+
$result['log'] = $log;
|
278 |
+
|
279 |
+
//The hash should contain info about all pieces of data that pertain to determining if the
|
280 |
+
//link is working.
|
281 |
+
$result['result_hash'] = implode('|', array(
|
282 |
+
$result['http_code'],
|
283 |
+
$result['broken']?'broken':'0',
|
284 |
+
$result['timeout']?'timeout':'0',
|
285 |
+
md5($result['final_url']),
|
286 |
+
));
|
287 |
+
|
288 |
+
return $result;
|
289 |
+
}
|
290 |
+
|
291 |
+
}
|
292 |
+
|
293 |
+
if ( function_exists('curl_init') ) {
|
294 |
+
blc_register_checker('blcCurlHttp');
|
295 |
+
} else {
|
296 |
+
//Try to load Snoopy.
|
297 |
+
if ( !class_exists('Snoopy') ){
|
298 |
+
$snoopy_file = ABSPATH. WPINC . '/class-snoopy.php';
|
299 |
+
if (file_exists($snoopy_file) ){
|
300 |
+
include $snoopy_file;
|
301 |
+
}
|
302 |
+
}
|
303 |
+
|
304 |
+
//If Snoopy is available, it will be used in place of CURL.
|
305 |
+
if ( class_exists('Snoopy') ){
|
306 |
+
blc_register_checker('blcSnoopyHttp');
|
307 |
+
}
|
308 |
+
}
|
309 |
+
|
310 |
+
|
311 |
+
|
312 |
+
?>
|
includes/containers.php
ADDED
@@ -0,0 +1,886 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* A class for handling link container types.
|
5 |
+
*
|
6 |
+
* This class keeps track of all registered container types and is used to retrieve and/or
|
7 |
+
* instantiate container objects. Mostly acts as a proxy between various container managers
|
8 |
+
* and the rest of plugin code. It does't know anything about how individual containers are
|
9 |
+
* implemented.
|
10 |
+
*
|
11 |
+
* Used as a singleton.
|
12 |
+
*
|
13 |
+
* @package Broken Link Checker
|
14 |
+
*/
|
15 |
+
class blcContainerRegistry {
|
16 |
+
|
17 |
+
var $registered_managers;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* blcContainerRegistry::__construct()
|
21 |
+
*
|
22 |
+
* @return void
|
23 |
+
*/
|
24 |
+
function __construct(){
|
25 |
+
$this->registered_managers = array();
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* blcContainerRegistry::blcContainerRegistry()
|
30 |
+
* Old-style class constructor
|
31 |
+
*
|
32 |
+
* @return void
|
33 |
+
*/
|
34 |
+
function blcContainerRegistry(){
|
35 |
+
$this->__construct();
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Register a new container type.
|
40 |
+
*
|
41 |
+
* A "container type" comprises three things :
|
42 |
+
* - An alphanumeric container type name, e.g. "post"
|
43 |
+
* - A class representing an individual container. Must inherit from blcContainer.
|
44 |
+
* - A "manager" class that builds container objects, knows how to retrieve multiple
|
45 |
+
* containers and their associated data from the database, and handles all other
|
46 |
+
* ancillary tasks associated with the particular container type (e.g. WP hooks).
|
47 |
+
*
|
48 |
+
* When registering a new container type you only need to provide the container type
|
49 |
+
* name and the container manager class name.
|
50 |
+
*
|
51 |
+
* @see blcContainer
|
52 |
+
* @see blcContainerManager
|
53 |
+
*
|
54 |
+
* @param string $container_type
|
55 |
+
* @param string $manager_class
|
56 |
+
* @return bool True on success, false if the container type is already registered.
|
57 |
+
*/
|
58 |
+
function register_container( $container_type, $manager_class ){
|
59 |
+
if ( isset($this->registered_managers[$container_type]) ){
|
60 |
+
return false;
|
61 |
+
}
|
62 |
+
|
63 |
+
$this->registered_managers[$container_type] = new $manager_class($container_type);
|
64 |
+
|
65 |
+
return true;
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Get the manager associated with a container type.
|
70 |
+
*
|
71 |
+
* @param string $container_type
|
72 |
+
* @param string $fallback If there is no manager associated with $container_type, return the manager of this container type instead.
|
73 |
+
* @return blcContainerManager|null
|
74 |
+
*/
|
75 |
+
function get_manager( $container_type, $fallback = '' ){
|
76 |
+
if ( isset($this->registered_managers[$container_type]) ){
|
77 |
+
return $this->registered_managers[$container_type];
|
78 |
+
} elseif ( !empty($fallback) && isset($this->registered_managers[$fallback]) ) {
|
79 |
+
return $this->registered_managers[$fallback];
|
80 |
+
} else {
|
81 |
+
return null;
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Retrieve or instantiate a container object.
|
87 |
+
*
|
88 |
+
* Pass an array containing the container type (string) and ID (int) to retrieve the container
|
89 |
+
* from the database. Alternatively, pass an associative array to create a new container object
|
90 |
+
* from the data in the array.
|
91 |
+
*
|
92 |
+
* @param array $container Either [container_type, container_id], or an assoc. array of container data.
|
93 |
+
* @return blcContainer|null
|
94 |
+
*/
|
95 |
+
function get_container( $container ){
|
96 |
+
global $wpdb;
|
97 |
+
|
98 |
+
if ( !is_array($container) || ( count($container) < 2 ) ){
|
99 |
+
return null;
|
100 |
+
}
|
101 |
+
|
102 |
+
if ( is_string($container[0]) && is_numeric($container[1]) ){
|
103 |
+
//The argument is in the [container_type, id] format
|
104 |
+
//Fetch the container's synch record.
|
105 |
+
$q = "SELECT * FROM {$wpdb->prefix}blc_synch WHERE container_type = %s AND container_id = %d";
|
106 |
+
$q = $wpdb->prepare($q, $container[0], $container[1]);
|
107 |
+
$rez = $wpdb->get_row($q, ARRAY_A);
|
108 |
+
|
109 |
+
if ( empty($rez) ){
|
110 |
+
//The container wasn't found, so we'll create a new one.
|
111 |
+
$container = array(
|
112 |
+
'container_type' => $container[0],
|
113 |
+
'container_id' => $container[1],
|
114 |
+
);
|
115 |
+
} else {
|
116 |
+
$container = $rez;
|
117 |
+
}
|
118 |
+
}
|
119 |
+
|
120 |
+
if ( !isset($this->registered_managers[$container['container_type']]) ){
|
121 |
+
return null;
|
122 |
+
}
|
123 |
+
|
124 |
+
$manager = $this->registered_managers[$container['container_type']];
|
125 |
+
|
126 |
+
return $manager->get_container($container);
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Retrieve or instantiate multiple link containers.
|
131 |
+
*
|
132 |
+
* Takes an array of container specifications and returns an array of container objects.
|
133 |
+
* Each input array entry should be an array and consist either of a container type (string)
|
134 |
+
* and container ID (int), or name => value pairs describing a container object.
|
135 |
+
*
|
136 |
+
* @see blcContainerRegistry::get_container()
|
137 |
+
*
|
138 |
+
* @param array $containers
|
139 |
+
* @param string $purpose Optional code indicating how the retrieved containers will be used.
|
140 |
+
* @param string $fallback The fallback container type to use for unrecognized containers.
|
141 |
+
* @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
|
142 |
+
* @return array of blcContainer indexed by "container_type|container_id"
|
143 |
+
*/
|
144 |
+
function get_containers( $containers, $purpose = '', $fallback = '', $load_wrapped_objects = false ){
|
145 |
+
global $wpdb;
|
146 |
+
|
147 |
+
//If the input is invalid or empty, return an empty array.
|
148 |
+
if ( !is_array($containers) || (count($containers) < 1) ) {
|
149 |
+
return array();
|
150 |
+
}
|
151 |
+
|
152 |
+
$first = reset($containers);
|
153 |
+
if ( !is_array($first) ){
|
154 |
+
return array();
|
155 |
+
}
|
156 |
+
|
157 |
+
if ( is_string($first[0]) && is_numeric($first[1]) ){
|
158 |
+
//The argument is an array of [container_type, id].
|
159 |
+
//Divide the container IDs by container type.
|
160 |
+
$by_type = array();
|
161 |
+
|
162 |
+
foreach($containers as $container){
|
163 |
+
if ( isset($by_type[$container[0]]) ){
|
164 |
+
array_push($by_type[$container[0]], intval($container[1]));
|
165 |
+
} else {
|
166 |
+
$by_type[$container[0]] = array( intval($container[1]) );
|
167 |
+
}
|
168 |
+
}
|
169 |
+
|
170 |
+
//Build the SQL to fetch all the specified containers
|
171 |
+
$q = "SELECT *
|
172 |
+
FROM {$wpdb->prefix}blc_synch
|
173 |
+
WHERE";
|
174 |
+
|
175 |
+
$pieces = array();
|
176 |
+
foreach($by_type as $container_type => $container_ids){
|
177 |
+
$pieces[] = '( container_type = "'. $wpdb->escape($container_type) .'" AND container_id IN ('. implode(', ', $container_ids) .') )';
|
178 |
+
}
|
179 |
+
|
180 |
+
$q .= implode("\n\t OR ", $pieces);
|
181 |
+
|
182 |
+
//Fetch the container synch. records from the DB.
|
183 |
+
$containers = $wpdb->get_results($q, ARRAY_A);
|
184 |
+
}
|
185 |
+
|
186 |
+
/*
|
187 |
+
Divide the inputs into separate arrays by container type (again), then invoke
|
188 |
+
the appropriate manager for each type to instantiate the container objects.
|
189 |
+
*/
|
190 |
+
|
191 |
+
//At this point, $containers is an array of assoc. arrays comprising container data.
|
192 |
+
$by_type = array();
|
193 |
+
foreach($containers as $container){
|
194 |
+
if ( isset($by_type[$container['container_type']]) ){
|
195 |
+
array_push($by_type[$container['container_type']], $container);
|
196 |
+
} else {
|
197 |
+
$by_type[$container['container_type']] = array($container);
|
198 |
+
}
|
199 |
+
}
|
200 |
+
|
201 |
+
$results = array();
|
202 |
+
foreach($by_type as $container_type => $entries){
|
203 |
+
$manager = $this->get_manager($container_type, $fallback);
|
204 |
+
if ( !is_null($manager) ){
|
205 |
+
$partial_results = $manager->get_containers($entries, $purpose, $load_wrapped_objects);
|
206 |
+
$results = array_merge($results, $partial_results);
|
207 |
+
}
|
208 |
+
}
|
209 |
+
|
210 |
+
return $results;
|
211 |
+
}
|
212 |
+
|
213 |
+
/**
|
214 |
+
* Retrieve link containers that need to be synchronized (parsed).
|
215 |
+
*
|
216 |
+
* @param integer $max_results The maximum number of containers to return. Defaults to returning all unsynched containers.
|
217 |
+
* @return array of blcContainer
|
218 |
+
*/
|
219 |
+
function get_unsynched_containers($max_results = 0){
|
220 |
+
global $wpdb;
|
221 |
+
|
222 |
+
$q = "SELECT * FROM {$wpdb->prefix}blc_synch WHERE synched = 0";
|
223 |
+
if ( $max_results > 0 ){
|
224 |
+
$q .= " LIMIT $max_results";
|
225 |
+
}
|
226 |
+
|
227 |
+
$container_data = $wpdb->get_results($q, ARRAY_A);
|
228 |
+
//FB::log($container_data, "Unsynched containers");
|
229 |
+
if( empty($container_data) ){
|
230 |
+
return array();
|
231 |
+
}
|
232 |
+
|
233 |
+
$containers = $this->get_containers($container_data, BLC_FOR_PARSING, 'dummy');
|
234 |
+
return $containers;
|
235 |
+
}
|
236 |
+
|
237 |
+
/**
|
238 |
+
* (Re)create and update synchronization records for all supported containers.
|
239 |
+
* Calls the resynch() method of all registered managers.
|
240 |
+
*
|
241 |
+
* @param bool $forced If true, assume that no synch. records exist and build all of them from scratch.
|
242 |
+
* @return void
|
243 |
+
*/
|
244 |
+
function resynch($forced = false){
|
245 |
+
global $wpdb;
|
246 |
+
|
247 |
+
foreach($this->registered_managers as $manager){
|
248 |
+
$manager->resynch($forced);
|
249 |
+
}
|
250 |
+
}
|
251 |
+
|
252 |
+
/**
|
253 |
+
* Get the message to display after $n containers of a specific type have been deleted.
|
254 |
+
*
|
255 |
+
* @param string $container_type
|
256 |
+
* @param int $n Number of deleted containers.
|
257 |
+
* @return string A delete confirmation message, e.g. "5 posts were moved to trash"
|
258 |
+
*/
|
259 |
+
function ui_bulk_delete_message($container_type, $n){
|
260 |
+
$manager = $this->get_manager($container_type);
|
261 |
+
if ( is_null($manager) ){
|
262 |
+
return sprintf(__("Container type '%s' not recognized", 'broken-link-checker'), $container_type);
|
263 |
+
} else {
|
264 |
+
return $manager->ui_bulk_delete_message($n);
|
265 |
+
}
|
266 |
+
}
|
267 |
+
}
|
268 |
+
|
269 |
+
//Init the container registry & make it global
|
270 |
+
$GLOBALS['blc_container_registry'] = new blcContainerRegistry();
|
271 |
+
|
272 |
+
|
273 |
+
|
274 |
+
/**
|
275 |
+
* The base class for link containers. All containers should extend this class.
|
276 |
+
*
|
277 |
+
* @package Broken Link Checker
|
278 |
+
* @access public
|
279 |
+
*/
|
280 |
+
class blcContainer {
|
281 |
+
|
282 |
+
var $fields = array();
|
283 |
+
var $default_field = '';
|
284 |
+
|
285 |
+
var $container_type;
|
286 |
+
var $container_id = 0;
|
287 |
+
|
288 |
+
var $synched = false;
|
289 |
+
var $last_synch = '0000-00-00 00:00:00';
|
290 |
+
|
291 |
+
var $wrapped_object = null;
|
292 |
+
|
293 |
+
/**
|
294 |
+
* Constructor
|
295 |
+
*
|
296 |
+
* @param array $data
|
297 |
+
* @param object $wrapped_object
|
298 |
+
* @return void
|
299 |
+
*/
|
300 |
+
function __construct( $data = null, $wrapped_object = null ){
|
301 |
+
$this->wrapped_object = $wrapped_object;
|
302 |
+
if ( !empty($data) && is_array($data) ){
|
303 |
+
foreach($data as $name => $value){
|
304 |
+
$this->$name = $value;
|
305 |
+
}
|
306 |
+
}
|
307 |
+
}
|
308 |
+
|
309 |
+
/**
|
310 |
+
* blcContainer::blcContainer()
|
311 |
+
* Old style class constructor
|
312 |
+
*
|
313 |
+
* @return void
|
314 |
+
*/
|
315 |
+
function blcContainer( $data = null, $wrapped_object = null ){
|
316 |
+
$this->__construct($data, $wrapped_object);
|
317 |
+
}
|
318 |
+
|
319 |
+
/**
|
320 |
+
* Get the value of the specified field of the object wrapped by this container.
|
321 |
+
*
|
322 |
+
* @access protected
|
323 |
+
*
|
324 |
+
* @param string $field Field name. If omitted, the value of the default field will be returned.
|
325 |
+
* @return string
|
326 |
+
*/
|
327 |
+
function get_field($field = ''){
|
328 |
+
if ( empty($field) ){
|
329 |
+
$field = $this->default_field;
|
330 |
+
}
|
331 |
+
|
332 |
+
$w = $this->get_wrapped_object();
|
333 |
+
return $w->$field;
|
334 |
+
}
|
335 |
+
|
336 |
+
/**
|
337 |
+
* Update the value of the specified field in the wrapped object.
|
338 |
+
* This method will also immediately save the changed value by calling update_wrapped_object().
|
339 |
+
*
|
340 |
+
* @access protected
|
341 |
+
*
|
342 |
+
* @param string $field Field name.
|
343 |
+
* @param string $new_value Set the field to this value.
|
344 |
+
* @param string $old_value The previous value of the field. Optional, but can be useful for container that need the old value to distinguish between several instances of the same field (e.g. post metadata).
|
345 |
+
* @return bool|WP_Error True on success, an error object if something went wrong.
|
346 |
+
*/
|
347 |
+
function update_field($field, $new_value, $old_value = ''){
|
348 |
+
$w = $this->get_wrapped_object();
|
349 |
+
$w->$field = $new_value;
|
350 |
+
return $this->update_wrapped_object();
|
351 |
+
}
|
352 |
+
|
353 |
+
/**
|
354 |
+
* Retrieve the entity wrapped by this container.
|
355 |
+
* The fetched object will also be cached in the $wrapped_object variable.
|
356 |
+
*
|
357 |
+
* @access protected
|
358 |
+
*
|
359 |
+
* @param bool $ensure_consistency Set this to true to ignore the cached $wrapped_object value and retrieve an up-to-date copy of the wrapped object from the DB (or WP's internal cache).
|
360 |
+
* @return object The wrapped object.
|
361 |
+
*/
|
362 |
+
function get_wrapped_object($ensure_consistency = false){
|
363 |
+
trigger_error('Function blcContainer::get_wrapped_object() must be over-ridden in a sub-class', E_USER_ERROR);
|
364 |
+
}
|
365 |
+
|
366 |
+
/**
|
367 |
+
* Update the entity wrapped by the container with values currently in the $wrapped_object.
|
368 |
+
*
|
369 |
+
* @access protected
|
370 |
+
*
|
371 |
+
* @return bool|WP_Error True on success, an error if something went wrong.
|
372 |
+
*/
|
373 |
+
function update_wrapped_object(){
|
374 |
+
trigger_error('Function blcContainer::update_wrapped_object() must be over-ridden in a sub-class', E_USER_ERROR);
|
375 |
+
}
|
376 |
+
|
377 |
+
/**
|
378 |
+
* Parse the container for links and save the results to the DB.
|
379 |
+
*
|
380 |
+
* @return void
|
381 |
+
*/
|
382 |
+
function synch(){
|
383 |
+
//FB::log("Parsing {$this->container_type}[{$this->container_id}]");
|
384 |
+
|
385 |
+
//Remove any existing link instance records associated with the container
|
386 |
+
$this->delete_instances();
|
387 |
+
|
388 |
+
//Load the wrapped object, if not done already
|
389 |
+
$this->get_wrapped_object();
|
390 |
+
|
391 |
+
//FB::log($this->fields, "Parseable fields :");
|
392 |
+
|
393 |
+
//Iterate over all parse-able fields
|
394 |
+
foreach($this->fields as $name => $format){
|
395 |
+
//Get the field value
|
396 |
+
$value = $this->get_field($name);
|
397 |
+
if ( empty($value) ){
|
398 |
+
//FB::log($name, "Skipping empty field");
|
399 |
+
continue;
|
400 |
+
}
|
401 |
+
//FB::log($name, "Parsing field");
|
402 |
+
|
403 |
+
//Get all parsers applicable to this field
|
404 |
+
$parsers = blc_get_parsers( $format, $this->container_type );
|
405 |
+
//FB::log($parsers, "Applicable parsers");
|
406 |
+
|
407 |
+
if ( empty($parsers) ) continue;
|
408 |
+
|
409 |
+
$base_url = $this->base_url();
|
410 |
+
$default_link_text = $this->default_link_text($name);
|
411 |
+
|
412 |
+
//Parse the field with each parser
|
413 |
+
foreach($parsers as $parser){
|
414 |
+
//FB::log("Parsing $name with '{$parser->parser_type}' parser");
|
415 |
+
$found_instances = $parser->parse( $value, $base_url, $default_link_text );
|
416 |
+
//FB::log($found_instances, "Found instances");
|
417 |
+
|
418 |
+
//Complete the link instances by adding container info, then save them to the DB.
|
419 |
+
foreach($found_instances as $instance){
|
420 |
+
$instance->set_container($this, $name);
|
421 |
+
$instance->save();
|
422 |
+
}
|
423 |
+
}
|
424 |
+
}
|
425 |
+
|
426 |
+
$this->mark_as_synched();
|
427 |
+
}
|
428 |
+
|
429 |
+
/**
|
430 |
+
* Mark the container as successfully synchronized (parsed for links).
|
431 |
+
*
|
432 |
+
* @return bool
|
433 |
+
*/
|
434 |
+
function mark_as_synched(){
|
435 |
+
global $wpdb;
|
436 |
+
|
437 |
+
$this->last_synch = time();
|
438 |
+
|
439 |
+
$q = "INSERT INTO {$wpdb->prefix}blc_synch( container_id, container_type, synched, last_synch)
|
440 |
+
VALUES( %d, %s, %d, NOW() )
|
441 |
+
ON DUPLICATE KEY UPDATE synched = VALUES(synched), last_synch = VALUES(last_synch)";
|
442 |
+
$rez = $wpdb->query( $wpdb->prepare( $q, $this->container_id, $this->container_type, 1 ) );
|
443 |
+
|
444 |
+
return ($rez !== false);
|
445 |
+
}
|
446 |
+
|
447 |
+
/**
|
448 |
+
* blcContainer::mark_as_unsynched()
|
449 |
+
* Mark the container as not synchronized (not parsed, or modified since the last parse).
|
450 |
+
* The plugin will attempt to (re)parse the container at the earliest opportunity.
|
451 |
+
*
|
452 |
+
* @return bool
|
453 |
+
*/
|
454 |
+
function mark_as_unsynched(){
|
455 |
+
global $wpdb;
|
456 |
+
|
457 |
+
$q = "INSERT INTO {$wpdb->prefix}blc_synch( container_id, container_type, synched, last_synch)
|
458 |
+
VALUES( %d, %s, %d, '0000-00-00 00:00:00' )
|
459 |
+
ON DUPLICATE KEY UPDATE synched = VALUES(synched)";
|
460 |
+
$rez = $wpdb->query( $wpdb->prepare( $q, $this->container_id, $this->container_type, 0 ) );
|
461 |
+
|
462 |
+
blc_got_unsynched_items();
|
463 |
+
|
464 |
+
return ($rez !== false);
|
465 |
+
}
|
466 |
+
|
467 |
+
/**
|
468 |
+
* Get the base URL of the container. Used to normalize relative URLs found
|
469 |
+
* in the container. For example, for posts this would be the post permalink.
|
470 |
+
*
|
471 |
+
* @return string
|
472 |
+
*/
|
473 |
+
function base_url(){
|
474 |
+
return get_option('siteurl');
|
475 |
+
}
|
476 |
+
|
477 |
+
/**
|
478 |
+
* Get the default link text to use for links found in a specific container field.
|
479 |
+
*
|
480 |
+
* This is generally only meaningful for non-HTML container fields.
|
481 |
+
* For example, if the container is post metadata, the default
|
482 |
+
* link text might be equal to the name of the custom field.
|
483 |
+
*
|
484 |
+
* @param string $field
|
485 |
+
* @return string
|
486 |
+
*/
|
487 |
+
function default_link_text($field = ''){
|
488 |
+
return '';
|
489 |
+
}
|
490 |
+
|
491 |
+
|
492 |
+
|
493 |
+
/**
|
494 |
+
* Delete the DB record of this container.
|
495 |
+
* Also deletes the DB records of all link instances associated with it.
|
496 |
+
* Calling this method will not affect the WP entity (e.g. a post) corresponding to this container.
|
497 |
+
*
|
498 |
+
* @return bool
|
499 |
+
*/
|
500 |
+
function delete(){
|
501 |
+
global $wpdb;
|
502 |
+
|
503 |
+
//Delete instances first.
|
504 |
+
$rez = $this->delete_instances();
|
505 |
+
if ( !$rez ){
|
506 |
+
return false;
|
507 |
+
}
|
508 |
+
|
509 |
+
//Now delete the container record.
|
510 |
+
$q = "DELETE FROM {$wpdb->prefix}blc_synch
|
511 |
+
WHERE container_id = %d AND container_type = %s";
|
512 |
+
$q = $wpdb->prepare($q, $this->container_id, $this->container_type);
|
513 |
+
|
514 |
+
if ( $wpdb->query( $q ) === false ){
|
515 |
+
return false;
|
516 |
+
} else {
|
517 |
+
return true;
|
518 |
+
}
|
519 |
+
}
|
520 |
+
|
521 |
+
/**
|
522 |
+
* Delete all link instance records associated with this container.
|
523 |
+
* NB: Calling this mehtod will not affect the WP entity (e.g. a post) corresponding to this container.
|
524 |
+
*
|
525 |
+
* @return bool
|
526 |
+
*/
|
527 |
+
function delete_instances(){
|
528 |
+
global $wpdb;
|
529 |
+
|
530 |
+
//Remove instances associated with this container
|
531 |
+
$q = "DELETE FROM {$wpdb->prefix}blc_instances
|
532 |
+
WHERE container_id = %d AND container_type = %s";
|
533 |
+
$q = $wpdb->prepare($q, $this->container_id, $this->container_type);
|
534 |
+
|
535 |
+
if ( $wpdb->query( $q ) === false ){
|
536 |
+
return false;
|
537 |
+
} else {
|
538 |
+
return true;
|
539 |
+
}
|
540 |
+
}
|
541 |
+
|
542 |
+
/**
|
543 |
+
* Delete the WP entity corresponding to this container.
|
544 |
+
* Also remove the synch. record of the container and all associated instances.
|
545 |
+
*
|
546 |
+
* Must be over-ridden in a sub-class.
|
547 |
+
*
|
548 |
+
* @return bool|WP_Error
|
549 |
+
*/
|
550 |
+
function delete_wrapped_object(){
|
551 |
+
trigger_error('Function blcContainer::delete_wrapped_object() must be over-ridden in a sub-class', E_USER_ERROR);
|
552 |
+
}
|
553 |
+
|
554 |
+
|
555 |
+
/**
|
556 |
+
* Change all links with the specified URL to a new URL.
|
557 |
+
*
|
558 |
+
* @param string $field_name
|
559 |
+
* @param blcParser $parser
|
560 |
+
* @param string $new_url
|
561 |
+
* @param string $old_url
|
562 |
+
* @param string $old_raw_url
|
563 |
+
* @return string|WP_Error The new value of raw_url on success, or an error object if something went wrong.
|
564 |
+
*/
|
565 |
+
function edit_link($field_name, $parser, $new_url, $old_url = '', $old_raw_url = ''){
|
566 |
+
//Ensure we're operating on a consistent copy of the wrapped object.
|
567 |
+
/*
|
568 |
+
Explanation
|
569 |
+
|
570 |
+
Consider this scenario where the container object wraps a blog post :
|
571 |
+
1) The container object gets created and loads the post data.
|
572 |
+
2) Someone modifies the DB data corresponding to the post.
|
573 |
+
3) The container tries to edit a link present in the post. However, the pots
|
574 |
+
has changed since the time it was first cached, so when the container updates
|
575 |
+
the post with it's changes, it will overwrite whatever modifications were made
|
576 |
+
in step 2.
|
577 |
+
|
578 |
+
This would not be a problem if WP entities like posts and comments were
|
579 |
+
actually real objects, not just bags of key=>value pairs, but oh well.
|
580 |
+
|
581 |
+
Therefore, it is necessary to re-load the wrapped object before editing it.
|
582 |
+
*/
|
583 |
+
$this->get_wrapped_object(true);
|
584 |
+
|
585 |
+
//Get the current value of the field that needs to be edited.
|
586 |
+
$old_value = $this->get_field($field_name);
|
587 |
+
|
588 |
+
//Have the parser modify the specified link. If successful, the parser will
|
589 |
+
//return an associative array with two keys - 'content' and 'raw_url'.
|
590 |
+
//Otherwise we'll get an instance of WP_Error.
|
591 |
+
$edit_result = $parser->edit($old_value, $new_url, $old_url, $old_raw_url);
|
592 |
+
if ( is_wp_error($edit_result) ){
|
593 |
+
return $edit_result;
|
594 |
+
}
|
595 |
+
|
596 |
+
//Update the field with the new value returned by the parser.
|
597 |
+
$update_result = $this->update_field( $field_name, $edit_result['content'], $old_value );
|
598 |
+
if ( is_wp_error($update_result) ){
|
599 |
+
return $update_result;
|
600 |
+
}
|
601 |
+
|
602 |
+
//Return the new "raw" URL.
|
603 |
+
return $edit_result['raw_url'];
|
604 |
+
}
|
605 |
+
|
606 |
+
/**
|
607 |
+
* Remove all links with the specified URL, leaving their anchor text intact.
|
608 |
+
*
|
609 |
+
* @param string $field_name
|
610 |
+
* @param blcParser $parser_type
|
611 |
+
* @param string $url
|
612 |
+
* @param string $raw_url
|
613 |
+
* @return bool|WP_Error True on success, or an error object if something went wrong.
|
614 |
+
*/
|
615 |
+
function unlink($field_name, $parser, $url, $raw_url =''){
|
616 |
+
//Ensure we're operating on a consistent copy of the wrapped object.
|
617 |
+
$this->get_wrapped_object(true);
|
618 |
+
|
619 |
+
$old_value = $this->get_field($field_name);
|
620 |
+
|
621 |
+
$new_value = $parser->unlink($old_value, $url, $raw_url);
|
622 |
+
if ( is_wp_error($new_value) ){
|
623 |
+
return $new_value;
|
624 |
+
}
|
625 |
+
|
626 |
+
return $this->update_field( $field_name, $new_value, $old_value );
|
627 |
+
}
|
628 |
+
|
629 |
+
/**
|
630 |
+
* Retrieve a list of links found in this container.
|
631 |
+
*
|
632 |
+
* @access public
|
633 |
+
*
|
634 |
+
* @return array of blcLink
|
635 |
+
*/
|
636 |
+
function get_links(){
|
637 |
+
$params = array(
|
638 |
+
's_container_type' => $this->container_type,
|
639 |
+
's_container_id' => $this->container_id,
|
640 |
+
);
|
641 |
+
return blc_get_links($params);
|
642 |
+
}
|
643 |
+
|
644 |
+
|
645 |
+
/**
|
646 |
+
* Get action links to display in the "Source" column of the Tools -> Broken Links link table.
|
647 |
+
*
|
648 |
+
* @param string $container_field
|
649 |
+
* @return array
|
650 |
+
*/
|
651 |
+
function ui_get_action_links($container_field){
|
652 |
+
return array();
|
653 |
+
}
|
654 |
+
|
655 |
+
/**
|
656 |
+
* Get the container name to display in the "Source" column of the Tools -> Broken Links link table.
|
657 |
+
*
|
658 |
+
* @param string $container_field
|
659 |
+
* @param string $context
|
660 |
+
* @return string
|
661 |
+
*/
|
662 |
+
function ui_get_source($container_field, $context = 'display'){
|
663 |
+
return sprintf('%s[%d] : %s', $this->container_type, $this->container_id, $container_field);
|
664 |
+
}
|
665 |
+
|
666 |
+
/**
|
667 |
+
* Get edit URL. Returns the URL of the Dashboard page where the item associated with this
|
668 |
+
* container can be edited.
|
669 |
+
*
|
670 |
+
* HTML entities like '&' will be properly escaped for display.
|
671 |
+
*
|
672 |
+
* @access protected
|
673 |
+
*
|
674 |
+
* @return string
|
675 |
+
*/
|
676 |
+
function get_edit_url(){
|
677 |
+
//Should be over-ridden in a sub-class.
|
678 |
+
return '';
|
679 |
+
}
|
680 |
+
}
|
681 |
+
|
682 |
+
/**
|
683 |
+
* The base class for link container manager.
|
684 |
+
*
|
685 |
+
* Sub-classes should override at least the get_containers() and resynch() methods.
|
686 |
+
*
|
687 |
+
* @package Broken Link Checker
|
688 |
+
* @access public
|
689 |
+
*/
|
690 |
+
class blcContainerManager {
|
691 |
+
|
692 |
+
var $container_type = '';
|
693 |
+
var $container_class_name = 'blcContainer';
|
694 |
+
|
695 |
+
function __construct($container_type){
|
696 |
+
$this->container_type = $container_type;
|
697 |
+
$this->init();
|
698 |
+
}
|
699 |
+
|
700 |
+
/**
|
701 |
+
* blcContainerManager::blcContainerManager()
|
702 |
+
* Old-style class constructor
|
703 |
+
*
|
704 |
+
* @return void
|
705 |
+
*/
|
706 |
+
function blcContainerManager($container_type){
|
707 |
+
$this->__construct($container_type);
|
708 |
+
}
|
709 |
+
|
710 |
+
/**
|
711 |
+
* Do whatever setup necessary that wasn't already done in the constructor.
|
712 |
+
*
|
713 |
+
* This method was added so that sub-classes would have something "safe" to
|
714 |
+
* over-ride without having to deal with PHP4/5 constructors and remember to
|
715 |
+
* call the parent constructor.
|
716 |
+
*
|
717 |
+
* @return void
|
718 |
+
*/
|
719 |
+
function init(){
|
720 |
+
//Do nothing. Sub-classes might use it to set up hooks, etc.
|
721 |
+
}
|
722 |
+
|
723 |
+
/**
|
724 |
+
* Instantiate a link container.
|
725 |
+
*
|
726 |
+
* @param array $container An associative array of container data.
|
727 |
+
* @return blcContainer
|
728 |
+
*/
|
729 |
+
function get_container($container){
|
730 |
+
return new $this->container_class_name($container);
|
731 |
+
}
|
732 |
+
|
733 |
+
/**
|
734 |
+
* Instantiate multiple containers of the container type managed by this class and optionally
|
735 |
+
* pre-load container data used for display/parsing.
|
736 |
+
*
|
737 |
+
* Sub-classes should, if possible, use the $purpose argument to pre-load any extra data required for
|
738 |
+
* the specified task right away, instead of making multiple DB roundtrips later. For example, if
|
739 |
+
* $purpose is set to the BLC_FOR_DISPLAY constant, you might want to preload any DB data that the
|
740 |
+
* container will need in blcContainer::ui_get_source().
|
741 |
+
*
|
742 |
+
* @see blcContainer::make_containers()
|
743 |
+
* @see blcContainer::ui_get_source()
|
744 |
+
* @see blcContainer::ui_get_action_links()
|
745 |
+
*
|
746 |
+
* @param array $containers Array of assoc. arrays containing container data.
|
747 |
+
* @param string $purpose An optional code indicating how the retrieved containers will be used.
|
748 |
+
* @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
|
749 |
+
*
|
750 |
+
* @return array of blcContainer indexed by "container_type|container_id"
|
751 |
+
*/
|
752 |
+
function get_containers($containers, $purpose = '', $load_wrapped_objects = false){
|
753 |
+
return $this->make_containers($containers);
|
754 |
+
}
|
755 |
+
|
756 |
+
/**
|
757 |
+
* Instantiate multiple containers of the container type managed by this class
|
758 |
+
*
|
759 |
+
* @param array $containers Array of assoc. arrays containing container data.
|
760 |
+
* @return array of blcContainer indexed by "container_type|container_id"
|
761 |
+
*/
|
762 |
+
function make_containers($containers){
|
763 |
+
$results = array();
|
764 |
+
foreach($containers as $container){
|
765 |
+
$key = $container['container_type'] . '|' . $container['container_id'];
|
766 |
+
$results[ $key ] = $this->get_container($container);
|
767 |
+
}
|
768 |
+
return $results;
|
769 |
+
}
|
770 |
+
|
771 |
+
/**
|
772 |
+
* Create or update synchronization records for all containers managed by this class.
|
773 |
+
*
|
774 |
+
* Must be over-ridden in subclasses.
|
775 |
+
*
|
776 |
+
* @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch.
|
777 |
+
* @return void
|
778 |
+
*/
|
779 |
+
function resynch($forced = false){
|
780 |
+
trigger_error('Function blcContainerManager::resynch() must be over-ridden in a sub-class', E_USER_ERROR);
|
781 |
+
}
|
782 |
+
|
783 |
+
/**
|
784 |
+
* Get the message to display after $n containers have been deleted.
|
785 |
+
*
|
786 |
+
* @param int $n Number of deleted containers.
|
787 |
+
* @return string A delete confirmation message, e.g. "5 posts were moved to trash"
|
788 |
+
*/
|
789 |
+
function ui_bulk_delete_message($n){
|
790 |
+
return sprintf(
|
791 |
+
_n(
|
792 |
+
"%d '%s' has been deleted",
|
793 |
+
"%d '%s' have been deleted",
|
794 |
+
$n,
|
795 |
+
'broken-link-checker'
|
796 |
+
),
|
797 |
+
$n,
|
798 |
+
$this->container_type
|
799 |
+
);
|
800 |
+
}
|
801 |
+
}
|
802 |
+
|
803 |
+
/**
|
804 |
+
* Register a new link container.
|
805 |
+
*
|
806 |
+
* Each container type is implemented by two related classes - the container manager class, and the
|
807 |
+
* container class itself. The container manager handles tasks like creating new instances of the container
|
808 |
+
* class, loading & filtering them to the database, handling WordPress hooks relevant to the container
|
809 |
+
* type, and so on. The container class handles the synchronization, parsing and modification of
|
810 |
+
* individual link containers (e.g. posts or comments).
|
811 |
+
*
|
812 |
+
* @see blcContainer
|
813 |
+
* @see blcContainerManager
|
814 |
+
*
|
815 |
+
* @param string $container_type A unique string identifying the container, e.g. "post" or "comment".
|
816 |
+
* @param string $manager_class Class name of the container manager corresponding to the container type you want to register.
|
817 |
+
* @return bool True if the container was successfully registered, false otherwise.
|
818 |
+
*/
|
819 |
+
function blc_register_container( $container_type, $manager_class ){
|
820 |
+
global $blc_container_registry;
|
821 |
+
return $blc_container_registry->register_container($container_type, $manager_class);
|
822 |
+
}
|
823 |
+
|
824 |
+
/**
|
825 |
+
* Retrieve or create a link container.
|
826 |
+
*
|
827 |
+
* @param array $container Either (container type, id), or an assoc. array of container data.
|
828 |
+
* @return blcContainer|null Returns null if the container type is unrecognized.
|
829 |
+
*/
|
830 |
+
function blc_get_container($container){
|
831 |
+
global $blc_container_registry;
|
832 |
+
return $blc_container_registry->get_container($container);
|
833 |
+
}
|
834 |
+
|
835 |
+
/**
|
836 |
+
* Retrieve multiple link containers.
|
837 |
+
*
|
838 |
+
* If you specify the optional $purpose argument, the relevant container managers might be
|
839 |
+
* able to use it to (pre)load container data more efficiently - e.g. loading all posts associated
|
840 |
+
* with the selected batch of containers in one go, instead of running a separate DB query for
|
841 |
+
* each individual container later.
|
842 |
+
*
|
843 |
+
* There are several predefined constants that can be used for the $purpose argument :
|
844 |
+
* BLC_FOR_EDITING, BLC_FOR_PARSING, BLC_FOR_DISPLAY
|
845 |
+
*
|
846 |
+
* For containers not found in the DB, the behaviour of this function depends on the format
|
847 |
+
* of the $containers argument. If $containers is an array of [container_type, container_id] pairs,
|
848 |
+
* only existing containers will be returned. If it's an array of assoc. arrays specifying container
|
849 |
+
* data, the function will create and return container objects for all specified containers.
|
850 |
+
*
|
851 |
+
* @see blc_get_container()
|
852 |
+
*
|
853 |
+
* @param array $containers Array of (container_type, id) pairs, or assoc. arrays with container data.
|
854 |
+
* @param string $purpose Optional code indicating how the retrieved containers are going to be used.
|
855 |
+
* @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
|
856 |
+
* @return array of blcContainer indexed by 'container_type|container_id'
|
857 |
+
*/
|
858 |
+
function blc_get_containers( $containers, $purpose = '', $load_wrapped_objects = false ){
|
859 |
+
global $blc_container_registry;
|
860 |
+
return $blc_container_registry->get_containers($containers, $purpose, '', $load_wrapped_objects);
|
861 |
+
}
|
862 |
+
|
863 |
+
/**
|
864 |
+
* Retrieve link containers that need to be synchronized (parsed).
|
865 |
+
*
|
866 |
+
* @param integer $max_results The maximum number of containers to return. Defaults to returning all unsynched containers.
|
867 |
+
* @return array of blcContainer
|
868 |
+
*/
|
869 |
+
function blc_get_unsynched_containers($max_results = 0){
|
870 |
+
global $blc_container_registry;
|
871 |
+
return $blc_container_registry->get_unsynched_containers($max_results);
|
872 |
+
}
|
873 |
+
|
874 |
+
/**
|
875 |
+
* (Re)create and update synchronization records for all supported containers.
|
876 |
+
* Calls the resynch() method of all registered managers.
|
877 |
+
*
|
878 |
+
* @param bool $forced If true, assume that no synch. records exist and build all of them from scratch.
|
879 |
+
* @return void
|
880 |
+
*/
|
881 |
+
function blc_resynch_containers($forced = false){
|
882 |
+
global $blc_container_registry;
|
883 |
+
$blc_container_registry->resynch($forced);
|
884 |
+
}
|
885 |
+
|
886 |
+
?>
|
includes/containers/blogroll.php
ADDED
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class blcBookmark extends blcContainer{
|
4 |
+
|
5 |
+
var $fields = array('link_url' => 'url_field');
|
6 |
+
|
7 |
+
function ui_get_source($container_field, $context = 'display'){
|
8 |
+
$bookmark = $this->get_wrapped_object();
|
9 |
+
|
10 |
+
$image = sprintf(
|
11 |
+
'<img src="%s/broken-link-checker/images/link.png" class="blc-small-image" title="%2$s" alt="%2$s">',
|
12 |
+
WP_PLUGIN_URL,
|
13 |
+
__('Bookmark', 'broken-link-checker')
|
14 |
+
);
|
15 |
+
|
16 |
+
$link_name = sprintf(
|
17 |
+
'<a class="row-title" href="%s" title="%s">%s</a>',
|
18 |
+
$this->get_edit_url(),
|
19 |
+
__('Edit this bookmark', 'broken-link-checker'),
|
20 |
+
sanitize_bookmark_field('link_name', $bookmark->link_name, $this->container_id, 'display')
|
21 |
+
);
|
22 |
+
|
23 |
+
if ( $context != 'email' ){
|
24 |
+
return "$image $link_name";
|
25 |
+
} else {
|
26 |
+
return $link_name;
|
27 |
+
}
|
28 |
+
}
|
29 |
+
|
30 |
+
function ui_get_action_links($container_field){
|
31 |
+
//Inline action links for bookmarks
|
32 |
+
$bookmark = $this->get_wrapped_object();
|
33 |
+
|
34 |
+
$delete_url = admin_url( wp_nonce_url("link.php?action=delete&link_id={$this->container_id}", 'delete-bookmark_' . $this->container_id) );
|
35 |
+
|
36 |
+
$actions = array();
|
37 |
+
if ( current_user_can('manage_links') ) {
|
38 |
+
$actions['edit'] = '<span class="edit"><a href="' . $this->get_edit_url() . '" title="' . attribute_escape(__('Edit this bookmark', 'broken-link-checker')) . '">' . __('Edit') . '</a>';
|
39 |
+
$actions['delete'] = "<span class='delete'><a class='submitdelete' href='" . esc_url($delete_url) . "' onclick=\"if ( confirm('" . js_escape(sprintf( __("You are about to delete this link '%s'\n 'Cancel' to stop, 'OK' to delete."), $bookmark->link_name)) . "') ) { return true;}return false;\">" . __('Delete') . "</a>";
|
40 |
+
}
|
41 |
+
|
42 |
+
return $actions;
|
43 |
+
}
|
44 |
+
|
45 |
+
function get_edit_url(){
|
46 |
+
return esc_url(admin_url("link.php?action=edit&link_id={$this->container_id}"));
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Retrieve the bookmark associated with this container.
|
51 |
+
*
|
52 |
+
* @access protected
|
53 |
+
*
|
54 |
+
* @param bool $ensure_consistency Set this to true to ignore the cached $wrapped_object value and retrieve an up-to-date copy of the wrapped object from the DB (or WP's internal cache).
|
55 |
+
* @return object Bookmark data.
|
56 |
+
*/
|
57 |
+
function get_wrapped_object($ensure_consistency = false){
|
58 |
+
if( $ensure_consistency || is_null($this->wrapped_object) ){
|
59 |
+
$this->wrapped_object = get_bookmark($this->container_id);
|
60 |
+
}
|
61 |
+
return $this->wrapped_object;
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Update the bookmark associated with this container.
|
66 |
+
*
|
67 |
+
* @access protected
|
68 |
+
*
|
69 |
+
* @return bool|WP_Error True on success, an error if something went wrong.
|
70 |
+
*/
|
71 |
+
function update_wrapped_object(){
|
72 |
+
if ( is_null($this->wrapped_object) ){
|
73 |
+
return new WP_Error(
|
74 |
+
'no_wrapped_object',
|
75 |
+
__('Nothing to update', 'broken-link-checker')
|
76 |
+
);
|
77 |
+
}
|
78 |
+
|
79 |
+
//wp_update_link() expects it's argument to be an array.
|
80 |
+
$data = (array)$this->wrapped_object;
|
81 |
+
//Update the bookmark
|
82 |
+
$rez = wp_update_link($data);
|
83 |
+
|
84 |
+
if ( !empty($rez) ){
|
85 |
+
return true;
|
86 |
+
} else {
|
87 |
+
return new WP_Error(
|
88 |
+
'update_failed',
|
89 |
+
sprintf(__('Updating bookmark %d failed', 'broken-link-checker'), $this->container_id)
|
90 |
+
);
|
91 |
+
}
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Delete the bookmark corresponding to this container.
|
96 |
+
* Also removes the synch. record of the container and removes all associated instances.
|
97 |
+
*
|
98 |
+
* @return bool|WP_error
|
99 |
+
*/
|
100 |
+
function delete_wrapped_object(){
|
101 |
+
if ( wp_delete_link($this->container_id) ){
|
102 |
+
//Note that there is no need to explicitly delete the synch. record and instances
|
103 |
+
//associated with this link - wp_delete_link() will execute the 'delete_link' action,
|
104 |
+
//which will be noticed by blcBookmarkManager, which will then delete anything that needs
|
105 |
+
//to be deleted.
|
106 |
+
|
107 |
+
//But in case the (undocumented) behaviour of wp_delete_link() changes in a later WP version,
|
108 |
+
//add a call to $this->delete() here.
|
109 |
+
return true;
|
110 |
+
} else {
|
111 |
+
$bookmark = $this->get_wrapped_object();
|
112 |
+
|
113 |
+
if ( is_null($bookmark) ){
|
114 |
+
$link_name = "[nonexistent]";
|
115 |
+
} else {
|
116 |
+
$link_name = sanitize_bookmark_field('link_name', $bookmark->link_name, $this->container_id, 'display');
|
117 |
+
}
|
118 |
+
|
119 |
+
$msg = sprintf(
|
120 |
+
__('Failed to delete blogroll link "%s" (%d)', 'broken-link-checker'),
|
121 |
+
$link_name,
|
122 |
+
$this->container_id
|
123 |
+
);
|
124 |
+
|
125 |
+
return new WP_Error( 'delete_failed', $msg );
|
126 |
+
};
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Get the default link text. For bookmarks, this is the bookmark name.
|
131 |
+
*
|
132 |
+
* @param string $field
|
133 |
+
* @return string
|
134 |
+
*/
|
135 |
+
function default_link_text($field = ''){
|
136 |
+
$bookmark = $this->get_wrapped_object();
|
137 |
+
return sanitize_bookmark_field('link_name', $bookmark->link_name, $this->container_id, 'display');
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
* For bookmarks, calling unlink() simply removes the bookmark.
|
142 |
+
*
|
143 |
+
* @return bool|WP_Error True on success, or an error object if something went wrong.
|
144 |
+
*/
|
145 |
+
function unlink($field_name, $parser, $url, $raw_url =''){
|
146 |
+
return $this->delete_wrapped_object();
|
147 |
+
}
|
148 |
+
|
149 |
+
}
|
150 |
+
|
151 |
+
class blcBookmarkManager extends blcContainerManager{
|
152 |
+
var $container_class_name = 'blcBookmark';
|
153 |
+
|
154 |
+
/**
|
155 |
+
* Set up hooks that monitor added/modified/deleted bookmarks.
|
156 |
+
*
|
157 |
+
* @return void
|
158 |
+
*/
|
159 |
+
function init(){
|
160 |
+
add_action('add_link', array(&$this,'hook_add_link'));
|
161 |
+
add_action('edit_link', array(&$this,'hook_edit_link'));
|
162 |
+
add_action('delete_link', array(&$this,'hook_delete_link'));
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Instantiate multiple containers of the container type managed by this class.
|
167 |
+
*
|
168 |
+
* @param array $containers Array of assoc. arrays containing container data.
|
169 |
+
* @param string $purpose An optional code indicating how the retrieved containers will be used.
|
170 |
+
* @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
|
171 |
+
*
|
172 |
+
* @return array of blcBookmark indexed by "container_type|container_id"
|
173 |
+
*/
|
174 |
+
function get_containers($containers, $purpose = '', $load_wrapped_objects = false){
|
175 |
+
$containers = $this->make_containers($containers);
|
176 |
+
|
177 |
+
//Preload bookmark data if it is likely to be useful later
|
178 |
+
$preload = $load_wrapped_objects || in_array($purpose, array(BLC_FOR_DISPLAY, BLC_FOR_PARSING));
|
179 |
+
if ( $preload ){
|
180 |
+
$bookmark_ids = array();
|
181 |
+
foreach($containers as $container){
|
182 |
+
$bookmark_ids[] = $container->container_id;
|
183 |
+
}
|
184 |
+
|
185 |
+
$args = array('include' => implode(',', $bookmark_ids));
|
186 |
+
$bookmarks = get_bookmarks($args);
|
187 |
+
|
188 |
+
foreach($bookmarks as $bookmark){
|
189 |
+
$key = $this->container_type . '|' . $bookmark->link_id;
|
190 |
+
if ( isset($containers[$key]) ){
|
191 |
+
$containers[$key]->wrapped_object = $bookmark;
|
192 |
+
}
|
193 |
+
}
|
194 |
+
}
|
195 |
+
|
196 |
+
return $containers;
|
197 |
+
}
|
198 |
+
|
199 |
+
/**
|
200 |
+
* Create or update synchronization records for all posts.
|
201 |
+
*
|
202 |
+
* @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch.
|
203 |
+
* @return void
|
204 |
+
*/
|
205 |
+
function resynch($forced = false){
|
206 |
+
global $wpdb;
|
207 |
+
|
208 |
+
if ( !$forced ){
|
209 |
+
//Usually the number of bookmarks is rather small, so it's cheap enough to always
|
210 |
+
//drop the entire list of bookmark-related synch records and recreate it from scratch.
|
211 |
+
$q = $wpdb->prepare(
|
212 |
+
"DELETE FROM {$wpdb->prefix}blc_synch WHERE container_type = %s",
|
213 |
+
$this->container_type
|
214 |
+
);
|
215 |
+
$wpdb->query( $q );
|
216 |
+
}
|
217 |
+
|
218 |
+
//Create new synchronization records for all bookmarks (AKA the blogroll).
|
219 |
+
$q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
|
220 |
+
SELECT link_id, %s, 0
|
221 |
+
FROM {$wpdb->links}
|
222 |
+
WHERE 1";
|
223 |
+
$q = $wpdb->prepare($q, $this->container_type);
|
224 |
+
$wpdb->query( $q );
|
225 |
+
}
|
226 |
+
|
227 |
+
/**
|
228 |
+
* When a bookmark is added mark it as unsynched.
|
229 |
+
*
|
230 |
+
* @param int $link_id
|
231 |
+
* @return void
|
232 |
+
*/
|
233 |
+
function hook_add_link( $link_id ){
|
234 |
+
$container = blc_get_container( array($this->container_type, $link_id) );
|
235 |
+
$container->mark_as_unsynched();
|
236 |
+
}
|
237 |
+
|
238 |
+
/**
|
239 |
+
* Ditto for modified bookmarks.
|
240 |
+
*
|
241 |
+
* @param int $link_id
|
242 |
+
* @return void
|
243 |
+
*/
|
244 |
+
function hook_edit_link( $link_id ){
|
245 |
+
$this->hook_add_link( $link_id );
|
246 |
+
}
|
247 |
+
|
248 |
+
/**
|
249 |
+
* When a bookmark is deleted, remove the related DB records.
|
250 |
+
*
|
251 |
+
* @param int $link_id
|
252 |
+
* @return void
|
253 |
+
*/
|
254 |
+
function hook_delete_link( $link_id ){
|
255 |
+
//Get the container object.
|
256 |
+
$container = blc_get_container( array($this->container_type, $link_id) );
|
257 |
+
//Get the link(s) associated with it.
|
258 |
+
$links = $container->get_links();
|
259 |
+
|
260 |
+
//Remove synch. record & instance records.
|
261 |
+
$container->delete();
|
262 |
+
|
263 |
+
//Clean up links associated with this bookmark (there's probably only one)
|
264 |
+
$link_ids = array();
|
265 |
+
foreach($links as $link){
|
266 |
+
$link_ids[] = $link->link_id;
|
267 |
+
}
|
268 |
+
blc_cleanup_links($link_ids);
|
269 |
+
}
|
270 |
+
|
271 |
+
/**
|
272 |
+
* Get the message to display after $n bookmarks have been deleted.
|
273 |
+
*
|
274 |
+
* @param int $n Number of deleted bookmarks.
|
275 |
+
* @return string The delete confirmation message.
|
276 |
+
*/
|
277 |
+
function ui_bulk_delete_message($n){
|
278 |
+
return sprintf(
|
279 |
+
_n(
|
280 |
+
"%d blogroll link deleted",
|
281 |
+
"%d blogroll links deleted",
|
282 |
+
$n,
|
283 |
+
'broken-link-checker'
|
284 |
+
),
|
285 |
+
$n
|
286 |
+
);
|
287 |
+
}
|
288 |
+
}
|
289 |
+
|
290 |
+
blc_register_container('blogroll', 'blcBookmarkManager');
|
291 |
+
|
292 |
+
?>
|
includes/containers/comment.php
ADDED
@@ -0,0 +1,336 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class blcComment extends blcContainer{
|
4 |
+
var $fields = array(
|
5 |
+
'comment_author_url' => 'url_field',
|
6 |
+
'comment_content' => 'html',
|
7 |
+
);
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Retrieve the comment wrapped by this container.
|
11 |
+
* The fetched object will also be cached in the $wrapped_object variable.
|
12 |
+
*
|
13 |
+
* @access protected
|
14 |
+
*
|
15 |
+
* @param bool $ensure_consistency
|
16 |
+
* @return object The comment.
|
17 |
+
*/
|
18 |
+
function get_wrapped_object($ensure_consistency = false){
|
19 |
+
if( $ensure_consistency || is_null($this->wrapped_object) ){
|
20 |
+
$this->wrapped_object = get_comment($this->container_id);
|
21 |
+
}
|
22 |
+
return $this->wrapped_object;
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Update the comment wrapped by the container with values currently in the $wrapped_object.
|
27 |
+
*
|
28 |
+
* @access protected
|
29 |
+
*
|
30 |
+
* @return bool|WP_Error True on success, an error if something went wrong.
|
31 |
+
*/
|
32 |
+
function update_wrapped_object(){
|
33 |
+
if ( is_null($this->wrapped_object) ){
|
34 |
+
return new WP_Error(
|
35 |
+
'no_wrapped_object',
|
36 |
+
__('Nothing to update', 'broken-link-checker')
|
37 |
+
);
|
38 |
+
}
|
39 |
+
|
40 |
+
$data = (array)$this->wrapped_object;
|
41 |
+
if ( wp_update_comment($data) ){
|
42 |
+
return true;
|
43 |
+
} else {
|
44 |
+
return new WP_Error(
|
45 |
+
'update_failed',
|
46 |
+
sprintf(__('Updating comment %d failed', 'broken-link-checker'), $this->container_id)
|
47 |
+
);
|
48 |
+
}
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Delete the comment corresponding to this container.
|
53 |
+
* This will actually move the comment to the trash in newer versions of WP.
|
54 |
+
*
|
55 |
+
* @return bool|WP_error
|
56 |
+
*/
|
57 |
+
function delete_wrapped_object(){
|
58 |
+
if ( wp_delete_comment($this->container_id) ){
|
59 |
+
return true;
|
60 |
+
} else {
|
61 |
+
return new WP_Error(
|
62 |
+
'delete_failed',
|
63 |
+
sprintf(
|
64 |
+
__('Failed to delete comment %d', 'broken-link-checker'),
|
65 |
+
$this->container_id
|
66 |
+
)
|
67 |
+
);
|
68 |
+
};
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Get the default link text to use for links found in a specific container field.
|
73 |
+
* For links in the comment body there is no default link text. For author links,
|
74 |
+
* the link text will be equal to the author name + comment type (if any).
|
75 |
+
*
|
76 |
+
* @param string $field
|
77 |
+
* @return string
|
78 |
+
*/
|
79 |
+
function default_link_text($field = ''){
|
80 |
+
|
81 |
+
if ( $field == 'comment_author_url' ){
|
82 |
+
$w = $this->get_wrapped_object();
|
83 |
+
if ( !is_null($w) ){
|
84 |
+
$text = $w->comment_author;
|
85 |
+
|
86 |
+
//This lets us identify pingbacks & trackbacks.
|
87 |
+
if ( !empty($w->comment_type) ){
|
88 |
+
$text .= sprintf(' [%s]', $w->comment_type);
|
89 |
+
}
|
90 |
+
|
91 |
+
return $text;
|
92 |
+
}
|
93 |
+
}
|
94 |
+
|
95 |
+
return '';
|
96 |
+
}
|
97 |
+
|
98 |
+
function ui_get_action_links($container_field){
|
99 |
+
$actions = array();
|
100 |
+
|
101 |
+
$comment = $this->get_wrapped_object();
|
102 |
+
|
103 |
+
//Display Edit & Delete/Trash links only if the user has the right caps.
|
104 |
+
$user_can = current_user_can('edit_post', $comment->comment_post_ID);
|
105 |
+
if ( $user_can ){
|
106 |
+
$actions['edit'] = "<a href='". $this->get_edit_url() ."' title='" . esc_attr__('Edit comment') . "'>". __('Edit') . '</a>';
|
107 |
+
|
108 |
+
$del_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "delete-comment_$comment->comment_ID" ) );
|
109 |
+
$trash_url = esc_url( admin_url("comment.php?action=trashcomment&p=$post->ID&c=$comment->comment_ID&$del_nonce") );
|
110 |
+
$delete_url = esc_url( admin_url("comment.php?action=deletecomment&p=$post->ID&c=$comment->comment_ID&$del_nonce") );
|
111 |
+
|
112 |
+
if ( !EMPTY_TRASH_DAYS ) {
|
113 |
+
$actions['delete'] = "<a href='$delete_url' class='delete:the-comment-list:comment-$comment->comment_ID::delete=1 delete vim-d vim-destructive'>" . __('Delete Permanently') . '</a>';
|
114 |
+
} else {
|
115 |
+
$actions['trash'] = "<a href='$trash_url' class='delete:the-comment-list:comment-$comment->comment_ID::trash=1 delete vim-d vim-destructive' title='" . esc_attr__( 'Move this comment to the trash' ) . "'>" . _x('Trash', 'verb') . '</a>';
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
$actions['view'] = '<span class="view"><a href="' . get_comment_link($this->container_id) . '" title="' . attribute_escape(__('View comment', 'broken-link-checker')) . '" rel="permalink">' . __('View') . '</a>';
|
120 |
+
|
121 |
+
return $actions;
|
122 |
+
}
|
123 |
+
|
124 |
+
function ui_get_source($container_field, $context = 'display'){
|
125 |
+
//Display a comment icon.
|
126 |
+
if ( $container_field == 'comment_author_url' ){
|
127 |
+
$image = 'user_comment.png';
|
128 |
+
} else {
|
129 |
+
$image = 'comment.png';
|
130 |
+
}
|
131 |
+
|
132 |
+
$image = sprintf(
|
133 |
+
'<img src="%s/broken-link-checker/images/%s" class="blc-small-image" title="%3$s" alt="%3$s"> ',
|
134 |
+
WP_PLUGIN_URL,
|
135 |
+
$image,
|
136 |
+
__('Comment', 'broken-link-checker')
|
137 |
+
);
|
138 |
+
|
139 |
+
$comment = $this->get_wrapped_object();
|
140 |
+
|
141 |
+
//Display a small text sample from the comment
|
142 |
+
$text_sample = strip_tags($comment->comment_content);
|
143 |
+
$text_sample = blcUtility::truncate($text_sample, 65);
|
144 |
+
|
145 |
+
$html = sprintf(
|
146 |
+
'<a href="%s" title="%s"><b>%s</b> — %s</a>',
|
147 |
+
$this->get_edit_url(),
|
148 |
+
esc_attr__('Edit comment'),
|
149 |
+
esc_attr($comment->comment_author),
|
150 |
+
$text_sample
|
151 |
+
);
|
152 |
+
|
153 |
+
//Don't show the image in email notifications.
|
154 |
+
if ( $context != 'email' ){
|
155 |
+
$html = $image . $html;
|
156 |
+
}
|
157 |
+
|
158 |
+
return $html;
|
159 |
+
}
|
160 |
+
|
161 |
+
function get_edit_url(){
|
162 |
+
return esc_url(admin_url("comment.php?action=editcomment&c={$this->container_id}"));
|
163 |
+
}
|
164 |
+
}
|
165 |
+
|
166 |
+
class blcCommentManager extends blcContainerManager {
|
167 |
+
var $container_class_name = 'blcComment';
|
168 |
+
|
169 |
+
function init(){
|
170 |
+
add_action('edit_comment', array(&$this, 'hook_modified_comment'));
|
171 |
+
add_action('unspammed_comment', array(&$this, 'hook_modified_comment'));
|
172 |
+
add_action('untrashed_comment', array(&$this, 'hook_modified_comment'));
|
173 |
+
|
174 |
+
add_action('wp_insert_comment', array(&$this, 'hook_wp_insert_comment'), 10, 2);
|
175 |
+
|
176 |
+
add_action('deleted_comment', array(&$this, 'hook_deleted_comment'));
|
177 |
+
add_action('spammed_comment', array(&$this, 'hook_deleted_comment'));
|
178 |
+
add_action('trashed_comment', array(&$this, 'hook_deleted_comment'));
|
179 |
+
|
180 |
+
add_action('transition_comment_status', array(&$this, 'hook_comment_status'), 10, 3);
|
181 |
+
}
|
182 |
+
|
183 |
+
function hook_modified_comment($comment_id){
|
184 |
+
$comment = get_comment($comment_id);
|
185 |
+
|
186 |
+
if ( $comment->comment_approved == '1'){
|
187 |
+
$container = blc_get_container(array($this->container_type, $comment_id));
|
188 |
+
$container->mark_as_unsynched();
|
189 |
+
}
|
190 |
+
}
|
191 |
+
|
192 |
+
function hook_wp_insert_comment($comment_id, $comment){
|
193 |
+
if ( $comment->comment_approved == '1'){
|
194 |
+
$container = blc_get_container(array($this->container_type, $comment_id));
|
195 |
+
$container->mark_as_unsynched();
|
196 |
+
}
|
197 |
+
}
|
198 |
+
|
199 |
+
function hook_deleted_comment($comment_id){
|
200 |
+
$container = blc_get_container(array($this->container_type, $comment_id));
|
201 |
+
$container->delete();
|
202 |
+
//Clean up any dangling links
|
203 |
+
blc_cleanup_links();
|
204 |
+
}
|
205 |
+
|
206 |
+
function hook_comment_status($new_status, $old_status, $comment){
|
207 |
+
$container = blc_get_container(array($this->container_type, $comment->comment_ID));
|
208 |
+
if ( $new_status == 'approved' ){
|
209 |
+
$container->mark_as_unsynched();
|
210 |
+
} else {
|
211 |
+
$container->delete();
|
212 |
+
blc_cleanup_links();
|
213 |
+
}
|
214 |
+
}
|
215 |
+
|
216 |
+
/**
|
217 |
+
* Create or update synchronization records for all comments.
|
218 |
+
*
|
219 |
+
* @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch.
|
220 |
+
* @return void
|
221 |
+
*/
|
222 |
+
function resynch($forced = false){
|
223 |
+
global $wpdb;
|
224 |
+
|
225 |
+
if ( $forced ){
|
226 |
+
//Create new synchronization records for all comments.
|
227 |
+
$q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
|
228 |
+
SELECT comment_ID, '{$this->container_type}', 0
|
229 |
+
FROM {$wpdb->comments}
|
230 |
+
WHERE
|
231 |
+
{$wpdb->comments}.comment_approved = '1'";
|
232 |
+
$wpdb->query( $q );
|
233 |
+
} else {
|
234 |
+
//Delete synch records corresponding to comments that no longer exist.
|
235 |
+
$q = "DELETE synch.*
|
236 |
+
FROM
|
237 |
+
{$wpdb->prefix}blc_synch AS synch LEFT JOIN {$wpdb->comments} AS comments
|
238 |
+
ON comments.ID = synch.container_id
|
239 |
+
WHERE
|
240 |
+
synch.container_type = '{$this->container_type}' AND comments.comment_ID IS NULL";
|
241 |
+
$wpdb->query( $q );
|
242 |
+
|
243 |
+
//Create synch. records for comments that don't have them.
|
244 |
+
$q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
|
245 |
+
SELECT comment_ID, '{$this->container_type}', 0
|
246 |
+
FROM
|
247 |
+
{$wpdb->comments} AS comments LEFT JOIN {$wpdb->prefix}blc_synch AS synch
|
248 |
+
ON (synch.container_id = comments.comment_ID and synch.container_type='{$this->container_type}')
|
249 |
+
WHERE
|
250 |
+
comments.comment_approved = '1'
|
251 |
+
AND synch.container_id IS NULL";
|
252 |
+
$wpdb->query($q);
|
253 |
+
|
254 |
+
/*
|
255 |
+
Note that there is no way to detect comments that were *edited* (not added - those
|
256 |
+
will be caught by the above query) while the plugin was inactive. Unlike with posts,
|
257 |
+
WP doesn't track comment modification times.
|
258 |
+
*/
|
259 |
+
}
|
260 |
+
}
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Get the message to display after $n comments have been deleted.
|
264 |
+
*
|
265 |
+
* @param int $n Number of deleted comments.
|
266 |
+
* @return string A delete confirmation message, e.g. "5 comments were moved to trash"
|
267 |
+
*/
|
268 |
+
function ui_bulk_delete_message($n){
|
269 |
+
if ( EMPTY_TRASH_DAYS ){
|
270 |
+
return sprintf(
|
271 |
+
_n(
|
272 |
+
"%d comment moved to the trash",
|
273 |
+
"%d comments moved to the trash",
|
274 |
+
$n,
|
275 |
+
'broken-link-checker'
|
276 |
+
),
|
277 |
+
$n
|
278 |
+
);
|
279 |
+
} else {
|
280 |
+
return sprintf(
|
281 |
+
_n(
|
282 |
+
"%d comment has been deleted",
|
283 |
+
"%d comments have been deleted",
|
284 |
+
$n,
|
285 |
+
'broken-link-checker'
|
286 |
+
),
|
287 |
+
$n
|
288 |
+
);
|
289 |
+
}
|
290 |
+
}
|
291 |
+
|
292 |
+
/**
|
293 |
+
* Instantiate multiple containers of the container type managed by this class.
|
294 |
+
*
|
295 |
+
* @param array $containers Array of assoc. arrays containing container data.
|
296 |
+
* @param string $purpose An optional code indicating how the retrieved containers will be used.
|
297 |
+
* @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
|
298 |
+
*
|
299 |
+
* @return array of blcPostContainer indexed by "container_type|container_id"
|
300 |
+
*/
|
301 |
+
function get_containers($containers, $purpose = '', $load_wrapped_objects = false){
|
302 |
+
global $wpdb;
|
303 |
+
|
304 |
+
$containers = $this->make_containers($containers);
|
305 |
+
|
306 |
+
//Preload comment data if it is likely to be useful later
|
307 |
+
$preload = $load_wrapped_objects || in_array($purpose, array(BLC_FOR_DISPLAY, BLC_FOR_PARSING));
|
308 |
+
if ( $preload ){
|
309 |
+
$comment_ids = array();
|
310 |
+
foreach($containers as $container){
|
311 |
+
$comment_ids[] = $container->container_id;
|
312 |
+
}
|
313 |
+
|
314 |
+
//There's no WP function for retrieving multiple comments by their IDs,
|
315 |
+
//so we query the DB directly.
|
316 |
+
$q = "SELECT * FROM {$wpdb->comments} WHERE comment_ID IN (" . implode(', ', $comment_ids) . ")";
|
317 |
+
$comments = $wpdb->get_results($q);
|
318 |
+
|
319 |
+
foreach($comments as $comment){
|
320 |
+
//Cache the comment in the internal WP object cache
|
321 |
+
$comment = get_comment($comment);
|
322 |
+
|
323 |
+
//Attach it to the container
|
324 |
+
$key = $this->container_type . '|' . $post->ID;
|
325 |
+
if ( isset($containers[$key]) ){
|
326 |
+
$containers[$key]->wrapped_object = $comment;
|
327 |
+
}
|
328 |
+
}
|
329 |
+
}
|
330 |
+
|
331 |
+
return $containers;
|
332 |
+
}
|
333 |
+
}
|
334 |
+
|
335 |
+
blc_register_container('comment', 'blcCommentManager');
|
336 |
+
?>
|
includes/containers/custom_field.php
ADDED
@@ -0,0 +1,489 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
//Note : If it ever becomes necessary to check metadata on objects other than posts, it will
|
4 |
+
//be fairly easy to extract a more general metadata container class from blcPostMeta.
|
5 |
+
|
6 |
+
/**
|
7 |
+
* blcPostMeta - A link container class for post metadata (AKA custom fields).
|
8 |
+
*
|
9 |
+
* Due to the way metadata works, this container differs significantly from other containers :
|
10 |
+
* - container_field is equal to meta name, and container_id holds the ID of the post.
|
11 |
+
* - There is one synch. record per post that determines the synch. state of all metadata fields of that post.
|
12 |
+
* - Unlinking simply deletes the meta entry in question without involving the parser.
|
13 |
+
* - The list of parse-able $fields is not fixed. Instead, it's initialized based on the
|
14 |
+
* custom field list defined in Settings -> Link Checker.
|
15 |
+
* - The $wrapped_object is an array (and isn't really used for anything).
|
16 |
+
* - update_wrapped_object() does nothing.
|
17 |
+
*
|
18 |
+
* @package Broken Link Checker
|
19 |
+
* @access public
|
20 |
+
*/
|
21 |
+
class blcPostMeta extends blcContainer {
|
22 |
+
|
23 |
+
var $meta_type = 'post';
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Retrieve all metadata fields of the post associated with this container.
|
27 |
+
* The results are cached in the internal $wrapped_object variable.
|
28 |
+
*
|
29 |
+
* @param bool $ensure_consistency
|
30 |
+
* @return object The wrapped object.
|
31 |
+
*/
|
32 |
+
function get_wrapped_object($ensure_consistency = false){
|
33 |
+
if ( is_null($this->wrapped_object) || $ensure_consistency ) {
|
34 |
+
$meta = get_metadata($this->meta_type, $this->container_id);
|
35 |
+
}
|
36 |
+
return $this->wrapped_object;
|
37 |
+
}
|
38 |
+
|
39 |
+
function update_wrapped_object(){
|
40 |
+
trigger_error('Function blcPostMeta::update_wrapped_object() does nothing and should not be used.', E_USER_WARNING);
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Get the value of the specified metadata field of the object wrapped by this container.
|
45 |
+
*
|
46 |
+
* @access protected
|
47 |
+
*
|
48 |
+
* @param string $field Field name. If omitted, the value of the default field will be returned.
|
49 |
+
* @return array
|
50 |
+
*/
|
51 |
+
function get_field($field = ''){
|
52 |
+
return get_metadata($this->meta_type, $this->container_id, $field);
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Update the value of the specified metadata field of the object wrapped by this container.
|
57 |
+
*
|
58 |
+
* @access protected
|
59 |
+
*
|
60 |
+
* @param string $field Meta name.
|
61 |
+
* @param string $new_value New meta value.
|
62 |
+
* @param string $old_value old meta value.
|
63 |
+
* @return bool|WP_Error True on success, an error object if something went wrong.
|
64 |
+
*/
|
65 |
+
function update_field($field, $new_value, $old_value = ''){
|
66 |
+
$rez = update_metadata($this->meta_type, $this->container_id, $field, $new_value, $old_value);
|
67 |
+
if ( $rez ){
|
68 |
+
return true;
|
69 |
+
} else {
|
70 |
+
return new WP_Error(
|
71 |
+
'metadata_update_failed',
|
72 |
+
sprintf(
|
73 |
+
__("Failed to update the meta field '%s' on %s [%d]", 'broken-link-checker'),
|
74 |
+
$field,
|
75 |
+
$this->meta_type,
|
76 |
+
$this->container_id
|
77 |
+
)
|
78 |
+
);
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* "Unlink"-ing a custom fields removes all metadata fields that contain the specified URL.
|
84 |
+
*
|
85 |
+
* @param string $field_name
|
86 |
+
* @param blcParser $parser_type
|
87 |
+
* @param string $url
|
88 |
+
* @param string $raw_url
|
89 |
+
* @return bool|WP_Error True on success, or an error object if something went wrong.
|
90 |
+
*/
|
91 |
+
function unlink($field_name, $parser, $url, $raw_url =''){
|
92 |
+
$rez = delete_metadata($this->meta_type, $this->container_id, $field_name, $raw_url);
|
93 |
+
if ( $rez ){
|
94 |
+
return true;
|
95 |
+
} else {
|
96 |
+
return new WP_Error(
|
97 |
+
'metadata_delete_failed',
|
98 |
+
sprintf(
|
99 |
+
__("Failed to delete the meta field '%s' on %s [%d]", 'broken-link-checker'),
|
100 |
+
$field,
|
101 |
+
$this->meta_type,
|
102 |
+
$this->container_id
|
103 |
+
)
|
104 |
+
);
|
105 |
+
}
|
106 |
+
}
|
107 |
+
|
108 |
+
/**
|
109 |
+
* Change a meta field containing the specified URL to a new URL.
|
110 |
+
*
|
111 |
+
* @param string $field_name Meta name
|
112 |
+
* @param blcParser $parser
|
113 |
+
* @param string $new_url New URL.
|
114 |
+
* @param string $old_url
|
115 |
+
* @param string $old_raw_url Old meta value.
|
116 |
+
* @return string|WP_Error The new value of raw_url on success, or an error object if something went wrong.
|
117 |
+
*/
|
118 |
+
function edit_link($field_name, $parser, $new_url, $old_url = '', $old_raw_url = ''){
|
119 |
+
/*
|
120 |
+
FB::log(sprintf(
|
121 |
+
'Editing %s[%d]:%s - %s to %s',
|
122 |
+
$this->container_type,
|
123 |
+
$this->container_id,
|
124 |
+
$field_name,
|
125 |
+
$old_url,
|
126 |
+
$new_url
|
127 |
+
));
|
128 |
+
*/
|
129 |
+
|
130 |
+
if ( empty($old_raw_url) ){
|
131 |
+
$old_raw_url = $old_url;
|
132 |
+
}
|
133 |
+
|
134 |
+
//Get the current values of the field that needs to be edited.
|
135 |
+
//The default metadata parser ignores them, but we're still going
|
136 |
+
//to set this argument to a valid value in case someone writes a
|
137 |
+
//custom meta parser that needs it.
|
138 |
+
$old_value = $this->get_field($field_name);
|
139 |
+
|
140 |
+
//Get the new field value (a string).
|
141 |
+
$edit_result = $parser->edit($old_value, $new_url, $old_url, $old_raw_url);
|
142 |
+
if ( is_wp_error($edit_result) ){
|
143 |
+
return $edit_result;
|
144 |
+
}
|
145 |
+
|
146 |
+
//Update the field with the new value returned by the parser.
|
147 |
+
//Notice how $old_raw_url is usead instead of $old_value. $old_raw_url contains the entire old
|
148 |
+
//value of the metadata field (see blcMetadataParser::parse()) and thus can be used to
|
149 |
+
//differentiate between multiple meta fields with identical names.
|
150 |
+
$update_result = $this->update_field( $field_name, $edit_result['content'], $old_raw_url );
|
151 |
+
if ( is_wp_error($update_result) ){
|
152 |
+
return $update_result;
|
153 |
+
}
|
154 |
+
|
155 |
+
//Return the new "raw" URL.
|
156 |
+
return $edit_result['raw_url'];
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* Get the default link text to use for links found in a specific container field.
|
161 |
+
*
|
162 |
+
* @param string $field
|
163 |
+
* @return string
|
164 |
+
*/
|
165 |
+
function default_link_text($field = ''){
|
166 |
+
//Just use the field name. There's no way to know how the links inside custom fields are
|
167 |
+
//used, so no way to know the "real" link text. Displaying the field name at least gives
|
168 |
+
//the user a clue where to look if they want to find/modify the field.
|
169 |
+
return $field;
|
170 |
+
}
|
171 |
+
|
172 |
+
function ui_get_source($container_field, $context = 'display'){
|
173 |
+
$image_html = sprintf(
|
174 |
+
'<img src="%s/broken-link-checker/images/script_code.png" class="blc-small-image" title="%2$s" alt="%2$s"> ',
|
175 |
+
WP_PLUGIN_URL,
|
176 |
+
__('Custom field', 'broken-link-checker')
|
177 |
+
);
|
178 |
+
|
179 |
+
$field_html = sprintf(
|
180 |
+
'<code>%s</code>',
|
181 |
+
$container_field
|
182 |
+
);
|
183 |
+
|
184 |
+
if ( $context != 'email' ){
|
185 |
+
$field_html = $image_html . $field_html;
|
186 |
+
}
|
187 |
+
|
188 |
+
$post_html = sprintf(
|
189 |
+
'<a class="row-title" href="%s" title="%s">%s</a>',
|
190 |
+
esc_url($this->get_edit_url()),
|
191 |
+
attribute_escape(__('Edit this post')),
|
192 |
+
get_the_title($this->container_id)
|
193 |
+
);
|
194 |
+
|
195 |
+
return "$post_html — $field_html";
|
196 |
+
}
|
197 |
+
|
198 |
+
function ui_get_action_links($container_field){
|
199 |
+
$actions = array();
|
200 |
+
if ( current_user_can('edit_post', $this->container_id) ) {
|
201 |
+
$actions['edit'] = '<span class="edit"><a href="' . $this->get_edit_url() . '" title="' . attribute_escape(__('Edit this post')) . '">' . __('Edit') . '</a>';
|
202 |
+
|
203 |
+
if ( EMPTY_TRASH_DAYS ) {
|
204 |
+
$actions['trash'] = "<a class='submitdelete' title='" . esc_attr(__('Move this post to the Trash')) . "' href='" . get_delete_post_link($this->container_id) . "'>" . __('Trash') . "</a>";
|
205 |
+
} else {
|
206 |
+
$actions['delete'] = "<a class='submitdelete' title='" . esc_attr(__('Delete this post permanently')) . "' href='" . wp_nonce_url( admin_url("post.php?action=delete&post=".$this->container_id), 'delete-post_' . $this->container_id) . "' onclick=\"if ( confirm('" . js_escape(sprintf( __("You are about to delete this post '%s'\n 'Cancel' to stop, 'OK' to delete."), get_the_title($this->container_id) )) . "') ) { return true;}return false;\">" . __('Delete') . "</a>";
|
207 |
+
}
|
208 |
+
}
|
209 |
+
$actions['view'] = '<span class="view"><a href="' . get_permalink($this->container_id) . '" title="' . attribute_escape(sprintf(__('View "%s"', 'broken-link-checker'), get_the_title($this->container_id))) . '" rel="permalink">' . __('View') . '</a>';
|
210 |
+
|
211 |
+
return $actions;
|
212 |
+
}
|
213 |
+
|
214 |
+
/**
|
215 |
+
* Get edit URL for this container. Returns the URL of the Dashboard page where the item
|
216 |
+
* associated with this container can be edited.
|
217 |
+
*
|
218 |
+
* @access protected
|
219 |
+
*
|
220 |
+
* @return
|
221 |
+
*/
|
222 |
+
function get_edit_url(){
|
223 |
+
return get_edit_post_link($this->container_id);
|
224 |
+
}
|
225 |
+
|
226 |
+
/**
|
227 |
+
* Get the base URL of the container. For custom fields, the base URL is the permalink of
|
228 |
+
* the post that the field is attached to.
|
229 |
+
*
|
230 |
+
* @return string
|
231 |
+
*/
|
232 |
+
function base_url(){
|
233 |
+
return get_permalink($this->container_id);
|
234 |
+
}
|
235 |
+
|
236 |
+
/**
|
237 |
+
* Delete the post corresponding to this container.
|
238 |
+
*
|
239 |
+
* @return bool|WP_error
|
240 |
+
*/
|
241 |
+
function delete_wrapped_object(){
|
242 |
+
if ( wp_delete_post($this->container_id) ){
|
243 |
+
return true;
|
244 |
+
} else {
|
245 |
+
return new WP_Error(
|
246 |
+
'delete_failed',
|
247 |
+
sprintf(
|
248 |
+
__('Failed to delete post "%s" (%d)', 'broken-link-checker'),
|
249 |
+
get_the_title($this->container_id),
|
250 |
+
$this->container_id
|
251 |
+
)
|
252 |
+
);
|
253 |
+
};
|
254 |
+
}
|
255 |
+
|
256 |
+
}
|
257 |
+
|
258 |
+
class blcPostMetaManager extends blcContainerManager {
|
259 |
+
var $container_class_name = 'blcPostMeta';
|
260 |
+
var $meta_type = 'post';
|
261 |
+
|
262 |
+
function init(){
|
263 |
+
//Intercept 2.9+ style metadata modification actions
|
264 |
+
add_action( "added_{$this->meta_type}_meta", array(&$this, 'meta_modified'), 10, 4 );
|
265 |
+
add_action( "updated_{$this->meta_type}_meta", array(&$this, 'meta_modified'), 10, 4 );
|
266 |
+
add_action( "deleted_{$this->meta_type}_meta", array(&$this, 'meta_modified'), 10, 4 );
|
267 |
+
//Also intercept the equivalent actions used in /wp-admin/includes/post.php.
|
268 |
+
//(WP is bloody inconsitent. The action names differ by a single character
|
269 |
+
//but have different argument counts)
|
270 |
+
add_action( "added_{$this->meta_type}meta", array(&$this, 'meta_modified'), 10, 4 );
|
271 |
+
add_action( "deleted_{$this->meta_type}meta", array(&$this, 'meta_modified'), 10, 1 );//NB : 1 argument!
|
272 |
+
|
273 |
+
//When a post is deleted, also delete the custom field container associated with it.
|
274 |
+
add_action('delete_post', array(&$this,'post_deleted'));
|
275 |
+
add_action('trash_post', array(&$this,'post_deleted'));
|
276 |
+
|
277 |
+
//Re-parse custom fields when a post is restored from trash
|
278 |
+
add_action('untrashed_post', array(&$this,'post_untrashed'));
|
279 |
+
}
|
280 |
+
|
281 |
+
|
282 |
+
/**
|
283 |
+
* Instantiate a link container.
|
284 |
+
*
|
285 |
+
* @param array $container An associative array of container data.
|
286 |
+
* @return blcPostMeta
|
287 |
+
*/
|
288 |
+
function get_container($container){
|
289 |
+
$container = parent::get_container($container);
|
290 |
+
|
291 |
+
//Set up the parseable fields
|
292 |
+
$fields = array();
|
293 |
+
|
294 |
+
$conf = blc_get_configuration();
|
295 |
+
if ( is_array($conf->options['custom_fields']) ){
|
296 |
+
foreach($conf->options['custom_fields'] as $meta_name){
|
297 |
+
$fields[$meta_name] = 'metadata';
|
298 |
+
}
|
299 |
+
}
|
300 |
+
|
301 |
+
$container->fields = $fields;
|
302 |
+
return $container;
|
303 |
+
}
|
304 |
+
|
305 |
+
/**
|
306 |
+
* Instantiate multiple containers of the container type managed by this class.
|
307 |
+
*
|
308 |
+
* @param array $containers Array of assoc. arrays containing container data.
|
309 |
+
* @param string $purpose An optional code indicating how the retrieved containers will be used.
|
310 |
+
* @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
|
311 |
+
*
|
312 |
+
* @return array of blcPostMeta indexed by "container_type|container_id"
|
313 |
+
*/
|
314 |
+
function get_containers($containers, $purpose = '', $load_wrapped_objects = false){
|
315 |
+
$containers = $this->make_containers($containers);
|
316 |
+
|
317 |
+
/*
|
318 |
+
When links from custom fields are displayed in Tools -> Broken Links,
|
319 |
+
each one also shows the title of the post that the custom field(s)
|
320 |
+
belong to. Thus it makes sense to pre-cache the posts beforehand - it's
|
321 |
+
faster to load them all at once than to make a separate query for each
|
322 |
+
one later.
|
323 |
+
|
324 |
+
So make a list of involved post IDs and load them.
|
325 |
+
|
326 |
+
Calling get_posts() will automatically populate the post cache, so we
|
327 |
+
don't need to actually store the results anywhere in the container object().
|
328 |
+
*/
|
329 |
+
$preload = $load_wrapped_objects || in_array($purpose, array(BLC_FOR_DISPLAY));
|
330 |
+
if ( $preload ){
|
331 |
+
$post_ids = array();
|
332 |
+
foreach($containers as $container){
|
333 |
+
$post_ids[] = $container->container_id;
|
334 |
+
}
|
335 |
+
|
336 |
+
$args = array('include' => implode(',', $post_ids));
|
337 |
+
get_posts($args);
|
338 |
+
}
|
339 |
+
|
340 |
+
return $containers;
|
341 |
+
}
|
342 |
+
|
343 |
+
/**
|
344 |
+
* Create or update synchronization records for all containers managed by this class.
|
345 |
+
*
|
346 |
+
* @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch.
|
347 |
+
* @return void
|
348 |
+
*/
|
349 |
+
function resynch($forced = false){
|
350 |
+
global $wpdb;
|
351 |
+
|
352 |
+
if ( $forced ){
|
353 |
+
//Create new synchronization records for all posts.
|
354 |
+
$q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
|
355 |
+
SELECT id, '{$this->container_type}', 0
|
356 |
+
FROM {$wpdb->posts}
|
357 |
+
WHERE
|
358 |
+
{$wpdb->posts}.post_status = 'publish'
|
359 |
+
AND {$wpdb->posts}.post_type IN ('post', 'page')";
|
360 |
+
$wpdb->query( $q );
|
361 |
+
} else {
|
362 |
+
//Delete synch records corresponding to posts that no longer exist.
|
363 |
+
$q = "DELETE synch.*
|
364 |
+
FROM
|
365 |
+
{$wpdb->prefix}blc_synch AS synch LEFT JOIN {$wpdb->posts} AS posts
|
366 |
+
ON posts.ID = synch.container_id
|
367 |
+
WHERE
|
368 |
+
synch.container_type = '{$this->container_type}' AND posts.ID IS NULL";
|
369 |
+
$wpdb->query( $q );
|
370 |
+
|
371 |
+
//Remove the 'synched' flag from all posts that have been updated
|
372 |
+
//since the last time they were parsed/synchronized.
|
373 |
+
$q = "UPDATE
|
374 |
+
{$wpdb->prefix}blc_synch AS synch
|
375 |
+
JOIN {$wpdb->posts} AS posts ON (synch.container_id = posts.ID and synch.container_type='{$this->container_type}')
|
376 |
+
SET
|
377 |
+
synched = 0
|
378 |
+
WHERE
|
379 |
+
synch.last_synch < posts.post_modified";
|
380 |
+
$wpdb->query( $q );
|
381 |
+
|
382 |
+
//Create synch. records for posts that don't have them.
|
383 |
+
$q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
|
384 |
+
SELECT id, '{$this->container_type}', 0
|
385 |
+
FROM
|
386 |
+
{$wpdb->posts} AS posts LEFT JOIN {$wpdb->prefix}blc_synch AS synch
|
387 |
+
ON (synch.container_id = posts.ID and synch.container_type='{$this->container_type}')
|
388 |
+
WHERE
|
389 |
+
posts.post_status = 'publish'
|
390 |
+
AND posts.post_type IN ('post', 'page')
|
391 |
+
AND synch.container_id IS NULL";
|
392 |
+
$wpdb->query($q);
|
393 |
+
}
|
394 |
+
}
|
395 |
+
|
396 |
+
/**
|
397 |
+
* Mark custom fields as unsynched when they're modified or deleted.
|
398 |
+
*
|
399 |
+
* @param array|int $meta_id
|
400 |
+
* @param int $object_id
|
401 |
+
* @param string $meta_key
|
402 |
+
* @param string $meta_value
|
403 |
+
* @return void
|
404 |
+
*/
|
405 |
+
function meta_modified($meta_id, $object_id = 0, $meta_key= '', $meta_value = ''){
|
406 |
+
global $wpdb;
|
407 |
+
|
408 |
+
//If object_id isn't specified then the hook was probably called from the
|
409 |
+
//stupidly inconsistent delete_meta() function in /wp-admin/includes/post.php.
|
410 |
+
if ( empty($object_id) ){
|
411 |
+
//We must manually retrieve object_id and meta_key from the DB.
|
412 |
+
if ( is_array($meta_id) ){
|
413 |
+
$meta_id = array_shift($meta_id);
|
414 |
+
}
|
415 |
+
|
416 |
+
$meta = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->postmeta WHERE meta_id = %d", $meta_id), ARRAY_A );
|
417 |
+
if ( empty($meta) ){
|
418 |
+
return;
|
419 |
+
}
|
420 |
+
|
421 |
+
$object_id = $meta['post_id'];
|
422 |
+
$meta_key = $meta['meta_key'];
|
423 |
+
}
|
424 |
+
|
425 |
+
|
426 |
+
//Metadata changes only matter to us if the modified key
|
427 |
+
//is one that the user wants checked.
|
428 |
+
$conf = blc_get_configuration();
|
429 |
+
if ( !is_array($conf->options['custom_fields']) ){
|
430 |
+
return;
|
431 |
+
}
|
432 |
+
if ( !in_array($meta_key, $conf->options['custom_fields']) ){
|
433 |
+
return;
|
434 |
+
}
|
435 |
+
|
436 |
+
$container = blc_get_container( array($this->container_type, intval($object_id)) );
|
437 |
+
$container->mark_as_unsynched();
|
438 |
+
}
|
439 |
+
|
440 |
+
/**
|
441 |
+
* Delete custom field synch. records when the post that they belong to is deleted.
|
442 |
+
*
|
443 |
+
* @param int $post_id
|
444 |
+
* @return void
|
445 |
+
*/
|
446 |
+
function post_deleted($post_id){
|
447 |
+
//Get the associated container object
|
448 |
+
$container = blc_get_container( array($this->container_type, intval($post_id)) );
|
449 |
+
//Delete it
|
450 |
+
$container->delete();
|
451 |
+
//Clean up any dangling links
|
452 |
+
blc_cleanup_links();
|
453 |
+
}
|
454 |
+
|
455 |
+
/**
|
456 |
+
* When a post is restored, mark all of its custom fields as unparsed.
|
457 |
+
* Called via the 'untrashed_post' action.
|
458 |
+
*
|
459 |
+
* @param int $post_id
|
460 |
+
* @return void
|
461 |
+
*/
|
462 |
+
function post_untrashed($post_id){
|
463 |
+
//Get the associated container object
|
464 |
+
$container = blc_get_container( array($this->container_type, intval($post_id)) );
|
465 |
+
$container->mark_as_unsynched();
|
466 |
+
}
|
467 |
+
|
468 |
+
/**
|
469 |
+
* Get the message to display after $n posts have been deleted.
|
470 |
+
*
|
471 |
+
* @see blcPostContainer::ui_bulk_delete_message()
|
472 |
+
*
|
473 |
+
* @param int $n Number of deleted posts.
|
474 |
+
* @return string A delete confirmation message, e.g. "5 posts were moved to the trash"
|
475 |
+
*/
|
476 |
+
function ui_bulk_delete_message($n){
|
477 |
+
//This is identical
|
478 |
+
if ( function_exists('wp_trash_post') && EMPTY_TRASH_DAYS ){
|
479 |
+
$delete_msg = _n("%d post moved to the trash", "%d posts moved to the trash", $n, 'broken-link-checker');
|
480 |
+
} else {
|
481 |
+
$delete_msg = _n("%d post deleted", "%d posts deleted", $n, 'broken-link-checker');
|
482 |
+
}
|
483 |
+
return sprintf($delete_msg, $n);
|
484 |
+
}
|
485 |
+
}
|
486 |
+
|
487 |
+
blc_register_container('custom_field', 'blcPostMetaManager');
|
488 |
+
|
489 |
+
?>
|
includes/containers/dummy.php
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* A "dummy" container class that can be used as a fallback when the real container class can't be found.
|
5 |
+
*
|
6 |
+
*
|
7 |
+
* @package Broken Link Checker
|
8 |
+
* @access public
|
9 |
+
*/
|
10 |
+
class blcDummyContainer extends blcContainer{
|
11 |
+
|
12 |
+
function synch(){
|
13 |
+
//Just mark it as synched so that it doesn't bother us anymore.
|
14 |
+
$this->mark_as_synched();
|
15 |
+
}
|
16 |
+
|
17 |
+
function edit_link($field_name, $parser, $new_url, $old_url = '', $old_raw_url = ''){
|
18 |
+
return new WP_Error(
|
19 |
+
'container_not_found',
|
20 |
+
sprintf(
|
21 |
+
__("I don't know how to edit a '%s' [%d].", 'broken-link-checker'),
|
22 |
+
$this->container_type,
|
23 |
+
$this->container_id
|
24 |
+
)
|
25 |
+
);
|
26 |
+
}
|
27 |
+
|
28 |
+
function unlink($field_name, $parser, $url, $raw_url =''){
|
29 |
+
return new WP_Error(
|
30 |
+
'container_not_found',
|
31 |
+
sprintf(
|
32 |
+
__("I don't know how to edit a '%s' [%d].", 'broken-link-checker'),
|
33 |
+
$this->container_type,
|
34 |
+
$this->container_id
|
35 |
+
)
|
36 |
+
);
|
37 |
+
}
|
38 |
+
|
39 |
+
function ui_get_source($container_field, $context = 'display'){
|
40 |
+
return sprintf(
|
41 |
+
'<em>Unknown source %s[%d]:%s</em>',
|
42 |
+
$this->container_type,
|
43 |
+
$this->container_id,
|
44 |
+
$container_field
|
45 |
+
);
|
46 |
+
}
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* A dummy manager class.
|
51 |
+
*
|
52 |
+
* @package Broken Link Checker
|
53 |
+
* @access public
|
54 |
+
*/
|
55 |
+
class blcDummyManager extends blcContainerManager {
|
56 |
+
|
57 |
+
var $container_class_name = 'blcDummyContainer';
|
58 |
+
|
59 |
+
function resynch($forced = false){
|
60 |
+
//Do nothing.
|
61 |
+
}
|
62 |
+
}
|
63 |
+
|
64 |
+
blc_register_container('dummy', 'blcDummyManager');
|
65 |
+
|
66 |
+
?>
|
includes/containers/post.php
ADDED
@@ -0,0 +1,392 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class blcPostContainer extends blcContainer {
|
4 |
+
var $fields = array('post_content' => 'html');
|
5 |
+
var $default_field = 'post_content';
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Get action links for this post.
|
9 |
+
*
|
10 |
+
* @param string $container_field Ignored.
|
11 |
+
* @return array of action link HTML.
|
12 |
+
*/
|
13 |
+
function ui_get_action_links($container_field = ''){
|
14 |
+
$actions = array();
|
15 |
+
if ( current_user_can('edit_post', $this->container_id) ) {
|
16 |
+
$actions['edit'] = '<span class="edit"><a href="' . $this->get_edit_url() . '" title="' . attribute_escape(__('Edit this post')) . '">' . __('Edit') . '</a>';
|
17 |
+
|
18 |
+
if ( EMPTY_TRASH_DAYS ) {
|
19 |
+
$actions['trash'] = "<a class='submitdelete' title='" . esc_attr(__('Move this post to the Trash')) . "' href='" . get_delete_post_link($this->container_id) . "'>" . __('Trash') . "</a>";
|
20 |
+
} else {
|
21 |
+
$actions['delete'] = "<a class='submitdelete' title='" . esc_attr(__('Delete this post permanently')) . "' href='" . wp_nonce_url( admin_url("post.php?action=delete&post=".$this->container_id), 'delete-post_' . $this->container_id) . "' onclick=\"if ( confirm('" . esc_js(sprintf( __("You are about to delete this post '%s'\n 'Cancel' to stop, 'OK' to delete."), get_the_title($this->container_id) )) . "') ) { return true;}return false;\">" . __('Delete') . "</a>";
|
22 |
+
}
|
23 |
+
}
|
24 |
+
$actions['view'] = '<span class="view"><a href="' . get_permalink($this->container_id) . '" title="' . attribute_escape(sprintf(__('View "%s"', 'broken-link-checker'), get_the_title($this->container_id))) . '" rel="permalink">' . __('View') . '</a>';
|
25 |
+
|
26 |
+
return $actions;
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Get the HTML for displaying the post title in the "Source" column.
|
31 |
+
*
|
32 |
+
* @param string $container_field Ignored.
|
33 |
+
* @param string $context How to filter the output. Optional, defaults to 'display'.
|
34 |
+
* @return string HTML
|
35 |
+
*/
|
36 |
+
function ui_get_source($container_field = '', $context = 'display'){
|
37 |
+
$source = '<a class="row-title" href="%s" title="%s">%s</a>';
|
38 |
+
$source = sprintf(
|
39 |
+
$source,
|
40 |
+
$this->get_edit_url(),
|
41 |
+
attribute_escape(__('Edit this post')),
|
42 |
+
get_the_title($this->container_id)
|
43 |
+
);
|
44 |
+
|
45 |
+
return $source;
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Get edit URL for this container. Returns the URL of the Dashboard page where the item
|
50 |
+
* associated with this container can be edited.
|
51 |
+
*
|
52 |
+
* @access protected
|
53 |
+
*
|
54 |
+
* @return
|
55 |
+
*/
|
56 |
+
function get_edit_url(){
|
57 |
+
return get_edit_post_link($this->container_id);
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Retrieve the post associated with this container.
|
62 |
+
*
|
63 |
+
* @access protected
|
64 |
+
*
|
65 |
+
* @param bool $ensure_consistency Set this to true to ignore the cached $wrapped_object value and retrieve an up-to-date copy of the wrapped object from the DB (or WP's internal cache).
|
66 |
+
* @return object Post data.
|
67 |
+
*/
|
68 |
+
function get_wrapped_object($ensure_consistency = false){
|
69 |
+
if( $ensure_consistency || is_null($this->wrapped_object) ){
|
70 |
+
$this->wrapped_object = get_post($this->container_id);
|
71 |
+
}
|
72 |
+
return $this->wrapped_object;
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Update the post associated with this container.
|
77 |
+
*
|
78 |
+
* @access protected
|
79 |
+
*
|
80 |
+
* @return bool|WP_Error True on success, an error if something went wrong.
|
81 |
+
*/
|
82 |
+
function update_wrapped_object(){
|
83 |
+
if ( is_null($this->wrapped_object) ){
|
84 |
+
return new WP_Error(
|
85 |
+
'no_wrapped_object',
|
86 |
+
__('Nothing to update', 'broken-link-checker')
|
87 |
+
);
|
88 |
+
}
|
89 |
+
|
90 |
+
$id = wp_update_post($this->wrapped_object);
|
91 |
+
if ( $id != 0 ){
|
92 |
+
return true;
|
93 |
+
} else {
|
94 |
+
return new WP_Error(
|
95 |
+
'update_failed',
|
96 |
+
sprintf(__('Updating post %d failed', 'broken-link-checker'), $this->container_id)
|
97 |
+
);
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Get the base URL of the container. For posts, the post permalink is used
|
103 |
+
* as the base URL when normalizing relative links.
|
104 |
+
*
|
105 |
+
* @return string
|
106 |
+
*/
|
107 |
+
function base_url(){
|
108 |
+
return get_permalink($this->container_id);
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Delete the post corresponding to this container.
|
113 |
+
*
|
114 |
+
* @return bool|WP_error
|
115 |
+
*/
|
116 |
+
function delete_wrapped_object(){
|
117 |
+
if ( wp_delete_post($this->container_id) ){
|
118 |
+
//Note that we don't need to delete the synch record and instances here -
|
119 |
+
//wp_delete_post() will run the post_delete hook, which will be caught
|
120 |
+
//by blcPostContainerManager, which will delete anything that needs to be
|
121 |
+
//deleted.
|
122 |
+
return true;
|
123 |
+
} else {
|
124 |
+
return new WP_Error(
|
125 |
+
'delete_failed',
|
126 |
+
sprintf(
|
127 |
+
__('Failed to delete post "%s" (%d)', 'broken-link-checker'),
|
128 |
+
get_the_title($this->container_id),
|
129 |
+
$this->container_id
|
130 |
+
)
|
131 |
+
);
|
132 |
+
};
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
class blcPostContainerManager extends blcContainerManager {
|
137 |
+
var $container_class_name = 'blcPostContainer';
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Set up hooks that monitor added/modified/deleted posts.
|
141 |
+
*
|
142 |
+
* @return void
|
143 |
+
*/
|
144 |
+
function init(){
|
145 |
+
//These hooks update the synch & instance records when posts are added, deleted or modified.
|
146 |
+
add_action('delete_post', array(&$this,'post_deleted'));
|
147 |
+
add_action('save_post', array(&$this,'post_saved'));
|
148 |
+
//We also treat post trashing/untrashing as delete/save.
|
149 |
+
add_action('trash_post', array(&$this,'post_deleted'));
|
150 |
+
add_action('untrash_post', array(&$this,'post_saved'));
|
151 |
+
|
152 |
+
//Highlight broken links in posts & pages
|
153 |
+
$conf = blc_get_configuration();
|
154 |
+
if ( $conf->options['mark_broken_links'] ){
|
155 |
+
add_filter( 'the_content', array(&$this,'hook_the_content') );
|
156 |
+
if ( !empty( $conf->options['broken_link_css'] ) ){
|
157 |
+
add_action( 'wp_head', array(&$this,'hook_wp_head') );
|
158 |
+
}
|
159 |
+
}
|
160 |
+
}
|
161 |
+
|
162 |
+
/**
|
163 |
+
* Remove the synch. record and link instances associated with a post when it's deleted
|
164 |
+
*
|
165 |
+
* @param int $post_id
|
166 |
+
* @return void
|
167 |
+
*/
|
168 |
+
function post_deleted($post_id){
|
169 |
+
//Get the associated container object
|
170 |
+
$post_container = blc_get_container( array($this->container_type, intval($post_id)) );
|
171 |
+
//Delete it
|
172 |
+
$post_container->delete();
|
173 |
+
//Clean up any dangling links
|
174 |
+
blc_cleanup_links();
|
175 |
+
}
|
176 |
+
|
177 |
+
/**
|
178 |
+
* When a post is saved or modified, mark it as unparsed.
|
179 |
+
*
|
180 |
+
* @param int $post_id
|
181 |
+
* @return void
|
182 |
+
*/
|
183 |
+
function post_saved($post_id){
|
184 |
+
//Get the container
|
185 |
+
$args = array($this->container_type, intval($post_id));
|
186 |
+
$post_container = blc_get_container( $args );
|
187 |
+
|
188 |
+
//Get the post
|
189 |
+
$post = $post_container->get_wrapped_object();
|
190 |
+
|
191 |
+
//Only check links in posts, not revisions and attachments
|
192 |
+
if ( ($post->post_type != 'post') && ($post->post_type != 'page') ) return;
|
193 |
+
//Only check published posts
|
194 |
+
if ( $post->post_status != 'publish' ) return;
|
195 |
+
|
196 |
+
$post_container->mark_as_unsynched();
|
197 |
+
}
|
198 |
+
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Instantiate multiple containers of the container type managed by this class.
|
202 |
+
*
|
203 |
+
* @param array $containers Array of assoc. arrays containing container data.
|
204 |
+
* @param string $purpose An optional code indicating how the retrieved containers will be used.
|
205 |
+
* @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
|
206 |
+
*
|
207 |
+
* @return array of blcPostContainer indexed by "container_type|container_id"
|
208 |
+
*/
|
209 |
+
function get_containers($containers, $purpose = '', $load_wrapped_objects = false){
|
210 |
+
$containers = $this->make_containers($containers);
|
211 |
+
|
212 |
+
//Preload post data if it is likely to be useful later
|
213 |
+
$preload = $load_wrapped_objects || in_array($purpose, array(BLC_FOR_DISPLAY, BLC_FOR_PARSING));
|
214 |
+
if ( $preload ){
|
215 |
+
$post_ids = array();
|
216 |
+
foreach($containers as $container){
|
217 |
+
$post_ids[] = $container->container_id;
|
218 |
+
}
|
219 |
+
|
220 |
+
$args = array('include' => implode(',', $post_ids));
|
221 |
+
$posts = get_posts($args);
|
222 |
+
|
223 |
+
foreach($posts as $post){
|
224 |
+
$key = $this->container_type . '|' . $post->ID;
|
225 |
+
if ( isset($containers[$key]) ){
|
226 |
+
$containers[$key]->wrapped_object = $post;
|
227 |
+
}
|
228 |
+
}
|
229 |
+
}
|
230 |
+
|
231 |
+
return $containers;
|
232 |
+
}
|
233 |
+
|
234 |
+
/**
|
235 |
+
* Create or update synchronization records for all posts.
|
236 |
+
*
|
237 |
+
* @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch.
|
238 |
+
* @return void
|
239 |
+
*/
|
240 |
+
function resynch($forced = false){
|
241 |
+
global $wpdb;
|
242 |
+
|
243 |
+
if ( $forced ){
|
244 |
+
//Create new synchronization records for all posts.
|
245 |
+
$q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
|
246 |
+
SELECT id, 'post', 0
|
247 |
+
FROM {$wpdb->posts}
|
248 |
+
WHERE
|
249 |
+
{$wpdb->posts}.post_status = 'publish'
|
250 |
+
AND {$wpdb->posts}.post_type IN ('post', 'page')";
|
251 |
+
$wpdb->query( $q );
|
252 |
+
} else {
|
253 |
+
//Delete synch records corresponding to posts that no longer exist.
|
254 |
+
$q = "DELETE synch.*
|
255 |
+
FROM
|
256 |
+
{$wpdb->prefix}blc_synch AS synch LEFT JOIN {$wpdb->posts} AS posts
|
257 |
+
ON posts.ID = synch.container_id
|
258 |
+
WHERE
|
259 |
+
synch.container_type = 'post' AND posts.ID IS NULL";
|
260 |
+
$wpdb->query( $q );
|
261 |
+
|
262 |
+
//Remove the 'synched' flag from all posts that have been updated
|
263 |
+
//since the last time they were parsed/synchronized.
|
264 |
+
$q = "UPDATE
|
265 |
+
{$wpdb->prefix}blc_synch AS synch
|
266 |
+
JOIN {$wpdb->posts} AS posts ON (synch.container_id = posts.ID and synch.container_type='post')
|
267 |
+
SET
|
268 |
+
synched = 0
|
269 |
+
WHERE
|
270 |
+
synch.last_synch < posts.post_modified";
|
271 |
+
$wpdb->query( $q );
|
272 |
+
|
273 |
+
//Create synch. records for posts that don't have them.
|
274 |
+
$q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
|
275 |
+
SELECT id, 'post', 0
|
276 |
+
FROM
|
277 |
+
{$wpdb->posts} AS posts LEFT JOIN {$wpdb->prefix}blc_synch AS synch
|
278 |
+
ON (synch.container_id = posts.ID and synch.container_type='post')
|
279 |
+
WHERE
|
280 |
+
posts.post_status = 'publish'
|
281 |
+
AND posts.post_type IN ('post', 'page')
|
282 |
+
AND synch.container_id IS NULL";
|
283 |
+
$wpdb->query($q);
|
284 |
+
}
|
285 |
+
}
|
286 |
+
|
287 |
+
/**
|
288 |
+
* Get the message to display after $n posts have been deleted.
|
289 |
+
*
|
290 |
+
* @param int $n Number of deleted posts.
|
291 |
+
* @return string A delete confirmation message, e.g. "5 posts were moved to trash"
|
292 |
+
*/
|
293 |
+
function ui_bulk_delete_message($n){
|
294 |
+
//Since the "Trash" feature has been introduced, calling wp_delete_post
|
295 |
+
//doesn't actually delete the post (unless you set force_delete to True),
|
296 |
+
//just moves it to the trash. So we pick the message accordingly.
|
297 |
+
if ( function_exists('wp_trash_post') && EMPTY_TRASH_DAYS ){
|
298 |
+
$delete_msg = _n("%d post moved to the trash", "%d posts moved to the trash", $n, 'broken-link-checker');
|
299 |
+
} else {
|
300 |
+
$delete_msg = _n("%d post deleted", "%d posts deleted", $n, 'broken-link-checker');
|
301 |
+
}
|
302 |
+
return sprintf($delete_msg, $n);
|
303 |
+
}
|
304 |
+
|
305 |
+
/**
|
306 |
+
* Hook for the 'the_content' filter. Scans the current post and adds the 'broken_link'
|
307 |
+
* CSS class to all links that are known to be broken. Currently works only on standard
|
308 |
+
* HTML links (i.e. the '<a href=...' kind).
|
309 |
+
*
|
310 |
+
* @param string $content Post content
|
311 |
+
* @return string Modified post content.
|
312 |
+
*/
|
313 |
+
function hook_the_content($content){
|
314 |
+
global $post, $wpdb;
|
315 |
+
if ( empty($post) ) return $content;
|
316 |
+
|
317 |
+
//Retrieve info about all occurences of broken links in the current post
|
318 |
+
$q = "
|
319 |
+
SELECT instances.raw_url
|
320 |
+
FROM {$wpdb->prefix}blc_instances AS instances JOIN {$wpdb->prefix}blc_links AS links
|
321 |
+
ON instances.link_id = links.link_id
|
322 |
+
WHERE
|
323 |
+
instances.container_type = %s
|
324 |
+
AND instances.container_id = %d
|
325 |
+
AND links.broken = 1
|
326 |
+
AND parser_type = 'link'
|
327 |
+
";
|
328 |
+
$q = $wpdb->prepare($q, $this->container_type, $post->ID);
|
329 |
+
$links = $wpdb->get_results($q, ARRAY_A);
|
330 |
+
|
331 |
+
//Return the content unmodified if there are no broken links in this post.
|
332 |
+
if ( empty($links) || !is_array($links) ){
|
333 |
+
return $content;
|
334 |
+
}
|
335 |
+
|
336 |
+
//Put the broken link URLs in an array
|
337 |
+
$broken_link_urls = array();
|
338 |
+
foreach($links as $link){
|
339 |
+
$broken_link_urls[] = $link['raw_url'];
|
340 |
+
}
|
341 |
+
|
342 |
+
|
343 |
+
//Iterate over all HTML links and modify the broken ones
|
344 |
+
$parser = blc_get_parser('link');
|
345 |
+
$content = $parser->multi_edit($content, array(&$this, 'highlight_broken_link'), $broken_link_urls);
|
346 |
+
|
347 |
+
return $content;
|
348 |
+
}
|
349 |
+
|
350 |
+
/**
|
351 |
+
* Analyse a link and add 'broken_link' CSS class if the link is broken.
|
352 |
+
*
|
353 |
+
* @see blcHtmlLink::multi_edit()
|
354 |
+
*
|
355 |
+
* @param array $link Associative array of link data.
|
356 |
+
* @param array $broken_link_urls List of broken link URLs present in the current post.
|
357 |
+
* @return array|string The modified link
|
358 |
+
*/
|
359 |
+
function highlight_broken_link($link, $broken_link_urls){
|
360 |
+
if ( !in_array($link['href'], $broken_link_urls) ){
|
361 |
+
//Link not broken = return the original link tag
|
362 |
+
return $link['#raw'];
|
363 |
+
}
|
364 |
+
|
365 |
+
//Add 'broken_link' to the 'class' attribute (unless already present).
|
366 |
+
if ( isset($link['class']) ){
|
367 |
+
$classes = explode(' ', $link['class']);
|
368 |
+
if ( !in_array('broken_link', $classes) ){
|
369 |
+
$classes[] = 'broken_link';
|
370 |
+
$link['class'] = implode(' ', $classes);
|
371 |
+
}
|
372 |
+
} else {
|
373 |
+
$link['class'] = 'broken_link';
|
374 |
+
}
|
375 |
+
|
376 |
+
return $link;
|
377 |
+
}
|
378 |
+
|
379 |
+
/**
|
380 |
+
* A hook for the 'wp_head' action. Outputs the user-defined broken link CSS.
|
381 |
+
*
|
382 |
+
* @return void
|
383 |
+
*/
|
384 |
+
function hook_wp_head(){
|
385 |
+
$conf = blc_get_configuration();
|
386 |
+
echo '<style type="text/css">',$conf->options['broken_link_css'],'</style>';
|
387 |
+
}
|
388 |
+
}
|
389 |
+
|
390 |
+
blc_register_container('post', 'blcPostContainerManager');
|
391 |
+
|
392 |
+
?>
|
includes/instances.php
ADDED
@@ -0,0 +1,549 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @author W-Shadow
|
5 |
+
* @copyright 2009
|
6 |
+
*/
|
7 |
+
|
8 |
+
if (!class_exists('blcLinkInstance')) {
|
9 |
+
class blcLinkInstance {
|
10 |
+
|
11 |
+
//Object state
|
12 |
+
var $is_new = false;
|
13 |
+
|
14 |
+
//DB fields
|
15 |
+
var $instance_id = 0;
|
16 |
+
var $link_id = 0;
|
17 |
+
|
18 |
+
var $container_id = 0;
|
19 |
+
var $container_type = '';
|
20 |
+
var $container_field = '';
|
21 |
+
|
22 |
+
var $parser_type = '';
|
23 |
+
|
24 |
+
var $link_text = '';
|
25 |
+
var $link_context = '';
|
26 |
+
var $raw_url = '';
|
27 |
+
|
28 |
+
var $_container = null;
|
29 |
+
var $_parser = null;
|
30 |
+
var $_link = null;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* blcLinkInstance::__construct()
|
34 |
+
* Class constructor
|
35 |
+
*
|
36 |
+
* @param int|array $arg Either the instance ID or an associate array repreenting the instance's DB record. Should be NULL for new instances.
|
37 |
+
* @return void
|
38 |
+
*/
|
39 |
+
function __construct($arg = null){
|
40 |
+
|
41 |
+
if (is_int($arg)){
|
42 |
+
//Load an instance with ID = $arg from the DB.
|
43 |
+
$q = $wpdb->prepare("SELECT * FROM {$wpdb->prefix}blc_instances WHERE instance_id=%d LIMIT 1", $arg);
|
44 |
+
$arr = $wpdb->get_row( $q, ARRAY_A );
|
45 |
+
|
46 |
+
if ( is_array($arr) ){ //Loaded successfully
|
47 |
+
$this->set_values($arr);
|
48 |
+
} else {
|
49 |
+
//Link instance not found. The object is invalid.
|
50 |
+
}
|
51 |
+
|
52 |
+
} else if (is_array($arg)){
|
53 |
+
$this->set_values($arg);
|
54 |
+
|
55 |
+
//Is this a new instance?
|
56 |
+
$this->is_new = empty($this->instance_id);
|
57 |
+
|
58 |
+
} else {
|
59 |
+
$this->is_new = true;
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* blcLinkInstance::blcLinkInstance()
|
65 |
+
* Old-style constructor for PHP 4. Do not use.
|
66 |
+
*
|
67 |
+
* @param mixed $arg
|
68 |
+
* @return void
|
69 |
+
*/
|
70 |
+
function blcLinkInstance($arg = null){
|
71 |
+
$this->__construct($arg);
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* blcLinkInstance::set_values()
|
76 |
+
* Set property values to the ones provided in an array (doesn't sanitize).
|
77 |
+
*
|
78 |
+
* @param array $arr An associative array
|
79 |
+
* @return void
|
80 |
+
*/
|
81 |
+
function set_values($arr){
|
82 |
+
foreach( $arr as $key => $value ){
|
83 |
+
$this->$key = $value;
|
84 |
+
}
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Replace this instance's URL with a new one.
|
89 |
+
* Warning : this shouldn't be called directly. Use blcLink->edit() instead.
|
90 |
+
*
|
91 |
+
* @param string $new_url
|
92 |
+
* @param string $old_url
|
93 |
+
* @return bool|WP_Error True on success, or an instance of WP_Error if something went wrong.
|
94 |
+
*/
|
95 |
+
function edit($new_url, $old_url = ''){
|
96 |
+
|
97 |
+
//Get the container that contains this link
|
98 |
+
$container = $this->get_container();
|
99 |
+
if ( is_null($container) ){
|
100 |
+
return new WP_Error(
|
101 |
+
'container_not_found',
|
102 |
+
sprintf(__("Container %s[%d] not found", 'broken-link-checker'), $this->container_type, $this->container_id)
|
103 |
+
);
|
104 |
+
}
|
105 |
+
|
106 |
+
//Get the parser.
|
107 |
+
$parser = $this->get_parser();
|
108 |
+
if ( is_null($parser) ){
|
109 |
+
return new WP_Error(
|
110 |
+
'parser_not_found',
|
111 |
+
sprintf(__("Parser '%s' not found.", 'broken-link-checker'), $this->parser_type)
|
112 |
+
);
|
113 |
+
}
|
114 |
+
|
115 |
+
//If the old URL isn't specified get it from the link record
|
116 |
+
if ( empty($old_url) ){
|
117 |
+
$old_url = $this->get_url();
|
118 |
+
}
|
119 |
+
|
120 |
+
//Attempt to modify the link(s)
|
121 |
+
$result = $container->edit_link($this->container_field, $parser, $new_url, $old_url, $this->raw_url);
|
122 |
+
if ( is_string($result) ){
|
123 |
+
//If the modification was successful, the container will return
|
124 |
+
//the new raw_url for the instance. Save the URL and return true,
|
125 |
+
//indicating success.
|
126 |
+
$this->raw_url = $result;
|
127 |
+
return true;
|
128 |
+
} else {
|
129 |
+
//Otherwise, it will return an error object. In this case we'll
|
130 |
+
//just pass it back to the caller and let them sort it out.
|
131 |
+
return $result;
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
/**
|
136 |
+
* blcLinkInstance::unlink()
|
137 |
+
* Remove this instance from the post/blogroll/etc. Also deletes the appropriate DB record(s).
|
138 |
+
*
|
139 |
+
* @return bool|WP_Error
|
140 |
+
*/
|
141 |
+
function unlink( $url = null ) {
|
142 |
+
|
143 |
+
//Get the container that contains this link
|
144 |
+
$container = $this->get_container();
|
145 |
+
if ( is_null($container) ){
|
146 |
+
return new WP_Error(
|
147 |
+
'container_not_found',
|
148 |
+
sprintf(__("Container %s[%d] not found", 'broken-link-checker'), $this->container_type, $this->container_id)
|
149 |
+
);
|
150 |
+
}
|
151 |
+
|
152 |
+
//Get the parser.
|
153 |
+
$parser = $this->get_parser();
|
154 |
+
if ( is_null($parser) ){
|
155 |
+
return new WP_Error(
|
156 |
+
'parser_not_found',
|
157 |
+
sprintf(__("Parser '%s' not found.", 'broken-link-checker'), $this->parser_type)
|
158 |
+
);
|
159 |
+
}
|
160 |
+
|
161 |
+
//If the old URL isn't specified get it from the link record
|
162 |
+
if ( empty($url) ){
|
163 |
+
$url = $this->get_url();
|
164 |
+
}
|
165 |
+
|
166 |
+
//Attempt to remove the link(s)
|
167 |
+
return $container->unlink($this->container_field, $parser, $url, $this->raw_url);
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Remove the link instance record from database. Doesn't affect the thing that contains the link.
|
172 |
+
*
|
173 |
+
* @return mixed 1 on success, 0 if the instance wasn't found, false on error
|
174 |
+
*/
|
175 |
+
function forget(){
|
176 |
+
global $wpdb;
|
177 |
+
|
178 |
+
if ( !empty($this->instance_id) ) {
|
179 |
+
$rez = $wpdb->query( $wpdb->prepare("DELETE FROM {$wpdb->prefix}blc_instances WHERE instance_id=%d", $this->instance_id) );
|
180 |
+
return $rez;
|
181 |
+
} else {
|
182 |
+
return false;
|
183 |
+
}
|
184 |
+
}
|
185 |
+
|
186 |
+
/**
|
187 |
+
* Store the link instance in the database.
|
188 |
+
* Saving the instance will also implicitly save the link record associated with it, if it wasn't already saved.
|
189 |
+
*
|
190 |
+
* @return bool TRUE on success, FALSE on error
|
191 |
+
*/
|
192 |
+
function save(){
|
193 |
+
global $wpdb;
|
194 |
+
|
195 |
+
//Refresh the locally cached link & container properties, in case
|
196 |
+
//the objects have changed since they were set.
|
197 |
+
|
198 |
+
if ( !is_null($this->_link) ){
|
199 |
+
|
200 |
+
//If we have a link object assigned, but it's new, it won't have a DB ID yet.
|
201 |
+
//We need to save the link to get the ID and be able to maintain the link <-> instance
|
202 |
+
//association.
|
203 |
+
if ( $this->_link->is_new ){
|
204 |
+
$rez = $this->_link->save();
|
205 |
+
if ( !$rez ){
|
206 |
+
return false;
|
207 |
+
}
|
208 |
+
}
|
209 |
+
|
210 |
+
$this->link_id = $this->_link->link_id;
|
211 |
+
}
|
212 |
+
|
213 |
+
if ( !is_null($this->_container) ){
|
214 |
+
$this->container_type = $this->_container->container_type;
|
215 |
+
$this->container_id = $this->_container->container_id;
|
216 |
+
}
|
217 |
+
|
218 |
+
//If the link is new, insert a new row into the DB. Otherwise updat the existing row.
|
219 |
+
if ( $this->is_new ){
|
220 |
+
|
221 |
+
$q = "
|
222 |
+
INSERT INTO {$wpdb->prefix}blc_instances
|
223 |
+
( link_id, container_type, container_id, container_field, parser_type, link_text, link_context, raw_url )
|
224 |
+
VALUES( %d, %s, %d, %s, %s, %s, %s, %s )";
|
225 |
+
|
226 |
+
$q = $wpdb->prepare(
|
227 |
+
$q,
|
228 |
+
|
229 |
+
$this->link_id,
|
230 |
+
$this->container_type,
|
231 |
+
$this->container_id,
|
232 |
+
$this->container_field,
|
233 |
+
$this->parser_type,
|
234 |
+
$this->link_text,
|
235 |
+
$this->link_context,
|
236 |
+
$this->raw_url
|
237 |
+
);
|
238 |
+
|
239 |
+
$rez = $wpdb->query($q) !== false;
|
240 |
+
|
241 |
+
if ($rez){
|
242 |
+
$this->instance_id = $wpdb->insert_id;
|
243 |
+
//If the instance was successfully saved then it's no longer "new".
|
244 |
+
$this->is_new = !$rez;
|
245 |
+
}
|
246 |
+
|
247 |
+
return $rez;
|
248 |
+
|
249 |
+
} else {
|
250 |
+
|
251 |
+
$q = "UPDATE {$wpdb->prefix}blc_instances
|
252 |
+
|
253 |
+
SET
|
254 |
+
link_id = %d,
|
255 |
+
container_type = %s,
|
256 |
+
container_id = %d,
|
257 |
+
container_field = %s,
|
258 |
+
parser_type = %s,
|
259 |
+
link_text = %s,
|
260 |
+
link_context = %s,
|
261 |
+
raw_url = %s
|
262 |
+
|
263 |
+
WHERE instance_id = %d";
|
264 |
+
|
265 |
+
$q = $wpdb->prepare(
|
266 |
+
$q,
|
267 |
+
|
268 |
+
$this->link_id,
|
269 |
+
$this->container_type,
|
270 |
+
$this->container_id,
|
271 |
+
$this->container_field,
|
272 |
+
$this->parser_type,
|
273 |
+
$this->link_text,
|
274 |
+
$this->link_context,
|
275 |
+
$this->raw_url,
|
276 |
+
|
277 |
+
$this->instance_id
|
278 |
+
);
|
279 |
+
|
280 |
+
$rez = $wpdb->query($q) !== false;
|
281 |
+
|
282 |
+
if ($rez){
|
283 |
+
//FB::info($this, "Instance updated");
|
284 |
+
} else {
|
285 |
+
//FB::error("DB error while updating instance {$this->instance_id} : {$wpdb->last_error}");
|
286 |
+
}
|
287 |
+
|
288 |
+
return $rez;
|
289 |
+
|
290 |
+
}
|
291 |
+
}
|
292 |
+
|
293 |
+
/**
|
294 |
+
* Get the URL associated with this instance.
|
295 |
+
*
|
296 |
+
* @return string The associated URL, or an empty string if the instance is currently not assigned to any link.
|
297 |
+
*/
|
298 |
+
function get_url(){
|
299 |
+
$link = $this->get_link();
|
300 |
+
|
301 |
+
if ( !is_null($link) ){
|
302 |
+
return $link->url;
|
303 |
+
} else {
|
304 |
+
return '';
|
305 |
+
}
|
306 |
+
}
|
307 |
+
|
308 |
+
/**
|
309 |
+
* Get the container object associated with this link instance
|
310 |
+
*
|
311 |
+
* @return blcContainer|null
|
312 |
+
*/
|
313 |
+
function get_container(){
|
314 |
+
if( is_null($this->_container) ){
|
315 |
+
$this->_container = blc_get_container( array($this->container_type, $this->container_id) );
|
316 |
+
}
|
317 |
+
|
318 |
+
return $this->_container;
|
319 |
+
}
|
320 |
+
|
321 |
+
/**
|
322 |
+
* Set a new container for the link instance.
|
323 |
+
*
|
324 |
+
* @param blcContainer $new_container
|
325 |
+
* @param string $field
|
326 |
+
* @return void
|
327 |
+
*/
|
328 |
+
function set_container($new_container, $field = ''){
|
329 |
+
$this->_container = $new_container;
|
330 |
+
|
331 |
+
$this->container_field = $field;
|
332 |
+
|
333 |
+
if( !is_null($new_container) ){
|
334 |
+
$this->container_type = $new_container->container_type;
|
335 |
+
$this->container_id = $new_container->container_id;
|
336 |
+
} else {
|
337 |
+
$this->container_type = '';
|
338 |
+
$this->container_id = 0;
|
339 |
+
}
|
340 |
+
}
|
341 |
+
|
342 |
+
/**
|
343 |
+
* Get the parser associated with this link instance.
|
344 |
+
*
|
345 |
+
* @return blcParser|null
|
346 |
+
*/
|
347 |
+
function get_parser(){
|
348 |
+
if ( is_null($this->_parser) ){
|
349 |
+
$this->_parser = blc_get_parser($this->parser_type);
|
350 |
+
}
|
351 |
+
|
352 |
+
return $this->_parser;
|
353 |
+
}
|
354 |
+
|
355 |
+
/**
|
356 |
+
* Set a new parser fo this link instance.
|
357 |
+
*
|
358 |
+
* @param blcParser|null $new_parser
|
359 |
+
* @return void
|
360 |
+
*/
|
361 |
+
function set_parser($new_parser){
|
362 |
+
$this->_parser = $new_parser;
|
363 |
+
|
364 |
+
if ( is_null($new_parser) ){
|
365 |
+
$this->parser_type = '';
|
366 |
+
} else {
|
367 |
+
$this->parser_type = $new_parser->parser_type;
|
368 |
+
}
|
369 |
+
}
|
370 |
+
|
371 |
+
/**
|
372 |
+
* Get the link object associated with this link intance.
|
373 |
+
*
|
374 |
+
* @return blcLink|null
|
375 |
+
*/
|
376 |
+
function get_link(){
|
377 |
+
if ( !is_null($this->_link) ){
|
378 |
+
return $this->_link;
|
379 |
+
}
|
380 |
+
|
381 |
+
if ( empty($this->link_id) ) {
|
382 |
+
return null;
|
383 |
+
}
|
384 |
+
|
385 |
+
$this->_link = new blcLink($this->link_id);
|
386 |
+
return $this->_link;
|
387 |
+
}
|
388 |
+
|
389 |
+
/**
|
390 |
+
* Set the link associated with this link instance.
|
391 |
+
*
|
392 |
+
* @param blcLink $new_link
|
393 |
+
* @return void
|
394 |
+
*/
|
395 |
+
function set_link($new_link){
|
396 |
+
$this->_link = $new_link;
|
397 |
+
|
398 |
+
if ( is_null($new_link) ){
|
399 |
+
$this->link_id = 0;
|
400 |
+
} else {
|
401 |
+
$this->link_id = $new_link->link_id;
|
402 |
+
}
|
403 |
+
}
|
404 |
+
|
405 |
+
/**
|
406 |
+
* Get the link text for printing in the "Broken Links" table.
|
407 |
+
*
|
408 |
+
* @param string $context How to filter the link text. Optional, defaults to 'display'.
|
409 |
+
* @return string HTML
|
410 |
+
*/
|
411 |
+
function ui_get_link_text($context = 'display'){
|
412 |
+
$parser = $this->get_parser();
|
413 |
+
|
414 |
+
if ( !is_null($parser) ){
|
415 |
+
$text = $parser->ui_get_link_text($this, $context);
|
416 |
+
} else {
|
417 |
+
$text = strip_tags($this->link_text);
|
418 |
+
}
|
419 |
+
|
420 |
+
if ( empty($text) ){
|
421 |
+
$text = "<em>(None)</em>";
|
422 |
+
}
|
423 |
+
|
424 |
+
return $text;
|
425 |
+
}
|
426 |
+
|
427 |
+
/**
|
428 |
+
* Get action links that should be displayed in the "Source" column of the "Broken Links" table.
|
429 |
+
*
|
430 |
+
* @return array An array of HTML links.
|
431 |
+
*/
|
432 |
+
function ui_get_action_links(){
|
433 |
+
//The container is responsible for generating the links.
|
434 |
+
$container = $this->get_container();
|
435 |
+
if ( !is_null($container) ){
|
436 |
+
return $container->ui_get_action_links($this->container_field);
|
437 |
+
} else {
|
438 |
+
//No valid container = no links.
|
439 |
+
return array();
|
440 |
+
}
|
441 |
+
}
|
442 |
+
|
443 |
+
/**
|
444 |
+
* Get the HTML describing the "source" of the instance. For example, for links found in posts,
|
445 |
+
* this could be the post title.
|
446 |
+
*
|
447 |
+
* @param string $context How to filter the output. Optional, defaults to 'display'.
|
448 |
+
* @return string HTML
|
449 |
+
*/
|
450 |
+
function ui_get_source($context = 'display'){
|
451 |
+
//The container is also responsible for generating the "Source" column HTML.
|
452 |
+
$container = $this->get_container();
|
453 |
+
if ( !is_null($container) ){
|
454 |
+
return $container->ui_get_source($this->container_field, $context);
|
455 |
+
} else {
|
456 |
+
//No valid container = generate some bare-bones debug output.
|
457 |
+
return sprintf('%s[%d] : %s', $this->container_type, $this->container_id, $this->container_field);
|
458 |
+
}
|
459 |
+
}
|
460 |
+
}
|
461 |
+
|
462 |
+
/**
|
463 |
+
* Get all link instances associated with one or more links.
|
464 |
+
*
|
465 |
+
* @param array $link_ids Array of link IDs.
|
466 |
+
* @param string $purpose An optional code indicating how the instances will be used. Available predefined constants : BLC_FOR_DISPLAY, BLC_FOR_EDITING
|
467 |
+
* @param bool $load_containers Preload containers regardless of purpose.
|
468 |
+
* @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
|
469 |
+
* @return array An array indexed by link ID. Each item of the array will be an array of blcLinkInstance objects.
|
470 |
+
*/
|
471 |
+
function blc_get_instances( $link_ids, $purpose = '', $load_containers = false, $load_wrapped_objects = false ){
|
472 |
+
global $wpdb;
|
473 |
+
|
474 |
+
if ( empty($link_ids) ){
|
475 |
+
return array();
|
476 |
+
}
|
477 |
+
|
478 |
+
$link_ids_in = implode(', ', $link_ids);
|
479 |
+
|
480 |
+
$q = "SELECT * FROM {$wpdb->prefix}blc_instances WHERE link_id IN ($link_ids_in)";
|
481 |
+
$results = $wpdb->get_results($q, ARRAY_A);
|
482 |
+
|
483 |
+
if ( empty($results) ) {
|
484 |
+
return array();
|
485 |
+
}
|
486 |
+
|
487 |
+
//Also retrieve the containers, if it could be useful.
|
488 |
+
$load_containers = $load_containers || in_array( $purpose, array(BLC_FOR_DISPLAY, BLC_FOR_EDITING) );
|
489 |
+
if ( $load_containers ){
|
490 |
+
//Collect a list of (container_type, container_id) pairs
|
491 |
+
$container_ids = array();
|
492 |
+
|
493 |
+
foreach($results as $result){
|
494 |
+
array_push(
|
495 |
+
$container_ids,
|
496 |
+
array( $result['container_type'], intval($result['container_id']) )
|
497 |
+
);
|
498 |
+
}
|
499 |
+
|
500 |
+
$containers = blc_get_containers($container_ids, $purpose, $load_wrapped_objects);
|
501 |
+
}
|
502 |
+
|
503 |
+
//Create an object for each instance and group them by link ID
|
504 |
+
$instances = array();
|
505 |
+
foreach ($results as $result){
|
506 |
+
$instance = new blcLinkInstance($result);
|
507 |
+
|
508 |
+
//Assign a container to the link instance, if available
|
509 |
+
if( $load_containers && !empty($containers) ){
|
510 |
+
$key = $instance->container_type . '|' . $instance->container_id;
|
511 |
+
if( isset($containers[$key]) ){
|
512 |
+
$instance->_container = $containers[$key];
|
513 |
+
}
|
514 |
+
}
|
515 |
+
|
516 |
+
if ( isset($instances[$instance->link_id]) ){
|
517 |
+
array_push( $instances[$instance->link_id], $instance );
|
518 |
+
} else {
|
519 |
+
$instances[$instance->link_id] = array($instance);
|
520 |
+
}
|
521 |
+
}
|
522 |
+
|
523 |
+
return $instances;
|
524 |
+
}
|
525 |
+
|
526 |
+
/**
|
527 |
+
* Remove instances that reference invalid containers
|
528 |
+
*
|
529 |
+
* @return bool
|
530 |
+
*/
|
531 |
+
function blc_cleanup_instances(){
|
532 |
+
global $wpdb;
|
533 |
+
|
534 |
+
//Delete all instances that reference non-existent containers
|
535 |
+
$q = "DELETE instances.*
|
536 |
+
FROM
|
537 |
+
{$wpdb->prefix}blc_instances AS instances LEFT JOIN {$wpdb->prefix}blc_synch AS synch
|
538 |
+
ON instances.container_type = synch.container_type AND instances.container_id = synch.container_id
|
539 |
+
WHERE
|
540 |
+
synch.container_id IS NULL";
|
541 |
+
$rez = $wpdb->query($q);
|
542 |
+
|
543 |
+
return $rez !== false;
|
544 |
+
}
|
545 |
+
|
546 |
+
|
547 |
+
}//class_exists
|
548 |
+
|
549 |
+
?>
|
includes/links.php
ADDED
@@ -0,0 +1,1346 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @author W-Shadow
|
5 |
+
* @copyright 2010
|
6 |
+
*/
|
7 |
+
|
8 |
+
if (!class_exists('blcLink')){
|
9 |
+
class blcLink {
|
10 |
+
|
11 |
+
//Object state
|
12 |
+
var $is_new = false;
|
13 |
+
|
14 |
+
//DB fields
|
15 |
+
var $link_id = 0;
|
16 |
+
var $url = '';
|
17 |
+
|
18 |
+
var $being_checked = false;
|
19 |
+
var $last_check = 0;
|
20 |
+
var $last_check_attempt = 0;
|
21 |
+
var $check_count = 0;
|
22 |
+
var $http_code = 0;
|
23 |
+
var $request_duration = 0;
|
24 |
+
var $timeout = false;
|
25 |
+
|
26 |
+
var $redirect_count = 0;
|
27 |
+
var $final_url = '';
|
28 |
+
|
29 |
+
var $broken = false;
|
30 |
+
var $first_failure = 0;
|
31 |
+
var $last_success = 0;
|
32 |
+
var $may_recheck = 1;
|
33 |
+
|
34 |
+
var $false_positive = false;
|
35 |
+
var $result_hash = '';
|
36 |
+
|
37 |
+
var $log = '';
|
38 |
+
|
39 |
+
//A list of DB fields and their storage formats
|
40 |
+
var $field_format;
|
41 |
+
|
42 |
+
//A cached list of the link's instances
|
43 |
+
var $_instances = null;
|
44 |
+
|
45 |
+
function __construct($arg = null){
|
46 |
+
global $wpdb;
|
47 |
+
|
48 |
+
$this->field_format = array(
|
49 |
+
'url' => '%s',
|
50 |
+
'first_failure' => 'datetime',
|
51 |
+
'last_check' => 'datetime',
|
52 |
+
'last_success' => 'datetime',
|
53 |
+
'last_check_attempt' => 'datetime',
|
54 |
+
'check_count' => '%d',
|
55 |
+
'final_url' => '%s',
|
56 |
+
'redirect_count' => '%d',
|
57 |
+
'log' => '%s',
|
58 |
+
'http_code' => '%d',
|
59 |
+
'request_duration' => '%f',
|
60 |
+
'timeout' => 'bool',
|
61 |
+
'result_hash' => '%s',
|
62 |
+
'broken' => 'bool',
|
63 |
+
'false_positive' => 'bool',
|
64 |
+
'may_recheck' => 'bool',
|
65 |
+
'being_checked' => 'bool',
|
66 |
+
);
|
67 |
+
|
68 |
+
if (is_int($arg)){
|
69 |
+
//Load a link with ID = $arg from the DB.
|
70 |
+
$q = $wpdb->prepare("SELECT * FROM {$wpdb->prefix}blc_links WHERE link_id=%d LIMIT 1", $arg);
|
71 |
+
$arr = $wpdb->get_row( $q, ARRAY_A );
|
72 |
+
|
73 |
+
if ( is_array($arr) ){ //Loaded successfully
|
74 |
+
$this->set_values($arr);
|
75 |
+
} else {
|
76 |
+
//Link not found. The object is invalid.
|
77 |
+
//I'd throw an error, but that wouldn't be PHP 4 compatible...
|
78 |
+
}
|
79 |
+
|
80 |
+
} else if (is_string($arg)){
|
81 |
+
//Load a link with URL = $arg from the DB. Create a new one if the record isn't found.
|
82 |
+
$q = $wpdb->prepare("SELECT * FROM {$wpdb->prefix}blc_links WHERE url=%s LIMIT 1", $arg);
|
83 |
+
$arr = $wpdb->get_row( $q, ARRAY_A );
|
84 |
+
|
85 |
+
if ( is_array($arr) ){ //Loaded successfully
|
86 |
+
$this->set_values($arr);
|
87 |
+
} else { //Link not found, treat as new
|
88 |
+
$this->url = $arg;
|
89 |
+
$this->is_new = true;
|
90 |
+
}
|
91 |
+
|
92 |
+
} else if (is_array($arg)){
|
93 |
+
$this->set_values($arg);
|
94 |
+
//Is this a new link?
|
95 |
+
$this->is_new = empty($this->link_id);
|
96 |
+
} else {
|
97 |
+
$this->is_new = true;
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
function blcLink($arg = null){
|
102 |
+
$this->__construct($arg);
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* blcLink::set_values()
|
107 |
+
* Set the internal values to the ones provided in an array (doesn't sanitize).
|
108 |
+
*
|
109 |
+
* @param array $arr An associative array of values
|
110 |
+
* @return void
|
111 |
+
*/
|
112 |
+
function set_values($arr){
|
113 |
+
$arr = $this->to_native_format($arr);
|
114 |
+
|
115 |
+
foreach( $arr as $key => $value ){
|
116 |
+
$this->$key = $value;
|
117 |
+
}
|
118 |
+
}
|
119 |
+
|
120 |
+
/**
|
121 |
+
* Check whether the object represents a valid link
|
122 |
+
*
|
123 |
+
* @return bool
|
124 |
+
*/
|
125 |
+
function valid(){
|
126 |
+
return !empty( $this->url ) && ( !empty($this->link_id) || $this->is_new );
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Check if the link is working.
|
131 |
+
*
|
132 |
+
* @param bool $save_results Automatically save the results of the check.
|
133 |
+
* @return bool
|
134 |
+
*/
|
135 |
+
function check( $save_results = true ){
|
136 |
+
if ( !$this->valid() ) return false;
|
137 |
+
|
138 |
+
$this->last_check_attempt = time();
|
139 |
+
|
140 |
+
/*
|
141 |
+
If the link is stil marked as in the process of being checked, that probably means
|
142 |
+
that the last time the plugin tried to check it the script got terminated by PHP for
|
143 |
+
running over the execution time limit or causing a fatal error. Lets assume the link is broken.
|
144 |
+
*/
|
145 |
+
if ( $this->being_checked ) {
|
146 |
+
|
147 |
+
$this->being_checked = false;
|
148 |
+
|
149 |
+
$this->broken = true;
|
150 |
+
$this->timeout = true;
|
151 |
+
$this->http_code = BLC_TIMEOUT;
|
152 |
+
|
153 |
+
$this->request_duration = 0;
|
154 |
+
$this->redirect_count = 0;
|
155 |
+
$this->final_url = $this->url;
|
156 |
+
|
157 |
+
$this->log .= "\r\n[" . __("The plugin script was terminated while trying to check the link.", 'broken-link-checker') . "]";
|
158 |
+
|
159 |
+
$this->status_changed($this->broken, 'link_checker_terminated');
|
160 |
+
|
161 |
+
|
162 |
+
if ( $save_results ){
|
163 |
+
$this->save();
|
164 |
+
}
|
165 |
+
|
166 |
+
return false;
|
167 |
+
}
|
168 |
+
|
169 |
+
$this->being_checked = true;
|
170 |
+
$this->check_count++;
|
171 |
+
|
172 |
+
if ( $save_results ) {
|
173 |
+
|
174 |
+
//Update the DB record before actually performing the check.
|
175 |
+
//Useful if something goes terribly wrong while checking this particular URL
|
176 |
+
//(e.g. the server might kill the script for running over the exec. time limit).
|
177 |
+
//Note : might be unnecessary.
|
178 |
+
$this->save();
|
179 |
+
}
|
180 |
+
|
181 |
+
$defaults = array(
|
182 |
+
'broken' => false,
|
183 |
+
'http_code' => 0,
|
184 |
+
'redirect_count' => 0,
|
185 |
+
'final_url' => $this->url,
|
186 |
+
'request_duration' => 0,
|
187 |
+
'timeout' => false,
|
188 |
+
'may_recheck' => true,
|
189 |
+
'log' => '',
|
190 |
+
'result_hash' => '',
|
191 |
+
);
|
192 |
+
|
193 |
+
|
194 |
+
$checker = blc_get_checker_for($this->url);
|
195 |
+
|
196 |
+
if ( is_null($checker) ){
|
197 |
+
//Oops, there are no checker implementations that can handle this link.
|
198 |
+
//Assume the link is working, but leave a note in the log.
|
199 |
+
$this->broken = false;
|
200 |
+
$this->being_checked = false;
|
201 |
+
$this->log = __("The plugin doesn't know how to check this type of link.", 'broken-link-checker');
|
202 |
+
|
203 |
+
if ( $save_results ){
|
204 |
+
$this->save();
|
205 |
+
}
|
206 |
+
|
207 |
+
return true;
|
208 |
+
}
|
209 |
+
|
210 |
+
//Check the link
|
211 |
+
$rez = $checker->check($this->url);
|
212 |
+
//FB::info($rez, "Check results");
|
213 |
+
|
214 |
+
//Filter the returned array to leave only the restricted set of keys that we're interested in.
|
215 |
+
$results = array();
|
216 |
+
foreach($rez as $name => $value){
|
217 |
+
if ( array_key_exists($name, $defaults) ){
|
218 |
+
$results[$name] = $value;
|
219 |
+
}
|
220 |
+
}
|
221 |
+
$results = array_merge($defaults, $results);
|
222 |
+
|
223 |
+
//The result hash is special - see blcLink::status_changed()
|
224 |
+
$new_result_hash = $results['result_hash'];
|
225 |
+
unset($results['result_hash']);
|
226 |
+
|
227 |
+
//Update the object's fields with the new results
|
228 |
+
$this->set_values($results);
|
229 |
+
|
230 |
+
//Update timestamps & state-dependent fields
|
231 |
+
$this->status_changed($results['broken'], $new_result_hash);
|
232 |
+
$this->being_checked = false;
|
233 |
+
|
234 |
+
//Save results to the DB
|
235 |
+
if($save_results){
|
236 |
+
$this->save();
|
237 |
+
}
|
238 |
+
|
239 |
+
return $this->broken;
|
240 |
+
}
|
241 |
+
|
242 |
+
/**
|
243 |
+
* A helper method used to update timestamps & other state-dependent fields
|
244 |
+
* after the state of the link (broken vs working) has just been determined.
|
245 |
+
*
|
246 |
+
* @access private
|
247 |
+
*
|
248 |
+
* @param bool $broken
|
249 |
+
* @return void
|
250 |
+
*/
|
251 |
+
function status_changed($broken, $new_result_hash = ''){
|
252 |
+
|
253 |
+
if ( $this->false_positive && !empty($new_result_hash) ){
|
254 |
+
//If the link has been marked as a (probable) false positive,
|
255 |
+
//mark it as broken *only* if the new result is different from
|
256 |
+
//the one that caused the user to mark it as a false positive.
|
257 |
+
if ( $broken ){
|
258 |
+
if ( $this->result_hash == $new_result_hash ){
|
259 |
+
//Got the same result as before, assume it's still incorrect and the link actually works.
|
260 |
+
$broken = false;
|
261 |
+
} else {
|
262 |
+
//Got a new result. Assume (quite optimistically) that it's not a false positive.
|
263 |
+
$this->false_positive = false;
|
264 |
+
}
|
265 |
+
} else {
|
266 |
+
//The plugin now thinks the link is working,
|
267 |
+
//so it's no longer a false positive.
|
268 |
+
$this->false_positive = false;
|
269 |
+
}
|
270 |
+
}
|
271 |
+
|
272 |
+
$this->broken = $broken;
|
273 |
+
$this->result_hash = $new_result_hash;
|
274 |
+
|
275 |
+
//Update timestamps
|
276 |
+
$this->last_check = $this->last_check_attempt;
|
277 |
+
if ( $this->broken ){
|
278 |
+
if ( empty($this->first_failure) ){
|
279 |
+
$this->first_failure = $this->last_check;
|
280 |
+
}
|
281 |
+
} else {
|
282 |
+
$this->first_failure = 0;
|
283 |
+
$this->last_success = $this->last_check;
|
284 |
+
$this->check_count = 0;
|
285 |
+
}
|
286 |
+
|
287 |
+
//Add a line indicating link status to the log
|
288 |
+
if ( !$broken ) {
|
289 |
+
$this->log .= "\n" . __("Link is valid.", 'broken-link-checker');
|
290 |
+
} else {
|
291 |
+
$this->log .= "\n" . __("Link is broken.", 'broken-link-checker');
|
292 |
+
}
|
293 |
+
}
|
294 |
+
|
295 |
+
/**
|
296 |
+
* blcLink::save()
|
297 |
+
* Save link data to DB.
|
298 |
+
*
|
299 |
+
* @return bool True if saved successfully, false otherwise.
|
300 |
+
*/
|
301 |
+
function save(){
|
302 |
+
global $wpdb;
|
303 |
+
|
304 |
+
if ( !$this->valid() ) return false;
|
305 |
+
|
306 |
+
//Make a list of fields to be saved and their values in DB format
|
307 |
+
$values = array();
|
308 |
+
foreach($this->field_format as $field => $format){
|
309 |
+
$values[$field] = $this->$field;
|
310 |
+
}
|
311 |
+
$values = $this->to_db_format($values);
|
312 |
+
|
313 |
+
if ( $this->is_new ){
|
314 |
+
|
315 |
+
//Insert a new row
|
316 |
+
$q = sprintf(
|
317 |
+
"INSERT INTO {$wpdb->prefix}blc_links( %s ) VALUES( %s )",
|
318 |
+
implode(', ', array_keys($values)),
|
319 |
+
implode(', ', array_values($values))
|
320 |
+
);
|
321 |
+
//FB::log($q, 'Link add query');
|
322 |
+
|
323 |
+
$rez = $wpdb->query($q) !== false;
|
324 |
+
|
325 |
+
if ($rez){
|
326 |
+
$this->link_id = $wpdb->insert_id;
|
327 |
+
//FB::info($this->link_id, "Link added");
|
328 |
+
//If the link was successfully saved then it's no longer "new"
|
329 |
+
$this->is_new = false;
|
330 |
+
} else {
|
331 |
+
//FB::error($wpdb->last_error, "Error adding link {$this->url}");
|
332 |
+
}
|
333 |
+
|
334 |
+
return $rez;
|
335 |
+
|
336 |
+
} else {
|
337 |
+
|
338 |
+
//Generate the field = dbvalue expressions
|
339 |
+
$set_exprs = array();
|
340 |
+
foreach($values as $name => $value){
|
341 |
+
$set_exprs[] = "$name = $value";
|
342 |
+
}
|
343 |
+
$set_exprs = implode(', ', $set_exprs);
|
344 |
+
|
345 |
+
//Update an existing DB record
|
346 |
+
$q = sprintf(
|
347 |
+
"UPDATE {$wpdb->prefix}blc_links SET %s WHERE link_id=%d",
|
348 |
+
$set_exprs,
|
349 |
+
intval($this->link_id)
|
350 |
+
);
|
351 |
+
//FB::log($q, 'Link update query');
|
352 |
+
|
353 |
+
$rez = $wpdb->query($q) !== false;
|
354 |
+
|
355 |
+
if ( $rez ){
|
356 |
+
//FB::log($this->link_id, "Link updated");
|
357 |
+
} else {
|
358 |
+
//FB::error($wpdb->last_error, "Error updating link {$this->url}");
|
359 |
+
}
|
360 |
+
|
361 |
+
return $rez;
|
362 |
+
}
|
363 |
+
}
|
364 |
+
|
365 |
+
/**
|
366 |
+
* A helper method for converting the link's field values to DB format and escaping them
|
367 |
+
* for use in SQL queries.
|
368 |
+
*
|
369 |
+
* @param array $values
|
370 |
+
* @return array
|
371 |
+
*/
|
372 |
+
function to_db_format($values){
|
373 |
+
global $wpdb;
|
374 |
+
|
375 |
+
$dbvalues = array();
|
376 |
+
|
377 |
+
foreach($values as $name => $value){
|
378 |
+
//Skip fields that don't exist in the blc_links table.
|
379 |
+
if ( !isset($this->field_format[$name]) ){
|
380 |
+
continue;
|
381 |
+
}
|
382 |
+
|
383 |
+
$format = $this->field_format[$name];
|
384 |
+
|
385 |
+
//Convert native values to a format comprehensible to the DB
|
386 |
+
switch($format){
|
387 |
+
|
388 |
+
case 'datetime' :
|
389 |
+
if ( empty($value) ){
|
390 |
+
$value = '0000-00-00 00:00:00';
|
391 |
+
} else {
|
392 |
+
$value = date('Y-m-d H:i:s', $value);
|
393 |
+
}
|
394 |
+
$format = '%s';
|
395 |
+
break;
|
396 |
+
|
397 |
+
case 'bool':
|
398 |
+
if ( $value ){
|
399 |
+
$value = 1;
|
400 |
+
} else {
|
401 |
+
$value = 0;
|
402 |
+
}
|
403 |
+
$format = '%d';
|
404 |
+
break;
|
405 |
+
}
|
406 |
+
|
407 |
+
//Escapize
|
408 |
+
$value = $wpdb->prepare($format, $value);
|
409 |
+
|
410 |
+
$dbvalues[$name] = $value;
|
411 |
+
}
|
412 |
+
|
413 |
+
return $dbvalues;
|
414 |
+
}
|
415 |
+
|
416 |
+
/**
|
417 |
+
* A helper method for converting values fetched from the database to native datatypes.
|
418 |
+
*
|
419 |
+
* @param array $values
|
420 |
+
* @return array
|
421 |
+
*/
|
422 |
+
function to_native_format($values){
|
423 |
+
|
424 |
+
foreach($values as $name => $value){
|
425 |
+
//Don't process ffields that don't exist in the blc_links table.
|
426 |
+
if ( !isset($this->field_format[$name]) ){
|
427 |
+
continue;
|
428 |
+
}
|
429 |
+
|
430 |
+
$format = $this->field_format[$name];
|
431 |
+
|
432 |
+
//Convert values in DB format to native datatypes.
|
433 |
+
switch($format){
|
434 |
+
|
435 |
+
case 'datetime' :
|
436 |
+
if ( $value == '0000-00-00 00:00:00' ){
|
437 |
+
$value = 0;
|
438 |
+
} elseif (is_string($value)) {
|
439 |
+
$value = strtotime($value);
|
440 |
+
}
|
441 |
+
break;
|
442 |
+
|
443 |
+
case 'bool':
|
444 |
+
$value = (bool)$value;
|
445 |
+
break;
|
446 |
+
|
447 |
+
case '%d':
|
448 |
+
$value = intval($value);
|
449 |
+
break;
|
450 |
+
|
451 |
+
case '%f':
|
452 |
+
$value = floatval($value);
|
453 |
+
break;
|
454 |
+
|
455 |
+
}
|
456 |
+
|
457 |
+
$values[$name] = $value;
|
458 |
+
}
|
459 |
+
|
460 |
+
return $values;
|
461 |
+
}
|
462 |
+
|
463 |
+
/**
|
464 |
+
* blcLink::edit()
|
465 |
+
* Edit all instances of the link by changing the URL.
|
466 |
+
*
|
467 |
+
* Here's how this really works : create a new link with the new URL. Then edit()
|
468 |
+
* all instances and point them to the new link record. If some instance can't be
|
469 |
+
* edited they will still point to the old record. The old record is deleted
|
470 |
+
* if all instances were edited successfully.
|
471 |
+
*
|
472 |
+
* @param string $new_url
|
473 |
+
* @return array An associative array with these keys :
|
474 |
+
* new_link_id - the database ID of the new link.
|
475 |
+
* new_link - the new link (an instance of blcLink).
|
476 |
+
* cnt_okay - the number of successfully edited link instances.
|
477 |
+
* cnt_error - the number of instances that caused problems.
|
478 |
+
* errors - an array of WP_Error objects corresponding to the failed edits.
|
479 |
+
*/
|
480 |
+
function edit($new_url){
|
481 |
+
if ( !$this->valid() ){
|
482 |
+
return new WP_Error(
|
483 |
+
'link_invalid',
|
484 |
+
__("Link is not valid", 'broken-link-checker')
|
485 |
+
);
|
486 |
+
}
|
487 |
+
|
488 |
+
//FB::info('Changing link '.$this->link_id .' to URL "'.$new_url.'"');
|
489 |
+
|
490 |
+
$instances = $this->get_instances();
|
491 |
+
//Fail if there are no instances
|
492 |
+
if (empty($instances)) {
|
493 |
+
return array(
|
494 |
+
'new_link_id' => $this->link_id,
|
495 |
+
'new_link' => $this,
|
496 |
+
'cnt_okay' => 0,
|
497 |
+
'cnt_error' => 0,
|
498 |
+
'errors' => array(
|
499 |
+
new WP_Error(
|
500 |
+
'no_instances_found',
|
501 |
+
__('This link can not be edited because it is not used anywhere on this site.', 'broken-link-checker')
|
502 |
+
)
|
503 |
+
)
|
504 |
+
);
|
505 |
+
};
|
506 |
+
|
507 |
+
//Load or create a link with the URL = $new_url
|
508 |
+
$new_link = new blcLink($new_url);
|
509 |
+
$was_new = $new_link->is_new;
|
510 |
+
if ($new_link->is_new) {
|
511 |
+
//FB::log($new_link, 'Saving a new link');
|
512 |
+
$new_link->save(); //so that we get a valid link_id
|
513 |
+
}
|
514 |
+
|
515 |
+
//FB::log("Changing link to $new_url");
|
516 |
+
|
517 |
+
if ( empty($new_link->link_id) ){
|
518 |
+
//FB::error("Failed to create a new link record");
|
519 |
+
return array(
|
520 |
+
'new_link_id' => $this->link_id,
|
521 |
+
'new_link' => $this,
|
522 |
+
'cnt_okay' => 0,
|
523 |
+
'cnt_error' => 0,
|
524 |
+
'errors' => array(
|
525 |
+
new WP_Error(
|
526 |
+
'link_creation_failed',
|
527 |
+
__('Failed to create a DB entry for the new URL.', 'broken-link-checker')
|
528 |
+
)
|
529 |
+
)
|
530 |
+
);;
|
531 |
+
}
|
532 |
+
|
533 |
+
$cnt_okay = $cnt_error = 0;
|
534 |
+
$errors = array();
|
535 |
+
|
536 |
+
//Edit each instance.
|
537 |
+
//FB::info('Editing ' . count($instances) . ' instances');
|
538 |
+
foreach ( $instances as $instance ){
|
539 |
+
$rez = $instance->edit( $new_url, $this->url );
|
540 |
+
if ( is_wp_error($rez) ){
|
541 |
+
$cnt_error++;
|
542 |
+
array_push($errors, $rez);
|
543 |
+
//FB::error($instance, 'Failed to edit instance ' . $instance->instance_id);
|
544 |
+
} else {
|
545 |
+
$cnt_okay++;
|
546 |
+
$instance->link_id = $new_link->link_id;
|
547 |
+
$instance->save();
|
548 |
+
//FB::info($instance, 'Successfully edited instance ' . $instance->instance_id);
|
549 |
+
}
|
550 |
+
}
|
551 |
+
|
552 |
+
//If all instances were edited successfully we can delete the old link record.
|
553 |
+
//UNLESS this link is equal to the new link (which should never happen, but whatever).
|
554 |
+
if ( ( $cnt_error == 0 ) && ( $cnt_okay > 0 ) && ( $this->link_id != $new_link->link_id ) ){
|
555 |
+
$this->forget( false );
|
556 |
+
}
|
557 |
+
|
558 |
+
//On the other hand, if no instances could be edited and the $new_link was really new,
|
559 |
+
//then delete it.
|
560 |
+
if ( ( $cnt_okay == 0 ) && $was_new ){
|
561 |
+
$new_link->forget( false );
|
562 |
+
$new_link = $this;
|
563 |
+
}
|
564 |
+
|
565 |
+
return array(
|
566 |
+
'new_link_id' => $new_link->link_id,
|
567 |
+
'new_link' => $new_link,
|
568 |
+
'cnt_okay' => $cnt_okay,
|
569 |
+
'cnt_error' => $cnt_error,
|
570 |
+
'errors' => $errors,
|
571 |
+
);
|
572 |
+
}
|
573 |
+
|
574 |
+
/**
|
575 |
+
* Edit all of of this link's instances and replace the URL with the URL that it redirects to.
|
576 |
+
* This method does nothing if the link isn't a redirect.
|
577 |
+
*
|
578 |
+
* @see blcLink::edit()
|
579 |
+
*
|
580 |
+
* @return array|WP_Error
|
581 |
+
*/
|
582 |
+
function deredirect(){
|
583 |
+
if ( !$this->valid() ){
|
584 |
+
return new WP_Error(
|
585 |
+
'link_invalid',
|
586 |
+
__("Link is not valid", 'broken-link-checker')
|
587 |
+
);
|
588 |
+
}
|
589 |
+
|
590 |
+
if ( ($this->redirect_count <= 0) || empty($this->final_url) ){
|
591 |
+
return array(
|
592 |
+
'new_link_id' => $this->link_id,
|
593 |
+
'new_link' => $this,
|
594 |
+
'cnt_okay' => 0,
|
595 |
+
'cnt_error' => 0,
|
596 |
+
'errors' => array(
|
597 |
+
new WP_Error(
|
598 |
+
'not_redirect',
|
599 |
+
__("This link is not a redirect", 'broken-link-checker')
|
600 |
+
)
|
601 |
+
),
|
602 |
+
);
|
603 |
+
}
|
604 |
+
|
605 |
+
return $this->edit($this->final_url);
|
606 |
+
}
|
607 |
+
|
608 |
+
/**
|
609 |
+
* Unlink all instances and delete the link record.
|
610 |
+
*
|
611 |
+
* @return array|WP_Error An associative array with these keys :
|
612 |
+
* cnt_okay - the number of successfully removed instances.
|
613 |
+
* cnt_error - the number of instances that couldn't be removed.
|
614 |
+
* link_deleted - true if the link record was deleted.
|
615 |
+
* errors - an array of WP_Error objects describing the errors that were encountered, if any.
|
616 |
+
*/
|
617 |
+
function unlink(){
|
618 |
+
if ( !$this->valid() ){
|
619 |
+
return new WP_Error(
|
620 |
+
'link_invalid',
|
621 |
+
__("Link is not valid", 'broken-link-checker')
|
622 |
+
);
|
623 |
+
}
|
624 |
+
|
625 |
+
//FB::info($this, 'Removing link');
|
626 |
+
$instances = $this->get_instances();
|
627 |
+
|
628 |
+
//No instances? Just remove the link then.
|
629 |
+
if (empty($instances)) {
|
630 |
+
//FB::warn("This link has no instances. Deleting the link.");
|
631 |
+
$rez = $this->forget( false ) !== false;
|
632 |
+
|
633 |
+
if ( $rez ){
|
634 |
+
return array(
|
635 |
+
'cnt_okay' => 1,
|
636 |
+
'cnt_error' => 0,
|
637 |
+
'link_deleted' => true,
|
638 |
+
'errors' => array(),
|
639 |
+
);
|
640 |
+
} else {
|
641 |
+
return array(
|
642 |
+
'cnt_okay' => 0,
|
643 |
+
'cnt_error' => 0,
|
644 |
+
'link_deleted' => false,
|
645 |
+
'errors' => array(
|
646 |
+
new WP_Error(
|
647 |
+
"deletion_failed",
|
648 |
+
__("Couldn't delete the link's database record", 'broken-link-checker')
|
649 |
+
)
|
650 |
+
),
|
651 |
+
);
|
652 |
+
}
|
653 |
+
}
|
654 |
+
|
655 |
+
|
656 |
+
//FB::info('Unlinking ' . count($instances) . ' instances');
|
657 |
+
|
658 |
+
$cnt_okay = $cnt_error = 0;
|
659 |
+
$errors = array();
|
660 |
+
|
661 |
+
//Unlink each instance.
|
662 |
+
foreach ( $instances as $instance ){
|
663 |
+
$rez = $instance->unlink( $this->url );
|
664 |
+
|
665 |
+
if ( is_wp_error($rez) ){
|
666 |
+
$cnt_error++;
|
667 |
+
array_push($errors, $rez);
|
668 |
+
//FB::error( $instance, 'Failed to unlink instance' );
|
669 |
+
} else {
|
670 |
+
$cnt_okay++;
|
671 |
+
//FB::info( $instance, 'Successfully unlinked instance' );
|
672 |
+
}
|
673 |
+
}
|
674 |
+
|
675 |
+
//If all instances were unlinked successfully we can delete the link record.
|
676 |
+
if ( ( $cnt_error == 0 ) && ( $cnt_okay > 0 ) ){
|
677 |
+
//FB::log('Instances removed, deleting the link.');
|
678 |
+
$link_deleted = $this->forget() !== false;
|
679 |
+
|
680 |
+
if ( !$link_deleted ){
|
681 |
+
array_push(
|
682 |
+
$errors,
|
683 |
+
new WP_Error(
|
684 |
+
"deletion_failed",
|
685 |
+
__("Couldn't delete the link's database record", 'broken-link-checker')
|
686 |
+
)
|
687 |
+
);
|
688 |
+
}
|
689 |
+
|
690 |
+
} else {
|
691 |
+
//FB::error("Something went wrong. Unlinked instances : $cnt_okay, errors : $cnt_error");
|
692 |
+
$link_deleted = false;
|
693 |
+
}
|
694 |
+
|
695 |
+
return array(
|
696 |
+
'cnt_okay' => $cnt_okay,
|
697 |
+
'cnt_error' => $cnt_error,
|
698 |
+
'link_deleted' => $link_deleted,
|
699 |
+
'errors' => $errors,
|
700 |
+
);
|
701 |
+
}
|
702 |
+
|
703 |
+
/**
|
704 |
+
* Remove the link and (optionally) its instance records from the DB. Doesn't alter posts/etc.
|
705 |
+
*
|
706 |
+
* @return mixed 1 on success, 0 if link not found, false on error.
|
707 |
+
*/
|
708 |
+
function forget($remove_instances = true){
|
709 |
+
global $wpdb;
|
710 |
+
if ( !$this->valid() ) return false;
|
711 |
+
|
712 |
+
if ( !empty($this->link_id) ){
|
713 |
+
//FB::info($this, 'Deleting link from DB');
|
714 |
+
|
715 |
+
if ( $remove_instances ){
|
716 |
+
//Remove instances, if any
|
717 |
+
$wpdb->query( $wpdb->prepare("DELETE FROM {$wpdb->prefix}blc_instances WHERE link_id=%d", $this->link_id) );
|
718 |
+
}
|
719 |
+
|
720 |
+
//Remove the link itself
|
721 |
+
$rez = $wpdb->query( $wpdb->prepare("DELETE FROM {$wpdb->prefix}blc_links WHERE link_id=%d", $this->link_id) );
|
722 |
+
$this->link_id = 0;
|
723 |
+
|
724 |
+
return $rez;
|
725 |
+
} else {
|
726 |
+
return false;
|
727 |
+
}
|
728 |
+
|
729 |
+
}
|
730 |
+
|
731 |
+
/**
|
732 |
+
* Get a list of the link's instances
|
733 |
+
*
|
734 |
+
* @param bool $ignore_cache Don't use the internally cached instance list.
|
735 |
+
* @param string $purpose
|
736 |
+
* @return array An array of instance objects or FALSE on failure.
|
737 |
+
*/
|
738 |
+
function get_instances( $ignore_cache = false, $purpose = '' ){
|
739 |
+
global $wpdb;
|
740 |
+
if ( !$this->valid() || empty($this->link_id) ) return false;
|
741 |
+
|
742 |
+
if ( $ignore_cache || is_null($this->_instances) ){
|
743 |
+
$instances = blc_get_instances( array($this->link_id), $purpose );
|
744 |
+
if ( !empty($instances) ){
|
745 |
+
$this->_instances = $instances[$this->link_id];
|
746 |
+
}
|
747 |
+
}
|
748 |
+
|
749 |
+
return $this->_instances;
|
750 |
+
}
|
751 |
+
}
|
752 |
+
|
753 |
+
} //class_exists
|
754 |
+
|
755 |
+
class blcLinkQuery {
|
756 |
+
|
757 |
+
var $native_filters;
|
758 |
+
var $search_filter;
|
759 |
+
var $custom_filters = array();
|
760 |
+
|
761 |
+
var $valid_url_params = array();
|
762 |
+
|
763 |
+
function __construct(){
|
764 |
+
//Init. the available native filters.
|
765 |
+
$this->native_filters = array(
|
766 |
+
'broken' => array(
|
767 |
+
'params' => array(
|
768 |
+
'where_expr' => '( broken = 1 )',
|
769 |
+
),
|
770 |
+
'name' => __('Broken', 'broken-link-checker'),
|
771 |
+
'heading' => __('Broken Links', 'broken-link-checker'),
|
772 |
+
'heading_zero' => __('No broken links found', 'broken-link-checker'),
|
773 |
+
'native' => true,
|
774 |
+
),
|
775 |
+
'redirects' => array(
|
776 |
+
'params' => array(
|
777 |
+
'where_expr' => '( redirect_count > 0 )',
|
778 |
+
),
|
779 |
+
'name' => __('Redirects', 'broken-link-checker'),
|
780 |
+
'heading' => __('Redirected Links', 'broken-link-checker'),
|
781 |
+
'heading_zero' => __('No redirects found', 'broken-link-checker'),
|
782 |
+
'native' => true,
|
783 |
+
),
|
784 |
+
|
785 |
+
'all' => array(
|
786 |
+
'params' => array(
|
787 |
+
'where_expr' => '1',
|
788 |
+
),
|
789 |
+
'name' => __('All', 'broken-link-checker'),
|
790 |
+
'heading' => __('Detected Links', 'broken-link-checker'),
|
791 |
+
'heading_zero' => __('No links found (yet)', 'broken-link-checker'),
|
792 |
+
'native' => true,
|
793 |
+
),
|
794 |
+
);
|
795 |
+
|
796 |
+
//Create the special "search" filter
|
797 |
+
$this->search_filter = array(
|
798 |
+
'name' => __('Search', 'broken-link-checker'),
|
799 |
+
'heading' => __('Search Results', 'broken-link-checker'),
|
800 |
+
'heading_zero' => __('No links found for your query', 'broken-link-checker'),
|
801 |
+
'params' => array(),
|
802 |
+
'use_url_params' => true,
|
803 |
+
'hidden' => true,
|
804 |
+
);
|
805 |
+
|
806 |
+
//These search arguments may be passed via the URL if the filter's 'use_url_params' field is set to True.
|
807 |
+
//They map to the fields of the search form on the Tools -> Broken Links page. Only these arguments
|
808 |
+
//can be used in user-defined filters.
|
809 |
+
$this->valid_url_params = array(
|
810 |
+
's_link_text',
|
811 |
+
's_link_url',
|
812 |
+
's_parser_type',
|
813 |
+
's_container_type',
|
814 |
+
's_link_type',
|
815 |
+
's_http_code',
|
816 |
+
's_filter',
|
817 |
+
);
|
818 |
+
}
|
819 |
+
|
820 |
+
function blcLinkQuery(){
|
821 |
+
$this->__construct();
|
822 |
+
}
|
823 |
+
|
824 |
+
/**
|
825 |
+
* Load and return the list of user-defined link filters.
|
826 |
+
*
|
827 |
+
* @return array An array of custom filter definitions. If there are no custom filters defined returns an empty array.
|
828 |
+
*/
|
829 |
+
function load_custom_filters(){
|
830 |
+
global $wpdb;
|
831 |
+
|
832 |
+
$filter_data = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}blc_filters ORDER BY name ASC", ARRAY_A);
|
833 |
+
$filters = array();
|
834 |
+
|
835 |
+
if ( !empty($filter_data) ) {
|
836 |
+
foreach($filter_data as $data){
|
837 |
+
wp_parse_str($data['params'], $params);
|
838 |
+
|
839 |
+
$filters[ 'f'.$data['id'] ] = array(
|
840 |
+
'name' => $data['name'],
|
841 |
+
'params' => $params,
|
842 |
+
'heading' => ucwords($data['name']),
|
843 |
+
'heading_zero' => __('No links found for your query', 'broken-link-checker'),
|
844 |
+
'custom' => true,
|
845 |
+
);
|
846 |
+
}
|
847 |
+
}
|
848 |
+
|
849 |
+
$this->custom_filters = $filters;
|
850 |
+
|
851 |
+
return $filters;
|
852 |
+
}
|
853 |
+
|
854 |
+
/**
|
855 |
+
* Add a custom link filter.
|
856 |
+
*
|
857 |
+
* @param string $name Filter name.
|
858 |
+
* @param string|array $params Filter params. Either as a query string, or an array.
|
859 |
+
* @return string|bool The ID of the newly added filter, or False.
|
860 |
+
*/
|
861 |
+
function create_custom_filter($name, $params){
|
862 |
+
global $wpdb;
|
863 |
+
|
864 |
+
if ( is_array($params) ){
|
865 |
+
$params = http_build_query($params, null, '&');
|
866 |
+
}
|
867 |
+
|
868 |
+
//Save the new filter
|
869 |
+
$q = $wpdb->prepare(
|
870 |
+
"INSERT INTO {$wpdb->prefix}blc_filters(name, params) VALUES (%s, %s)",
|
871 |
+
$name, $params
|
872 |
+
);
|
873 |
+
|
874 |
+
if ( $wpdb->query($q) !== false ){
|
875 |
+
$filter_id = 'f'.$wpdb->insert_id;
|
876 |
+
return $filter_id;
|
877 |
+
} else {
|
878 |
+
return false;
|
879 |
+
}
|
880 |
+
}
|
881 |
+
|
882 |
+
/**
|
883 |
+
* Delete a custom filter
|
884 |
+
*
|
885 |
+
* @param string $filter_id
|
886 |
+
* @return bool True on success, False if a database error occured.
|
887 |
+
*/
|
888 |
+
function delete_custom_filter($filter_id){
|
889 |
+
global $wpdb;
|
890 |
+
|
891 |
+
//Remove the "f" character from the filter ID to get its database key
|
892 |
+
$filter_id = intval(ltrim($_POST['filter_id'], 'f'));
|
893 |
+
|
894 |
+
//Try to delete the filter
|
895 |
+
$q = $wpdb->prepare("DELETE FROM {$wpdb->prefix}blc_filters WHERE id = %d", $filter_id);
|
896 |
+
if ( $wpdb->query($q) !== false ){
|
897 |
+
return true;
|
898 |
+
} else {
|
899 |
+
return false;
|
900 |
+
}
|
901 |
+
}
|
902 |
+
|
903 |
+
function get_filters(){
|
904 |
+
$filters = array_merge($this->native_filters, $this->custom_filters);
|
905 |
+
$filters['search'] = $this->search_filter;
|
906 |
+
return $filters;
|
907 |
+
}
|
908 |
+
|
909 |
+
/**
|
910 |
+
* Get a link search filter by filter ID.
|
911 |
+
*
|
912 |
+
* @param string $filter_id
|
913 |
+
* @return array|null
|
914 |
+
*/
|
915 |
+
function get_filter($filter_id){
|
916 |
+
$filters = $this->get_filters();
|
917 |
+
if ( isset($filters[$filter_id]) ){
|
918 |
+
return $filters[$filter_id];
|
919 |
+
} else {
|
920 |
+
return null;
|
921 |
+
}
|
922 |
+
}
|
923 |
+
|
924 |
+
/**
|
925 |
+
* Get link search parameters from the specified filter.
|
926 |
+
*
|
927 |
+
* @param array $filter
|
928 |
+
* @return array An array of parameters suitable for use with blcLinkQuery::get_links()
|
929 |
+
*/
|
930 |
+
function get_search_params( $filter = null ){
|
931 |
+
//If present, the filter's parameters may be saved either as an array or a string.
|
932 |
+
$params = array();
|
933 |
+
if ( !empty($filter) && !empty($filter['params']) ){
|
934 |
+
$params = $filter['params'];
|
935 |
+
if ( is_string( $params ) ){
|
936 |
+
wp_parse_str($params, $params);
|
937 |
+
}
|
938 |
+
}
|
939 |
+
|
940 |
+
//Merge in the parameters from the current request, if required
|
941 |
+
if ( isset($filter['use_url_params']) && $filter['use_url_params'] ){
|
942 |
+
$params = array_merge($params, $this->get_url_search_params());
|
943 |
+
}
|
944 |
+
|
945 |
+
return $params;
|
946 |
+
}
|
947 |
+
|
948 |
+
/**
|
949 |
+
* Extract search query parameters from the current URL
|
950 |
+
*
|
951 |
+
* @return array
|
952 |
+
*/
|
953 |
+
function get_url_search_params(){
|
954 |
+
$url_params = array();
|
955 |
+
foreach ($_GET as $param => $value){
|
956 |
+
if ( in_array($param, $this->valid_url_params) ){
|
957 |
+
$url_params[$param] = $value;
|
958 |
+
}
|
959 |
+
}
|
960 |
+
return $url_params;
|
961 |
+
}
|
962 |
+
|
963 |
+
|
964 |
+
|
965 |
+
/**
|
966 |
+
* A helper method for parsing a list of search criteria and generating the parts of the SQL query.
|
967 |
+
*
|
968 |
+
* @see blcLinkQuery::get_links()
|
969 |
+
*
|
970 |
+
* @param array $params An array of search criteria.
|
971 |
+
* @return array 'where_exprs' - an array of search expressions, 'join_instances' - whether joining the instance table is required.
|
972 |
+
*/
|
973 |
+
function compile_search_params($params){
|
974 |
+
global $wpdb;
|
975 |
+
|
976 |
+
//Track whether we'll need to left-join the instance table to run the query.
|
977 |
+
$join_instances = false;
|
978 |
+
|
979 |
+
//Generate the individual clauses of the WHERE expression and store them in an array.
|
980 |
+
$pieces = array();
|
981 |
+
|
982 |
+
//A part of the WHERE expression can be specified explicitly
|
983 |
+
if ( !empty($params['where_expr']) ){
|
984 |
+
$pieces[] = $params['where_expr'];
|
985 |
+
$join_instances = $join_instances || ( stripos($params['where_expr'], 'instances') !== false );
|
986 |
+
}
|
987 |
+
|
988 |
+
//List of allowed link ids (either an array or comma-separated)
|
989 |
+
if ( !empty($params['link_ids']) ){
|
990 |
+
$link_ids = $params['link_ids'];
|
991 |
+
|
992 |
+
if ( is_string($link_ids) ){
|
993 |
+
$link_ids = preg_split('/[,\s]+/', $link_ids);
|
994 |
+
}
|
995 |
+
|
996 |
+
//Only accept non-zero integers
|
997 |
+
$sanitized_link_ids = array();
|
998 |
+
foreach($link_ids as $id){
|
999 |
+
$id = intval($id);
|
1000 |
+
if ( $id != 0 ){
|
1001 |
+
$sanitized_link_ids[] = $id;
|
1002 |
+
}
|
1003 |
+
}
|
1004 |
+
|
1005 |
+
$pieces[] = 'link_id IN (' . implode(', ', $sanitized_link_ids) . ')';
|
1006 |
+
}
|
1007 |
+
|
1008 |
+
//Anchor text - use LIKE search
|
1009 |
+
if ( !empty($params['s_link_text']) ){
|
1010 |
+
$s_link_text = like_escape($wpdb->escape($params['s_link_text']));
|
1011 |
+
$s_link_text = str_replace('*', '%', $s_link_text);
|
1012 |
+
|
1013 |
+
$pieces[] = '(instances.link_text LIKE "%' . $s_link_text . '%")';
|
1014 |
+
$join_instances = true;
|
1015 |
+
}
|
1016 |
+
|
1017 |
+
//URL - try to match both the initial URL and the final URL.
|
1018 |
+
//There is limited wildcard support, e.g. "google.*/search" will match both
|
1019 |
+
//"google.com/search" and "google.lv/search"
|
1020 |
+
if ( !empty($params['s_link_url']) ){
|
1021 |
+
$s_link_url = like_escape($wpdb->escape($params['s_link_url']));
|
1022 |
+
$s_link_url = str_replace('*', '%', $s_link_url);
|
1023 |
+
|
1024 |
+
$pieces[] = '(links.url LIKE "%'. $s_link_url .'%") OR '.
|
1025 |
+
'(links.final_url LIKE "%'. $s_link_url .'%")';
|
1026 |
+
}
|
1027 |
+
|
1028 |
+
//Parser type should match the parser_type column in the instance table.
|
1029 |
+
if ( !empty($params['s_parser_type']) ){
|
1030 |
+
$s_parser_type = $wpdb->escape($params['s_parser_type']);
|
1031 |
+
$pieces[] = "instances.parser_type = '$s_parser_type'";
|
1032 |
+
$join_instances = true;
|
1033 |
+
}
|
1034 |
+
|
1035 |
+
//Container type should match the container_type column in the instance table.
|
1036 |
+
if ( !empty($params['s_container_type']) ){
|
1037 |
+
$s_container_type = $wpdb->escape($params['s_container_type']);
|
1038 |
+
$pieces[] = "instances.container_type = '$s_container_type'";
|
1039 |
+
$join_instances = true;
|
1040 |
+
}
|
1041 |
+
|
1042 |
+
//Container ID should match... you guessed it - container_id
|
1043 |
+
if ( !empty($params['s_container_id']) ){
|
1044 |
+
$s_container_id = intval($params['s_container_id']);
|
1045 |
+
if ( $s_container_id != 0 ){
|
1046 |
+
$pieces[] = "instances.container_id = $s_container_id";
|
1047 |
+
$join_instances = true;
|
1048 |
+
}
|
1049 |
+
}
|
1050 |
+
|
1051 |
+
//Link type can match either the the parser_type or the container_type.
|
1052 |
+
if ( !empty($params['s_link_type']) ){
|
1053 |
+
$s_link_type = $wpdb->escape($params['s_link_type']);
|
1054 |
+
$pieces[] = "instances.parser_type = '$s_link_type' OR instances.container_type='$s_link_type'";
|
1055 |
+
$join_instances = true;
|
1056 |
+
}
|
1057 |
+
|
1058 |
+
//HTTP code - the user can provide a list of HTTP response codes and code ranges.
|
1059 |
+
//Example : 201,400-410,500
|
1060 |
+
if ( !empty($params['s_http_code']) ){
|
1061 |
+
//Strip spaces.
|
1062 |
+
$params['s_http_code'] = str_replace(' ', '', $params['s_http_code']);
|
1063 |
+
//Split by comma
|
1064 |
+
$codes = explode(',', $params['s_http_code']);
|
1065 |
+
|
1066 |
+
$individual_codes = array();
|
1067 |
+
$ranges = array();
|
1068 |
+
|
1069 |
+
//Try to parse each response code or range. Invalid ones are simply ignored.
|
1070 |
+
foreach($codes as $code){
|
1071 |
+
if ( is_numeric($code) ){
|
1072 |
+
//It's a single number
|
1073 |
+
$individual_codes[] = abs(intval($code));
|
1074 |
+
} elseif ( strpos($code, '-') !== false ) {
|
1075 |
+
//Try to parse it as a range
|
1076 |
+
$range = explode( '-', $code, 2 );
|
1077 |
+
if ( (count($range) == 2) && is_numeric($range[0]) && is_numeric($range[0]) ){
|
1078 |
+
//Make sure the smaller code comes first
|
1079 |
+
$range = array( intval($range[0]), intval($range[1]) );
|
1080 |
+
$ranges[] = array( min($range), max($range) );
|
1081 |
+
}
|
1082 |
+
}
|
1083 |
+
}
|
1084 |
+
|
1085 |
+
$piece = array();
|
1086 |
+
|
1087 |
+
//All individual response codes get one "http_code IN (...)" clause
|
1088 |
+
if ( !empty($individual_codes) ){
|
1089 |
+
$piece[] = '(links.http_code IN ('. implode(', ', $individual_codes) .'))';
|
1090 |
+
}
|
1091 |
+
|
1092 |
+
//Ranges get a "http_code BETWEEN min AND max" clause each
|
1093 |
+
if ( !empty($ranges) ){
|
1094 |
+
$range_strings = array();
|
1095 |
+
foreach($ranges as $range){
|
1096 |
+
$range_strings[] = "(links.http_code BETWEEN $range[0] AND $range[1])";
|
1097 |
+
}
|
1098 |
+
$piece[] = '( ' . implode(' OR ', $range_strings) . ' )';
|
1099 |
+
}
|
1100 |
+
|
1101 |
+
//Finally, generate a composite WHERE clause for both types of response code queries
|
1102 |
+
if ( !empty($piece) ){
|
1103 |
+
$pieces[] = implode(' OR ', $piece);
|
1104 |
+
}
|
1105 |
+
|
1106 |
+
}
|
1107 |
+
|
1108 |
+
//Custom filters can optionally call one of the native filters
|
1109 |
+
//to narrow down the result set.
|
1110 |
+
if ( !empty($params['s_filter']) && isset($this->native_filters[$params['s_filter']]) ){
|
1111 |
+
$the_filter = $this->native_filters[$params['s_filter']];
|
1112 |
+
$extra_criteria = $this->compile_search_params($the_filter['params']);
|
1113 |
+
|
1114 |
+
$pieces = array_merge($pieces, $extra_criteria['where_exprs']);
|
1115 |
+
$join_instances = $join_instances || $extra_criteria['join_instances'];
|
1116 |
+
}
|
1117 |
+
|
1118 |
+
return array(
|
1119 |
+
'where_exprs' => $pieces,
|
1120 |
+
'join_instances' => $join_instances,
|
1121 |
+
);
|
1122 |
+
}
|
1123 |
+
|
1124 |
+
/**
|
1125 |
+
* blcLinkQuery::get_links()
|
1126 |
+
*
|
1127 |
+
* @see blc_get_links()
|
1128 |
+
*
|
1129 |
+
* @param array $params
|
1130 |
+
* @param string $purpose
|
1131 |
+
* @return array|int
|
1132 |
+
*/
|
1133 |
+
function get_links($params = null){
|
1134 |
+
global $wpdb;
|
1135 |
+
|
1136 |
+
if( !is_array($params) ){
|
1137 |
+
$params = array();
|
1138 |
+
}
|
1139 |
+
|
1140 |
+
$defaults = array(
|
1141 |
+
'offset' => 0,
|
1142 |
+
'max_results' => 0,
|
1143 |
+
'load_instances' => false,
|
1144 |
+
'load_containers' => false,
|
1145 |
+
'load_wrapped_objects' => false,
|
1146 |
+
'count_only' => false,
|
1147 |
+
'purpose' => '',
|
1148 |
+
);
|
1149 |
+
|
1150 |
+
$params = array_merge($defaults, $params);
|
1151 |
+
|
1152 |
+
//Compile the search-related params into search expressions usable in a WHERE clause
|
1153 |
+
$criteria = $this->compile_search_params($params);
|
1154 |
+
|
1155 |
+
//Build the WHERE clause
|
1156 |
+
if ( !empty($criteria['where_exprs']) ){
|
1157 |
+
$where_expr = "\t( " . implode(" ) AND\n\t( ", $criteria['where_exprs']) . ' ) ';
|
1158 |
+
} else {
|
1159 |
+
$where_expr = '1';
|
1160 |
+
}
|
1161 |
+
|
1162 |
+
//Join the blc_instances table if it's required to perform the search.
|
1163 |
+
$joins = "";
|
1164 |
+
if ( $criteria['join_instances'] ){
|
1165 |
+
$joins = "JOIN {$wpdb->prefix}blc_instances AS instances ON links.link_id = instances.link_id";
|
1166 |
+
}
|
1167 |
+
|
1168 |
+
if ( $params['count_only'] ){
|
1169 |
+
//Only get the number of matching links.
|
1170 |
+
$q = "
|
1171 |
+
SELECT COUNT(*)
|
1172 |
+
FROM (
|
1173 |
+
SELECT 0
|
1174 |
+
|
1175 |
+
FROM
|
1176 |
+
{$wpdb->prefix}blc_links AS links
|
1177 |
+
$joins
|
1178 |
+
|
1179 |
+
WHERE
|
1180 |
+
$where_expr
|
1181 |
+
|
1182 |
+
GROUP BY links.link_id) AS foo";
|
1183 |
+
|
1184 |
+
return $wpdb->get_var($q);
|
1185 |
+
}
|
1186 |
+
|
1187 |
+
//Select the required links.
|
1188 |
+
$q = "SELECT
|
1189 |
+
links.*
|
1190 |
+
|
1191 |
+
FROM
|
1192 |
+
{$wpdb->prefix}blc_links AS links
|
1193 |
+
$joins
|
1194 |
+
|
1195 |
+
WHERE
|
1196 |
+
$where_expr
|
1197 |
+
|
1198 |
+
GROUP BY links.link_id";
|
1199 |
+
|
1200 |
+
//Add the LIMIT clause
|
1201 |
+
if ( $params['max_results'] || $params['offset'] ){
|
1202 |
+
$q .= sprintf("\nLIMIT %d, %d", $params['offset'], $params['max_results']);
|
1203 |
+
}
|
1204 |
+
|
1205 |
+
$results = $wpdb->get_results($q, ARRAY_A);
|
1206 |
+
if ( empty($results) ){
|
1207 |
+
return array();
|
1208 |
+
}
|
1209 |
+
|
1210 |
+
//Create the link objects
|
1211 |
+
$links = array();
|
1212 |
+
|
1213 |
+
foreach($results as $result){
|
1214 |
+
$link = new blcLink($result);
|
1215 |
+
$links[$link->link_id] = $link;
|
1216 |
+
}
|
1217 |
+
|
1218 |
+
$purpose = $params['purpose'];
|
1219 |
+
/*
|
1220 |
+
Preload instances if :
|
1221 |
+
* It has been requested via the 'load_instances' argument.
|
1222 |
+
* The links are going to be displayed or edited, which involves instances.
|
1223 |
+
*/
|
1224 |
+
$load_instances = $params['load_instances'] || in_array($purpose, array(BLC_FOR_DISPLAY, BLC_FOR_EDITING));
|
1225 |
+
|
1226 |
+
if ( $load_instances ){
|
1227 |
+
$link_ids = array_keys($links);
|
1228 |
+
$all_instances = blc_get_instances($link_ids, $purpose, $params['load_containers'], $params['load_wrapped_objects']);
|
1229 |
+
//Assign each batch of instances to the right link
|
1230 |
+
foreach($all_instances as $link_id => $instances){
|
1231 |
+
$links[$link_id]->_instances = $instances;
|
1232 |
+
}
|
1233 |
+
}
|
1234 |
+
|
1235 |
+
return $links;
|
1236 |
+
}
|
1237 |
+
|
1238 |
+
/**
|
1239 |
+
* Calculate the number of results for all known filters
|
1240 |
+
*
|
1241 |
+
* @return void
|
1242 |
+
*/
|
1243 |
+
function count_filter_results(){
|
1244 |
+
foreach($this->native_filters as $filter_id => $filter){
|
1245 |
+
$this->native_filters[$filter_id]['count'] = $this->get_filter_links(
|
1246 |
+
$filter, array('count_only' => true)
|
1247 |
+
);
|
1248 |
+
}
|
1249 |
+
|
1250 |
+
foreach($this->custom_filters as $filter_id => $filter){
|
1251 |
+
$this->custom_filters[$filter_id]['count'] = $this->get_filter_links(
|
1252 |
+
$filter, array('count_only' => true)
|
1253 |
+
);
|
1254 |
+
}
|
1255 |
+
|
1256 |
+
$this->search_filter['count'] = $this->get_filter_links($this->search_filter, array('count_only' => true));
|
1257 |
+
}
|
1258 |
+
|
1259 |
+
/**
|
1260 |
+
* Retrieve a list of links matching a filter.
|
1261 |
+
*
|
1262 |
+
* @uses blcLinkQuery::get_links()
|
1263 |
+
*
|
1264 |
+
* @param string|array $filter Either a filter ID or an array containing filter data.
|
1265 |
+
* @param array $extra_params Optional extra criteria that will override those set by the filter. See blc_get_links() for details.
|
1266 |
+
* @return array|int Either an array of blcLink objects, or an integer indicating the number of links that match the filter.
|
1267 |
+
*/
|
1268 |
+
function get_filter_links($filter, $extra_params = null){
|
1269 |
+
if ( is_string($filter) ){
|
1270 |
+
$filter = $this->get_filter($filter);
|
1271 |
+
}
|
1272 |
+
|
1273 |
+
$params = $this->get_search_params($filter);
|
1274 |
+
|
1275 |
+
|
1276 |
+
if ( !empty($extra_params) ){
|
1277 |
+
$params = array_merge($params, $extra_params);
|
1278 |
+
}
|
1279 |
+
|
1280 |
+
return $this->get_links($params);
|
1281 |
+
}
|
1282 |
+
}
|
1283 |
+
|
1284 |
+
$GLOBALS['blc_link_query'] = new blcLinkQuery();
|
1285 |
+
|
1286 |
+
/**
|
1287 |
+
* Retrieve a list of links matching some criteria.
|
1288 |
+
*
|
1289 |
+
* The function argument should be an associative array describing the criteria.
|
1290 |
+
* The supported keys are :
|
1291 |
+
* 'offset' - Skip the first X results. Default is 0.
|
1292 |
+
* 'max_results' - The maximum number of links to return. Defaults to returning all results.
|
1293 |
+
* 'link_ids' - Retrieve only links with these IDs. This should either be a comma-separated list or an array.
|
1294 |
+
* 's_link_text' - Link text must match this keyphrase (performs a fulltext search).
|
1295 |
+
* 's_link_url' - Link URL must contain this string. You can use "*" as a wildcard.
|
1296 |
+
* 's_parser_type' - Filter links by the type of link parser that was used to find them.
|
1297 |
+
* 's_container_type' - Filter links by where they were found, e.g. 'post'.
|
1298 |
+
* 's_container_id' - Find links that belong to a container with this ID (should be used together with s_container_type).
|
1299 |
+
* 's_link_type' - Either parser type or container type must match this.
|
1300 |
+
* 's_http_code' - Filter by HTTP code. Example : 201,400-410,500
|
1301 |
+
* 's_filter' - Use a built-in filter. Available filters : 'broken', 'redirects', 'all'
|
1302 |
+
* 'where_expr' - Advanced. Lets you directly specify a part of the WHERE clause.
|
1303 |
+
* 'load_instances' - Pre-load all link instance data for each link. Default is false.
|
1304 |
+
* 'load_containers' - Pre-load container data for each instance. Default is false.
|
1305 |
+
* 'load_wrapped_objects' - Pre-load wrapped object data (e.g. posts, comments, etc) for each container. Default is false.
|
1306 |
+
* 'count_only' - Only return the number of results (int), not the whole result set. 'offset' and 'max_results' will be ignored if this is set. Default is false.
|
1307 |
+
* 'purpose' - An optional code indicating how the links will be used.
|
1308 |
+
*
|
1309 |
+
* All keys are optional.
|
1310 |
+
*
|
1311 |
+
* @uses blcLinkQuery::get_links();
|
1312 |
+
*
|
1313 |
+
* @param array $params
|
1314 |
+
* @return int|array Either an array of blcLink objects, or the number of results for the query.
|
1315 |
+
*/
|
1316 |
+
function blc_get_links($params = null){
|
1317 |
+
global $blc_link_query;
|
1318 |
+
return $blc_link_query->get_links($params, $purpose);
|
1319 |
+
}
|
1320 |
+
|
1321 |
+
/**
|
1322 |
+
* Remove orphaned links that have no corresponding instances.
|
1323 |
+
*
|
1324 |
+
* @param int|array $link_id (optional) Only check these links
|
1325 |
+
* @return bool
|
1326 |
+
*/
|
1327 |
+
function blc_cleanup_links( $link_id = null ){
|
1328 |
+
global $wpdb;
|
1329 |
+
|
1330 |
+
$q = "DELETE FROM {$wpdb->prefix}blc_links
|
1331 |
+
USING {$wpdb->prefix}blc_links LEFT JOIN {$wpdb->prefix}blc_instances
|
1332 |
+
ON {$wpdb->prefix}blc_instances.link_id = {$wpdb->prefix}blc_links.link_id
|
1333 |
+
WHERE
|
1334 |
+
{$wpdb->prefix}blc_instances.link_id IS NULL";
|
1335 |
+
|
1336 |
+
if ( $link_id !== null ) {
|
1337 |
+
if ( !is_array($link_id) ){
|
1338 |
+
$link_id = array( intval($link_id) );
|
1339 |
+
}
|
1340 |
+
$q .= " AND {$wpdb->prefix}blc_links.link_id IN (" . implode(', ', $link_id) . ')';
|
1341 |
+
}
|
1342 |
+
|
1343 |
+
return $wpdb->query( $q ) !== false;
|
1344 |
+
}
|
1345 |
+
|
1346 |
+
?>
|
includes/parsers.php
ADDED
@@ -0,0 +1,356 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Parser Registry class for managing parsers.
|
5 |
+
*
|
6 |
+
* @see blcParser
|
7 |
+
*
|
8 |
+
* @package Broken Link Checker
|
9 |
+
* @access public
|
10 |
+
*/
|
11 |
+
class blcParserRegistry {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @access protected
|
15 |
+
*/
|
16 |
+
var $registered_parsers = array();
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Register a new link parser.
|
20 |
+
*
|
21 |
+
* @param string $parser_type A unique string identifying the parser.
|
22 |
+
* @param string $class_name Name of the class implementing the parser.
|
23 |
+
* @return bool True on success, false if this parser type is already registered.
|
24 |
+
*/
|
25 |
+
function register_parser( $parser_type, $class_name ){
|
26 |
+
if ( isset($this->registered_parsers[$parser_type]) ){
|
27 |
+
return false;
|
28 |
+
}
|
29 |
+
|
30 |
+
$parser = new $class_name($parser_type);
|
31 |
+
$this->registered_parsers[$parser_type] = $parser;
|
32 |
+
|
33 |
+
return true;
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Get the parser matching a parser type ID.
|
38 |
+
*
|
39 |
+
* @param string $parser_type
|
40 |
+
* @return blcParser|null
|
41 |
+
*/
|
42 |
+
function get_parser( $parser_type ){
|
43 |
+
if ( isset($this->registered_parsers[$parser_type]) ){
|
44 |
+
return $this->registered_parsers[$parser_type];
|
45 |
+
} else {
|
46 |
+
return null;
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Get all parsers that support either the specified format or the container type.
|
52 |
+
* If a parser supports both, it will still be included only once.
|
53 |
+
*
|
54 |
+
* @param string $format
|
55 |
+
* @param string $container_type
|
56 |
+
* @return array of blcParser
|
57 |
+
*/
|
58 |
+
function get_parsers( $format, $container_type ){
|
59 |
+
$found = array();
|
60 |
+
|
61 |
+
foreach($this->registered_parsers as $parser){
|
62 |
+
if ( in_array($format, $parser->supported_formats) || in_array($container_type, $parser->supported_containers) ){
|
63 |
+
array_push($found, $parser);
|
64 |
+
}
|
65 |
+
}
|
66 |
+
|
67 |
+
return $found;
|
68 |
+
}
|
69 |
+
|
70 |
+
}
|
71 |
+
|
72 |
+
//Create the parser registry singleton.
|
73 |
+
$GLOBALS['blc_parser_registry'] = new blcParserRegistry();
|
74 |
+
|
75 |
+
|
76 |
+
/**
|
77 |
+
* A base class for parsers.
|
78 |
+
*
|
79 |
+
* In the context of this plugin, a "parser" is a class that knows how to extract or modfify
|
80 |
+
* a specific type of links from a given piece of text. For example, there could be a "HTML Link"
|
81 |
+
* parser that knows how to find and modify standard HTML links such as this one :
|
82 |
+
* <a href="http://example.com/">Example</a>
|
83 |
+
*
|
84 |
+
* Other parsers could extract plaintext URLs or handle metadata fields.
|
85 |
+
*
|
86 |
+
* Each parser has a list of supported formats (e.g. "html", "plaintext", etc) and container types
|
87 |
+
* (e.g. "post", "comment", "blogroll", etc). When something needs to be parsed, the involved
|
88 |
+
* container class will look up the parsers that support the relevant format or the container's type,
|
89 |
+
* and apply them to the to-be-parsed string.
|
90 |
+
*
|
91 |
+
* All sub-classes of blcParser should override at least the blcParser::parse() method.
|
92 |
+
*
|
93 |
+
* @see blcContainer::$fields
|
94 |
+
*
|
95 |
+
* @package Broken Link Checker
|
96 |
+
* @access public
|
97 |
+
*/
|
98 |
+
class blcParser {
|
99 |
+
|
100 |
+
var $parser_type;
|
101 |
+
var $supported_formats = array();
|
102 |
+
var $supported_containers = array();
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Class construtor.
|
106 |
+
*
|
107 |
+
* @param string $parser_type
|
108 |
+
* @return void
|
109 |
+
*/
|
110 |
+
function __construct( $parser_type ){
|
111 |
+
$this->parser_type = $parser_type;
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* PHP4 constructor
|
116 |
+
*
|
117 |
+
* @param string $parser_type
|
118 |
+
* @return void
|
119 |
+
*/
|
120 |
+
function blcParser( $parser_type ){
|
121 |
+
$this->__construct( $parser_type );
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* Parse a string for links.
|
126 |
+
*
|
127 |
+
* @param string $content The text to parse.
|
128 |
+
* @param string $base_url The base URL to use for normalizing relative URLs. If ommitted, the blog's root URL will be used.
|
129 |
+
* @param string $default_link_text
|
130 |
+
* @return array An array of new blcLinkInstance objects. The objects will include info about the links found, but not about the corresponding container entity.
|
131 |
+
*/
|
132 |
+
function parse($content, $base_url = '', $default_link_text = ''){
|
133 |
+
return array();
|
134 |
+
}
|
135 |
+
|
136 |
+
/**
|
137 |
+
* Change all links that have a certain URL to a new URL.
|
138 |
+
*
|
139 |
+
* @param string $content Look for links in this string.
|
140 |
+
* @param string $new_url Change the links to this URL.
|
141 |
+
* @param string $old_url The URL to look for.
|
142 |
+
* @param string $old_raw_url The raw, not-normalized URL of the links to look for. Optional.
|
143 |
+
*
|
144 |
+
* @return array|WP_Error If successful, the return value will be an associative array with two
|
145 |
+
* keys : 'content' - the modified content, and 'raw_url' - the new raw, non-normalized URL used
|
146 |
+
* for the modified links. In most cases, the returned raw_url will be equal to the new_url.
|
147 |
+
*/
|
148 |
+
function edit($content, $new_url, $old_url, $old_raw_url){
|
149 |
+
return new WP_Error(
|
150 |
+
'not_implemented',
|
151 |
+
sprintf(__("Editing is not implemented in the '%s' parser", 'broken-link-checker'), $this->parser_type)
|
152 |
+
);
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Remove all links that have a certain URL, leaving anchor text intact.
|
157 |
+
*
|
158 |
+
* @param string $content Look for links in this string.
|
159 |
+
* @param string $url The URL to look for.
|
160 |
+
* @param string $raw_url The raw, non-normalized version of the URL to look for. Optional.
|
161 |
+
* @return string Input string with all matching links removed.
|
162 |
+
*/
|
163 |
+
function unlink($content, $url, $raw_url){
|
164 |
+
return new WP_Error(
|
165 |
+
'not_implemented',
|
166 |
+
sprintf(__("Unlinking is not implemented in the '%s' parser", 'broken-link-checker'), $this->parser_type)
|
167 |
+
);
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Get the link text for printing in the "Broken Links" table.
|
172 |
+
* Sub-classes should override this method and display the link text in a way appropriate for the link type.
|
173 |
+
*
|
174 |
+
* @param blcLinkInstance $instance
|
175 |
+
* @return string HTML
|
176 |
+
*/
|
177 |
+
function ui_get_link_text($instance, $context = 'display'){
|
178 |
+
return $instance->link_text;
|
179 |
+
}
|
180 |
+
|
181 |
+
/**
|
182 |
+
* Turn a relative URL into an absolute one.
|
183 |
+
*
|
184 |
+
* @param string $url Relative URL.
|
185 |
+
* @param string $base_url Base URL. If omitted, the blog's root URL will be used.
|
186 |
+
* @return string
|
187 |
+
*/
|
188 |
+
function relative2absolute($url, $base_url = ''){
|
189 |
+
if ( empty($base_url) ){
|
190 |
+
$base_url = get_option('siteurl');
|
191 |
+
}
|
192 |
+
|
193 |
+
$p = @parse_url($url);
|
194 |
+
if(!$p) {
|
195 |
+
//URL is a malformed
|
196 |
+
return false;
|
197 |
+
}
|
198 |
+
if( isset($p["scheme"]) ) return $url;
|
199 |
+
|
200 |
+
//If the relative URL is just a query string, simply attach it to the absolute URL and return
|
201 |
+
if ( substr($relative, 0, 1) == '?' ){
|
202 |
+
return $absolute . $relative;
|
203 |
+
}
|
204 |
+
|
205 |
+
$parts=(parse_url($base_url));
|
206 |
+
|
207 |
+
if(substr($url,0,1)=='/') {
|
208 |
+
//Relative URL starts with a slash => ignore the base path and jump straight to the root.
|
209 |
+
$path_segments = explode("/", $url);
|
210 |
+
array_shift($path_segments);
|
211 |
+
} else {
|
212 |
+
if(isset($parts['path'])){
|
213 |
+
$aparts=explode('/',$parts['path']);
|
214 |
+
array_pop($aparts);
|
215 |
+
$aparts=array_filter($aparts);
|
216 |
+
} else {
|
217 |
+
$aparts=array();
|
218 |
+
}
|
219 |
+
|
220 |
+
//Merge together the base path & the relative path
|
221 |
+
$aparts = array_merge($aparts, explode("/", $url));
|
222 |
+
|
223 |
+
//Filter the merged path
|
224 |
+
$path_segments = array();
|
225 |
+
foreach($aparts as $part){
|
226 |
+
if ( $part == '.' ){
|
227 |
+
continue; //. = "this directory". It's basically a no-op, so we skip it.
|
228 |
+
} elseif ( $part == '..' ) {
|
229 |
+
array_pop($path_segments); //.. = one directory up. Remove the last seen path segment.
|
230 |
+
} else {
|
231 |
+
array_push($path_segments, $part); //Normal directory -> add it to the path.
|
232 |
+
}
|
233 |
+
}
|
234 |
+
}
|
235 |
+
$path = implode("/", $path_segments);
|
236 |
+
|
237 |
+
//Build the absolute URL.
|
238 |
+
$url = '';
|
239 |
+
if($parts['scheme']) {
|
240 |
+
$url = "$parts[scheme]://";
|
241 |
+
}
|
242 |
+
if(isset($parts['user'])) {
|
243 |
+
$url .= $parts['user'];
|
244 |
+
if(isset($parts['pass'])) {
|
245 |
+
$url .= ":".$parts['pass'];
|
246 |
+
}
|
247 |
+
$url .= "@";
|
248 |
+
}
|
249 |
+
if(isset($parts['host'])) {
|
250 |
+
$url .= $parts['host']."/";
|
251 |
+
}
|
252 |
+
$url .= $path;
|
253 |
+
|
254 |
+
return $url;
|
255 |
+
}
|
256 |
+
|
257 |
+
/**
|
258 |
+
* Apply a callback function to all links found in a string and return the results.
|
259 |
+
*
|
260 |
+
* The first argument passed to the callback function will be an associative array
|
261 |
+
* of link data. If the optional $extra parameter is set, it will be passed as the
|
262 |
+
* second argument to the callback function.
|
263 |
+
*
|
264 |
+
* The link data array will contain at least these keys :
|
265 |
+
* 'href' - the URL of the link, as-is (i.e. without any sanitization or relative-to-absolute translation).
|
266 |
+
* '#raw' - the raw link code, e.g. the entire '<a href="...">...</a>' tag of a HTML link.
|
267 |
+
*
|
268 |
+
* Sub-classes may also set additional keys.
|
269 |
+
*
|
270 |
+
* This method is currently used only internally, so sub-classes are not required
|
271 |
+
* to implement it.
|
272 |
+
*
|
273 |
+
* @param string $content A text string to parse for links.
|
274 |
+
* @param callback $callback Callback function to apply to all found links.
|
275 |
+
* @param mixed $extra If the optional $extra param. is supplied, it will be passed as the second parameter to the function $callback.
|
276 |
+
* @return array An array of all detected links after applying $callback to each of them.
|
277 |
+
*/
|
278 |
+
function map($content, $callback, $extra = null){
|
279 |
+
return array();
|
280 |
+
}
|
281 |
+
|
282 |
+
/**
|
283 |
+
* Modify all links found in a string using a callback function.
|
284 |
+
*
|
285 |
+
* The first argument passed to the callback function will be an associative array
|
286 |
+
* of link data. If the optional $extra parameter is set, it will be passed as the
|
287 |
+
* second argument to the callback function. See the map() method of this class for
|
288 |
+
* details on the first argument.
|
289 |
+
*
|
290 |
+
* The callback function should return either an associative array or a string. If
|
291 |
+
* a string is returned, the parser will replace the current link with the contents
|
292 |
+
* of that string. If an array is returned, the current link will be modified/rebuilt
|
293 |
+
* by substituting the new values for the old ones (e.g. returning array with the key
|
294 |
+
* 'href' set to 'http://example.com/' will replace the current link's URL with
|
295 |
+
* http://example.com/).
|
296 |
+
*
|
297 |
+
* This method is currently only used internally, so sub-classes are not required
|
298 |
+
* to implement it.
|
299 |
+
*
|
300 |
+
* @see blcParser::map()
|
301 |
+
*
|
302 |
+
* @param string $content A text string containing the links to edit.
|
303 |
+
* @param callback $callback Callback function used to modify the links.
|
304 |
+
* @param mixed $extra If supplied, $extra will be passed as the second parameter to the function $callback.
|
305 |
+
* @return string The modified input string.
|
306 |
+
*/
|
307 |
+
function multi_edit($content, $callback, $extra = null){
|
308 |
+
return $content; //No-op
|
309 |
+
}
|
310 |
+
}
|
311 |
+
|
312 |
+
/**
|
313 |
+
* Register a new link parser.
|
314 |
+
*
|
315 |
+
* @see blcParser
|
316 |
+
*
|
317 |
+
* @uses blcParserRegistry::register_parser()
|
318 |
+
*
|
319 |
+
* @param string $parser_type A unique string identifying the parser, e.g. "html_link"
|
320 |
+
* @param string $class_name Name of the class that implements the parser.
|
321 |
+
* @return bool
|
322 |
+
*/
|
323 |
+
function blc_register_parser( $parser_type, $class_name ) {
|
324 |
+
global $blc_parser_registry;
|
325 |
+
return $blc_parser_registry->register_parser($parser_type, $class_name);
|
326 |
+
}
|
327 |
+
|
328 |
+
/**
|
329 |
+
* Get the parser matching a parser type id.
|
330 |
+
*
|
331 |
+
* @uses blcParserRegistry::get_parser()
|
332 |
+
*
|
333 |
+
* @param string $parser_type
|
334 |
+
* @return blcParser|null
|
335 |
+
*/
|
336 |
+
function blc_get_parser( $parser_type ){
|
337 |
+
global $blc_parser_registry;
|
338 |
+
return $blc_parser_registry->get_parser($parser_type);
|
339 |
+
}
|
340 |
+
|
341 |
+
/**
|
342 |
+
* Get all parsers that support either the specified format or container type.
|
343 |
+
*
|
344 |
+
* @uses blcParserRegistry::get_parsers()
|
345 |
+
*
|
346 |
+
* @param string $format
|
347 |
+
* @param string $container_type
|
348 |
+
* @return array of blcParser
|
349 |
+
*/
|
350 |
+
function blc_get_parsers( $format, $container_type ){
|
351 |
+
global $blc_parser_registry;
|
352 |
+
return $blc_parser_registry->get_parsers($format, $container_type);
|
353 |
+
}
|
354 |
+
|
355 |
+
|
356 |
+
?>
|
includes/parsers/html_link.php
ADDED
@@ -0,0 +1,328 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class blcHTMLLink extends blcParser {
|
4 |
+
var $supported_formats = array('html');
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Parse a string for HTML links - <a href="URL">anchor text</a>
|
8 |
+
*
|
9 |
+
* @param string $content The text to parse.
|
10 |
+
* @param string $base_url The base URL to use for normalizing relative URLs. If ommitted, the blog's root URL will be used.
|
11 |
+
* @param string $default_link_text
|
12 |
+
* @return array An array of new blcLinkInstance objects. The objects will include info about the links found, but not about the corresponding container entity.
|
13 |
+
*/
|
14 |
+
function parse($content, $base_url = '', $default_link_text = ''){
|
15 |
+
$instances = array();
|
16 |
+
|
17 |
+
//remove all <code></code> blocks first
|
18 |
+
$content = preg_replace('/<code[^>]*>.+?<\/code>/si', ' ', $content);
|
19 |
+
|
20 |
+
//Find links
|
21 |
+
$params = array(
|
22 |
+
'base_url' => $base_url,
|
23 |
+
'default_link_text' => $default_link_text,
|
24 |
+
);
|
25 |
+
$instances = $this->map($content, array(&$this, 'parser_callback'), $params);
|
26 |
+
|
27 |
+
//The parser callback returns NULL when it finds an invalid link. Filter out those nulls
|
28 |
+
//from the list of instances.
|
29 |
+
$instances = array_filter($instances);
|
30 |
+
|
31 |
+
return $instances;
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* blcHTMLLink::parser_callback()
|
36 |
+
*
|
37 |
+
* @access private
|
38 |
+
*
|
39 |
+
* @param array $link
|
40 |
+
* @param array $params
|
41 |
+
* @return blcLinkInstance|null
|
42 |
+
*/
|
43 |
+
function parser_callback($link, $params){
|
44 |
+
extract($params);
|
45 |
+
|
46 |
+
$url = $raw_url = $link['href'];
|
47 |
+
$url = trim($url);
|
48 |
+
//FB::log($url, "Found link");
|
49 |
+
|
50 |
+
//Sometimes links may contain shortcodes. Execute them.
|
51 |
+
$url = do_shortcode($url);
|
52 |
+
|
53 |
+
//Skip empty URLs
|
54 |
+
if ( empty($url) ){
|
55 |
+
return null;
|
56 |
+
};
|
57 |
+
|
58 |
+
//Attempt to parse the URL
|
59 |
+
$parts = @parse_url($url);
|
60 |
+
if(!$parts) {
|
61 |
+
return null; //Skip invalid URLs
|
62 |
+
};
|
63 |
+
|
64 |
+
if ( !isset($parts['scheme']) ){
|
65 |
+
//No sheme - likely a relative URL. Turn it into an absolute one.
|
66 |
+
$url = $this->relative2absolute($url, $base_url);
|
67 |
+
}
|
68 |
+
|
69 |
+
//Skip invalid links (again)
|
70 |
+
if ( !$url || (strlen($url)<6) ) {
|
71 |
+
continue;
|
72 |
+
}
|
73 |
+
|
74 |
+
$text = strip_tags( $link['#link_text'] );
|
75 |
+
|
76 |
+
//The URL is okay, create and populate a new link instance.
|
77 |
+
$instance = new blcLinkInstance();
|
78 |
+
|
79 |
+
$instance->set_parser($this);
|
80 |
+
$instance->raw_url = $raw_url;
|
81 |
+
$instance->link_text = $text;
|
82 |
+
|
83 |
+
$link_obj = new blcLink($url); //Creates or loads the link
|
84 |
+
$instance->set_link($link_obj);
|
85 |
+
|
86 |
+
return $instance;
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Change all links that have a certain URL to a new URL.
|
91 |
+
*
|
92 |
+
* @param string $content Look for links in this string.
|
93 |
+
* @param string $new_url Change the links to this URL.
|
94 |
+
* @param string $old_url The URL to look for.
|
95 |
+
* @param string $old_raw_url The raw, not-normalized URL of the links to look for. Optional.
|
96 |
+
*
|
97 |
+
* @return array|WP_Error If successful, the return value will be an associative array with two
|
98 |
+
* keys : 'content' - the modified content, and 'raw_url' - the new raw, non-normalized URL used
|
99 |
+
* for the modified links. In most cases, the returned raw_url will be equal to the new_url.
|
100 |
+
*/
|
101 |
+
function edit($content, $new_url, $old_url, $old_raw_url){
|
102 |
+
if ( empty($old_raw_url) ){
|
103 |
+
$old_raw_url = $old_url;
|
104 |
+
}
|
105 |
+
|
106 |
+
//Save the old & new URLs for use in the edit callback.
|
107 |
+
$args = array(
|
108 |
+
'old_url' => $old_raw_url,
|
109 |
+
'new_url' => $new_url,
|
110 |
+
);
|
111 |
+
|
112 |
+
//Find all links and replace those that match $old_url.
|
113 |
+
$content = $this->multi_edit($content, array(&$this, 'edit_callback'), $args);
|
114 |
+
|
115 |
+
return array(
|
116 |
+
'content' => $content,
|
117 |
+
'raw_url' => $new_url,
|
118 |
+
);
|
119 |
+
}
|
120 |
+
|
121 |
+
function edit_callback($link, $params){
|
122 |
+
if ($link['href'] == $params['old_url']){
|
123 |
+
return array(
|
124 |
+
'href' => $params['new_url'],
|
125 |
+
);
|
126 |
+
} else {
|
127 |
+
return $link['#raw'];
|
128 |
+
}
|
129 |
+
}
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Remove all links that have a certain URL, leaving anchor text intact.
|
133 |
+
*
|
134 |
+
* @param string $content Look for links in this string.
|
135 |
+
* @param string $url The URL to look for.
|
136 |
+
* @param string $raw_url The raw, non-normalized version of the URL to look for. Optional.
|
137 |
+
* @return string Input string with all matching links removed.
|
138 |
+
*/
|
139 |
+
function unlink($content, $url, $raw_url){
|
140 |
+
if ( empty($raw_url) ){
|
141 |
+
$raw_url = $url;
|
142 |
+
}
|
143 |
+
|
144 |
+
$args = array(
|
145 |
+
'old_url' => $raw_url,
|
146 |
+
);
|
147 |
+
|
148 |
+
//Find all links and remove those that match $raw_url.
|
149 |
+
$content = $this->multi_edit($content, array(&$this, 'unlink_callback'), $args);
|
150 |
+
|
151 |
+
return $content;
|
152 |
+
}
|
153 |
+
|
154 |
+
/**
|
155 |
+
* blcHTMLLink::unlink_callback()
|
156 |
+
*
|
157 |
+
* @access private
|
158 |
+
*
|
159 |
+
* @param array $link
|
160 |
+
* @param array $params
|
161 |
+
* @return string
|
162 |
+
*/
|
163 |
+
function unlink_callback($link, $params){
|
164 |
+
//Skip links that don't match the specified URL
|
165 |
+
if ($link['href'] != $params['old_url']){
|
166 |
+
return $link['#raw'];
|
167 |
+
}
|
168 |
+
|
169 |
+
$config = blc_get_configuration();
|
170 |
+
if ( $config->options['mark_removed_links'] ){
|
171 |
+
//Leave only the anchor text + the removed_link CSS class
|
172 |
+
return '<span class="removed_link">' . $link['#link_text'] . '</span>';
|
173 |
+
} else {
|
174 |
+
//Just the anchor text
|
175 |
+
return $link['#link_text'];
|
176 |
+
}
|
177 |
+
}
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Get the link text for printing in the "Broken Links" table.
|
181 |
+
* Sub-classes should override this method and display the link text in a way appropriate for the link type.
|
182 |
+
*
|
183 |
+
* @param blcLinkInstance $instance
|
184 |
+
* @return string HTML
|
185 |
+
*/
|
186 |
+
function ui_get_link_text($instance){
|
187 |
+
return $instance->link_text;
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Apply a callback function to all HTML links found in a string and return the results.
|
192 |
+
*
|
193 |
+
* The link data array will contain at least these keys :
|
194 |
+
* 'href' - the URL of the link (with htmlentitydecode() already applied).
|
195 |
+
* '#raw' - the raw link code, e.g. the entire '<a href="...">...</a>' tag of a HTML link.
|
196 |
+
* '#offset' - the offset within $content at which the first character of the link tag was found.
|
197 |
+
* '#link_text' - the link's anchor text, if any. May contain HTML tags.
|
198 |
+
*
|
199 |
+
* Any attributes of the link tag will also be included in the returned array as attr_name => attr_value
|
200 |
+
* pairs. This function will also automatically decode any HTML entities found in attribute values.
|
201 |
+
*
|
202 |
+
* @see blcParser::map()
|
203 |
+
*
|
204 |
+
* @param string $content A text string to parse for links.
|
205 |
+
* @param callback $callback Callback function to apply to all found links.
|
206 |
+
* @param mixed $extra If the optional $extra param. is supplied, it will be passed as the second parameter to the function $callback.
|
207 |
+
* @return array An array of all detected links after applying $callback to each of them.
|
208 |
+
*/
|
209 |
+
function map($content, $callback, $extra = null){
|
210 |
+
$results = array();
|
211 |
+
|
212 |
+
//Find all links
|
213 |
+
$links = blcUtility::extract_tags($content, 'a', false, true);
|
214 |
+
|
215 |
+
//Iterate over the links and apply $callback to each
|
216 |
+
foreach($links as $link){
|
217 |
+
|
218 |
+
//Massage the found link into a form required for the callback function
|
219 |
+
$param = $link['attributes'];
|
220 |
+
$param = array_merge(
|
221 |
+
$param,
|
222 |
+
array(
|
223 |
+
'#raw' => $link['full_tag'],
|
224 |
+
'#offset' => $link['offset'],
|
225 |
+
'#link_text' => $link['contents'],
|
226 |
+
'href' => isset($link['attributes']['href'])?$link['attributes']['href']:'',
|
227 |
+
)
|
228 |
+
);
|
229 |
+
|
230 |
+
//Prepare arguments for the callback
|
231 |
+
$params = array($param);
|
232 |
+
if ( isset($extra) ){
|
233 |
+
$params[] = $extra;
|
234 |
+
}
|
235 |
+
|
236 |
+
//Execute & store :)
|
237 |
+
$results[] = call_user_func_array($callback, $params);
|
238 |
+
}
|
239 |
+
|
240 |
+
return $results;
|
241 |
+
}
|
242 |
+
|
243 |
+
/**
|
244 |
+
* Modify all HTML links found in a string using a callback function.
|
245 |
+
*
|
246 |
+
* The callback function should return either an associative array or a string. If
|
247 |
+
* a string is returned, the parser will replace the current link with the contents
|
248 |
+
* of that string. If an array is returned, the current link will be modified/rebuilt
|
249 |
+
* by substituting the new values for the old ones.
|
250 |
+
*
|
251 |
+
* htmlentities() will be automatically applied to attribute values (but not to #link_text).
|
252 |
+
*
|
253 |
+
* @see blcParser::multi_edit()
|
254 |
+
*
|
255 |
+
* @param string $content A text string containing the links to edit.
|
256 |
+
* @param callback $callback Callback function used to modify the links.
|
257 |
+
* @param mixed $extra If supplied, $extra will be passed as the second parameter to the function $callback.
|
258 |
+
* @return string The modified input string.
|
259 |
+
*/
|
260 |
+
function multi_edit($content, $callback, $extra = null){
|
261 |
+
//Just reuse map() + a little helper func. to apply the callback to all links and get modified links
|
262 |
+
$modified_links = $this->map($content, array(&$this, 'execute_edit_callback'), array($callback, $extra));
|
263 |
+
|
264 |
+
//Replace each old link with the modified one
|
265 |
+
$offset = 0;
|
266 |
+
foreach($modified_links as $link){
|
267 |
+
if ( isset($link['#new_raw']) ){
|
268 |
+
$new_html = $link['#new_raw'];
|
269 |
+
} else {
|
270 |
+
//Assemble the new link tag
|
271 |
+
$new_html = '<a';
|
272 |
+
foreach ( $link as $name => $value ){
|
273 |
+
|
274 |
+
//Skip special keys like '#raw' and '#offset'
|
275 |
+
if ( substr($name, 0, 1) == '#' ){
|
276 |
+
continue;
|
277 |
+
}
|
278 |
+
|
279 |
+
$new_html .= sprintf(' %s="%s"', $name, htmlentities( $value, ENT_COMPAT ));
|
280 |
+
}
|
281 |
+
$new_html .= '>' . $link['#link_text'] . '</a>';
|
282 |
+
}
|
283 |
+
|
284 |
+
$content = substr_replace($content, $new_html, $link['#offset'] + $offset, strlen($link['#raw']));
|
285 |
+
//Update the replacement offset
|
286 |
+
$offset += ( strlen($new_html) - strlen($link['#raw']) );
|
287 |
+
}
|
288 |
+
|
289 |
+
return $content;
|
290 |
+
}
|
291 |
+
|
292 |
+
/**
|
293 |
+
* Helper function for blcHtmlLink::multi_edit()
|
294 |
+
* Applies the specified callback function to each link and merges
|
295 |
+
* the result with the current link attributes. If the callback returns
|
296 |
+
* a replacement HTML tag instead, it will be stored in the '#new_raw'
|
297 |
+
* key of the return array.
|
298 |
+
*
|
299 |
+
* @access protected
|
300 |
+
*
|
301 |
+
* @param array $link
|
302 |
+
* @param array $info The callback function and the extra argument to pass to that function (if any).
|
303 |
+
* @return array
|
304 |
+
*/
|
305 |
+
function execute_edit_callback($link, $info){
|
306 |
+
list($callback, $extra) = $info;
|
307 |
+
|
308 |
+
//Prepare arguments for the callback
|
309 |
+
$params = array($link);
|
310 |
+
if ( isset($extra) ){
|
311 |
+
$params[] = $extra;
|
312 |
+
}
|
313 |
+
|
314 |
+
$new_link = call_user_func_array($callback, $params);
|
315 |
+
|
316 |
+
if ( is_array($new_link) ){
|
317 |
+
$link = array_merge($link, $new_link);
|
318 |
+
} elseif (is_string($new_link)) {
|
319 |
+
$link['#new_raw'] = $new_link;
|
320 |
+
}
|
321 |
+
|
322 |
+
return $link;
|
323 |
+
}
|
324 |
+
}
|
325 |
+
|
326 |
+
blc_register_parser('link', 'blcHTMLLink');
|
327 |
+
|
328 |
+
?>
|
includes/parsers/image.php
ADDED
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
//TODO: Update image parser to use the same HTML tag parsing routine as the HTML link parser.
|
4 |
+
class blcHTMLImage extends blcParser {
|
5 |
+
var $supported_formats = array('html');
|
6 |
+
|
7 |
+
// \1 \2 \3 URL \4
|
8 |
+
var $img_pattern = '/(<img[\s]+[^>]*src\s*=\s*)([\"\'])([^>]+?)\2([^<>]*>)/i';
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Parse a string for HTML images - <img src="URL">
|
12 |
+
*
|
13 |
+
* @param string $content The text to parse.
|
14 |
+
* @param string $base_url The base URL to use for normalizing relative URLs. If ommitted, the blog's root URL will be used.
|
15 |
+
* @param string $default_link_text
|
16 |
+
* @return array An array of new blcLinkInstance objects. The objects will include info about the links found, but not about the corresponding container entity.
|
17 |
+
*/
|
18 |
+
function parse($content, $base_url = '', $default_link_text = ''){
|
19 |
+
$instances = array();
|
20 |
+
|
21 |
+
//remove all <code></code> blocks first
|
22 |
+
$content = preg_replace('/<code[^>]*>.+?<\/code>/si', ' ', $content);
|
23 |
+
|
24 |
+
//Find images
|
25 |
+
if(preg_match_all($this->img_pattern, $content, $matches, PREG_SET_ORDER)){
|
26 |
+
foreach($matches as $link){
|
27 |
+
$url = $raw_url = $link[3];
|
28 |
+
//FB::log($url, "Found image");
|
29 |
+
|
30 |
+
//Decode & and other entities
|
31 |
+
$url = html_entity_decode($url);
|
32 |
+
$url = trim($url);
|
33 |
+
|
34 |
+
//Attempt to parse the URL
|
35 |
+
$parts = @parse_url($url);
|
36 |
+
if(!$parts) {
|
37 |
+
continue; //Skip invalid URLs
|
38 |
+
};
|
39 |
+
|
40 |
+
if ( !isset($parts['scheme']) ){
|
41 |
+
//No sheme - likely a relative URL. Turn it into an absolute one.
|
42 |
+
$url = $this->relative2absolute($url, $base_url);
|
43 |
+
}
|
44 |
+
|
45 |
+
//Skip invalid URLs (again)
|
46 |
+
if ( !$url || (strlen($url)<6) ) {
|
47 |
+
continue;
|
48 |
+
}
|
49 |
+
|
50 |
+
//The URL is okay, create and populate a new link instance.
|
51 |
+
$instance = new blcLinkInstance();
|
52 |
+
|
53 |
+
$instance->set_parser($this);
|
54 |
+
$instance->raw_url = $raw_url;
|
55 |
+
$instance->link_text = '';
|
56 |
+
|
57 |
+
$link_obj = new blcLink($url); //Creates or loads the link
|
58 |
+
$instance->set_link($link_obj);
|
59 |
+
|
60 |
+
$instances[] = $instance;
|
61 |
+
}
|
62 |
+
};
|
63 |
+
|
64 |
+
return $instances;
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Change all images that have a certain source URL to a new URL.
|
69 |
+
*
|
70 |
+
* @param string $content Look for images in this string.
|
71 |
+
* @param string $new_url Change the images to this URL.
|
72 |
+
* @param string $old_url The URL to look for.
|
73 |
+
* @param string $old_raw_url The raw, not-normalized URL of the links to look for. Optional.
|
74 |
+
*
|
75 |
+
* @return array|WP_Error If successful, the return value will be an associative array with two
|
76 |
+
* keys : 'content' - the modified content, and 'raw_url' - the new raw, non-normalized URL used
|
77 |
+
* for the modified images. In most cases, the returned raw_url will be equal to the new_url.
|
78 |
+
*/
|
79 |
+
function edit($content, $new_url, $old_url, $old_raw_url){
|
80 |
+
if ( empty($old_raw_url) ){
|
81 |
+
$old_raw_url = $old_url;
|
82 |
+
}
|
83 |
+
//Save the old & new URLs for use in the regex callback.
|
84 |
+
$this->old_url = $old_raw_url;
|
85 |
+
$this->new_url = htmlentities($new_url);
|
86 |
+
|
87 |
+
//Find all images and replace those that match $old_url.
|
88 |
+
$content = preg_replace_callback($this->img_pattern, array(&$this, 'edit_callback'), $content);
|
89 |
+
|
90 |
+
return array(
|
91 |
+
'content' => $content,
|
92 |
+
'raw_url' => $this->new_url,
|
93 |
+
);
|
94 |
+
}
|
95 |
+
|
96 |
+
function edit_callback($matches){
|
97 |
+
$url = $matches[3];
|
98 |
+
if ($url == $this->old_url){
|
99 |
+
return $matches[1].'"'.$this->new_url.'"'.$matches[4];
|
100 |
+
} else {
|
101 |
+
return $matches[0];
|
102 |
+
}
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Remove all images that have a certain URL.
|
107 |
+
*
|
108 |
+
* @param string $content Look for images in this string.
|
109 |
+
* @param string $url The URL to look for.
|
110 |
+
* @param string $raw_url The raw, non-normalized version of the URL to look for. Optional.
|
111 |
+
* @return string Input string with all matching images removed.
|
112 |
+
*/
|
113 |
+
function unlink($content, $url, $raw_url){
|
114 |
+
if ( empty($raw_url) ){
|
115 |
+
$raw_url = $url;
|
116 |
+
}
|
117 |
+
$this->old_url = $raw_url; //used by the callback
|
118 |
+
$content = preg_replace_callback($this->img_pattern, array(&$this, 'unlink_callback'), $content);
|
119 |
+
return $content;
|
120 |
+
}
|
121 |
+
|
122 |
+
function unlink_callback($matches){
|
123 |
+
$url = $matches[3];
|
124 |
+
|
125 |
+
//Does the URL match?
|
126 |
+
if ($url == $this->old_url){
|
127 |
+
return ''; //Completely remove the IMG tag
|
128 |
+
} else {
|
129 |
+
return $matches[0]; //return the image unchanged
|
130 |
+
}
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Get the link text for printing in the "Broken Links" table.
|
135 |
+
* Sub-classes should override this method and display the link text in a way appropriate for the link type.
|
136 |
+
*
|
137 |
+
* @param blcLinkInstance $instance
|
138 |
+
* @param string $context
|
139 |
+
* @return string HTML
|
140 |
+
*/
|
141 |
+
function ui_get_link_text($instance, $context = 'display'){
|
142 |
+
$text = __('Image', 'broken-link-checker');
|
143 |
+
|
144 |
+
$image = sprintf(
|
145 |
+
'<img src="%s/broken-link-checker/images/image.png" class="blc-small-image" alt="%2$s" title="%2$s"> ',
|
146 |
+
WP_PLUGIN_URL, //TODO: Use plugin_dir_url() instead
|
147 |
+
esc_attr($text)
|
148 |
+
);
|
149 |
+
|
150 |
+
if ( $context != 'email' ){
|
151 |
+
$text = $image . $text;
|
152 |
+
}
|
153 |
+
|
154 |
+
return $text;
|
155 |
+
}
|
156 |
+
}
|
157 |
+
|
158 |
+
blc_register_parser('image', 'blcHTMLImage');
|
159 |
+
|
160 |
+
|
161 |
+
?>
|
includes/parsers/metadata.php
ADDED
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class blcMetadataParser extends blcParser {
|
4 |
+
var $supported_formats = array('metadata');
|
5 |
+
var $supported_containers = array('custom_field');
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Parse a metadata value.
|
9 |
+
*
|
10 |
+
* @param string|array $content Metadata value(s).
|
11 |
+
* @param string $base_url The base URL to use for normalizing relative URLs. If ommitted, the blog's root URL will be used.
|
12 |
+
* @param string $default_link_text
|
13 |
+
* @return array An array of new blcLinkInstance objects.
|
14 |
+
*/
|
15 |
+
function parse($content, $base_url = '', $default_link_text = ''){
|
16 |
+
$instances = array();
|
17 |
+
|
18 |
+
if ( !is_array($content) ){
|
19 |
+
$content = array($content);
|
20 |
+
}
|
21 |
+
|
22 |
+
foreach($content as $value){
|
23 |
+
//The complete contents of the meta field are stored in raw_url.
|
24 |
+
//This is useful for editing/unlinking, when one may need to
|
25 |
+
//distinguish between multiple fields with the same name.
|
26 |
+
$raw_url = $value;
|
27 |
+
|
28 |
+
//If this is a multiline metadata field take only the first line (workaround for the 'enclosure' field).
|
29 |
+
$url = trim( array_shift( explode("\n", $value) ) );
|
30 |
+
|
31 |
+
//Attempt to parse the URL
|
32 |
+
$parts = @parse_url($url);
|
33 |
+
if(!$parts) {
|
34 |
+
return $instances; //Ignore invalid URLs
|
35 |
+
};
|
36 |
+
|
37 |
+
if ( !isset($parts['scheme']) ){
|
38 |
+
//No sheme - likely a relative URL. Turn it into an absolute one.
|
39 |
+
$url = $this->relative2absolute($url, $base_url);
|
40 |
+
|
41 |
+
//Skip invalid URLs (again)
|
42 |
+
if ( !$url || (strlen($url)<6) ) {
|
43 |
+
return $instances;
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
//The URL is okay, create and populate a new link instance.
|
48 |
+
$instance = new blcLinkInstance();
|
49 |
+
|
50 |
+
$instance->set_parser($this);
|
51 |
+
$instance->raw_url = $raw_url;
|
52 |
+
$instance->link_text = $default_link_text;
|
53 |
+
|
54 |
+
$link_obj = new blcLink($url); //Creates or loads the link
|
55 |
+
$instance->set_link($link_obj);
|
56 |
+
|
57 |
+
$instances[] = $instance;
|
58 |
+
}
|
59 |
+
|
60 |
+
return $instances;
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Change the URL in a metadata field to another one.
|
65 |
+
*
|
66 |
+
* This is tricky because there can be multiple metadata fields with the same name
|
67 |
+
* but different values. So we ignore $content (which might be an array of multiple
|
68 |
+
* metadata values) and use the old raw_url that we stored when parsing the field(s)
|
69 |
+
* instead.
|
70 |
+
*
|
71 |
+
* @see blcMetadataParser::parse()
|
72 |
+
*
|
73 |
+
* @param string $content Ignored.
|
74 |
+
* @param string $new_url The new URL.
|
75 |
+
* @param string $old_url Ignored.
|
76 |
+
* @param string $old_raw_url The current meta value.
|
77 |
+
*
|
78 |
+
* @return array|WP_Error
|
79 |
+
*/
|
80 |
+
function edit($content, $new_url, $old_url, $old_raw_url){
|
81 |
+
//For multiline fields (like 'enclosure') we only want to change the first line.
|
82 |
+
$lines = explode("\n", $old_raw_url);
|
83 |
+
array_shift($lines); //Discard the old first line
|
84 |
+
array_unshift($lines, $new_url); //Insert the new URL in its place.
|
85 |
+
$content = implode("\n", $lines);
|
86 |
+
|
87 |
+
return array(
|
88 |
+
'content' => $content,
|
89 |
+
'raw_url' => $new_url,
|
90 |
+
);
|
91 |
+
}
|
92 |
+
}
|
93 |
+
|
94 |
+
blc_register_parser('metadata', 'blcMetadataParser');
|
95 |
+
|
96 |
+
|
97 |
+
?>
|
includes/parsers/url_field.php
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* A "parser" for data fields that contain a single, plaintext URL.
|
5 |
+
*
|
6 |
+
* Intended for parsing stuff like bookmarks and comment author links.
|
7 |
+
*
|
8 |
+
* @package Broken Link Checker
|
9 |
+
* @access public
|
10 |
+
*/
|
11 |
+
class blcUrlField extends blcParser {
|
12 |
+
var $supported_formats = array('url_field');
|
13 |
+
|
14 |
+
/**
|
15 |
+
* "Parse" an URL into an instance.
|
16 |
+
*
|
17 |
+
* @param string $content The entire content is expected to be a single plaintext URL.
|
18 |
+
* @param string $base_url The base URL to use for normalizing relative URLs. If ommitted, the blog's root URL will be used.
|
19 |
+
* @param string $default_link_text
|
20 |
+
* @return array An array of new blcLinkInstance objects.
|
21 |
+
*/
|
22 |
+
function parse($content, $base_url = '', $default_link_text = ''){
|
23 |
+
$instances = array();
|
24 |
+
|
25 |
+
$url = $raw_url = trim($content);
|
26 |
+
|
27 |
+
//Attempt to parse the URL
|
28 |
+
$parts = @parse_url($url);
|
29 |
+
if(!$parts) {
|
30 |
+
return $instances; //Ignore invalid URLs
|
31 |
+
};
|
32 |
+
|
33 |
+
if ( !isset($parts['scheme']) ){
|
34 |
+
//No sheme - likely a relative URL. Turn it into an absolute one.
|
35 |
+
$url = $this->relative2absolute($url, $base_url);
|
36 |
+
|
37 |
+
//Skip invalid URLs (again)
|
38 |
+
if ( !$url || (strlen($url)<6) ) {
|
39 |
+
return $instances;
|
40 |
+
}
|
41 |
+
}
|
42 |
+
|
43 |
+
//The URL is okay, create and populate a new link instance.
|
44 |
+
$instance = new blcLinkInstance();
|
45 |
+
|
46 |
+
$instance->set_parser($this);
|
47 |
+
$instance->raw_url = $raw_url;
|
48 |
+
$instance->link_text = $default_link_text;
|
49 |
+
|
50 |
+
$link_obj = new blcLink($url); //Creates or loads the link
|
51 |
+
$instance->set_link($link_obj);
|
52 |
+
|
53 |
+
$instances[] = $instance;
|
54 |
+
|
55 |
+
return $instances;
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Change one URL to another (just returns the new URL).
|
60 |
+
*
|
61 |
+
* @param string $content The old URL.
|
62 |
+
* @param string $new_url The new URL.
|
63 |
+
* @param string $old_url Ignored.
|
64 |
+
* @param string $old_raw_url Ignored.
|
65 |
+
*
|
66 |
+
* @return array|WP_Error
|
67 |
+
*/
|
68 |
+
function edit($content, $new_url, $old_url, $old_raw_url){
|
69 |
+
return array(
|
70 |
+
'content' => $new_url,
|
71 |
+
'raw_url' => $new_url,
|
72 |
+
);
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* For URL fields, "unlinking" simply means blanking the field.
|
77 |
+
* (However, invididual link containers may implement a different logic for those fields.)
|
78 |
+
*/
|
79 |
+
function unlink($content, $url, $raw_url){
|
80 |
+
return '';
|
81 |
+
}
|
82 |
+
}
|
83 |
+
|
84 |
+
blc_register_parser('url_field', 'blcUrlField');
|
85 |
+
|
86 |
+
|
87 |
+
?>
|
instance-classes.php
DELETED
@@ -1,585 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* @author W-Shadow
|
5 |
-
* @copyright 2009
|
6 |
-
*/
|
7 |
-
|
8 |
-
if (!class_exists('blcLinkInstance')) {
|
9 |
-
class blcLinkInstance {
|
10 |
-
|
11 |
-
//Object state
|
12 |
-
var $is_new = false;
|
13 |
-
|
14 |
-
//DB fields
|
15 |
-
var $instance_id = 0;
|
16 |
-
var $link_id = 0;
|
17 |
-
var $source_id = 0;
|
18 |
-
var $source_type = '';
|
19 |
-
var $link_text = '';
|
20 |
-
var $instance_type = '';
|
21 |
-
|
22 |
-
//These are used to pass info to callbacks when editing an instance
|
23 |
-
var $old_url = null;
|
24 |
-
var $new_url = null;
|
25 |
-
|
26 |
-
/**
|
27 |
-
* blcLinkInstance::__construct()
|
28 |
-
* Class constructor
|
29 |
-
*
|
30 |
-
* @param mixed $arg XXXXX look up how to do a multiline doc here (phpdoc)
|
31 |
-
* @return void
|
32 |
-
*/
|
33 |
-
function __construct($arg = null){
|
34 |
-
|
35 |
-
if (is_int($arg)){
|
36 |
-
//Load an instance with ID = $arg from the DB.
|
37 |
-
$q = $wpdb->prepare("SELECT * FROM {$wpdb->prefix}blc_instances WHERE instance_id=%d LIMIT 1", $arg);
|
38 |
-
$arr = $wpdb->get_row( $q, ARRAY_A );
|
39 |
-
|
40 |
-
if ( is_array($arr) ){ //Loaded successfully
|
41 |
-
$this->set_values($arr);
|
42 |
-
} else {
|
43 |
-
//Link instance not found. The object is invalid.
|
44 |
-
}
|
45 |
-
|
46 |
-
} else if (is_array($arg)){
|
47 |
-
$this->set_values($arg);
|
48 |
-
|
49 |
-
//Is this a new instance?
|
50 |
-
$this->is_new = empty($this->instance_id);
|
51 |
-
|
52 |
-
} else {
|
53 |
-
$this->is_new = true;
|
54 |
-
}
|
55 |
-
}
|
56 |
-
|
57 |
-
/**
|
58 |
-
* blcLinkInstance::blcLinkInstance()
|
59 |
-
* Old-style constructor for PHP 4. Do not use.
|
60 |
-
*
|
61 |
-
* @param mixed $arg
|
62 |
-
* @return void
|
63 |
-
*/
|
64 |
-
function blcLinkInstance($arg = null){
|
65 |
-
$this->__construct($arg);
|
66 |
-
}
|
67 |
-
|
68 |
-
/**
|
69 |
-
* blcLinkInstance::valid()
|
70 |
-
* Verifies whether the object represents a valid link instance
|
71 |
-
*
|
72 |
-
* @return bool
|
73 |
-
*/
|
74 |
-
function valid(){
|
75 |
-
//Some basic validation to ensure the required properties are set.
|
76 |
-
return !empty($this->link_id) && !empty($this->instance_type) && !empty($this->source_id)
|
77 |
-
&& !empty($this->source_type) && (!empty($this->instance_id) || $this->is_new);
|
78 |
-
}
|
79 |
-
|
80 |
-
/**
|
81 |
-
* blcLinkInstance::set_values()
|
82 |
-
* Set property values to the ones provided in an array (doesn't sanitize).
|
83 |
-
*
|
84 |
-
* @param array $arr An associative array
|
85 |
-
* @return void
|
86 |
-
*/
|
87 |
-
function set_values($arr){
|
88 |
-
foreach( $arr as $key => $value ){
|
89 |
-
$this->$key = $value;
|
90 |
-
}
|
91 |
-
}
|
92 |
-
|
93 |
-
/**
|
94 |
-
* blcLinkInstance::edit()
|
95 |
-
* Replace this instance's URL with a new one.
|
96 |
-
* Warning : this shouldn't be called directly. Use blcLink->edit() instead.
|
97 |
-
*
|
98 |
-
* @param string $new_url
|
99 |
-
* @return bool
|
100 |
-
*/
|
101 |
-
function edit($old_url, $new_url){
|
102 |
-
echo "Error : The stub function blcLinkInstance->edit() was executed!\r\n";
|
103 |
-
return false;
|
104 |
-
}
|
105 |
-
|
106 |
-
/**
|
107 |
-
* blcLinkInstance::unlink()
|
108 |
-
* Remove this instance from the post/blogroll/etc. Also deletes the appropriate DB record(s).
|
109 |
-
*
|
110 |
-
* @return bool
|
111 |
-
*/
|
112 |
-
function unlink( $url = null ) {
|
113 |
-
//FB::warn("The stub function blcLinkInstance->unlink() was executed!");
|
114 |
-
return false;
|
115 |
-
}
|
116 |
-
|
117 |
-
/**
|
118 |
-
* blcLinkInstance::forget()
|
119 |
-
* Remove the link instance record from database. Doesn't affect the post/link/whatever.
|
120 |
-
*
|
121 |
-
* @return mixed 1 on success, 0 if the instance wasn't found, false on error
|
122 |
-
*/
|
123 |
-
function forget(){
|
124 |
-
global $wpdb;
|
125 |
-
|
126 |
-
if ( !$this->valid() ) return false;
|
127 |
-
|
128 |
-
if ( !empty($this->link_id) ) {
|
129 |
-
$rez = $wpdb->query( $wpdb->prepare("DELETE FROM {$wpdb->prefix}blc_instances WHERE instance_id=%d", $this->instance_id) );
|
130 |
-
$this->link_id = 0;
|
131 |
-
return $rez;
|
132 |
-
} else {
|
133 |
-
return false;
|
134 |
-
}
|
135 |
-
}
|
136 |
-
|
137 |
-
/**
|
138 |
-
* blcLinkInstance::save()
|
139 |
-
* Store the instance in the database.
|
140 |
-
*
|
141 |
-
* @return bool TRUE on success, FALSE on failure
|
142 |
-
*/
|
143 |
-
function save(){
|
144 |
-
global $wpdb;
|
145 |
-
|
146 |
-
if ( !$this->valid() ) return false;
|
147 |
-
|
148 |
-
if ( $this->is_new ){
|
149 |
-
|
150 |
-
//Insert a new row
|
151 |
-
$q = "
|
152 |
-
INSERT INTO {$wpdb->prefix}blc_instances
|
153 |
-
( link_id, source_id, source_type, link_text, instance_type )
|
154 |
-
VALUES( %d, %d, %s, %s, %s )";
|
155 |
-
|
156 |
-
$q = $wpdb->prepare($q, $this->link_id, $this->source_id, $this->source_type,
|
157 |
-
$this->link_text, $this->instance_type );
|
158 |
-
|
159 |
-
$rez = $wpdb->query($q);
|
160 |
-
$rez = $rez !== false;
|
161 |
-
|
162 |
-
if ($rez){
|
163 |
-
$this->instance_id = $wpdb->insert_id;
|
164 |
-
//If the instance was successfully saved then it's no longer "new".
|
165 |
-
$this->is_new = !$rez;
|
166 |
-
}
|
167 |
-
|
168 |
-
return $rez;
|
169 |
-
|
170 |
-
} else {
|
171 |
-
|
172 |
-
//Create a new DB record
|
173 |
-
$q = "UPDATE {$wpdb->prefix}blc_instances
|
174 |
-
SET link_id = %d, source_id = %d, source_type = %s, link_text = %s, instance_type = %s
|
175 |
-
WHERE instance_id = %d";
|
176 |
-
|
177 |
-
$q = $wpdb->prepare($q, $this->link_id, $this->source_id, $this->source_type,
|
178 |
-
$this->link_text, $this->instance_type, $this->instance_id );
|
179 |
-
|
180 |
-
$rez = $wpdb->query($q) !== false;
|
181 |
-
|
182 |
-
if ($rez){
|
183 |
-
//FB::info($this, "Instance updated");
|
184 |
-
} else {
|
185 |
-
//FB::error("DB error while updating instance {$this->instance_id} : {$wpdb->last_error}");
|
186 |
-
}
|
187 |
-
|
188 |
-
return $rez;
|
189 |
-
|
190 |
-
}
|
191 |
-
}
|
192 |
-
|
193 |
-
/**
|
194 |
-
* blcLinkInstance::get_url()
|
195 |
-
* Get the URL associated with this instance
|
196 |
-
*
|
197 |
-
* @return string
|
198 |
-
*/
|
199 |
-
function get_url(){
|
200 |
-
if ( !$this->valid() ){
|
201 |
-
return false;
|
202 |
-
}
|
203 |
-
|
204 |
-
//If the URL isn't specified get it from the link record
|
205 |
-
$link = new blcLink( intval($this->link_id) );
|
206 |
-
return $link->url;
|
207 |
-
}
|
208 |
-
}
|
209 |
-
|
210 |
-
class blcLinkInstance_post_link extends blcLinkInstance {
|
211 |
-
|
212 |
-
var $post_permalink = '';
|
213 |
-
var $changed_links = 0;
|
214 |
-
|
215 |
-
function edit($old_url, $new_url){
|
216 |
-
global $wpdb;
|
217 |
-
|
218 |
-
if ( !$this->valid() ){
|
219 |
-
return false;
|
220 |
-
}
|
221 |
-
|
222 |
-
//If the old URL isn't specified get it from the link record
|
223 |
-
if ( empty($old_url) ){
|
224 |
-
$old_url = $this->get_url();
|
225 |
-
}
|
226 |
-
|
227 |
-
//Load the post
|
228 |
-
$post = get_post($this->source_id, ARRAY_A);
|
229 |
-
if (!$post){
|
230 |
-
//FB::error('Can\'t load post ' . $this->source_id);
|
231 |
-
return false;
|
232 |
-
}
|
233 |
-
//FB::info('Post ' . $this->source_id . ' loaded successfully');
|
234 |
-
//Figure out the post's permalink - it'll be needed when normalizing relative URLs
|
235 |
-
$this->post_permalink = get_permalink( $post['ID'] );
|
236 |
-
|
237 |
-
$this->old_url = $old_url;
|
238 |
-
$this->new_url = $new_url;
|
239 |
-
|
240 |
-
//Track how many links in the post are successfully edited so that we can report an error if none are.
|
241 |
-
$this->changed_links = 0;
|
242 |
-
|
243 |
-
//Find all links and replace those that match $old_url.
|
244 |
-
$content = preg_replace_callback(blcUtility::link_pattern(), array(&$this, 'edit_callback'), $post['post_content']);
|
245 |
-
|
246 |
-
if ( $this->changed_links <= 0 ){
|
247 |
-
//FB::error("Didn't find any links to edit in this post!");
|
248 |
-
return false;
|
249 |
-
}
|
250 |
-
|
251 |
-
//Clear the post/page cache. This ensures that any further calls to this method
|
252 |
-
//will not load the post content from the cache and thus discard the changes
|
253 |
-
//we just made.
|
254 |
-
if ( 'page' == $post['post_type'] )
|
255 |
-
clean_page_cache($this->source_id);
|
256 |
-
else
|
257 |
-
clean_post_cache($this->source_id);
|
258 |
-
|
259 |
-
//Update the post
|
260 |
-
$rez = $wpdb->update(
|
261 |
-
$wpdb->posts,
|
262 |
-
array( 'post_content' => $content ),
|
263 |
-
array( 'id' => $this->source_id )
|
264 |
-
);
|
265 |
-
|
266 |
-
return $rez !== false;
|
267 |
-
}
|
268 |
-
|
269 |
-
function edit_callback($matches){
|
270 |
-
$url = blcUtility::normalize_url($matches[3], $this->post_permalink);
|
271 |
-
//FB::log('Found a link with URL "' . $matches[3] . '", normalized URL = "' . $url . '"');
|
272 |
-
|
273 |
-
if ($url == $this->old_url){
|
274 |
-
//FB::log('Changing this link');
|
275 |
-
$this->changed_links++;
|
276 |
-
return $matches[1].$matches[2].$this->new_url.$matches[2].$matches[4].$matches[5].$matches[6];
|
277 |
-
} else {
|
278 |
-
return $matches[0];
|
279 |
-
}
|
280 |
-
}
|
281 |
-
|
282 |
-
function unlink( $url = null ){
|
283 |
-
global $wpdb;
|
284 |
-
|
285 |
-
if ( !$this->valid() ){
|
286 |
-
return false;
|
287 |
-
}
|
288 |
-
|
289 |
-
//If the URL isn't specified get it from the link record
|
290 |
-
if ( empty($url) ){
|
291 |
-
$url = $this->get_url();
|
292 |
-
}
|
293 |
-
|
294 |
-
//Load the post
|
295 |
-
$post = get_post($this->source_id, ARRAY_A);
|
296 |
-
if (!$post){
|
297 |
-
//FB::error('Can\'t load post ' . $this->source_id);
|
298 |
-
return false;
|
299 |
-
}
|
300 |
-
//FB::info('Post ' . $this->source_id . ' loaded successfully');
|
301 |
-
//Figure out the post's permalink - it'll be needed when normalizing relative URLs
|
302 |
-
$this->post_permalink = get_permalink( $post['ID'] );
|
303 |
-
|
304 |
-
//Track how many links in the post are successfully removed so that we can report an error if none are.
|
305 |
-
$this->changed_links = 0;
|
306 |
-
|
307 |
-
//Find all links and remove those that match $url.
|
308 |
-
$this->old_url = $url; //used by the callback
|
309 |
-
$content = preg_replace_callback(blcUtility::link_pattern(), array(&$this, 'unlink_callback'), $post['post_content']);
|
310 |
-
|
311 |
-
if ( $this->changed_links <= 0 ){
|
312 |
-
return false;
|
313 |
-
}
|
314 |
-
|
315 |
-
//Clear the post/page cache. This ensures that any further calls to this method
|
316 |
-
//will not load the post content from the cache and thus discard the changes
|
317 |
-
//we just made.
|
318 |
-
if ( 'page' == $post['post_type'] )
|
319 |
-
clean_page_cache($this->source_id);
|
320 |
-
else
|
321 |
-
clean_post_cache($this->source_id);
|
322 |
-
|
323 |
-
//Update the post
|
324 |
-
$rez = $wpdb->update(
|
325 |
-
$wpdb->posts,
|
326 |
-
array( 'post_content' => $content ),
|
327 |
-
array( 'id' => $this->source_id )
|
328 |
-
);
|
329 |
-
|
330 |
-
if ( $rez !== false ){
|
331 |
-
//Delete the instance record
|
332 |
-
//FB::info("Post updated, deleting instance from DB");
|
333 |
-
return $this->forget() !== false;
|
334 |
-
} else {
|
335 |
-
//FB::error("Failed to update the post");
|
336 |
-
return false;
|
337 |
-
};
|
338 |
-
}
|
339 |
-
|
340 |
-
/**
|
341 |
-
* blcLinkInstance_post_link::unlink_callback()
|
342 |
-
* Remove the link while leaving the anchor text intact.
|
343 |
-
*
|
344 |
-
* @uses $blc_config_manager Global variable pointing to the plugin's configuration manager
|
345 |
-
*
|
346 |
-
* @param array $matches
|
347 |
-
* @return string
|
348 |
-
*/
|
349 |
-
function unlink_callback($matches){
|
350 |
-
global $blc_config_manager;
|
351 |
-
|
352 |
-
$url = blcUtility::normalize_url($matches[3], $this->post_permalink);
|
353 |
-
|
354 |
-
//Does the URL match?
|
355 |
-
if ($url == $this->old_url){
|
356 |
-
$this->changed_links++;
|
357 |
-
if ( $blc_config_manager->options['mark_removed_links'] ){
|
358 |
-
//leave only the anchor text + the removed_link CSS class
|
359 |
-
return '<span class="removed_link">' . $matches[5] . '</span>';
|
360 |
-
} else {
|
361 |
-
return $matches[5]; //just the anchor text
|
362 |
-
}
|
363 |
-
|
364 |
-
} else {
|
365 |
-
return $matches[0]; //return the link unchanged
|
366 |
-
}
|
367 |
-
}
|
368 |
-
|
369 |
-
}
|
370 |
-
|
371 |
-
class blcLinkInstance_post_image extends blcLinkInstance {
|
372 |
-
|
373 |
-
var $post_permalink = '';
|
374 |
-
var $changed_images = 0;
|
375 |
-
|
376 |
-
function edit($old_url, $new_url){
|
377 |
-
global $wpdb;
|
378 |
-
|
379 |
-
if ( !$this->valid() ){
|
380 |
-
return false;
|
381 |
-
}
|
382 |
-
|
383 |
-
//If the URL isn't specified get it from the link record
|
384 |
-
if ( empty($old_url) ){
|
385 |
-
$old_url = $this->get_url();
|
386 |
-
}
|
387 |
-
|
388 |
-
//Load the post
|
389 |
-
$post = get_post($this->source_id, ARRAY_A);
|
390 |
-
if (!$post){
|
391 |
-
return false;
|
392 |
-
}
|
393 |
-
//Figure out the post's permalink - it'll be needed when normalizing relative URLs
|
394 |
-
$this->post_permalink = get_permalink( $post['ID'] );
|
395 |
-
|
396 |
-
$this->old_url = $old_url;
|
397 |
-
$this->new_url = $new_url;
|
398 |
-
|
399 |
-
//Find all images and change the URL of those that match $old_url.
|
400 |
-
//Note : this might be inefficient if there's more than one instance of the same link
|
401 |
-
//in one post, as each instances would be called when editing the link.
|
402 |
-
//Either way, I thing the overhead is small enough to ignore for now.
|
403 |
-
$this->changed_images = 0;
|
404 |
-
$content = preg_replace_callback(blcUtility::img_pattern(), array(&$this, 'edit_callback'), $post['post_content']);
|
405 |
-
|
406 |
-
if ( $this->changed_images <= 0 ){
|
407 |
-
return false;
|
408 |
-
}
|
409 |
-
|
410 |
-
//Clear the post/page cache. This ensures that any further calls to this method
|
411 |
-
//will not load the post content from the cache and thus discard the changes
|
412 |
-
//we just made.
|
413 |
-
if ( 'page' == $post['post_type'] )
|
414 |
-
clean_page_cache($this->source_id);
|
415 |
-
else
|
416 |
-
clean_post_cache($this->source_id);
|
417 |
-
|
418 |
-
//Save the modified post
|
419 |
-
$rez = $wpdb->update(
|
420 |
-
$wpdb->posts,
|
421 |
-
array( 'post_content' => $content ),
|
422 |
-
array( 'id' => $this->source_id )
|
423 |
-
);
|
424 |
-
|
425 |
-
return $rez !== false;
|
426 |
-
}
|
427 |
-
|
428 |
-
function edit_callback($matches){
|
429 |
-
$url = blcUtility::normalize_url($matches[3], $this->post_permalink);
|
430 |
-
|
431 |
-
if ($url == $this->old_url){
|
432 |
-
$this->changed_images++;
|
433 |
-
return $matches[1].$matches[2].$this->new_url.$matches[2].$matches[4].$matches[5];
|
434 |
-
} else {
|
435 |
-
return $matches[0];
|
436 |
-
}
|
437 |
-
}
|
438 |
-
|
439 |
-
function unlink( $url = null ){
|
440 |
-
global $wpdb;
|
441 |
-
|
442 |
-
if ( !$this->valid() ){
|
443 |
-
return false;
|
444 |
-
}
|
445 |
-
|
446 |
-
//If the URL isn't specified get it from the link record
|
447 |
-
if ( empty($url) ){
|
448 |
-
$url = $this->get_url();
|
449 |
-
}
|
450 |
-
|
451 |
-
//Load the post
|
452 |
-
$post = get_post($this->source_id, ARRAY_A);
|
453 |
-
if (!$post){
|
454 |
-
//FB::error('Can\'t load post ' . $this->source_id);
|
455 |
-
return false;
|
456 |
-
}
|
457 |
-
//FB::info('Post ' . $this->source_id . ' loaded successfully');
|
458 |
-
//Figure out the post's permalink - it'll be needed when normalizing relative URLs
|
459 |
-
$this->post_permalink = get_permalink( $post['ID'] );
|
460 |
-
|
461 |
-
//Find all links and remove those that match $url.
|
462 |
-
$this->old_url = $url; //used by the callback
|
463 |
-
$this->changed_images = 0;
|
464 |
-
$content = preg_replace_callback(blcUtility::img_pattern(), array(&$this, 'unlink_callback'), $post['post_content']);
|
465 |
-
|
466 |
-
if ( $this->changed_images <= 0 ){
|
467 |
-
return false;
|
468 |
-
}
|
469 |
-
|
470 |
-
//Clear the post/page cache. This ensures that any further calls to this method
|
471 |
-
//will not load the post content from the cache and thus discard the changes
|
472 |
-
//we just made.
|
473 |
-
if ( 'page' == $post['post_type'] )
|
474 |
-
clean_page_cache($this->source_id);
|
475 |
-
else
|
476 |
-
clean_post_cache($this->source_id);
|
477 |
-
|
478 |
-
//Save the modified post
|
479 |
-
$rez = $wpdb->update(
|
480 |
-
$wpdb->posts,
|
481 |
-
array( 'post_content' => $content ),
|
482 |
-
array( 'id' => $this->source_id )
|
483 |
-
);
|
484 |
-
|
485 |
-
if ( $rez !== false ){
|
486 |
-
//Delete the instance record
|
487 |
-
//FB::info("Post updated, deleting instance from DB");
|
488 |
-
return $this->forget() !== false;
|
489 |
-
} else {
|
490 |
-
//FB::error("Failed to update the post");
|
491 |
-
return false;
|
492 |
-
};
|
493 |
-
}
|
494 |
-
|
495 |
-
function unlink_callback($matches){
|
496 |
-
$url = blcUtility::normalize_url($matches[3], $this->post_permalink);
|
497 |
-
|
498 |
-
if ($url == $this->old_url){
|
499 |
-
$this->changed_images++;
|
500 |
-
return ''; //remove the image completely
|
501 |
-
} else {
|
502 |
-
return $matches[0]; //return the image unchanged
|
503 |
-
}
|
504 |
-
}
|
505 |
-
|
506 |
-
}
|
507 |
-
|
508 |
-
class blcLinkInstance_custom_field_link extends blcLinkInstance {
|
509 |
-
|
510 |
-
function edit($old_url, $new_url){
|
511 |
-
if ( !$this->valid() ){
|
512 |
-
return false;
|
513 |
-
}
|
514 |
-
|
515 |
-
//If the URL isn't specified get it from the link record
|
516 |
-
if ( empty($old_url) ){
|
517 |
-
$old_url = $this->old_url;
|
518 |
-
}
|
519 |
-
|
520 |
-
//FB::log("Changing [{$this->link_text}] to '$new_url' on post {$this->source_id}");
|
521 |
-
//Change the meta value
|
522 |
-
return update_post_meta( $this->source_id, $this->link_text, $new_url, $old_url );
|
523 |
-
}
|
524 |
-
|
525 |
-
function unlink( $url = null ){
|
526 |
-
//Get the URL from the link record if it wasn't specified
|
527 |
-
if ( empty($url) ){
|
528 |
-
$url = $this->get_url();
|
529 |
-
}
|
530 |
-
|
531 |
-
//FB::log("Removing [{$this->link_text}] from post {$this->source_id} where value is '$url'");
|
532 |
-
delete_post_meta( $this->source_id, $this->link_text, $url );
|
533 |
-
//TODO: Make unlink work for custom fields where the URL is only the first line, not the entire value
|
534 |
-
|
535 |
-
return $this->forget() !== false;
|
536 |
-
}
|
537 |
-
|
538 |
-
}
|
539 |
-
|
540 |
-
class blcLinkInstance_blogroll_link extends blcLinkInstance {
|
541 |
-
|
542 |
-
function edit($old_url, $new_url){
|
543 |
-
if ( !$this->valid() ){
|
544 |
-
return false;
|
545 |
-
}
|
546 |
-
|
547 |
-
//FB::log("Changing the bookmark [{$this->link_text}] to '$new_url'");
|
548 |
-
//Update the bookmark. Note : wp_update_link calls the edit_link hook, which is also
|
549 |
-
//hooked by the plugin for maintaining bookmark->instance integrity... Conclusion :
|
550 |
-
//don't ever call $instance->edit() in that hook!
|
551 |
-
return wp_update_link( array(
|
552 |
-
'link_id' => $this->source_id,
|
553 |
-
'link_url' => $new_url
|
554 |
-
) );
|
555 |
-
}
|
556 |
-
|
557 |
-
function unlink( $url = null ){
|
558 |
-
if ( !$this->valid() ){
|
559 |
-
return false;
|
560 |
-
}
|
561 |
-
|
562 |
-
//Get the URL from the link record if it wasn't specified
|
563 |
-
if ( empty($url) ){
|
564 |
-
$url = $this->get_url();
|
565 |
-
}
|
566 |
-
|
567 |
-
//FB::log("Removing bookmark [{$this->link_text}] ( ID : {$this->source_id} )");
|
568 |
-
//Note : wp_delete_link calls the delete_link hook, which is also used by the plugin
|
569 |
-
//for removing instances associated with links deleted through the WP link manager.
|
570 |
-
//This means that when you delete a bookmark via the plugin's interface, the plugin will
|
571 |
-
//attempt to delete it twice. Anybody have a better idea?
|
572 |
-
if ( wp_delete_link( $this->source_id ) ){
|
573 |
-
return $this->forget() !== false;
|
574 |
-
} else {
|
575 |
-
//FB::error("Failed to delete the bookmark.");
|
576 |
-
return false;
|
577 |
-
};
|
578 |
-
|
579 |
-
}
|
580 |
-
|
581 |
-
}
|
582 |
-
|
583 |
-
}//class_exists
|
584 |
-
|
585 |
-
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
js/sprintf.js
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* sprintf() for JavaScript v.0.4
|
3 |
+
*
|
4 |
+
* Copyright (c) 2007 Alexandru Marasteanu <http://alexei.417.ro/>
|
5 |
+
* Thanks to David Baird (unit test and patch).
|
6 |
+
*
|
7 |
+
* This program is free software; you can redistribute it and/or modify it under
|
8 |
+
* the terms of the GNU General Public License as published by the Free Software
|
9 |
+
* Foundation; either version 2 of the License, or (at your option) any later
|
10 |
+
* version.
|
11 |
+
*
|
12 |
+
* This program is distributed in the hope that it will be useful, but WITHOUT
|
13 |
+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
14 |
+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
15 |
+
* details.
|
16 |
+
*
|
17 |
+
* You should have received a copy of the GNU General Public License along with
|
18 |
+
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
19 |
+
* Place, Suite 330, Boston, MA 02111-1307 USA
|
20 |
+
*/
|
21 |
+
|
22 |
+
function str_repeat(i, m) { for (var o = []; m > 0; o[--m] = i); return(o.join('')); }
|
23 |
+
|
24 |
+
function sprintf () {
|
25 |
+
var i = 0, a, f = arguments[i++], o = [], m, p, c, x;
|
26 |
+
while (f) {
|
27 |
+
if (m = /^[^\x25]+/.exec(f)) o.push(m[0]);
|
28 |
+
else if (m = /^\x25{2}/.exec(f)) o.push('%');
|
29 |
+
else if (m = /^\x25(?:(\d+)\$)?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(f)) {
|
30 |
+
if (((a = arguments[m[1] || i++]) == null) || (a == undefined)) throw("Too few arguments.");
|
31 |
+
if (/[^s]/.test(m[7]) && (typeof(a) != 'number'))
|
32 |
+
throw("Expecting number but found " + typeof(a));
|
33 |
+
switch (m[7]) {
|
34 |
+
case 'b': a = a.toString(2); break;
|
35 |
+
case 'c': a = String.fromCharCode(a); break;
|
36 |
+
case 'd': a = parseInt(a); break;
|
37 |
+
case 'e': a = m[6] ? a.toExponential(m[6]) : a.toExponential(); break;
|
38 |
+
case 'f': a = m[6] ? parseFloat(a).toFixed(m[6]) : parseFloat(a); break;
|
39 |
+
case 'o': a = a.toString(8); break;
|
40 |
+
case 's': a = ((a = String(a)) && m[6] ? a.substring(0, m[6]) : a); break;
|
41 |
+
case 'u': a = Math.abs(a); break;
|
42 |
+
case 'x': a = a.toString(16); break;
|
43 |
+
case 'X': a = a.toString(16).toUpperCase(); break;
|
44 |
+
}
|
45 |
+
a = (/[def]/.test(m[7]) && m[2] && a > 0 ? '+' + a : a);
|
46 |
+
c = m[3] ? m[3] == '0' ? '0' : m[3].charAt(1) : ' ';
|
47 |
+
x = m[5] - String(a).length;
|
48 |
+
p = m[5] ? str_repeat(c, x) : '';
|
49 |
+
o.push(m[4] ? a + p : p + a);
|
50 |
+
}
|
51 |
+
else throw ("Huh ?!");
|
52 |
+
f = f.substring(m[0].length);
|
53 |
+
}
|
54 |
+
return o.join('');
|
55 |
+
}
|
languages/broken-link-checker-cs_CZ.mo
ADDED
Binary file
|
languages/broken-link-checker-cs_CZ.po
ADDED
@@ -0,0 +1,872 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Czech translation for Broken Link Checker plugin.
|
2 |
+
# Copyright (C) 2010 Janis Elsts
|
3 |
+
# This file is distributed under the same license as the Broken Link Checker package.
|
4 |
+
# Janis Elsts <whiteshadow@w-shadow.com>, 2010.
|
5 |
+
# Lelkoun <vydrus@klikni.cz>, http://lelkoun.cz/, 2010.
|
6 |
+
msgid ""
|
7 |
+
msgstr ""
|
8 |
+
"Project-Id-Version: Broken Link Checker 0.8\n"
|
9 |
+
"Report-Msgid-Bugs-To: whiteshadow@w-shadow.com\n"
|
10 |
+
"POT-Creation-Date: 2010-01-24 15:25+0000\n"
|
11 |
+
"PO-Revision-Date: 2010-03-11 00:54+0100\n"
|
12 |
+
"Last-Translator: Lelkoun <vydrus@klikni.cz>\n"
|
13 |
+
"MIME-Version: 1.0\n"
|
14 |
+
"Content-Type: text/plain; charset=utf-8\n"
|
15 |
+
"Content-Transfer-Encoding: 8bit\n"
|
16 |
+
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
17 |
+
"Language-Team: Czech <vydrus@klikni.cz>\n"
|
18 |
+
|
19 |
+
#: core.php:143
|
20 |
+
#: core.php:1835
|
21 |
+
msgid "Loading..."
|
22 |
+
msgstr "Načítání..."
|
23 |
+
|
24 |
+
#: core.php:166
|
25 |
+
#: core.php:604
|
26 |
+
msgid "[ Network error ]"
|
27 |
+
msgstr "[ Chyba sítě ]"
|
28 |
+
|
29 |
+
#: core.php:191
|
30 |
+
msgid "Automatically expand the widget if broken links have been detected"
|
31 |
+
msgstr "Automaticky rozvinout widget v případě detekování nefunkčních odkazů"
|
32 |
+
|
33 |
+
#: core.php:375
|
34 |
+
#: core.php:384
|
35 |
+
#: core.php:414
|
36 |
+
#: core.php:426
|
37 |
+
#: core.php:1014
|
38 |
+
#: core.php:1038
|
39 |
+
#: core.php:1316
|
40 |
+
#, php-format
|
41 |
+
msgid "Database error : %s"
|
42 |
+
msgstr "Chyba databáze: %s"
|
43 |
+
|
44 |
+
#: core.php:452
|
45 |
+
msgid "Link Checker Settings"
|
46 |
+
msgstr "Link Checker - Nastavení"
|
47 |
+
|
48 |
+
#: core.php:453
|
49 |
+
msgid "Link Checker"
|
50 |
+
msgstr "Link Checker"
|
51 |
+
|
52 |
+
#: core.php:459
|
53 |
+
msgid "View Broken Links"
|
54 |
+
msgstr "Zobrazit nefunkční odkazy"
|
55 |
+
|
56 |
+
#: core.php:460
|
57 |
+
#: core.php:892
|
58 |
+
msgid "Broken Links"
|
59 |
+
msgstr "Nefunkční odkazy"
|
60 |
+
|
61 |
+
#: core.php:484
|
62 |
+
msgid "Settings"
|
63 |
+
msgstr "Nastavení"
|
64 |
+
|
65 |
+
#: core.php:568
|
66 |
+
msgid "Broken Link Checker Options"
|
67 |
+
msgstr "Broken Link Checker - Nastavení"
|
68 |
+
|
69 |
+
#: core.php:581
|
70 |
+
msgid "Status"
|
71 |
+
msgstr "Status"
|
72 |
+
|
73 |
+
#: core.php:583
|
74 |
+
#: core.php:823
|
75 |
+
msgid "Show debug info"
|
76 |
+
msgstr "Zobrazit ladící informace"
|
77 |
+
|
78 |
+
#: core.php:617
|
79 |
+
msgid "Re-check all pages"
|
80 |
+
msgstr "Překontrolovat všechny stránky"
|
81 |
+
|
82 |
+
#: core.php:641
|
83 |
+
msgid "Check each link"
|
84 |
+
msgstr "Zkontrolovat každý odkaz"
|
85 |
+
|
86 |
+
#: core.php:646
|
87 |
+
#, php-format
|
88 |
+
msgid "Every %s hours"
|
89 |
+
msgstr "Každých %s hodin"
|
90 |
+
|
91 |
+
#: core.php:655
|
92 |
+
msgid "Existing links will be checked this often. New links will usually be checked ASAP."
|
93 |
+
msgstr "Existující odkazy budou kontrolovány v určeném intervalu. Nové odkazy budou zkontrolovány hned, jak to bude možné."
|
94 |
+
|
95 |
+
#: core.php:662
|
96 |
+
msgid "Broken link CSS"
|
97 |
+
msgstr "CSS nefunkčního odkazu"
|
98 |
+
|
99 |
+
#: core.php:667
|
100 |
+
msgid "Apply <em>class=\"broken_link\"</em> to broken links"
|
101 |
+
msgstr "Přidat <em>class=\"broken_link\"</em> k nefunkčním odkazům"
|
102 |
+
|
103 |
+
#: core.php:679
|
104 |
+
msgid "Removed link CSS"
|
105 |
+
msgstr "CSS odstraněného odkazu"
|
106 |
+
|
107 |
+
#: core.php:684
|
108 |
+
msgid "Apply <em>class=\"removed_link\"</em> to unlinked links"
|
109 |
+
msgstr "Přidat <em>class=\"removed_link\"</em> k odstraněným odkazům"
|
110 |
+
|
111 |
+
#: core.php:696
|
112 |
+
msgid "Exclusion list"
|
113 |
+
msgstr "Seznam výjimek"
|
114 |
+
|
115 |
+
#: core.php:697
|
116 |
+
msgid "Don't check links where the URL contains any of these words (one per line) :"
|
117 |
+
msgstr "Nekontrolovat odkazy, kde URL adresa obsahuje nějaký z těchto výrazů (jeden na řádek):"
|
118 |
+
|
119 |
+
#: core.php:707
|
120 |
+
msgid "Custom fields"
|
121 |
+
msgstr "Uživatelské pole"
|
122 |
+
|
123 |
+
#: core.php:708
|
124 |
+
msgid "Check URLs entered in these custom fields (one per line) :"
|
125 |
+
msgstr "Kontrolovat URL adresy v tomto poli (jednu na řádek):"
|
126 |
+
|
127 |
+
#: core.php:719
|
128 |
+
msgid "Advanced"
|
129 |
+
msgstr "Pokročilé"
|
130 |
+
|
131 |
+
#: core.php:725
|
132 |
+
msgid "Timeout"
|
133 |
+
msgstr "Čas vypršení"
|
134 |
+
|
135 |
+
#: core.php:731
|
136 |
+
#: core.php:787
|
137 |
+
#, php-format
|
138 |
+
msgid "%s seconds"
|
139 |
+
msgstr "%s sekund"
|
140 |
+
|
141 |
+
#: core.php:740
|
142 |
+
msgid "Links that take longer than this to load will be marked as broken."
|
143 |
+
msgstr "Odkazy, jejichž načtení bude trvat delší dobu než tuto, budou označeny jako nefunkční."
|
144 |
+
|
145 |
+
#: core.php:749
|
146 |
+
msgid "Custom temporary directory"
|
147 |
+
msgstr "Uživatelský dočasný adresář"
|
148 |
+
|
149 |
+
#: core.php:758
|
150 |
+
#: core.php:2792
|
151 |
+
msgid "OK"
|
152 |
+
msgstr "OK"
|
153 |
+
|
154 |
+
#: core.php:761
|
155 |
+
msgid "Error : This directory isn't writable by PHP."
|
156 |
+
msgstr "Chyba: Tento adresář není zapisovatelný jazykem PHP."
|
157 |
+
|
158 |
+
#: core.php:766
|
159 |
+
msgid "Error : This directory doesn't exist."
|
160 |
+
msgstr "Chyba: Tento adresář neexistuje."
|
161 |
+
|
162 |
+
#: core.php:774
|
163 |
+
msgid "Set this field if you want the plugin to use a custom directory for its lockfiles. Otherwise, leave it blank."
|
164 |
+
msgstr "Nastavte toto pole, pokud chcete použít uživatelský adresář pro ukládání zamykacích souborů. Jinak jej nechte prázdné."
|
165 |
+
|
166 |
+
#: core.php:781
|
167 |
+
msgid "Max. execution time"
|
168 |
+
msgstr "Max. čas provádění"
|
169 |
+
|
170 |
+
#: core.php:798
|
171 |
+
msgid "The plugin works by periodically creating a background worker instance that parses your posts looking for links, checks the discovered URLs, and performs other time-consuming tasks. Here you can set for how long, at most, the background instance may run each time before stopping."
|
172 |
+
msgstr "Plugin pracuje na principu periodického vytváření pracovní instance na pozadí, která hledá odkazy ve vašich příspěvcích, kontroluje objevené URL adresy a vykonává další časově náročné úkoly. Zde můžete nastavit, jakou maximální dobu bude instance na pozadí pracovat každou periodu, než bude zastavena."
|
173 |
+
|
174 |
+
#: core.php:808
|
175 |
+
msgid "Save Changes"
|
176 |
+
msgstr "Uložit změny"
|
177 |
+
|
178 |
+
#: core.php:821
|
179 |
+
msgid "Hide debug info"
|
180 |
+
msgstr "Skrýt ladící informace"
|
181 |
+
|
182 |
+
#: core.php:891
|
183 |
+
msgid "Broken"
|
184 |
+
msgstr "Nefunkční"
|
185 |
+
|
186 |
+
#: core.php:893
|
187 |
+
msgid "No broken links found"
|
188 |
+
msgstr "Nebyly nalezeny žádné nefunkční odkazy."
|
189 |
+
|
190 |
+
#: core.php:897
|
191 |
+
msgid "Redirects"
|
192 |
+
msgstr "Přesměrování"
|
193 |
+
|
194 |
+
#: core.php:898
|
195 |
+
msgid "Redirected Links"
|
196 |
+
msgstr "Přesměrované odkazy"
|
197 |
+
|
198 |
+
#: core.php:899
|
199 |
+
msgid "No redirects found"
|
200 |
+
msgstr "Nebyla nalezena žádná přesměrování"
|
201 |
+
|
202 |
+
#: core.php:904
|
203 |
+
msgid "All"
|
204 |
+
msgstr "Všechno"
|
205 |
+
|
206 |
+
#: core.php:905
|
207 |
+
msgid "Detected Links"
|
208 |
+
msgstr "Odstraněné odkazy"
|
209 |
+
|
210 |
+
#: core.php:906
|
211 |
+
msgid "No links found (yet)"
|
212 |
+
msgstr "Ještě nebyly nalezeny žádné odkazy"
|
213 |
+
|
214 |
+
#: core.php:933
|
215 |
+
#: core.php:1281
|
216 |
+
msgid "No links found for your query"
|
217 |
+
msgstr "Nebyly nalezeny žádné odkazy na váš dotaz"
|
218 |
+
|
219 |
+
#: core.php:994
|
220 |
+
msgid "You must enter a filter name!"
|
221 |
+
msgstr "Musíte zadat jméno filtru!"
|
222 |
+
|
223 |
+
#: core.php:998
|
224 |
+
msgid "Invalid search query."
|
225 |
+
msgstr "Nevalidní hledací dotaz."
|
226 |
+
|
227 |
+
#: core.php:1009
|
228 |
+
#, php-format
|
229 |
+
msgid "Filter \"%s\" created"
|
230 |
+
msgstr "Filtr \"%s\" byl vytvořen."
|
231 |
+
|
232 |
+
#: core.php:1026
|
233 |
+
msgid "Filter ID not specified."
|
234 |
+
msgstr "ID filtru nebylo specifikováno."
|
235 |
+
|
236 |
+
#: core.php:1035
|
237 |
+
msgid "Filter deleted"
|
238 |
+
msgstr "Filtr byl smazán"
|
239 |
+
|
240 |
+
#: core.php:1084
|
241 |
+
#, php-format
|
242 |
+
msgid "Failed to delete post \"%s\" (%d)"
|
243 |
+
msgstr "Selhalo smazání příspěvku \"%s\" (%d)"
|
244 |
+
|
245 |
+
#: core.php:1097
|
246 |
+
#, php-format
|
247 |
+
msgid "%d post moved to the trash"
|
248 |
+
msgid_plural "%d posts moved to the trash"
|
249 |
+
msgstr[0] "%d příspěvek byl přesunut do koše"
|
250 |
+
msgstr[1] "%d příspěvků bylo přesunuto do koše"
|
251 |
+
|
252 |
+
#: core.php:1099
|
253 |
+
#, php-format
|
254 |
+
msgid "%d post deleted"
|
255 |
+
msgid_plural "%d posts deleted"
|
256 |
+
msgstr[0] "%d příspěvek byl smazán"
|
257 |
+
msgstr[1] "%d příspěvků bylo smazán"
|
258 |
+
|
259 |
+
#: core.php:1134
|
260 |
+
#, php-format
|
261 |
+
msgid "Failed to delete blogroll link \"%s\" (%d)"
|
262 |
+
msgstr "Selhalo smazání odkazu \"%s\" (%d)"
|
263 |
+
|
264 |
+
#: core.php:1144
|
265 |
+
#, php-format
|
266 |
+
msgid "%d blogroll link deleted"
|
267 |
+
msgid_plural "%d blogroll links deleted"
|
268 |
+
msgstr[0] "%d odkaz byl smazán"
|
269 |
+
msgstr[1] "%d odkazů bylo smazáno"
|
270 |
+
|
271 |
+
#: core.php:1153
|
272 |
+
msgid "Didn't find anything to delete!"
|
273 |
+
msgstr "Nebylo nalezeno nic, co by se mohlo smazat!"
|
274 |
+
|
275 |
+
#: core.php:1191
|
276 |
+
#, php-format
|
277 |
+
msgid "%d link removed"
|
278 |
+
msgid_plural "%d links removed"
|
279 |
+
msgstr[0] "%d odkaz byl odstraněn."
|
280 |
+
msgstr[1] "%d odkazů bylo odstraněno"
|
281 |
+
|
282 |
+
#: core.php:1202
|
283 |
+
#, php-format
|
284 |
+
msgid "Failed to remove %d link"
|
285 |
+
msgid_plural "Failed to remove %d links"
|
286 |
+
msgstr[0] "Selhalo odstranění %d odkazu"
|
287 |
+
msgstr[1] "Selhalo odstranění %d odkazů"
|
288 |
+
|
289 |
+
#: core.php:1243
|
290 |
+
#, php-format
|
291 |
+
msgid "Replaced %d redirect with a direct link"
|
292 |
+
msgid_plural "Replaced %d redirects with direct links"
|
293 |
+
msgstr[0] "Nahrazeno %d přesměrování přímým odkazem"
|
294 |
+
msgstr[1] "Nahrazeno %d přesměrování přímými odkazy"
|
295 |
+
|
296 |
+
#: core.php:1254
|
297 |
+
#, php-format
|
298 |
+
msgid "Failed to fix %d redirect"
|
299 |
+
msgid_plural "Failed to fix %d redirects"
|
300 |
+
msgstr[0] "Selhalo opravení %d přesměrování"
|
301 |
+
msgstr[1] "Selhalo opravení %d přesměrování"
|
302 |
+
|
303 |
+
#: core.php:1264
|
304 |
+
msgid "None of the selected links are redirects!"
|
305 |
+
msgstr "Žádný z vybraných odkazů není přesměrován!"
|
306 |
+
|
307 |
+
#: core.php:1279
|
308 |
+
#: core.php:1400
|
309 |
+
msgid "Search"
|
310 |
+
msgstr "Hledat"
|
311 |
+
|
312 |
+
#: core.php:1280
|
313 |
+
msgid "Search Results"
|
314 |
+
msgstr "Výsledky hledání"
|
315 |
+
|
316 |
+
#: core.php:1384
|
317 |
+
msgid "Save This Search As a Filter"
|
318 |
+
msgstr "Uložit toto hledání jako filtr"
|
319 |
+
|
320 |
+
#: core.php:1394
|
321 |
+
msgid "Delete This Filter"
|
322 |
+
msgstr "Smazat tento filtr"
|
323 |
+
|
324 |
+
#: core.php:1410
|
325 |
+
msgid "Link text"
|
326 |
+
msgstr "Text odkazu"
|
327 |
+
|
328 |
+
#: core.php:1413
|
329 |
+
#: core.php:1526
|
330 |
+
msgid "URL"
|
331 |
+
msgstr "URL"
|
332 |
+
|
333 |
+
#: core.php:1416
|
334 |
+
#: core.php:2141
|
335 |
+
msgid "HTTP code"
|
336 |
+
msgstr "HTTP kód"
|
337 |
+
|
338 |
+
#: core.php:1419
|
339 |
+
msgid "Link status"
|
340 |
+
msgstr "Status odkazu"
|
341 |
+
|
342 |
+
#: core.php:1435
|
343 |
+
msgid "Link type"
|
344 |
+
msgstr "Typ odkazu"
|
345 |
+
|
346 |
+
#: core.php:1439
|
347 |
+
msgid "Any"
|
348 |
+
msgstr "Žádný"
|
349 |
+
|
350 |
+
#: core.php:1440
|
351 |
+
msgid "Normal link"
|
352 |
+
msgstr "Normální odkaz"
|
353 |
+
|
354 |
+
#: core.php:1441
|
355 |
+
#: core.php:1602
|
356 |
+
msgid "Image"
|
357 |
+
msgstr "Obrázek"
|
358 |
+
|
359 |
+
#: core.php:1442
|
360 |
+
#: core.php:1613
|
361 |
+
msgid "Custom field"
|
362 |
+
msgstr "Uživatelské pole"
|
363 |
+
|
364 |
+
#: core.php:1443
|
365 |
+
#: core.php:1621
|
366 |
+
msgid "Bookmark"
|
367 |
+
msgstr "Záložka"
|
368 |
+
|
369 |
+
#: core.php:1456
|
370 |
+
msgid "Search Links"
|
371 |
+
msgstr "Hledat odkazy"
|
372 |
+
|
373 |
+
#: core.php:1457
|
374 |
+
#: core.php:1654
|
375 |
+
msgid "Cancel"
|
376 |
+
msgstr "Zrušit"
|
377 |
+
|
378 |
+
#: core.php:1473
|
379 |
+
msgid "Bulk Actions"
|
380 |
+
msgstr "Hromadné akce"
|
381 |
+
|
382 |
+
#: core.php:1474
|
383 |
+
#: core.php:1639
|
384 |
+
#: core.php:1922
|
385 |
+
msgid "Unlink"
|
386 |
+
msgstr "Odstranit odkaz"
|
387 |
+
|
388 |
+
#: core.php:1475
|
389 |
+
msgid "Fix redirects"
|
390 |
+
msgstr "Opravit přesměrování"
|
391 |
+
|
392 |
+
#: core.php:1476
|
393 |
+
msgid "Delete sources"
|
394 |
+
msgstr "Smazat zdroje"
|
395 |
+
|
396 |
+
#: core.php:1490
|
397 |
+
#: core.php:1686
|
398 |
+
msgid "Apply"
|
399 |
+
msgstr "Aplikovat"
|
400 |
+
|
401 |
+
#: core.php:1497
|
402 |
+
msgid "«"
|
403 |
+
msgstr "«"
|
404 |
+
|
405 |
+
#: core.php:1498
|
406 |
+
msgid "»"
|
407 |
+
msgstr "»"
|
408 |
+
|
409 |
+
#: core.php:1505
|
410 |
+
#: core.php:1692
|
411 |
+
#, php-format
|
412 |
+
msgid "Displaying %s–%s of <span class=\"current-link-count\">%s</span>"
|
413 |
+
msgstr "Zobrazeno %s–%s z <span class=\"current-link-count\">%s</span>"
|
414 |
+
|
415 |
+
#: core.php:1524
|
416 |
+
msgid "Source"
|
417 |
+
msgstr "Zdroj"
|
418 |
+
|
419 |
+
#: core.php:1525
|
420 |
+
msgid "Link Text"
|
421 |
+
msgstr "Text odkazu"
|
422 |
+
|
423 |
+
#: core.php:1557
|
424 |
+
#: core.php:1563
|
425 |
+
msgid "Edit this post"
|
426 |
+
msgstr "Upravit tento příspěvek"
|
427 |
+
|
428 |
+
#: core.php:1563
|
429 |
+
#: core.php:1578
|
430 |
+
msgid "Edit"
|
431 |
+
msgstr "Upravit"
|
432 |
+
|
433 |
+
#: core.php:1564
|
434 |
+
msgid "Delete this post"
|
435 |
+
msgstr "Smazat tento příspěvek"
|
436 |
+
|
437 |
+
#: core.php:1564
|
438 |
+
#, php-format
|
439 |
+
msgid ""
|
440 |
+
"You are about to delete this post '%s'\n"
|
441 |
+
" 'Cancel' to stop, 'OK' to delete."
|
442 |
+
msgstr ""
|
443 |
+
"Chystáte se smazat tento příspěvek '%s'\n"
|
444 |
+
" Klikněte na 'Cancel' pro zrušení, 'OK' pro smazání."
|
445 |
+
|
446 |
+
#: core.php:1564
|
447 |
+
#: core.php:1579
|
448 |
+
msgid "Delete"
|
449 |
+
msgstr "Smazat"
|
450 |
+
|
451 |
+
#: core.php:1566
|
452 |
+
#, php-format
|
453 |
+
msgid "View \"%s\""
|
454 |
+
msgstr "Zobrazit \"%s\""
|
455 |
+
|
456 |
+
#: core.php:1566
|
457 |
+
msgid "View"
|
458 |
+
msgstr "Zobrazit"
|
459 |
+
|
460 |
+
#: core.php:1573
|
461 |
+
#: core.php:1578
|
462 |
+
msgid "Edit this bookmark"
|
463 |
+
msgstr "Upravit tuto záložku"
|
464 |
+
|
465 |
+
#: core.php:1579
|
466 |
+
#, php-format
|
467 |
+
msgid ""
|
468 |
+
"You are about to delete this link '%s'\n"
|
469 |
+
" 'Cancel' to stop, 'OK' to delete."
|
470 |
+
msgstr ""
|
471 |
+
"Chystáte se smazat tento odkaz '%s'\n"
|
472 |
+
" Klikněte na 'Cancel' pro zrušení, 'OK' pro smazání."
|
473 |
+
|
474 |
+
#: core.php:1588
|
475 |
+
msgid "[An orphaned link! This is a bug.]"
|
476 |
+
msgstr "[Osiřelý odkaz! Toto je chyba programu.]"
|
477 |
+
|
478 |
+
#: core.php:1636
|
479 |
+
msgid "Show more info about this link"
|
480 |
+
msgstr "Ukázat více informací o tomto odkazu"
|
481 |
+
|
482 |
+
#: core.php:1636
|
483 |
+
#: core.php:3085
|
484 |
+
msgid "Details"
|
485 |
+
msgstr "Detaily"
|
486 |
+
|
487 |
+
#: core.php:1638
|
488 |
+
msgid "Remove this link from all posts"
|
489 |
+
msgstr "Odstranit tento odkaz ze všech příspěvků"
|
490 |
+
|
491 |
+
#: core.php:1642
|
492 |
+
#: core.php:1952
|
493 |
+
#: core.php:1963
|
494 |
+
msgid "Excluded"
|
495 |
+
msgstr "Vynechán"
|
496 |
+
|
497 |
+
#: core.php:1644
|
498 |
+
msgid "Add this URL to the exclusion list"
|
499 |
+
msgstr "Přidat tuto URL adresu do seznamu výjimek"
|
500 |
+
|
501 |
+
#: core.php:1645
|
502 |
+
#: core.php:1966
|
503 |
+
msgid "Exclude"
|
504 |
+
msgstr "Vynechat"
|
505 |
+
|
506 |
+
#: core.php:1648
|
507 |
+
msgid "Edit link URL"
|
508 |
+
msgstr "Upravit URL adresu odkazu"
|
509 |
+
|
510 |
+
#: core.php:1648
|
511 |
+
#: core.php:1863
|
512 |
+
#: core.php:1891
|
513 |
+
msgid "Edit URL"
|
514 |
+
msgstr "Upravit URL"
|
515 |
+
|
516 |
+
#: core.php:1654
|
517 |
+
msgid "Cancel URL editing"
|
518 |
+
msgstr "Zrušit upravování URL adresy"
|
519 |
+
|
520 |
+
#: core.php:1668
|
521 |
+
msgid "Remove this link from the list of broken links and mark it as valid"
|
522 |
+
msgstr "Odstranit tento odkaz ze seznamu nefunkčních odkazů a označit jako validní"
|
523 |
+
|
524 |
+
#: core.php:1670
|
525 |
+
#: core.php:1755
|
526 |
+
msgid "Discard"
|
527 |
+
msgstr "Zrušit"
|
528 |
+
|
529 |
+
#: core.php:1731
|
530 |
+
#: core.php:1898
|
531 |
+
#: core.php:1935
|
532 |
+
msgid "Wait..."
|
533 |
+
msgstr "Čekejte..."
|
534 |
+
|
535 |
+
#: core.php:1789
|
536 |
+
msgid "Save URL"
|
537 |
+
msgstr "Uložit URL"
|
538 |
+
|
539 |
+
#: core.php:1799
|
540 |
+
msgid "Saving changes..."
|
541 |
+
msgstr "Ukládání změn..."
|
542 |
+
|
543 |
+
#: core.php:2011
|
544 |
+
msgid "Enter a name for the new custom filter"
|
545 |
+
msgstr "Zadejte jméno pro nový uživatelský filtr"
|
546 |
+
|
547 |
+
#: core.php:2022
|
548 |
+
msgid ""
|
549 |
+
"You are about to delete the current filter.\n"
|
550 |
+
"'Cancel' to stop, 'OK' to delete"
|
551 |
+
msgstr ""
|
552 |
+
"Chystáte se smazat současný filtr '%s'\n"
|
553 |
+
" Klikněte na 'Cancel' pro zrušení, 'OK' pro smazání."
|
554 |
+
|
555 |
+
#: core.php:2118
|
556 |
+
msgid "Log"
|
557 |
+
msgstr "Záznam"
|
558 |
+
|
559 |
+
#: core.php:2126
|
560 |
+
msgid "Post published on"
|
561 |
+
msgstr "Příspěvek publikován"
|
562 |
+
|
563 |
+
#: core.php:2131
|
564 |
+
msgid "Link last checked"
|
565 |
+
msgstr "Poslední kontrola odkazu"
|
566 |
+
|
567 |
+
#: core.php:2135
|
568 |
+
msgid "Never"
|
569 |
+
msgstr "Nikdy"
|
570 |
+
|
571 |
+
#: core.php:2146
|
572 |
+
msgid "Response time"
|
573 |
+
msgstr "Čas odpovědi"
|
574 |
+
|
575 |
+
#: core.php:2148
|
576 |
+
#, php-format
|
577 |
+
msgid "%2.3f seconds"
|
578 |
+
msgstr "%2.3f sekund"
|
579 |
+
|
580 |
+
#: core.php:2151
|
581 |
+
msgid "Final URL"
|
582 |
+
msgstr "Konečné URL"
|
583 |
+
|
584 |
+
#: core.php:2156
|
585 |
+
msgid "Redirect count"
|
586 |
+
msgstr "Počet přesměrování"
|
587 |
+
|
588 |
+
#: core.php:2161
|
589 |
+
msgid "Instance count"
|
590 |
+
msgstr "Počet instancí"
|
591 |
+
|
592 |
+
#: core.php:2170
|
593 |
+
#, php-format
|
594 |
+
msgid "This link has failed %d time."
|
595 |
+
msgid_plural "This link has failed %d times."
|
596 |
+
msgstr[0] "Tento link selhal %d x."
|
597 |
+
msgstr[1] "Tento link selhal %d x."
|
598 |
+
|
599 |
+
#: core.php:2580
|
600 |
+
#: core.php:2910
|
601 |
+
msgid "This link wasn't checked because a matching keyword was found on your exclusion list."
|
602 |
+
msgstr "Tento odkaz nebyl zkontrolován kvůli klíčovému slovu nalezenému ve vašem seznam výjimek."
|
603 |
+
|
604 |
+
#: core.php:2622
|
605 |
+
msgid "View broken links"
|
606 |
+
msgstr "Zobrazit nefunkční odkazy"
|
607 |
+
|
608 |
+
#: core.php:2623
|
609 |
+
#, php-format
|
610 |
+
msgid "Found %d broken link"
|
611 |
+
msgid_plural "Found %d broken links"
|
612 |
+
msgstr[0] "Nalezen %d nefunkční odkaz"
|
613 |
+
msgstr[1] "Nalezeno %d nefunkčních odkazů"
|
614 |
+
|
615 |
+
#: core.php:2629
|
616 |
+
msgid "No broken links found."
|
617 |
+
msgstr "Nebyly nalezeny žádné nefunkční odkazy."
|
618 |
+
|
619 |
+
#: core.php:2636
|
620 |
+
#, php-format
|
621 |
+
msgid "%d URL in the work queue"
|
622 |
+
msgid_plural "%d URLs in the work queue"
|
623 |
+
msgstr[0] "%d URL adresa ve frontě"
|
624 |
+
msgstr[1] "%d URL adres ve frontě"
|
625 |
+
|
626 |
+
#: core.php:2639
|
627 |
+
msgid "No URLs in the work queue."
|
628 |
+
msgstr "Žádná URL adresa není ve frontě."
|
629 |
+
|
630 |
+
#: core.php:2645
|
631 |
+
#, php-format
|
632 |
+
msgid "Detected %d unique URL"
|
633 |
+
msgid_plural "Detected %d unique URLs"
|
634 |
+
msgstr[0] "Nalezena %d unikátní URL adresa"
|
635 |
+
msgstr[1] "Nalezeno %d unikátních URL adres"
|
636 |
+
|
637 |
+
#: core.php:2646
|
638 |
+
#, php-format
|
639 |
+
msgid "in %d link"
|
640 |
+
msgid_plural "in %d links"
|
641 |
+
msgstr[0] "v %d odkazu"
|
642 |
+
msgstr[1] "v %d odkazech"
|
643 |
+
|
644 |
+
#: core.php:2651
|
645 |
+
msgid "and still searching..."
|
646 |
+
msgstr "a pořád se hledá...."
|
647 |
+
|
648 |
+
#: core.php:2657
|
649 |
+
msgid "Searching your blog for links..."
|
650 |
+
msgstr "Hledání odkazů ve vašem blogu..."
|
651 |
+
|
652 |
+
#: core.php:2659
|
653 |
+
msgid "No links detected."
|
654 |
+
msgstr "Žádné odkazy nebyly zjištěny"
|
655 |
+
|
656 |
+
#: core.php:2731
|
657 |
+
#: core.php:2763
|
658 |
+
#: core.php:2806
|
659 |
+
#: core.php:2887
|
660 |
+
msgid "You're not allowed to do that!"
|
661 |
+
msgstr "Nejste oprávněni toto dělat!"
|
662 |
+
|
663 |
+
#: core.php:2739
|
664 |
+
#: core.php:2773
|
665 |
+
#: core.php:2816
|
666 |
+
#: core.php:2897
|
667 |
+
#, php-format
|
668 |
+
msgid "Oops, I can't find the link %d"
|
669 |
+
msgstr "Jejda, nemůžu najít odkaz %d"
|
670 |
+
|
671 |
+
#: core.php:2747
|
672 |
+
msgid "This link was manually marked as working by the user."
|
673 |
+
msgstr "Tento odkaz byl uživatelem manuálně označen jako funkční"
|
674 |
+
|
675 |
+
#: core.php:2753
|
676 |
+
msgid "Oops, couldn't modify the link!"
|
677 |
+
msgstr "Jejda, nemohl jsem upravit odkaz!"
|
678 |
+
|
679 |
+
#: core.php:2756
|
680 |
+
#: core.php:2833
|
681 |
+
msgid "Error : link_id not specified"
|
682 |
+
msgstr "Chyba: link_id nebyl specifikován"
|
683 |
+
|
684 |
+
#: core.php:2780
|
685 |
+
msgid "Oops, the new URL is invalid!"
|
686 |
+
msgstr "Jejda, nová URL adresa je nevalidní!"
|
687 |
+
|
688 |
+
#: core.php:2789
|
689 |
+
msgid "An unexpected error occured!"
|
690 |
+
msgstr "Nastala neočekávaná chyba!"
|
691 |
+
|
692 |
+
#: core.php:2798
|
693 |
+
msgid "Error : link_id or new_url not specified"
|
694 |
+
msgstr "Chyba: link_id nebo new_url nebylo specifikováno"
|
695 |
+
|
696 |
+
#: core.php:2823
|
697 |
+
#, php-format
|
698 |
+
msgid "URL %s was removed."
|
699 |
+
msgstr "URL adresa %s byla odstraněna"
|
700 |
+
|
701 |
+
#: core.php:2827
|
702 |
+
msgid "The plugin failed to remove the link."
|
703 |
+
msgstr "Plugin selhal při odstraňování odkazu."
|
704 |
+
|
705 |
+
#: core.php:2842
|
706 |
+
msgid "You don't have sufficient privileges to access this information!"
|
707 |
+
msgstr "Nemáte dostatečná práva k zpřístupnění těchto informací!"
|
708 |
+
|
709 |
+
#: core.php:2855
|
710 |
+
msgid "Error : link ID not specified"
|
711 |
+
msgstr "Chyba: ID odkazu nebylo specifikováno"
|
712 |
+
|
713 |
+
#: core.php:2879
|
714 |
+
#, php-format
|
715 |
+
msgid "Failed to load link details (%s)"
|
716 |
+
msgstr "Selhalo načtení detailů odkazu (%s)"
|
717 |
+
|
718 |
+
#: core.php:2917
|
719 |
+
#, php-format
|
720 |
+
msgid "URL %s added to the exclusion list"
|
721 |
+
msgstr "URL adresa %s byla přidána na seznam výjimek"
|
722 |
+
|
723 |
+
#: core.php:2921
|
724 |
+
msgid "Link ID not specified"
|
725 |
+
msgstr "ID odkazu nebylo specifikováno"
|
726 |
+
|
727 |
+
#: core.php:3071
|
728 |
+
#, php-format
|
729 |
+
msgid "The current temporary directory is not accessible; please <a href=\"%s\">set a different one</a>."
|
730 |
+
msgstr "Stávající dočasný adresář je nepřístupný; <a href=\"%s\">zvolte jiný</a>, prosím."
|
731 |
+
|
732 |
+
#: core.php:3076
|
733 |
+
#, php-format
|
734 |
+
msgid "Please make the directory <code>%1$s</code> writable by plugins or <a href=\"%2$s\">set a custom temporary directory</a>."
|
735 |
+
msgstr "Učiňte adresář <code>%1$s</code> zapisovatelným pro pluginy nebo <a href=\"%2$s\">nastavte uživatelský dočasný adresář</a>."
|
736 |
+
|
737 |
+
#: core.php:3083
|
738 |
+
msgid "Broken Link Checker can't create a lockfile."
|
739 |
+
msgstr "Broken Link Checker nemůže vytvořit zamykací soubor."
|
740 |
+
|
741 |
+
#: core.php:3088
|
742 |
+
msgid "The plugin uses a file-based locking mechanism to ensure that only one instance of the resource-heavy link checking algorithm is running at any given time. Unfortunately, BLC can't find a writable directory where it could store the lockfile - it failed to detect the location of your server's temporary directory, and the plugin's own directory isn't writable by PHP. To fix this problem, please make the plugin's directory writable or enter a specify a custom temporary directory in the plugin's settings."
|
743 |
+
msgstr "Plugin používá souborově založený zamykací mechanismus k zaručení vykonávání činnosti pouze jedné instance zdrojově náročného odkazy kontrolujícího algoritmu v dané době. Bohužel, BLC nemůže najít zapisovatelný adresář, kde by mohl skladovat zamykací soubory - selhalo zjištění pozice dočasného adresáře vašeho serveru a vlastní adresář pluginu není zapisovatelný jazykem PHP. K opravení tohoto problému učiňte adresář pluginu zapisovatelným nebo zadejte specifický uživatelský dočasný adresář v nastavení pluginu."
|
744 |
+
|
745 |
+
#: core.php:3108
|
746 |
+
msgid "PHP version"
|
747 |
+
msgstr "Verze PHP"
|
748 |
+
|
749 |
+
#: core.php:3114
|
750 |
+
msgid "MySQL version"
|
751 |
+
msgstr "Verze MySQL"
|
752 |
+
|
753 |
+
#: core.php:3127
|
754 |
+
msgid "You have an old version of CURL. Redirect detection may not work properly."
|
755 |
+
msgstr "Máte starou verzi CURL. Detekce přesměrování nemusí fungovat správně."
|
756 |
+
|
757 |
+
#: core.php:3139
|
758 |
+
#: core.php:3155
|
759 |
+
#: core.php:3160
|
760 |
+
msgid "Not installed"
|
761 |
+
msgstr "Nenainstalováno"
|
762 |
+
|
763 |
+
#: core.php:3142
|
764 |
+
msgid "CURL version"
|
765 |
+
msgstr "Verze CURL"
|
766 |
+
|
767 |
+
#: core.php:3148
|
768 |
+
msgid "Installed"
|
769 |
+
msgstr "Nainstalováno"
|
770 |
+
|
771 |
+
#: core.php:3161
|
772 |
+
msgid "You must have either CURL or Snoopy installed for the plugin to work!"
|
773 |
+
msgstr "Musíte mít nainstalovaný buď CURL anebo Snoopy, aby plugin pracoval!"
|
774 |
+
|
775 |
+
#: core.php:3172
|
776 |
+
msgid "On"
|
777 |
+
msgstr "Zapnuto"
|
778 |
+
|
779 |
+
#: core.php:3173
|
780 |
+
msgid "Redirects may be detected as broken links when safe_mode is on."
|
781 |
+
msgstr "Když je safe_mode zapnutý, může být přesměrování detekováno jako nefunkční odkaz."
|
782 |
+
|
783 |
+
#: core.php:3178
|
784 |
+
#: core.php:3192
|
785 |
+
msgid "Off"
|
786 |
+
msgstr "Vypnuto"
|
787 |
+
|
788 |
+
#: core.php:3186
|
789 |
+
#, php-format
|
790 |
+
msgid "On ( %s )"
|
791 |
+
msgstr "Zapnuto ( %s )"
|
792 |
+
|
793 |
+
#: core.php:3187
|
794 |
+
msgid "Redirects may be detected as broken links when open_basedir is on."
|
795 |
+
msgstr "Když je open_basedir zapnutý, může být přesměrování detekováno jako nefunkční odkaz."
|
796 |
+
|
797 |
+
#: core.php:3206
|
798 |
+
msgid "Can't create a lockfile. Please specify a custom temporary directory."
|
799 |
+
msgstr "Nemůže být vytvořen zamykací soubor. Specifikujte uživatelský dočasný adresář, prosím."
|
800 |
+
|
801 |
+
#: link-classes.php:212
|
802 |
+
#, php-format
|
803 |
+
msgid "First try : %d"
|
804 |
+
msgstr "První pokus: %d"
|
805 |
+
|
806 |
+
#: link-classes.php:214
|
807 |
+
msgid "First try : 0 (No response)"
|
808 |
+
msgstr "První pokus: 0 (žádná reakce)"
|
809 |
+
|
810 |
+
#: link-classes.php:222
|
811 |
+
msgid "Trying a second time with different settings..."
|
812 |
+
msgstr "Zkouším podruhé s odlišným nastavením..."
|
813 |
+
|
814 |
+
#: link-classes.php:237
|
815 |
+
#, php-format
|
816 |
+
msgid "Second try : %d"
|
817 |
+
msgstr "Druhý pokus: %d"
|
818 |
+
|
819 |
+
#: link-classes.php:239
|
820 |
+
msgid "Second try : 0 (No response)"
|
821 |
+
msgstr "Druhý pokus: 0 (žádná reakce)"
|
822 |
+
|
823 |
+
#: link-classes.php:265
|
824 |
+
msgid "Using Snoopy"
|
825 |
+
msgstr "Používám Snoopy"
|
826 |
+
|
827 |
+
#: link-classes.php:285
|
828 |
+
msgid "Request timed out."
|
829 |
+
msgstr "Žádost vypršela."
|
830 |
+
|
831 |
+
#: link-classes.php:304
|
832 |
+
msgid "Link is valid."
|
833 |
+
msgstr "Odkaz je v pořádku."
|
834 |
+
|
835 |
+
#: link-classes.php:309
|
836 |
+
msgid "Link is broken."
|
837 |
+
msgstr "Odkaz je nefunkční."
|
838 |
+
|
839 |
+
#: link-classes.php:313
|
840 |
+
msgid "Most likely the connection timed out or the domain doesn't exist."
|
841 |
+
msgstr "S největší pravděpodobností vypršel časový limit nebo doména neexistuje."
|
842 |
+
|
843 |
+
#: link-classes.php:354
|
844 |
+
#, php-format
|
845 |
+
msgid "Error adding link %s : %s"
|
846 |
+
msgstr "Chyba přidávání odkazu: %s : %s"
|
847 |
+
|
848 |
+
#: link-classes.php:374
|
849 |
+
#, php-format
|
850 |
+
msgid "Error updating link %d : %s"
|
851 |
+
msgstr "Chyba aktualizace odkazu: %d : %s"
|
852 |
+
|
853 |
+
#. Plugin Name of an extension
|
854 |
+
msgid "Broken Link Checker"
|
855 |
+
msgstr "Broken Link Checker"
|
856 |
+
|
857 |
+
#. Plugin URI of an extension
|
858 |
+
msgid "http://w-shadow.com/blog/2007/08/05/broken-link-checker-for-wordpress/"
|
859 |
+
msgstr "http://w-shadow.com/blog/2007/08/05/broken-link-checker-for-wordpress/"
|
860 |
+
|
861 |
+
#. Description of an extension
|
862 |
+
msgid "Checks your posts for broken links and missing images and notifies you on the dashboard if any are found."
|
863 |
+
msgstr "Kontroluje vaše příspěvky a hledá nefunkční odkazy a obrázky a upozorňuje vás na nástěnce, pokud jsou nějaké nalezeny."
|
864 |
+
|
865 |
+
#. Author of an extension
|
866 |
+
msgid "Janis Elsts"
|
867 |
+
msgstr "Janis Elsts"
|
868 |
+
|
869 |
+
#. Author URI of an extension
|
870 |
+
msgid "http://w-shadow.com/blog/"
|
871 |
+
msgstr "http://w-shadow.com/blog/"
|
872 |
+
|
languages/broken-link-checker.pot
CHANGED
@@ -1,15 +1,15 @@
|
|
1 |
-
# Broken Link Checker
|
2 |
# Copyright (C) 2010 Janis Elsts
|
3 |
# This file is distributed under the same license as the Broken Link Checker package.
|
4 |
-
#
|
5 |
#
|
6 |
#, fuzzy
|
7 |
msgid ""
|
8 |
msgstr ""
|
9 |
-
"Project-Id-Version: Broken Link Checker 0.
|
10 |
-
"Report-Msgid-Bugs-To:
|
11 |
-
"POT-Creation-Date: 2010-
|
12 |
-
"PO-Revision-Date:
|
13 |
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
14 |
"Language-Team: LANGUAGE <LL@li.org>\n"
|
15 |
"MIME-Version: 1.0\n"
|
@@ -17,828 +17,1085 @@ msgstr ""
|
|
17 |
"Content-Transfer-Encoding: 8bit\n"
|
18 |
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
19 |
|
20 |
-
#:
|
|
|
|
|
|
|
|
|
21 |
msgid "Loading..."
|
22 |
msgstr ""
|
23 |
|
24 |
-
#: core.php:
|
25 |
msgid "[ Network error ]"
|
26 |
msgstr ""
|
27 |
|
28 |
-
#: core.php:
|
29 |
msgid "Automatically expand the widget if broken links have been detected"
|
30 |
msgstr ""
|
31 |
|
32 |
-
#: core.php:
|
33 |
-
#: core.php:1038 core.php:1316
|
34 |
#, php-format
|
35 |
-
msgid "Database error : %s"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
msgstr ""
|
37 |
|
38 |
-
#: core.php:
|
39 |
msgid "Link Checker Settings"
|
40 |
msgstr ""
|
41 |
|
42 |
-
#: core.php:
|
43 |
msgid "Link Checker"
|
44 |
msgstr ""
|
45 |
|
46 |
-
#: core.php:
|
47 |
msgid "View Broken Links"
|
48 |
msgstr ""
|
49 |
|
50 |
-
#: core.php:
|
51 |
msgid "Broken Links"
|
52 |
msgstr ""
|
53 |
|
54 |
-
#: core.php:
|
55 |
msgid "Settings"
|
56 |
msgstr ""
|
57 |
|
58 |
-
#: core.php:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
msgid "Broken Link Checker Options"
|
60 |
msgstr ""
|
61 |
|
62 |
-
#: core.php:
|
63 |
msgid "Status"
|
64 |
msgstr ""
|
65 |
|
66 |
-
#: core.php:
|
67 |
msgid "Show debug info"
|
68 |
msgstr ""
|
69 |
|
70 |
-
#: core.php:
|
71 |
msgid "Re-check all pages"
|
72 |
msgstr ""
|
73 |
|
74 |
-
#: core.php:
|
75 |
msgid "Check each link"
|
76 |
msgstr ""
|
77 |
|
78 |
-
#: core.php:
|
79 |
#, php-format
|
80 |
msgid "Every %s hours"
|
81 |
msgstr ""
|
82 |
|
83 |
-
#: core.php:
|
84 |
msgid ""
|
85 |
"Existing links will be checked this often. New links will usually be checked "
|
86 |
"ASAP."
|
87 |
msgstr ""
|
88 |
|
89 |
-
#: core.php:
|
90 |
msgid "Broken link CSS"
|
91 |
msgstr ""
|
92 |
|
93 |
-
#: core.php:
|
94 |
msgid "Apply <em>class=\"broken_link\"</em> to broken links"
|
95 |
msgstr ""
|
96 |
|
97 |
-
#: core.php:
|
98 |
msgid "Removed link CSS"
|
99 |
msgstr ""
|
100 |
|
101 |
-
#: core.php:
|
102 |
msgid "Apply <em>class=\"removed_link\"</em> to unlinked links"
|
103 |
msgstr ""
|
104 |
|
105 |
-
#: core.php:
|
106 |
msgid "Exclusion list"
|
107 |
msgstr ""
|
108 |
|
109 |
-
#: core.php:
|
110 |
msgid ""
|
111 |
"Don't check links where the URL contains any of these words (one per line) :"
|
112 |
msgstr ""
|
113 |
|
114 |
-
#: core.php:
|
115 |
msgid "Custom fields"
|
116 |
msgstr ""
|
117 |
|
118 |
-
#: core.php:
|
119 |
msgid "Check URLs entered in these custom fields (one per line) :"
|
120 |
msgstr ""
|
121 |
|
122 |
-
#: core.php:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
msgid "Advanced"
|
124 |
msgstr ""
|
125 |
|
126 |
-
#: core.php:
|
127 |
msgid "Timeout"
|
128 |
msgstr ""
|
129 |
|
130 |
-
#: core.php:
|
131 |
#, php-format
|
132 |
msgid "%s seconds"
|
133 |
msgstr ""
|
134 |
|
135 |
-
#: core.php:
|
136 |
msgid "Links that take longer than this to load will be marked as broken."
|
137 |
msgstr ""
|
138 |
|
139 |
-
#: core.php:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
msgid "Custom temporary directory"
|
141 |
msgstr ""
|
142 |
|
143 |
-
#: core.php:
|
144 |
msgid "OK"
|
145 |
msgstr ""
|
146 |
|
147 |
-
#: core.php:
|
148 |
msgid "Error : This directory isn't writable by PHP."
|
149 |
msgstr ""
|
150 |
|
151 |
-
#: core.php:
|
152 |
msgid "Error : This directory doesn't exist."
|
153 |
msgstr ""
|
154 |
|
155 |
-
#: core.php:
|
156 |
msgid ""
|
157 |
"Set this field if you want the plugin to use a custom directory for its "
|
158 |
"lockfiles. Otherwise, leave it blank."
|
159 |
msgstr ""
|
160 |
|
161 |
-
#: core.php:
|
162 |
-
msgid "
|
163 |
msgstr ""
|
164 |
|
165 |
-
#: core.php:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
166 |
msgid ""
|
167 |
-
"
|
168 |
-
"
|
169 |
-
"performs other time-consuming tasks. Here you can set for how long, at most, "
|
170 |
-
"the background instance may run each time before stopping."
|
171 |
msgstr ""
|
172 |
|
173 |
-
#: core.php:
|
174 |
msgid "Save Changes"
|
175 |
msgstr ""
|
176 |
|
177 |
-
#: core.php:
|
178 |
msgid "Hide debug info"
|
179 |
msgstr ""
|
180 |
|
181 |
-
#: core.php:
|
182 |
-
|
|
|
183 |
msgstr ""
|
184 |
|
185 |
-
#: core.php:
|
186 |
-
msgid "
|
187 |
msgstr ""
|
188 |
|
189 |
-
#: core.php:
|
190 |
-
msgid "
|
191 |
msgstr ""
|
192 |
|
193 |
-
#: core.php:
|
194 |
-
msgid "
|
195 |
msgstr ""
|
196 |
|
197 |
-
#: core.php:
|
198 |
-
msgid "
|
199 |
msgstr ""
|
200 |
|
201 |
-
#: core.php:
|
202 |
-
msgid "
|
203 |
msgstr ""
|
204 |
|
205 |
-
#: core.php:
|
206 |
-
msgid "
|
207 |
msgstr ""
|
208 |
|
209 |
-
#: core.php:
|
210 |
-
msgid "
|
211 |
msgstr ""
|
212 |
|
213 |
-
#: core.php:
|
214 |
-
msgid "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
215 |
msgstr ""
|
216 |
|
217 |
-
#: core.php:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
218 |
msgid "You must enter a filter name!"
|
219 |
msgstr ""
|
220 |
|
221 |
-
#: core.php:
|
222 |
msgid "Invalid search query."
|
223 |
msgstr ""
|
224 |
|
225 |
-
#: core.php:
|
226 |
#, php-format
|
227 |
msgid "Filter \"%s\" created"
|
228 |
msgstr ""
|
229 |
|
230 |
-
#: core.php:
|
231 |
msgid "Filter ID not specified."
|
232 |
msgstr ""
|
233 |
|
234 |
-
#: core.php:
|
235 |
msgid "Filter deleted"
|
236 |
msgstr ""
|
237 |
|
238 |
-
#: core.php:
|
239 |
#, php-format
|
240 |
-
msgid "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
241 |
msgstr ""
|
242 |
|
243 |
-
#: core.php:
|
244 |
#, php-format
|
245 |
-
msgid "%d
|
246 |
-
msgid_plural "%d
|
247 |
msgstr[0] ""
|
248 |
msgstr[1] ""
|
249 |
|
250 |
-
#: core.php:
|
251 |
#, php-format
|
252 |
-
msgid "%d
|
253 |
-
msgid_plural "%d
|
254 |
msgstr[0] ""
|
255 |
msgstr[1] ""
|
256 |
|
257 |
-
#: core.php:
|
|
|
|
|
|
|
|
|
258 |
#, php-format
|
259 |
-
msgid "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
260 |
msgstr ""
|
261 |
|
262 |
-
#: core.php:
|
263 |
#, php-format
|
264 |
-
msgid "%
|
265 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
266 |
msgstr[0] ""
|
267 |
msgstr[1] ""
|
268 |
|
269 |
-
#: core.php:
|
270 |
-
msgid "
|
|
|
|
|
|
|
|
|
271 |
msgstr ""
|
272 |
|
273 |
-
#: core.php:
|
274 |
#, php-format
|
275 |
-
msgid "%d link
|
276 |
-
msgid_plural "%d links
|
277 |
msgstr[0] ""
|
278 |
msgstr[1] ""
|
279 |
|
280 |
-
#: core.php:
|
|
|
|
|
|
|
|
|
281 |
#, php-format
|
282 |
-
msgid "
|
283 |
-
msgid_plural "
|
284 |
msgstr[0] ""
|
285 |
msgstr[1] ""
|
286 |
|
287 |
-
#: core.php:
|
|
|
|
|
|
|
|
|
288 |
#, php-format
|
289 |
-
msgid "
|
290 |
-
msgid_plural "
|
291 |
msgstr[0] ""
|
292 |
msgstr[1] ""
|
293 |
|
294 |
-
#: core.php:
|
295 |
#, php-format
|
296 |
-
msgid "
|
297 |
-
msgid_plural "
|
298 |
msgstr[0] ""
|
299 |
msgstr[1] ""
|
300 |
|
301 |
-
#: core.php:
|
302 |
-
msgid "
|
303 |
msgstr ""
|
304 |
|
305 |
-
#: core.php:
|
306 |
-
msgid "
|
307 |
msgstr ""
|
308 |
|
309 |
-
#: core.php:
|
310 |
-
msgid "
|
311 |
msgstr ""
|
312 |
|
313 |
-
#: core.php:
|
314 |
-
msgid "
|
315 |
msgstr ""
|
316 |
|
317 |
-
#: core.php:
|
318 |
-
|
|
|
319 |
msgstr ""
|
320 |
|
321 |
-
#: core.php:
|
322 |
-
msgid "
|
323 |
msgstr ""
|
324 |
|
325 |
-
#: core.php:
|
326 |
-
msgid "
|
327 |
msgstr ""
|
328 |
|
329 |
-
#: core.php:
|
330 |
-
msgid "
|
331 |
msgstr ""
|
332 |
|
333 |
-
#: core.php:
|
334 |
-
msgid "
|
335 |
msgstr ""
|
336 |
|
337 |
-
#: core.php:
|
338 |
-
msgid "
|
339 |
msgstr ""
|
340 |
|
341 |
-
#: core.php:
|
342 |
-
msgid "
|
343 |
msgstr ""
|
344 |
|
345 |
-
#: core.php:
|
346 |
-
msgid "
|
347 |
msgstr ""
|
348 |
|
349 |
-
#: core.php:
|
350 |
-
msgid "
|
351 |
msgstr ""
|
352 |
|
353 |
-
#: core.php:
|
354 |
-
|
|
|
355 |
msgstr ""
|
356 |
|
357 |
-
#: core.php:
|
358 |
-
|
|
|
|
|
|
|
359 |
msgstr ""
|
360 |
|
361 |
-
#: core.php:
|
362 |
-
|
|
|
|
|
|
|
363 |
msgstr ""
|
364 |
|
365 |
-
#: core.php:
|
366 |
-
msgid "
|
367 |
msgstr ""
|
368 |
|
369 |
-
#: core.php:
|
370 |
-
msgid "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
371 |
msgstr ""
|
372 |
|
373 |
-
#: core.php:
|
374 |
-
msgid "
|
375 |
msgstr ""
|
376 |
|
377 |
-
#: core.php:
|
378 |
-
msgid "
|
379 |
msgstr ""
|
380 |
|
381 |
-
#: core.php:
|
382 |
-
msgid "
|
|
|
383 |
msgstr ""
|
384 |
|
385 |
-
#: core.php:
|
386 |
-
msgid "
|
387 |
msgstr ""
|
388 |
|
389 |
-
#: core.php:
|
390 |
-
msgid "
|
391 |
msgstr ""
|
392 |
|
393 |
-
#: core.php:
|
394 |
-
msgid "
|
395 |
msgstr ""
|
396 |
|
397 |
-
#: core.php:
|
398 |
-
|
399 |
-
msgid "Displaying %s–%s of <span class=\"current-link-count\">%s</span>"
|
400 |
msgstr ""
|
401 |
|
402 |
-
#: core.php:
|
403 |
-
msgid "
|
404 |
msgstr ""
|
405 |
|
406 |
-
#: core.php:
|
407 |
-
msgid "
|
408 |
msgstr ""
|
409 |
|
410 |
-
#: core.php:
|
411 |
-
msgid "
|
412 |
msgstr ""
|
413 |
|
414 |
-
#: core.php:
|
415 |
-
|
|
|
416 |
msgstr ""
|
417 |
|
418 |
-
#: core.php:
|
419 |
-
msgid "
|
420 |
msgstr ""
|
421 |
|
422 |
-
#: core.php:
|
423 |
-
|
424 |
-
msgid ""
|
425 |
-
"You are about to delete this post '%s'\n"
|
426 |
-
" 'Cancel' to stop, 'OK' to delete."
|
427 |
msgstr ""
|
428 |
|
429 |
-
#: core.php:
|
430 |
-
|
|
|
431 |
msgstr ""
|
432 |
|
433 |
-
#: core.php:
|
434 |
#, php-format
|
435 |
-
msgid "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
436 |
msgstr ""
|
437 |
|
438 |
-
#: core.php:
|
439 |
-
|
|
|
440 |
msgstr ""
|
441 |
|
442 |
-
#: core.php:
|
443 |
-
|
|
|
444 |
msgstr ""
|
445 |
|
446 |
-
#: core.php:
|
447 |
#, php-format
|
448 |
-
msgid ""
|
449 |
-
"You are about to delete this link '%s'\n"
|
450 |
-
" 'Cancel' to stop, 'OK' to delete."
|
451 |
msgstr ""
|
452 |
|
453 |
-
#: core.php:
|
454 |
-
msgid "
|
455 |
msgstr ""
|
456 |
|
457 |
-
#:
|
458 |
-
msgid "
|
459 |
msgstr ""
|
460 |
|
461 |
-
#:
|
462 |
-
msgid "
|
463 |
msgstr ""
|
464 |
|
465 |
-
#:
|
466 |
-
msgid "
|
467 |
msgstr ""
|
468 |
|
469 |
-
#:
|
470 |
-
|
|
|
471 |
msgstr ""
|
472 |
|
473 |
-
#:
|
474 |
-
|
|
|
|
|
475 |
msgstr ""
|
476 |
|
477 |
-
#:
|
478 |
-
msgid "
|
479 |
msgstr ""
|
480 |
|
481 |
-
#:
|
482 |
-
msgid "
|
483 |
msgstr ""
|
484 |
|
485 |
-
#:
|
486 |
-
|
|
|
487 |
msgstr ""
|
488 |
|
489 |
-
#:
|
490 |
-
|
|
|
491 |
msgstr ""
|
492 |
|
493 |
-
#:
|
494 |
-
msgid "
|
495 |
msgstr ""
|
496 |
|
497 |
-
#:
|
498 |
-
msgid "
|
499 |
msgstr ""
|
500 |
|
501 |
-
#:
|
502 |
-
msgid "
|
|
|
|
|
503 |
msgstr ""
|
504 |
|
505 |
-
#:
|
506 |
-
msgid "
|
|
|
|
|
|
|
507 |
msgstr ""
|
508 |
|
509 |
-
#:
|
510 |
-
msgid "
|
511 |
msgstr ""
|
512 |
|
513 |
-
#:
|
514 |
-
msgid "
|
515 |
msgstr ""
|
516 |
|
517 |
-
#:
|
518 |
-
msgid ""
|
519 |
-
"You are about to delete the current filter.\n"
|
520 |
-
"'Cancel' to stop, 'OK' to delete"
|
521 |
msgstr ""
|
522 |
|
523 |
-
#:
|
524 |
-
msgid "
|
525 |
msgstr ""
|
526 |
|
527 |
-
#:
|
528 |
-
msgid "
|
529 |
msgstr ""
|
530 |
|
531 |
-
#:
|
532 |
-
msgid "Link
|
533 |
msgstr ""
|
534 |
|
535 |
-
#:
|
536 |
-
msgid "
|
537 |
msgstr ""
|
538 |
|
539 |
-
#:
|
540 |
-
msgid "
|
541 |
msgstr ""
|
542 |
|
543 |
-
#:
|
544 |
-
|
545 |
-
msgid "%2.3f seconds"
|
546 |
msgstr ""
|
547 |
|
548 |
-
#:
|
549 |
-
msgid "
|
550 |
msgstr ""
|
551 |
|
552 |
-
#:
|
553 |
-
msgid "
|
554 |
msgstr ""
|
555 |
|
556 |
-
#:
|
557 |
-
msgid "
|
|
|
|
|
|
|
|
|
558 |
msgstr ""
|
559 |
|
560 |
-
#:
|
561 |
#, php-format
|
562 |
-
msgid "
|
563 |
-
|
564 |
-
msgstr[0] ""
|
565 |
-
msgstr[1] ""
|
566 |
|
567 |
-
#:
|
568 |
-
msgid ""
|
569 |
-
"This link wasn't checked because a matching keyword was found on your "
|
570 |
-
"exclusion list."
|
571 |
msgstr ""
|
572 |
|
573 |
-
#:
|
574 |
-
msgid "
|
575 |
msgstr ""
|
576 |
|
577 |
-
#:
|
578 |
-
|
579 |
-
|
580 |
-
msgid_plural "Found %d broken links"
|
581 |
-
msgstr[0] ""
|
582 |
-
msgstr[1] ""
|
583 |
|
584 |
-
#:
|
585 |
-
msgid "
|
586 |
msgstr ""
|
587 |
|
588 |
-
#:
|
589 |
#, php-format
|
590 |
-
msgid "
|
591 |
-
msgid_plural "%d URLs in the work queue"
|
592 |
-
msgstr[0] ""
|
593 |
-
msgstr[1] ""
|
594 |
-
|
595 |
-
#: core.php:2639
|
596 |
-
msgid "No URLs in the work queue."
|
597 |
msgstr ""
|
598 |
|
599 |
-
#:
|
600 |
#, php-format
|
601 |
-
msgid "
|
602 |
-
msgid_plural "
|
603 |
msgstr[0] ""
|
604 |
msgstr[1] ""
|
605 |
|
606 |
-
#:
|
607 |
-
|
608 |
-
|
609 |
-
msgid_plural "in %d links"
|
610 |
-
msgstr[0] ""
|
611 |
-
msgstr[1] ""
|
612 |
|
613 |
-
#:
|
614 |
-
|
|
|
615 |
msgstr ""
|
616 |
|
617 |
-
#:
|
618 |
-
|
|
|
|
|
|
|
619 |
msgstr ""
|
620 |
|
621 |
-
#:
|
622 |
-
|
|
|
623 |
msgstr ""
|
624 |
|
625 |
-
#:
|
626 |
-
|
|
|
627 |
msgstr ""
|
628 |
|
629 |
-
#:
|
630 |
#, php-format
|
631 |
-
msgid "
|
632 |
msgstr ""
|
633 |
|
634 |
-
#:
|
635 |
-
|
|
|
636 |
msgstr ""
|
637 |
|
638 |
-
#:
|
639 |
-
|
640 |
-
|
|
|
|
|
|
|
641 |
|
642 |
-
#:
|
643 |
-
|
|
|
644 |
msgstr ""
|
645 |
|
646 |
-
#:
|
647 |
-
|
|
|
648 |
msgstr ""
|
649 |
|
650 |
-
#:
|
651 |
-
msgid "
|
652 |
msgstr ""
|
653 |
|
654 |
-
#:
|
655 |
-
msgid "
|
656 |
msgstr ""
|
657 |
|
658 |
-
#:
|
659 |
-
|
660 |
-
msgid "URL %s was removed."
|
661 |
msgstr ""
|
662 |
|
663 |
-
#:
|
664 |
-
|
|
|
665 |
msgstr ""
|
666 |
|
667 |
-
#:
|
668 |
-
msgid "
|
669 |
msgstr ""
|
670 |
|
671 |
-
#:
|
672 |
-
|
|
|
673 |
msgstr ""
|
674 |
|
675 |
-
#:
|
676 |
#, php-format
|
677 |
-
msgid "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
678 |
msgstr ""
|
679 |
|
680 |
-
#:
|
681 |
#, php-format
|
682 |
-
msgid "
|
683 |
msgstr ""
|
684 |
|
685 |
-
#:
|
686 |
-
|
|
|
|
|
687 |
msgstr ""
|
688 |
|
689 |
-
#:
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
|
|
694 |
msgstr ""
|
695 |
|
696 |
-
#:
|
|
|
|
|
|
|
|
|
697 |
#, php-format
|
698 |
msgid ""
|
699 |
-
"
|
700 |
-
"
|
701 |
msgstr ""
|
702 |
|
703 |
-
#:
|
704 |
-
|
|
|
705 |
msgstr ""
|
706 |
|
707 |
-
#:
|
708 |
-
|
709 |
-
"
|
710 |
-
"instance of the resource-heavy link checking algorithm is running at any "
|
711 |
-
"given time. Unfortunately, BLC can't find a writable directory where it "
|
712 |
-
"could store the lockfile - it failed to detect the location of your server's "
|
713 |
-
"temporary directory, and the plugin's own directory isn't writable by PHP. "
|
714 |
-
"To fix this problem, please make the plugin's directory writable or enter a "
|
715 |
-
"specify a custom temporary directory in the plugin's settings."
|
716 |
msgstr ""
|
717 |
|
718 |
-
#:
|
719 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
720 |
msgstr ""
|
721 |
|
722 |
-
#:
|
723 |
-
|
|
|
724 |
msgstr ""
|
725 |
|
726 |
-
#:
|
727 |
-
|
728 |
-
"
|
729 |
msgstr ""
|
730 |
|
731 |
-
#:
|
732 |
-
|
|
|
733 |
msgstr ""
|
734 |
|
735 |
-
#:
|
736 |
-
msgid "
|
737 |
msgstr ""
|
738 |
|
739 |
-
#:
|
740 |
-
msgid "
|
741 |
msgstr ""
|
742 |
|
743 |
-
#:
|
744 |
-
msgid "
|
745 |
msgstr ""
|
746 |
|
747 |
-
#:
|
748 |
-
msgid "
|
749 |
msgstr ""
|
750 |
|
751 |
-
#:
|
752 |
-
msgid "
|
753 |
msgstr ""
|
754 |
|
755 |
-
#:
|
756 |
-
msgid "
|
|
|
757 |
msgstr ""
|
758 |
|
759 |
-
#:
|
760 |
-
|
761 |
-
msgid "On ( %s )"
|
762 |
msgstr ""
|
763 |
|
764 |
-
#:
|
765 |
-
msgid "
|
766 |
msgstr ""
|
767 |
|
768 |
-
#:
|
769 |
-
msgid "
|
770 |
msgstr ""
|
771 |
|
772 |
-
#:
|
773 |
-
|
774 |
-
msgid "First try : %d"
|
775 |
msgstr ""
|
776 |
|
777 |
-
#:
|
778 |
-
msgid "
|
779 |
msgstr ""
|
780 |
|
781 |
-
#:
|
782 |
-
msgid "
|
783 |
msgstr ""
|
784 |
|
785 |
-
#:
|
786 |
-
|
787 |
-
msgid "Second try : %d"
|
788 |
msgstr ""
|
789 |
|
790 |
-
#:
|
791 |
-
msgid "
|
792 |
msgstr ""
|
793 |
|
794 |
-
#:
|
795 |
-
msgid "
|
796 |
msgstr ""
|
797 |
|
798 |
-
#:
|
799 |
-
msgid "
|
800 |
msgstr ""
|
801 |
|
802 |
-
#:
|
803 |
-
msgid "
|
804 |
msgstr ""
|
805 |
|
806 |
-
#:
|
807 |
-
msgid "
|
808 |
msgstr ""
|
809 |
|
810 |
-
#:
|
811 |
-
msgid "
|
812 |
msgstr ""
|
813 |
|
814 |
-
#:
|
815 |
#, php-format
|
816 |
-
msgid "
|
817 |
msgstr ""
|
818 |
|
819 |
-
#:
|
820 |
#, php-format
|
821 |
-
msgid "
|
822 |
msgstr ""
|
823 |
|
824 |
-
#. Plugin Name of
|
825 |
msgid "Broken Link Checker"
|
826 |
msgstr ""
|
827 |
|
828 |
-
#. Plugin URI of
|
829 |
msgid "http://w-shadow.com/blog/2007/08/05/broken-link-checker-for-wordpress/"
|
830 |
msgstr ""
|
831 |
|
832 |
-
#. Description of
|
833 |
msgid ""
|
834 |
-
"Checks your
|
835 |
-
"
|
836 |
msgstr ""
|
837 |
|
838 |
-
#. Author of
|
839 |
msgid "Janis Elsts"
|
840 |
msgstr ""
|
841 |
|
842 |
-
#. Author URI of
|
843 |
msgid "http://w-shadow.com/blog/"
|
844 |
msgstr ""
|
1 |
+
# Translation of the WordPress plugin Broken Link Checker 0.9 by Janis Elsts.
|
2 |
# Copyright (C) 2010 Janis Elsts
|
3 |
# This file is distributed under the same license as the Broken Link Checker package.
|
4 |
+
# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
|
5 |
#
|
6 |
#, fuzzy
|
7 |
msgid ""
|
8 |
msgstr ""
|
9 |
+
"Project-Id-Version: Broken Link Checker 0.9\n"
|
10 |
+
"Report-Msgid-Bugs-To: http://wordpress.org/tag/broken-link-checker\n"
|
11 |
+
"POT-Creation-Date: 2010-04-21 17:01+0000\n"
|
12 |
+
"PO-Revision-Date: 2010-MO-DA HO:MI+ZONE\n"
|
13 |
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
14 |
"Language-Team: LANGUAGE <LL@li.org>\n"
|
15 |
"MIME-Version: 1.0\n"
|
17 |
"Content-Transfer-Encoding: 8bit\n"
|
18 |
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
19 |
|
20 |
+
#: broken-link-checker.php:268
|
21 |
+
msgid "Once Weekly"
|
22 |
+
msgstr ""
|
23 |
+
|
24 |
+
#: core.php:136 includes/admin/links-page-js.php:21
|
25 |
msgid "Loading..."
|
26 |
msgstr ""
|
27 |
|
28 |
+
#: core.php:159 core.php:669
|
29 |
msgid "[ Network error ]"
|
30 |
msgstr ""
|
31 |
|
32 |
+
#: core.php:184
|
33 |
msgid "Automatically expand the widget if broken links have been detected"
|
34 |
msgstr ""
|
35 |
|
36 |
+
#: core.php:295
|
|
|
37 |
#, php-format
|
38 |
+
msgid "Failed to delete old DB tables. Database error : %s"
|
39 |
+
msgstr ""
|
40 |
+
|
41 |
+
#: core.php:312
|
42 |
+
#, php-format
|
43 |
+
msgid ""
|
44 |
+
"Unexpected error: The plugin doesn't know how to upgrade its database to "
|
45 |
+
"version '%d'."
|
46 |
+
msgstr ""
|
47 |
+
|
48 |
+
#: core.php:348 core.php:377 core.php:419 core.php:444
|
49 |
+
#, php-format
|
50 |
+
msgid "Failed to create table '%s'. Database error: %s"
|
51 |
msgstr ""
|
52 |
|
53 |
+
#: core.php:472
|
54 |
msgid "Link Checker Settings"
|
55 |
msgstr ""
|
56 |
|
57 |
+
#: core.php:473
|
58 |
msgid "Link Checker"
|
59 |
msgstr ""
|
60 |
|
61 |
+
#: core.php:479
|
62 |
msgid "View Broken Links"
|
63 |
msgstr ""
|
64 |
|
65 |
+
#: core.php:480 includes/links.php:771
|
66 |
msgid "Broken Links"
|
67 |
msgstr ""
|
68 |
|
69 |
+
#: core.php:503
|
70 |
msgid "Settings"
|
71 |
msgstr ""
|
72 |
|
73 |
+
#: core.php:513 core.php:1001
|
74 |
+
#, php-format
|
75 |
+
msgid ""
|
76 |
+
"Error: The plugin's database tables are not up to date! (Current version : %"
|
77 |
+
"d, expected : %d)"
|
78 |
+
msgstr ""
|
79 |
+
|
80 |
+
#: core.php:626
|
81 |
+
msgid "Settings saved."
|
82 |
+
msgstr ""
|
83 |
+
|
84 |
+
#: core.php:634
|
85 |
msgid "Broken Link Checker Options"
|
86 |
msgstr ""
|
87 |
|
88 |
+
#: core.php:647
|
89 |
msgid "Status"
|
90 |
msgstr ""
|
91 |
|
92 |
+
#: core.php:649 core.php:981
|
93 |
msgid "Show debug info"
|
94 |
msgstr ""
|
95 |
|
96 |
+
#: core.php:682
|
97 |
msgid "Re-check all pages"
|
98 |
msgstr ""
|
99 |
|
100 |
+
#: core.php:706
|
101 |
msgid "Check each link"
|
102 |
msgstr ""
|
103 |
|
104 |
+
#: core.php:711
|
105 |
#, php-format
|
106 |
msgid "Every %s hours"
|
107 |
msgstr ""
|
108 |
|
109 |
+
#: core.php:720
|
110 |
msgid ""
|
111 |
"Existing links will be checked this often. New links will usually be checked "
|
112 |
"ASAP."
|
113 |
msgstr ""
|
114 |
|
115 |
+
#: core.php:727
|
116 |
msgid "Broken link CSS"
|
117 |
msgstr ""
|
118 |
|
119 |
+
#: core.php:732
|
120 |
msgid "Apply <em>class=\"broken_link\"</em> to broken links"
|
121 |
msgstr ""
|
122 |
|
123 |
+
#: core.php:744
|
124 |
msgid "Removed link CSS"
|
125 |
msgstr ""
|
126 |
|
127 |
+
#: core.php:749
|
128 |
msgid "Apply <em>class=\"removed_link\"</em> to unlinked links"
|
129 |
msgstr ""
|
130 |
|
131 |
+
#: core.php:761
|
132 |
msgid "Exclusion list"
|
133 |
msgstr ""
|
134 |
|
135 |
+
#: core.php:762
|
136 |
msgid ""
|
137 |
"Don't check links where the URL contains any of these words (one per line) :"
|
138 |
msgstr ""
|
139 |
|
140 |
+
#: core.php:772
|
141 |
msgid "Custom fields"
|
142 |
msgstr ""
|
143 |
|
144 |
+
#: core.php:773
|
145 |
msgid "Check URLs entered in these custom fields (one per line) :"
|
146 |
msgstr ""
|
147 |
|
148 |
+
#: core.php:783
|
149 |
+
msgid "E-mail notifications"
|
150 |
+
msgstr ""
|
151 |
+
|
152 |
+
#: core.php:789
|
153 |
+
msgid "Send me e-mail notifications about newly detected broken links"
|
154 |
+
msgstr ""
|
155 |
+
|
156 |
+
#: core.php:797
|
157 |
msgid "Advanced"
|
158 |
msgstr ""
|
159 |
|
160 |
+
#: core.php:803
|
161 |
msgid "Timeout"
|
162 |
msgstr ""
|
163 |
|
164 |
+
#: core.php:809 core.php:853
|
165 |
#, php-format
|
166 |
msgid "%s seconds"
|
167 |
msgstr ""
|
168 |
|
169 |
+
#: core.php:818
|
170 |
msgid "Links that take longer than this to load will be marked as broken."
|
171 |
msgstr ""
|
172 |
|
173 |
+
#: core.php:825
|
174 |
+
msgid "Link monitor"
|
175 |
+
msgstr ""
|
176 |
+
|
177 |
+
#: core.php:831
|
178 |
+
msgid "Run continuously while the Dashboard is open"
|
179 |
+
msgstr ""
|
180 |
+
|
181 |
+
#: core.php:839
|
182 |
+
msgid "Run hourly in the background"
|
183 |
+
msgstr ""
|
184 |
+
|
185 |
+
#: core.php:847
|
186 |
+
msgid "Max. execution time"
|
187 |
+
msgstr ""
|
188 |
+
|
189 |
+
#: core.php:864
|
190 |
+
msgid ""
|
191 |
+
"The plugin works by periodically launching a background job that parses your "
|
192 |
+
"posts for links, checks the discovered URLs, and performs other time-"
|
193 |
+
"consuming tasks. Here you can set for how long, at most, the link monitor "
|
194 |
+
"may run each time before stopping."
|
195 |
+
msgstr ""
|
196 |
+
|
197 |
+
#: core.php:874
|
198 |
msgid "Custom temporary directory"
|
199 |
msgstr ""
|
200 |
|
201 |
+
#: core.php:883
|
202 |
msgid "OK"
|
203 |
msgstr ""
|
204 |
|
205 |
+
#: core.php:886
|
206 |
msgid "Error : This directory isn't writable by PHP."
|
207 |
msgstr ""
|
208 |
|
209 |
+
#: core.php:891
|
210 |
msgid "Error : This directory doesn't exist."
|
211 |
msgstr ""
|
212 |
|
213 |
+
#: core.php:899
|
214 |
msgid ""
|
215 |
"Set this field if you want the plugin to use a custom directory for its "
|
216 |
"lockfiles. Otherwise, leave it blank."
|
217 |
msgstr ""
|
218 |
|
219 |
+
#: core.php:906
|
220 |
+
msgid "Server load limit"
|
221 |
msgstr ""
|
222 |
|
223 |
+
#: core.php:947
|
224 |
+
#, php-format
|
225 |
+
msgid ""
|
226 |
+
"Link checking will be suspended if the average <a href=\"%s\">server load</"
|
227 |
+
"a> rises above this number. Leave this field blank to disable load limiting."
|
228 |
+
msgstr ""
|
229 |
+
|
230 |
+
#: core.php:957
|
231 |
msgid ""
|
232 |
+
"Load limiting only works on Linux-like systems where <code>/proc/loadavg</"
|
233 |
+
"code> is present and accessible."
|
|
|
|
|
234 |
msgstr ""
|
235 |
|
236 |
+
#: core.php:966
|
237 |
msgid "Save Changes"
|
238 |
msgstr ""
|
239 |
|
240 |
+
#: core.php:979
|
241 |
msgid "Hide debug info"
|
242 |
msgstr ""
|
243 |
|
244 |
+
#: core.php:1087 core.php:1409 core.php:1441
|
245 |
+
#, php-format
|
246 |
+
msgid "Database error : %s"
|
247 |
msgstr ""
|
248 |
|
249 |
+
#: core.php:1162
|
250 |
+
msgid "Bulk Actions"
|
251 |
msgstr ""
|
252 |
|
253 |
+
#: core.php:1163
|
254 |
+
msgid "Recheck"
|
255 |
msgstr ""
|
256 |
|
257 |
+
#: core.php:1164
|
258 |
+
msgid "Fix redirects"
|
259 |
msgstr ""
|
260 |
|
261 |
+
#: core.php:1165 core.php:1308 includes/admin/links-page-js.php:293
|
262 |
+
msgid "Unlink"
|
263 |
msgstr ""
|
264 |
|
265 |
+
#: core.php:1166
|
266 |
+
msgid "Delete sources"
|
267 |
msgstr ""
|
268 |
|
269 |
+
#: core.php:1180 core.php:1343
|
270 |
+
msgid "Apply"
|
271 |
msgstr ""
|
272 |
|
273 |
+
#: core.php:1187
|
274 |
+
msgid "«"
|
275 |
msgstr ""
|
276 |
|
277 |
+
#: core.php:1188
|
278 |
+
msgid "»"
|
279 |
+
msgstr ""
|
280 |
+
|
281 |
+
#: core.php:1195 core.php:1349
|
282 |
+
#, php-format
|
283 |
+
msgid "Displaying %s–%s of <span class=\"current-link-count\">%s</span>"
|
284 |
+
msgstr ""
|
285 |
+
|
286 |
+
#: core.php:1214
|
287 |
+
msgid "Source"
|
288 |
+
msgstr ""
|
289 |
+
|
290 |
+
#: core.php:1215
|
291 |
+
msgid "Link Text"
|
292 |
+
msgstr ""
|
293 |
+
|
294 |
+
#: core.php:1216 includes/admin/search-form.php:42
|
295 |
+
msgid "URL"
|
296 |
+
msgstr ""
|
297 |
+
|
298 |
+
#: core.php:1281
|
299 |
+
msgid "[An orphaned link! This is a bug.]"
|
300 |
+
msgstr ""
|
301 |
+
|
302 |
+
#: core.php:1305
|
303 |
+
msgid "Show more info about this link"
|
304 |
+
msgstr ""
|
305 |
+
|
306 |
+
#: core.php:1305 core.php:2542
|
307 |
+
msgid "Details"
|
308 |
+
msgstr ""
|
309 |
+
|
310 |
+
#: core.php:1307
|
311 |
+
msgid "Remove this link from all posts"
|
312 |
+
msgstr ""
|
313 |
+
|
314 |
+
#: core.php:1313
|
315 |
+
msgid "Remove this link from the list of broken links and mark it as valid"
|
316 |
+
msgstr ""
|
317 |
+
|
318 |
+
#: core.php:1314 includes/admin/links-page-js.php:78
|
319 |
+
msgid "Not broken"
|
320 |
msgstr ""
|
321 |
|
322 |
+
#: core.php:1318
|
323 |
+
msgid "Edit link URL"
|
324 |
+
msgstr ""
|
325 |
+
|
326 |
+
#: core.php:1318 includes/admin/links-page-js.php:199
|
327 |
+
#: includes/admin/links-page-js.php:227
|
328 |
+
msgid "Edit URL"
|
329 |
+
msgstr ""
|
330 |
+
|
331 |
+
#: core.php:1324
|
332 |
+
msgid "Cancel URL editing"
|
333 |
+
msgstr ""
|
334 |
+
|
335 |
+
#: core.php:1324 includes/admin/search-form.php:87
|
336 |
+
msgid "Cancel"
|
337 |
+
msgstr ""
|
338 |
+
|
339 |
+
#: core.php:1392
|
340 |
msgid "You must enter a filter name!"
|
341 |
msgstr ""
|
342 |
|
343 |
+
#: core.php:1396
|
344 |
msgid "Invalid search query."
|
345 |
msgstr ""
|
346 |
|
347 |
+
#: core.php:1404
|
348 |
#, php-format
|
349 |
msgid "Filter \"%s\" created"
|
350 |
msgstr ""
|
351 |
|
352 |
+
#: core.php:1432
|
353 |
msgid "Filter ID not specified."
|
354 |
msgstr ""
|
355 |
|
356 |
+
#: core.php:1438
|
357 |
msgid "Filter deleted"
|
358 |
msgstr ""
|
359 |
|
360 |
+
#: core.php:1486
|
361 |
#, php-format
|
362 |
+
msgid "Replaced %d redirect with a direct link"
|
363 |
+
msgid_plural "Replaced %d redirects with direct links"
|
364 |
+
msgstr[0] ""
|
365 |
+
msgstr[1] ""
|
366 |
+
|
367 |
+
#: core.php:1497
|
368 |
+
#, php-format
|
369 |
+
msgid "Failed to fix %d redirect"
|
370 |
+
msgid_plural "Failed to fix %d redirects"
|
371 |
+
msgstr[0] ""
|
372 |
+
msgstr[1] ""
|
373 |
+
|
374 |
+
#: core.php:1507
|
375 |
+
msgid "None of the selected links are redirects!"
|
376 |
msgstr ""
|
377 |
|
378 |
+
#: core.php:1553
|
379 |
#, php-format
|
380 |
+
msgid "%d link removed"
|
381 |
+
msgid_plural "%d links removed"
|
382 |
msgstr[0] ""
|
383 |
msgstr[1] ""
|
384 |
|
385 |
+
#: core.php:1564
|
386 |
#, php-format
|
387 |
+
msgid "Failed to remove %d link"
|
388 |
+
msgid_plural "Failed to remove %d links"
|
389 |
msgstr[0] ""
|
390 |
msgstr[1] ""
|
391 |
|
392 |
+
#: core.php:1652
|
393 |
+
msgid "Didn't find anything to delete!"
|
394 |
+
msgstr ""
|
395 |
+
|
396 |
+
#: core.php:1680
|
397 |
#, php-format
|
398 |
+
msgid "%d link scheduled for rechecking"
|
399 |
+
msgid_plural "%d links scheduled for rechecking"
|
400 |
+
msgstr[0] ""
|
401 |
+
msgstr[1] ""
|
402 |
+
|
403 |
+
#: core.php:1703
|
404 |
+
msgid "Post published on"
|
405 |
+
msgstr ""
|
406 |
+
|
407 |
+
#: core.php:1708
|
408 |
+
msgid "Link last checked"
|
409 |
+
msgstr ""
|
410 |
+
|
411 |
+
#: core.php:1712
|
412 |
+
msgid "Never"
|
413 |
+
msgstr ""
|
414 |
+
|
415 |
+
#: core.php:1718 includes/admin/search-form.php:45
|
416 |
+
msgid "HTTP code"
|
417 |
+
msgstr ""
|
418 |
+
|
419 |
+
#: core.php:1723
|
420 |
+
msgid "Response time"
|
421 |
msgstr ""
|
422 |
|
423 |
+
#: core.php:1725
|
424 |
#, php-format
|
425 |
+
msgid "%2.3f seconds"
|
426 |
+
msgstr ""
|
427 |
+
|
428 |
+
#: core.php:1728
|
429 |
+
msgid "Final URL"
|
430 |
+
msgstr ""
|
431 |
+
|
432 |
+
#: core.php:1733
|
433 |
+
msgid "Redirect count"
|
434 |
+
msgstr ""
|
435 |
+
|
436 |
+
#: core.php:1738
|
437 |
+
msgid "Instance count"
|
438 |
+
msgstr ""
|
439 |
+
|
440 |
+
#: core.php:1747
|
441 |
+
#, php-format
|
442 |
+
msgid "This link has failed %d time."
|
443 |
+
msgid_plural "This link has failed %d times."
|
444 |
msgstr[0] ""
|
445 |
msgstr[1] ""
|
446 |
|
447 |
+
#: core.php:1758
|
448 |
+
msgid "Log"
|
449 |
+
msgstr ""
|
450 |
+
|
451 |
+
#: core.php:2070
|
452 |
+
msgid "View broken links"
|
453 |
msgstr ""
|
454 |
|
455 |
+
#: core.php:2071
|
456 |
#, php-format
|
457 |
+
msgid "Found %d broken link"
|
458 |
+
msgid_plural "Found %d broken links"
|
459 |
msgstr[0] ""
|
460 |
msgstr[1] ""
|
461 |
|
462 |
+
#: core.php:2077
|
463 |
+
msgid "No broken links found."
|
464 |
+
msgstr ""
|
465 |
+
|
466 |
+
#: core.php:2084
|
467 |
#, php-format
|
468 |
+
msgid "%d URL in the work queue"
|
469 |
+
msgid_plural "%d URLs in the work queue"
|
470 |
msgstr[0] ""
|
471 |
msgstr[1] ""
|
472 |
|
473 |
+
#: core.php:2087
|
474 |
+
msgid "No URLs in the work queue."
|
475 |
+
msgstr ""
|
476 |
+
|
477 |
+
#: core.php:2093
|
478 |
#, php-format
|
479 |
+
msgid "Detected %d unique URL"
|
480 |
+
msgid_plural "Detected %d unique URLs"
|
481 |
msgstr[0] ""
|
482 |
msgstr[1] ""
|
483 |
|
484 |
+
#: core.php:2094
|
485 |
#, php-format
|
486 |
+
msgid "in %d link"
|
487 |
+
msgid_plural "in %d links"
|
488 |
msgstr[0] ""
|
489 |
msgstr[1] ""
|
490 |
|
491 |
+
#: core.php:2099
|
492 |
+
msgid "and still searching..."
|
493 |
msgstr ""
|
494 |
|
495 |
+
#: core.php:2105
|
496 |
+
msgid "Searching your blog for links..."
|
497 |
msgstr ""
|
498 |
|
499 |
+
#: core.php:2107
|
500 |
+
msgid "No links detected."
|
501 |
msgstr ""
|
502 |
|
503 |
+
#: core.php:2192 core.php:2228 core.php:2291
|
504 |
+
msgid "You're not allowed to do that!"
|
505 |
msgstr ""
|
506 |
|
507 |
+
#: core.php:2200 core.php:2238 core.php:2301
|
508 |
+
#, php-format
|
509 |
+
msgid "Oops, I can't find the link %d"
|
510 |
msgstr ""
|
511 |
|
512 |
+
#: core.php:2207
|
513 |
+
msgid "This link was manually marked as working by the user."
|
514 |
msgstr ""
|
515 |
|
516 |
+
#: core.php:2213
|
517 |
+
msgid "Oops, couldn't modify the link!"
|
518 |
msgstr ""
|
519 |
|
520 |
+
#: core.php:2216 core.php:2327
|
521 |
+
msgid "Error : link_id not specified"
|
522 |
msgstr ""
|
523 |
|
524 |
+
#: core.php:2248
|
525 |
+
msgid "Oops, the new URL is invalid!"
|
526 |
msgstr ""
|
527 |
|
528 |
+
#: core.php:2259 core.php:2310
|
529 |
+
msgid "An unexpected error occured!"
|
530 |
msgstr ""
|
531 |
|
532 |
+
#: core.php:2277
|
533 |
+
msgid "Error : link_id or new_url not specified"
|
534 |
msgstr ""
|
535 |
|
536 |
+
#: core.php:2336
|
537 |
+
msgid "You don't have sufficient privileges to access this information!"
|
538 |
msgstr ""
|
539 |
|
540 |
+
#: core.php:2349
|
541 |
+
msgid "Error : link ID not specified"
|
542 |
msgstr ""
|
543 |
|
544 |
+
#: core.php:2360
|
545 |
+
#, php-format
|
546 |
+
msgid "Failed to load link details (%s)"
|
547 |
msgstr ""
|
548 |
|
549 |
+
#: core.php:2528
|
550 |
+
#, php-format
|
551 |
+
msgid ""
|
552 |
+
"The current temporary directory is not accessible; please <a href=\"%s\">set "
|
553 |
+
"a different one</a>."
|
554 |
msgstr ""
|
555 |
|
556 |
+
#: core.php:2533
|
557 |
+
#, php-format
|
558 |
+
msgid ""
|
559 |
+
"Please make the directory <code>%1$s</code> writable by plugins or <a href="
|
560 |
+
"\"%2$s\">set a custom temporary directory</a>."
|
561 |
msgstr ""
|
562 |
|
563 |
+
#: core.php:2540
|
564 |
+
msgid "Broken Link Checker can't create a lockfile."
|
565 |
msgstr ""
|
566 |
|
567 |
+
#: core.php:2545
|
568 |
+
msgid ""
|
569 |
+
"The plugin uses a file-based locking mechanism to ensure that only one "
|
570 |
+
"instance of the resource-heavy link checking algorithm is running at any "
|
571 |
+
"given time. Unfortunately, BLC can't find a writable directory where it "
|
572 |
+
"could store the lockfile - it failed to detect the location of your server's "
|
573 |
+
"temporary directory, and the plugin's own directory isn't writable by PHP. "
|
574 |
+
"To fix this problem, please make the plugin's directory writable or enter a "
|
575 |
+
"specify a custom temporary directory in the plugin's settings."
|
576 |
msgstr ""
|
577 |
|
578 |
+
#: core.php:2564
|
579 |
+
msgid "PHP version"
|
580 |
msgstr ""
|
581 |
|
582 |
+
#: core.php:2570
|
583 |
+
msgid "MySQL version"
|
584 |
msgstr ""
|
585 |
|
586 |
+
#: core.php:2583
|
587 |
+
msgid ""
|
588 |
+
"You have an old version of CURL. Redirect detection may not work properly."
|
589 |
msgstr ""
|
590 |
|
591 |
+
#: core.php:2595 core.php:2611 core.php:2616
|
592 |
+
msgid "Not installed"
|
593 |
msgstr ""
|
594 |
|
595 |
+
#: core.php:2598
|
596 |
+
msgid "CURL version"
|
597 |
msgstr ""
|
598 |
|
599 |
+
#: core.php:2604
|
600 |
+
msgid "Installed"
|
601 |
msgstr ""
|
602 |
|
603 |
+
#: core.php:2617
|
604 |
+
msgid "You must have either CURL or Snoopy installed for the plugin to work!"
|
|
|
605 |
msgstr ""
|
606 |
|
607 |
+
#: core.php:2628
|
608 |
+
msgid "On"
|
609 |
msgstr ""
|
610 |
|
611 |
+
#: core.php:2629
|
612 |
+
msgid "Redirects may be detected as broken links when safe_mode is on."
|
613 |
msgstr ""
|
614 |
|
615 |
+
#: core.php:2634 core.php:2648
|
616 |
+
msgid "Off"
|
617 |
msgstr ""
|
618 |
|
619 |
+
#: core.php:2642
|
620 |
+
#, php-format
|
621 |
+
msgid "On ( %s )"
|
622 |
msgstr ""
|
623 |
|
624 |
+
#: core.php:2643
|
625 |
+
msgid "Redirects may be detected as broken links when open_basedir is on."
|
626 |
msgstr ""
|
627 |
|
628 |
+
#: core.php:2662
|
629 |
+
msgid "Can't create a lockfile. Please specify a custom temporary directory."
|
|
|
|
|
|
|
630 |
msgstr ""
|
631 |
|
632 |
+
#: core.php:2691
|
633 |
+
#, php-format
|
634 |
+
msgid "[%s] Broken links detected"
|
635 |
msgstr ""
|
636 |
|
637 |
+
#: core.php:2697
|
638 |
#, php-format
|
639 |
+
msgid "Broken Link Checker has detected %d new broken link on your site."
|
640 |
+
msgid_plural ""
|
641 |
+
"Broken Link Checker has detected %d new broken links on your site."
|
642 |
+
msgstr[0] ""
|
643 |
+
msgstr[1] ""
|
644 |
+
|
645 |
+
#: core.php:2712
|
646 |
+
#, php-format
|
647 |
+
msgid "Here's a list of the first %d broken links:"
|
648 |
+
msgid_plural "Here's a list of the first %d broken links:"
|
649 |
+
msgstr[0] ""
|
650 |
+
msgstr[1] ""
|
651 |
+
|
652 |
+
#: core.php:2720
|
653 |
+
msgid "Here's a list of the new broken links: "
|
654 |
msgstr ""
|
655 |
|
656 |
+
#: core.php:2732
|
657 |
+
#, php-format
|
658 |
+
msgid "Link text : %s"
|
659 |
msgstr ""
|
660 |
|
661 |
+
#: core.php:2733
|
662 |
+
#, php-format
|
663 |
+
msgid "Link URL : <a href=\"%s\">%s</a>"
|
664 |
msgstr ""
|
665 |
|
666 |
+
#: core.php:2734
|
667 |
#, php-format
|
668 |
+
msgid "Source : %s"
|
|
|
|
|
669 |
msgstr ""
|
670 |
|
671 |
+
#: core.php:2748
|
672 |
+
msgid "You can see all broken links here:"
|
673 |
msgstr ""
|
674 |
|
675 |
+
#: includes/admin/links-page-js.php:40 includes/admin/links-page-js.php:234
|
676 |
+
msgid "Wait..."
|
677 |
msgstr ""
|
678 |
|
679 |
+
#: includes/admin/links-page-js.php:109
|
680 |
+
msgid "Save URL"
|
681 |
msgstr ""
|
682 |
|
683 |
+
#: includes/admin/links-page-js.php:120
|
684 |
+
msgid "Saving changes..."
|
685 |
msgstr ""
|
686 |
|
687 |
+
#: includes/admin/links-page-js.php:166
|
688 |
+
#, php-format
|
689 |
+
msgid "%d instances of the link were successfully modified."
|
690 |
msgstr ""
|
691 |
|
692 |
+
#: includes/admin/links-page-js.php:172
|
693 |
+
#, php-format
|
694 |
+
msgid ""
|
695 |
+
"However, %d instances couldn't be edited and still point to the old URL."
|
696 |
msgstr ""
|
697 |
|
698 |
+
#: includes/admin/links-page-js.php:178
|
699 |
+
msgid "The link could not be modified."
|
700 |
msgstr ""
|
701 |
|
702 |
+
#: includes/admin/links-page-js.php:181 includes/admin/links-page-js.php:285
|
703 |
+
msgid "The following error(s) occured :"
|
704 |
msgstr ""
|
705 |
|
706 |
+
#: includes/admin/links-page-js.php:271
|
707 |
+
#, php-format
|
708 |
+
msgid "%d instances of the link were successfully unlinked."
|
709 |
msgstr ""
|
710 |
|
711 |
+
#: includes/admin/links-page-js.php:277
|
712 |
+
#, php-format
|
713 |
+
msgid "However, %d instances couldn't be removed."
|
714 |
msgstr ""
|
715 |
|
716 |
+
#: includes/admin/links-page-js.php:282
|
717 |
+
msgid "The plugin failed to remove the link."
|
718 |
msgstr ""
|
719 |
|
720 |
+
#: includes/admin/links-page-js.php:337
|
721 |
+
msgid "Enter a name for the new custom filter"
|
722 |
msgstr ""
|
723 |
|
724 |
+
#: includes/admin/links-page-js.php:348
|
725 |
+
msgid ""
|
726 |
+
"You are about to delete the current filter.\n"
|
727 |
+
"'Cancel' to stop, 'OK' to delete"
|
728 |
msgstr ""
|
729 |
|
730 |
+
#: includes/admin/links-page-js.php:371
|
731 |
+
msgid ""
|
732 |
+
"Are you sure you want to delete all posts, bookmarks or other items that "
|
733 |
+
"contain any of the selected links? This action can't be undone.\n"
|
734 |
+
"'Cancel' to stop, 'OK' to delete"
|
735 |
msgstr ""
|
736 |
|
737 |
+
#: includes/admin/search-form.php:13
|
738 |
+
msgid "Save This Search As a Filter"
|
739 |
msgstr ""
|
740 |
|
741 |
+
#: includes/admin/search-form.php:23
|
742 |
+
msgid "Delete This Filter"
|
743 |
msgstr ""
|
744 |
|
745 |
+
#: includes/admin/search-form.php:29 includes/links.php:798
|
746 |
+
msgid "Search"
|
|
|
|
|
747 |
msgstr ""
|
748 |
|
749 |
+
#: includes/admin/search-form.php:39
|
750 |
+
msgid "Link text"
|
751 |
msgstr ""
|
752 |
|
753 |
+
#: includes/admin/search-form.php:48
|
754 |
+
msgid "Link status"
|
755 |
msgstr ""
|
756 |
|
757 |
+
#: includes/admin/search-form.php:64
|
758 |
+
msgid "Link type"
|
759 |
msgstr ""
|
760 |
|
761 |
+
#: includes/admin/search-form.php:68
|
762 |
+
msgid "Any"
|
763 |
msgstr ""
|
764 |
|
765 |
+
#: includes/admin/search-form.php:69
|
766 |
+
msgid "Normal link"
|
767 |
msgstr ""
|
768 |
|
769 |
+
#: includes/admin/search-form.php:70 includes/parsers/image.php:142
|
770 |
+
msgid "Image"
|
|
|
771 |
msgstr ""
|
772 |
|
773 |
+
#: includes/admin/search-form.php:71 includes/containers/custom_field.php:176
|
774 |
+
msgid "Custom field"
|
775 |
msgstr ""
|
776 |
|
777 |
+
#: includes/admin/search-form.php:72 includes/containers/blogroll.php:13
|
778 |
+
msgid "Bookmark"
|
779 |
msgstr ""
|
780 |
|
781 |
+
#: includes/admin/search-form.php:73 includes/containers/comment.php:136
|
782 |
+
msgid "Comment"
|
783 |
+
msgstr ""
|
784 |
+
|
785 |
+
#: includes/admin/search-form.php:86
|
786 |
+
msgid "Search Links"
|
787 |
msgstr ""
|
788 |
|
789 |
+
#: includes/checkers/http.php:182 includes/checkers/http.php:249
|
790 |
#, php-format
|
791 |
+
msgid "HTTP code : %d"
|
792 |
+
msgstr ""
|
|
|
|
|
793 |
|
794 |
+
#: includes/checkers/http.php:184 includes/checkers/http.php:251
|
795 |
+
msgid "(No response)"
|
|
|
|
|
796 |
msgstr ""
|
797 |
|
798 |
+
#: includes/checkers/http.php:190
|
799 |
+
msgid "Most likely the connection timed out or the domain doesn't exist."
|
800 |
msgstr ""
|
801 |
|
802 |
+
#: includes/checkers/http.php:258
|
803 |
+
msgid "Request timed out."
|
804 |
+
msgstr ""
|
|
|
|
|
|
|
805 |
|
806 |
+
#: includes/checkers/http.php:276
|
807 |
+
msgid "Using Snoopy"
|
808 |
msgstr ""
|
809 |
|
810 |
+
#: includes/containers.php:262
|
811 |
#, php-format
|
812 |
+
msgid "Container type '%s' not recognized"
|
|
|
|
|
|
|
|
|
|
|
|
|
813 |
msgstr ""
|
814 |
|
815 |
+
#: includes/containers.php:792
|
816 |
#, php-format
|
817 |
+
msgid "%d '%s' has been deleted"
|
818 |
+
msgid_plural "%d '%s' have been deleted"
|
819 |
msgstr[0] ""
|
820 |
msgstr[1] ""
|
821 |
|
822 |
+
#: includes/containers/blogroll.php:19 includes/containers/blogroll.php:38
|
823 |
+
msgid "Edit this bookmark"
|
824 |
+
msgstr ""
|
|
|
|
|
|
|
825 |
|
826 |
+
#: includes/containers/blogroll.php:38 includes/containers/comment.php:106
|
827 |
+
#: includes/containers/custom_field.php:201 includes/containers/post.php:16
|
828 |
+
msgid "Edit"
|
829 |
msgstr ""
|
830 |
|
831 |
+
#: includes/containers/blogroll.php:39
|
832 |
+
#, php-format
|
833 |
+
msgid ""
|
834 |
+
"You are about to delete this link '%s'\n"
|
835 |
+
" 'Cancel' to stop, 'OK' to delete."
|
836 |
msgstr ""
|
837 |
|
838 |
+
#: includes/containers/blogroll.php:39
|
839 |
+
#: includes/containers/custom_field.php:206 includes/containers/post.php:21
|
840 |
+
msgid "Delete"
|
841 |
msgstr ""
|
842 |
|
843 |
+
#: includes/containers/blogroll.php:75 includes/containers/comment.php:36
|
844 |
+
#: includes/containers/post.php:86
|
845 |
+
msgid "Nothing to update"
|
846 |
msgstr ""
|
847 |
|
848 |
+
#: includes/containers/blogroll.php:89
|
849 |
#, php-format
|
850 |
+
msgid "Updating bookmark %d failed"
|
851 |
msgstr ""
|
852 |
|
853 |
+
#: includes/containers/blogroll.php:120
|
854 |
+
#, php-format
|
855 |
+
msgid "Failed to delete blogroll link \"%s\" (%d)"
|
856 |
msgstr ""
|
857 |
|
858 |
+
#: includes/containers/blogroll.php:280
|
859 |
+
#, php-format
|
860 |
+
msgid "%d blogroll link deleted"
|
861 |
+
msgid_plural "%d blogroll links deleted"
|
862 |
+
msgstr[0] ""
|
863 |
+
msgstr[1] ""
|
864 |
|
865 |
+
#: includes/containers/comment.php:46
|
866 |
+
#, php-format
|
867 |
+
msgid "Updating comment %d failed"
|
868 |
msgstr ""
|
869 |
|
870 |
+
#: includes/containers/comment.php:64
|
871 |
+
#, php-format
|
872 |
+
msgid "Failed to delete comment %d"
|
873 |
msgstr ""
|
874 |
|
875 |
+
#: includes/containers/comment.php:106 includes/containers/comment.php:148
|
876 |
+
msgid "Edit comment"
|
877 |
msgstr ""
|
878 |
|
879 |
+
#: includes/containers/comment.php:113
|
880 |
+
msgid "Delete Permanently"
|
881 |
msgstr ""
|
882 |
|
883 |
+
#: includes/containers/comment.php:115
|
884 |
+
msgid "Move this comment to the trash"
|
|
|
885 |
msgstr ""
|
886 |
|
887 |
+
#: includes/containers/comment.php:115
|
888 |
+
msgctxt "verb"
|
889 |
+
msgid "Trash"
|
890 |
msgstr ""
|
891 |
|
892 |
+
#: includes/containers/comment.php:119
|
893 |
+
msgid "View comment"
|
894 |
msgstr ""
|
895 |
|
896 |
+
#: includes/containers/comment.php:119
|
897 |
+
#: includes/containers/custom_field.php:209 includes/containers/post.php:24
|
898 |
+
msgid "View"
|
899 |
msgstr ""
|
900 |
|
901 |
+
#: includes/containers/comment.php:272
|
902 |
#, php-format
|
903 |
+
msgid "%d comment moved to the trash"
|
904 |
+
msgid_plural "%d comments moved to the trash"
|
905 |
+
msgstr[0] ""
|
906 |
+
msgstr[1] ""
|
907 |
+
|
908 |
+
#: includes/containers/comment.php:282
|
909 |
+
#, php-format
|
910 |
+
msgid "%d comment has been deleted"
|
911 |
+
msgid_plural "%d comments have been deleted"
|
912 |
+
msgstr[0] ""
|
913 |
+
msgstr[1] ""
|
914 |
+
|
915 |
+
#: includes/containers/custom_field.php:73
|
916 |
+
#, php-format
|
917 |
+
msgid "Failed to update the meta field '%s' on %s [%d]"
|
918 |
msgstr ""
|
919 |
|
920 |
+
#: includes/containers/custom_field.php:99
|
921 |
#, php-format
|
922 |
+
msgid "Failed to delete the meta field '%s' on %s [%d]"
|
923 |
msgstr ""
|
924 |
|
925 |
+
#: includes/containers/custom_field.php:191
|
926 |
+
#: includes/containers/custom_field.php:201 includes/containers/post.php:16
|
927 |
+
#: includes/containers/post.php:41
|
928 |
+
msgid "Edit this post"
|
929 |
msgstr ""
|
930 |
|
931 |
+
#: includes/containers/custom_field.php:204 includes/containers/post.php:19
|
932 |
+
msgid "Move this post to the Trash"
|
933 |
+
msgstr ""
|
934 |
+
|
935 |
+
#: includes/containers/custom_field.php:204 includes/containers/post.php:19
|
936 |
+
msgid "Trash"
|
937 |
msgstr ""
|
938 |
|
939 |
+
#: includes/containers/custom_field.php:206 includes/containers/post.php:21
|
940 |
+
msgid "Delete this post permanently"
|
941 |
+
msgstr ""
|
942 |
+
|
943 |
+
#: includes/containers/custom_field.php:206 includes/containers/post.php:21
|
944 |
#, php-format
|
945 |
msgid ""
|
946 |
+
"You are about to delete this post '%s'\n"
|
947 |
+
" 'Cancel' to stop, 'OK' to delete."
|
948 |
msgstr ""
|
949 |
|
950 |
+
#: includes/containers/custom_field.php:209 includes/containers/post.php:24
|
951 |
+
#, php-format
|
952 |
+
msgid "View \"%s\""
|
953 |
msgstr ""
|
954 |
|
955 |
+
#: includes/containers/custom_field.php:248 includes/containers/post.php:127
|
956 |
+
#, php-format
|
957 |
+
msgid "Failed to delete post \"%s\" (%d)"
|
|
|
|
|
|
|
|
|
|
|
|
|
958 |
msgstr ""
|
959 |
|
960 |
+
#: includes/containers/custom_field.php:479 includes/containers/post.php:298
|
961 |
+
#, php-format
|
962 |
+
msgid "%d post moved to the trash"
|
963 |
+
msgid_plural "%d posts moved to the trash"
|
964 |
+
msgstr[0] ""
|
965 |
+
msgstr[1] ""
|
966 |
+
|
967 |
+
#: includes/containers/custom_field.php:481 includes/containers/post.php:300
|
968 |
+
#, php-format
|
969 |
+
msgid "%d post deleted"
|
970 |
+
msgid_plural "%d posts deleted"
|
971 |
+
msgstr[0] ""
|
972 |
+
msgstr[1] ""
|
973 |
+
|
974 |
+
#: includes/containers/dummy.php:21 includes/containers/dummy.php:32
|
975 |
+
#, php-format
|
976 |
+
msgid "I don't know how to edit a '%s' [%d]."
|
977 |
msgstr ""
|
978 |
|
979 |
+
#: includes/containers/post.php:96
|
980 |
+
#, php-format
|
981 |
+
msgid "Updating post %d failed"
|
982 |
msgstr ""
|
983 |
|
984 |
+
#: includes/instances.php:102 includes/instances.php:148
|
985 |
+
#, php-format
|
986 |
+
msgid "Container %s[%d] not found"
|
987 |
msgstr ""
|
988 |
|
989 |
+
#: includes/instances.php:111 includes/instances.php:157
|
990 |
+
#, php-format
|
991 |
+
msgid "Parser '%s' not found."
|
992 |
msgstr ""
|
993 |
|
994 |
+
#: includes/links.php:157
|
995 |
+
msgid "The plugin script was terminated while trying to check the link."
|
996 |
msgstr ""
|
997 |
|
998 |
+
#: includes/links.php:201
|
999 |
+
msgid "The plugin doesn't know how to check this type of link."
|
1000 |
msgstr ""
|
1001 |
|
1002 |
+
#: includes/links.php:289
|
1003 |
+
msgid "Link is valid."
|
1004 |
msgstr ""
|
1005 |
|
1006 |
+
#: includes/links.php:291
|
1007 |
+
msgid "Link is broken."
|
1008 |
msgstr ""
|
1009 |
|
1010 |
+
#: includes/links.php:484 includes/links.php:586 includes/links.php:621
|
1011 |
+
msgid "Link is not valid"
|
1012 |
msgstr ""
|
1013 |
|
1014 |
+
#: includes/links.php:501
|
1015 |
+
msgid ""
|
1016 |
+
"This link can not be edited because it is not used anywhere on this site."
|
1017 |
msgstr ""
|
1018 |
|
1019 |
+
#: includes/links.php:527
|
1020 |
+
msgid "Failed to create a DB entry for the new URL."
|
|
|
1021 |
msgstr ""
|
1022 |
|
1023 |
+
#: includes/links.php:599
|
1024 |
+
msgid "This link is not a redirect"
|
1025 |
msgstr ""
|
1026 |
|
1027 |
+
#: includes/links.php:648 includes/links.php:685
|
1028 |
+
msgid "Couldn't delete the link's database record"
|
1029 |
msgstr ""
|
1030 |
|
1031 |
+
#: includes/links.php:770
|
1032 |
+
msgid "Broken"
|
|
|
1033 |
msgstr ""
|
1034 |
|
1035 |
+
#: includes/links.php:772
|
1036 |
+
msgid "No broken links found"
|
1037 |
msgstr ""
|
1038 |
|
1039 |
+
#: includes/links.php:779
|
1040 |
+
msgid "Redirects"
|
1041 |
msgstr ""
|
1042 |
|
1043 |
+
#: includes/links.php:780
|
1044 |
+
msgid "Redirected Links"
|
|
|
1045 |
msgstr ""
|
1046 |
|
1047 |
+
#: includes/links.php:781
|
1048 |
+
msgid "No redirects found"
|
1049 |
msgstr ""
|
1050 |
|
1051 |
+
#: includes/links.php:789
|
1052 |
+
msgid "All"
|
1053 |
msgstr ""
|
1054 |
|
1055 |
+
#: includes/links.php:790
|
1056 |
+
msgid "Detected Links"
|
1057 |
msgstr ""
|
1058 |
|
1059 |
+
#: includes/links.php:791
|
1060 |
+
msgid "No links found (yet)"
|
1061 |
msgstr ""
|
1062 |
|
1063 |
+
#: includes/links.php:799
|
1064 |
+
msgid "Search Results"
|
1065 |
msgstr ""
|
1066 |
|
1067 |
+
#: includes/links.php:800 includes/links.php:843
|
1068 |
+
msgid "No links found for your query"
|
1069 |
msgstr ""
|
1070 |
|
1071 |
+
#: includes/parsers.php:151
|
1072 |
#, php-format
|
1073 |
+
msgid "Editing is not implemented in the '%s' parser"
|
1074 |
msgstr ""
|
1075 |
|
1076 |
+
#: includes/parsers.php:166
|
1077 |
#, php-format
|
1078 |
+
msgid "Unlinking is not implemented in the '%s' parser"
|
1079 |
msgstr ""
|
1080 |
|
1081 |
+
#. Plugin Name of the plugin/theme
|
1082 |
msgid "Broken Link Checker"
|
1083 |
msgstr ""
|
1084 |
|
1085 |
+
#. Plugin URI of the plugin/theme
|
1086 |
msgid "http://w-shadow.com/blog/2007/08/05/broken-link-checker-for-wordpress/"
|
1087 |
msgstr ""
|
1088 |
|
1089 |
+
#. Description of the plugin/theme
|
1090 |
msgid ""
|
1091 |
+
"Checks your blog for broken links and missing images and notifies you on the "
|
1092 |
+
"dashboard if any are found."
|
1093 |
msgstr ""
|
1094 |
|
1095 |
+
#. Author of the plugin/theme
|
1096 |
msgid "Janis Elsts"
|
1097 |
msgstr ""
|
1098 |
|
1099 |
+
#. Author URI of the plugin/theme
|
1100 |
msgid "http://w-shadow.com/blog/"
|
1101 |
msgstr ""
|
link-classes.php
DELETED
@@ -1,622 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* @author W-Shadow
|
5 |
-
* @copyright 2009
|
6 |
-
*/
|
7 |
-
|
8 |
-
if (!class_exists('blcLink')){
|
9 |
-
class blcLink {
|
10 |
-
|
11 |
-
//Object state
|
12 |
-
var $is_new = false;
|
13 |
-
var $last_headers = '';
|
14 |
-
var $meets_check_threshold = false; //currently unused
|
15 |
-
|
16 |
-
//DB fields
|
17 |
-
var $link_id = 0;
|
18 |
-
var $url = '';
|
19 |
-
var $last_check='0000-00-00 00:00:00';
|
20 |
-
var $check_count = 0;
|
21 |
-
var $final_url = '';
|
22 |
-
var $log = '';
|
23 |
-
var $http_code = 0;
|
24 |
-
var $request_duration = 0;
|
25 |
-
var $timeout = false;
|
26 |
-
var $redirect_count = 0;
|
27 |
-
|
28 |
-
function __construct($arg = null){
|
29 |
-
global $wpdb;
|
30 |
-
|
31 |
-
if (is_int($arg)){
|
32 |
-
//Load a link with ID = $arg from the DB.
|
33 |
-
$q = $wpdb->prepare("SELECT * FROM {$wpdb->prefix}blc_links WHERE link_id=%d LIMIT 1", $arg);
|
34 |
-
$arr = $wpdb->get_row( $q, ARRAY_A );
|
35 |
-
|
36 |
-
if ( is_array($arr) ){ //Loaded successfully
|
37 |
-
$this->set_values($arr);
|
38 |
-
} else {
|
39 |
-
//Link not found. The object is invalid.
|
40 |
-
//I'd throw an error, but that wouldn't be PHP 4 compatible...
|
41 |
-
}
|
42 |
-
|
43 |
-
} else if (is_string($arg)){
|
44 |
-
//Load a link with URL = $arg from the DB. Create a new one if the record isn't found.
|
45 |
-
$q = $wpdb->prepare("SELECT * FROM {$wpdb->prefix}blc_links WHERE url=%s LIMIT 1", $arg);
|
46 |
-
$arr = $wpdb->get_row( $q, ARRAY_A );
|
47 |
-
|
48 |
-
if ( is_array($arr) ){ //Loaded successfully
|
49 |
-
$this->set_values($arr);
|
50 |
-
} else { //Link not found, treat as new
|
51 |
-
$this->url = $arg;
|
52 |
-
$this->is_new = true;
|
53 |
-
}
|
54 |
-
|
55 |
-
} else if (is_array($arg)){
|
56 |
-
$this->set_values($arg);
|
57 |
-
//Is this a new link?
|
58 |
-
$this->is_new = empty($this->link_id);
|
59 |
-
} else {
|
60 |
-
$this->is_new = true;
|
61 |
-
}
|
62 |
-
}
|
63 |
-
|
64 |
-
function blcLink($arg = null){
|
65 |
-
$this->__construct($arg);
|
66 |
-
}
|
67 |
-
|
68 |
-
/**
|
69 |
-
* blcLink::set_values()
|
70 |
-
* Set the internal values to the ones provided in an array (doesn't sanitize).
|
71 |
-
*
|
72 |
-
* @param array $arr An associative array of values
|
73 |
-
* @return void
|
74 |
-
*/
|
75 |
-
function set_values($arr){
|
76 |
-
foreach( $arr as $key => $value ){
|
77 |
-
$this->$key = $value;
|
78 |
-
}
|
79 |
-
}
|
80 |
-
|
81 |
-
/**
|
82 |
-
* blcLink::valid()
|
83 |
-
* Verifies whether the object represents a valid link
|
84 |
-
*
|
85 |
-
* @return bool
|
86 |
-
*/
|
87 |
-
function valid(){
|
88 |
-
return !empty( $this->url ) && ( !empty($this->link_id) || $this->is_new );
|
89 |
-
}
|
90 |
-
|
91 |
-
/**
|
92 |
-
* blcLink::check()
|
93 |
-
* Check if the link is working.
|
94 |
-
*
|
95 |
-
* @return bool
|
96 |
-
*/
|
97 |
-
function check( $timeout = 40 ){
|
98 |
-
if ( !$this->valid() ) return false;
|
99 |
-
|
100 |
-
//General note : there is usually no need to save() the result of the check
|
101 |
-
//in this method because it will be typically called from wsBrokenLinkChecker::work()
|
102 |
-
//that will call the save() method for us.
|
103 |
-
|
104 |
-
/*
|
105 |
-
Check for problematic (though not necessarily "broken") links.
|
106 |
-
If a link has been checked multiple times and still hasn't been marked as
|
107 |
-
timed-out or broken then probably the checking algorithm is having problems with
|
108 |
-
that link. Mark it as timed-out and hope the user sorts it out.
|
109 |
-
*/
|
110 |
-
if ( ($this->check_count >= 3) && ( !$this->timeout ) && ( $this->http_code == BLC_CHECKING ) ) {
|
111 |
-
$this->timeout = true;
|
112 |
-
$this->http_code = BLC_TIMEOUT;
|
113 |
-
$this->last_check = date('Y-m-d H:i:s');
|
114 |
-
$this->log .= "\r\n[A weird error was detected. This should never happen.]";
|
115 |
-
return false;
|
116 |
-
}
|
117 |
-
|
118 |
-
//Update the DB record before actually performing the check.
|
119 |
-
//Useful if something goes terribly wrong while checkint this particular URL.
|
120 |
-
//Note : might be unnecessary.
|
121 |
-
$this->check_count++;
|
122 |
-
$this->last_check = date('Y-m-d H:i:s');
|
123 |
-
$this->log = '';
|
124 |
-
$this->final_url = '';
|
125 |
-
$this->http_code = BLC_CHECKING;
|
126 |
-
$this->request_duration = 0;
|
127 |
-
$this->timeout = false;
|
128 |
-
$this->redirect_count = 0;
|
129 |
-
$this->save();
|
130 |
-
|
131 |
-
//Empty some variables before running the check
|
132 |
-
$this->last_headers = '';
|
133 |
-
|
134 |
-
//Save the URL into a local var; we'll need it later.
|
135 |
-
$url = $this->url;
|
136 |
-
|
137 |
-
$parts = parse_url($url);
|
138 |
-
//Only HTTP links are checked. All others are automatically considered okay.
|
139 |
-
if ( ($parts['scheme'] != 'http') && ($parts['scheme'] != 'https') ) {
|
140 |
-
$this->log .= "URL protocol ($parts[scheme]) is not HTTP(S). This link won't be checked.\n";
|
141 |
-
$this->http_code = 200;
|
142 |
-
return true;
|
143 |
-
}
|
144 |
-
|
145 |
-
//Kill the #anchor if it's present
|
146 |
-
$anchor_start = strpos($url, '#');
|
147 |
-
if ( $anchor_start !== false ){
|
148 |
-
$url = substr($url, 0, $anchor_start);
|
149 |
-
}
|
150 |
-
|
151 |
-
//******* Use CURL if available ***********
|
152 |
-
if ( function_exists('curl_init') ) {
|
153 |
-
$ch = curl_init();
|
154 |
-
curl_setopt($ch, CURLOPT_URL, blcUtility::urlencodefix($url));
|
155 |
-
//Masquerade as Internet explorer
|
156 |
-
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)');
|
157 |
-
//Add a semi-plausible referer header to avoid tripping up some bot traps
|
158 |
-
curl_setopt($ch, CURLOPT_REFERER, get_option('home'));
|
159 |
-
|
160 |
-
//Redirects don't work when safe mode or open_basedir is enabled.
|
161 |
-
if ( !blcUtility::is_safe_mode() && !blcUtility::is_open_basedir() ) {
|
162 |
-
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
163 |
-
}
|
164 |
-
curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
|
165 |
-
|
166 |
-
//Set the timeout
|
167 |
-
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
168 |
-
|
169 |
-
//Set the proxy configuration. The user can provide this in wp-config.php
|
170 |
-
if (defined('WP_PROXY_HOST')) {
|
171 |
-
curl_setopt($ch, CURLOPT_PROXY, WP_PROXY_HOST);
|
172 |
-
}
|
173 |
-
|
174 |
-
if (defined('WP_PROXY_PORT')) {
|
175 |
-
curl_setopt($ch, CURLOPT_PROXYPORT, WP_PROXY_PORT);
|
176 |
-
}
|
177 |
-
|
178 |
-
if (defined('WP_PROXY_USERNAME')){
|
179 |
-
$auth = WP_PROXY_USERNAME;
|
180 |
-
if (defined('WP_PROXY_PASSWORD')){
|
181 |
-
$auth .= ':' . WP_PROXY_PASSWORD;
|
182 |
-
}
|
183 |
-
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $auth);
|
184 |
-
}
|
185 |
-
|
186 |
-
//Is this even necessary?
|
187 |
-
curl_setopt($ch, CURLOPT_FAILONERROR, false);
|
188 |
-
|
189 |
-
$nobody = false;
|
190 |
-
if( $parts['scheme'] == 'https' ){
|
191 |
-
//TODO: Redirects don't work with HTTPS
|
192 |
-
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
193 |
-
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
|
194 |
-
} else {
|
195 |
-
$nobody = true;
|
196 |
-
curl_setopt($ch, CURLOPT_NOBODY, true); //Use the HEAD method for non-https URLs
|
197 |
-
}
|
198 |
-
|
199 |
-
//Register a callback function which will process the HTTP header(s).
|
200 |
-
//It can be called multiple times if the remote server performs a redirect.
|
201 |
-
curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$this,'read_header'));
|
202 |
-
|
203 |
-
//Execute the request
|
204 |
-
curl_exec($ch);
|
205 |
-
|
206 |
-
$info = curl_getinfo($ch);
|
207 |
-
$code = intval( $info['http_code'] );
|
208 |
-
|
209 |
-
$this->log .= '=== ';
|
210 |
-
|
211 |
-
if ( $code ){
|
212 |
-
$this->log .= sprintf( __('First try : %d', 'broken-link-checker'), $code);
|
213 |
-
} else {
|
214 |
-
$this->log .= __('First try : 0 (No response)', 'broken-link-checker');
|
215 |
-
}
|
216 |
-
|
217 |
-
$this->log .= " ===\n\n";
|
218 |
-
|
219 |
-
$this->log .= $this->last_headers."\n";
|
220 |
-
|
221 |
-
if ( (($code<200) || ($code>=400)) && $nobody) {
|
222 |
-
$this->log .= __("Trying a second time with different settings...", 'broken-link-checker') . "\n";
|
223 |
-
$this->last_headers = '';
|
224 |
-
|
225 |
-
curl_setopt($ch, CURLOPT_NOBODY, false); //Don't send a HEAD request this time
|
226 |
-
curl_setopt($ch, CURLOPT_HTTPGET, true); //Switch back to GET instead.
|
227 |
-
curl_setopt($ch, CURLOPT_RANGE, '0-2047');//But limit the desired response size,
|
228 |
-
//we don't want to eat the user's bandwidth.
|
229 |
-
//Run it again
|
230 |
-
curl_exec($ch);
|
231 |
-
|
232 |
-
$info = curl_getinfo($ch);
|
233 |
-
$code = intval( $info['http_code'] );
|
234 |
-
|
235 |
-
$this->log .= '=== ';
|
236 |
-
if ( $code ){
|
237 |
-
$this->log .= sprintf( __('Second try : %d', 'broken-link-checker'), $code);
|
238 |
-
} else {
|
239 |
-
$this->log .= __('Second try : 0 (No response)', 'broken-link-checker');
|
240 |
-
}
|
241 |
-
$this->log .= " ===\n\n";
|
242 |
-
|
243 |
-
$this->log .= $this->last_headers."\n";
|
244 |
-
}
|
245 |
-
|
246 |
-
$this->http_code = $code != 0 ? $code : BLC_TIMEOUT;
|
247 |
-
$this->final_url = $info['url'];
|
248 |
-
$this->request_duration = $info['total_time'];
|
249 |
-
$this->redirect_count = $info['redirect_count'];
|
250 |
-
|
251 |
-
//When safe_mode or open_basedir is enabled CURL will be forbidden from following redirects,
|
252 |
-
//so redirect_count will be 0 for all URLs. As a workaround, set it to 1 when the HTTP
|
253 |
-
//response codes indicates a redirect but redirect_count is zero.
|
254 |
-
//Note to self : Extracting the Location header might also be helpful.
|
255 |
-
if ( ($this->redirect_count == 0) && ( in_array( $this->http_code, array(301, 302, 307) ) ) ){
|
256 |
-
$this->redirect_count = 1;
|
257 |
-
}
|
258 |
-
|
259 |
-
|
260 |
-
curl_close($ch);
|
261 |
-
|
262 |
-
} elseif ( class_exists('Snoopy') ) {
|
263 |
-
//******** Use Snoopy if CURL is not available *********
|
264 |
-
//Note : Snoopy doesn't work too well with HTTPS URLs.
|
265 |
-
$this->log .= "<em>(" . __('Using Snoopy', 'broken-link-checker') . ")</em>\n";
|
266 |
-
|
267 |
-
$start_time = microtime_float(true);
|
268 |
-
|
269 |
-
$snoopy = new Snoopy;
|
270 |
-
$snoopy->read_timeout = $timeout; //read timeout in seconds
|
271 |
-
$snoopy->maxlength = 1024*5; //load up to 5 kilobytes
|
272 |
-
$snoopy->fetch($url);
|
273 |
-
|
274 |
-
$this->request_duration = microtime_float(true) - $start_time;
|
275 |
-
|
276 |
-
$this->http_code = $snoopy->status; //HTTP status code (note : Snoopy returns -100 on timeout)
|
277 |
-
if ( $this->http_code == -100 ){
|
278 |
-
$this->http_code = BLC_TIMEOUT;
|
279 |
-
$this->timeout = true;
|
280 |
-
}
|
281 |
-
|
282 |
-
if ($snoopy->error)
|
283 |
-
$this->log .= $snoopy->error."\n";
|
284 |
-
if ($snoopy->timed_out)
|
285 |
-
$this->log .= __("Request timed out.", 'broken-link-checker') . "\n";
|
286 |
-
|
287 |
-
if ( is_array($snoopy->headers) )
|
288 |
-
$this->log .= implode("", $snoopy->headers)."\n"; //those headers already contain newlines
|
289 |
-
|
290 |
-
//Redirected?
|
291 |
-
if ( $snoopy->lastredirectaddr ) {
|
292 |
-
$this->final_url = $snoopy->lastredirectaddr;
|
293 |
-
$this->redirect_count = $snoopy->_redirectdepth;
|
294 |
-
} else {
|
295 |
-
$this->final_url = $this->url;
|
296 |
-
}
|
297 |
-
}
|
298 |
-
|
299 |
-
/*"Good" response codes are anything in the 2XX range (e.g "200 OK") and redirects - the 3XX range.
|
300 |
-
HTTP 401 Unauthorized is a special case that is considered OK as well. Other errors - the 4XX range -
|
301 |
-
are treated as "page doesn't exist'". */
|
302 |
-
//TODO: Treat circular redirects as broken links.
|
303 |
-
if ( (($this->http_code>=200) && ($this->http_code<400)) || ($this->http_code == 401) ) {
|
304 |
-
$this->log .= __("Link is valid.", 'broken-link-checker');
|
305 |
-
//Reset the check count for valid links.
|
306 |
-
$this->check_count = 0;
|
307 |
-
return true;
|
308 |
-
} else {
|
309 |
-
$this->log .= __("Link is broken.", 'broken-link-checker');
|
310 |
-
if ( $this->http_code == BLC_TIMEOUT ){
|
311 |
-
//This is probably a timeout
|
312 |
-
$this->timeout = true;
|
313 |
-
$this->log .= "\r\n(" . __("Most likely the connection timed out or the domain doesn't exist.", 'broken-link-checker') . ')';
|
314 |
-
}
|
315 |
-
return false;
|
316 |
-
}
|
317 |
-
}
|
318 |
-
|
319 |
-
function read_header($ch, $header){
|
320 |
-
$this->last_headers .= $header;
|
321 |
-
return strlen($header);
|
322 |
-
}
|
323 |
-
|
324 |
-
/**
|
325 |
-
* blcLink::save()
|
326 |
-
* Save link data to DB.
|
327 |
-
*
|
328 |
-
* @return bool True if saved successfully, false otherwise.
|
329 |
-
*/
|
330 |
-
function save(){
|
331 |
-
global $wpdb;
|
332 |
-
|
333 |
-
if ( !$this->valid() ) return false;
|
334 |
-
|
335 |
-
if ( $this->is_new ){
|
336 |
-
|
337 |
-
//Insert a new row
|
338 |
-
$q = "
|
339 |
-
INSERT INTO {$wpdb->prefix}blc_links
|
340 |
-
( url, last_check, check_count, final_url, redirect_count, log, http_code, request_duration, timeout )
|
341 |
-
VALUES( %s, %s, %d, %s, %d, %s, %d, %f, %d )";
|
342 |
-
$q = $wpdb->prepare($q, $this->url, $this->last_check, $this->check_count, $this->final_url,
|
343 |
-
$this->redirect_count, $this->log, $this->http_code, $this->request_duration, (integer)$this->timeout );
|
344 |
-
$rez = $wpdb->query($q);
|
345 |
-
|
346 |
-
$rez = $rez !== false;
|
347 |
-
|
348 |
-
if ($rez){
|
349 |
-
$this->link_id = $wpdb->insert_id;
|
350 |
-
//echo "Link added, ID : {$this->link_id}\r\n<br>";
|
351 |
-
//If the link was successfully saved then it's no longer "new"
|
352 |
-
$this->is_new = !$rez;
|
353 |
-
} else {
|
354 |
-
printf( __('Error adding link %s : %s', 'broken-link-checker'), $url, $wpdb->last_error );
|
355 |
-
echo "\r\n<br>";
|
356 |
-
}
|
357 |
-
|
358 |
-
return $rez;
|
359 |
-
|
360 |
-
} else {
|
361 |
-
|
362 |
-
//Update an existing DB record
|
363 |
-
$q = "UPDATE {$wpdb->prefix}blc_links SET url=%s, last_check=%s, check_count=%d, final_url=%s,
|
364 |
-
redirect_count=%d, log=%s, http_code=%d, request_duration=%f, timeout=%d
|
365 |
-
WHERE link_id=%d";
|
366 |
-
|
367 |
-
$q = $wpdb->prepare($q, $this->url, $this->last_check, $this->check_count, $this->final_url,
|
368 |
-
$this->redirect_count, $this->log, $this->http_code, $this->request_duration, (integer)$this->timeout, $this->link_id );
|
369 |
-
|
370 |
-
$rez = $wpdb->query($q);
|
371 |
-
if ( $rez !== false ){
|
372 |
-
//echo "Link updated, ID : {$this->link_id}\r\n<br>";
|
373 |
-
} else {
|
374 |
-
printf( __('Error updating link %d : %s', 'broken-link-checker'), $this->link_id, $wpdb->last_error );
|
375 |
-
echo "\r\n<br>";
|
376 |
-
}
|
377 |
-
return $rez !== false;
|
378 |
-
}
|
379 |
-
}
|
380 |
-
|
381 |
-
/**
|
382 |
-
* blcLink::edit()
|
383 |
-
* Edit all instances of the link by changing the URL.
|
384 |
-
*
|
385 |
-
* Here's how this really works : create a new link with the new URL. Then edit()
|
386 |
-
* all instances and point them to the new link record. If some instance can't be
|
387 |
-
* edited they will still point to the old record. The old record is deleted
|
388 |
-
* if all instances were edited successfully.
|
389 |
-
*
|
390 |
-
* @param string $new_url
|
391 |
-
* @return array An associative array with the new link ID, the number of successfully edited instances and the number of failed edits.
|
392 |
-
*/
|
393 |
-
function edit($new_url){
|
394 |
-
if ( !$this->valid() ){
|
395 |
-
return false;
|
396 |
-
}
|
397 |
-
|
398 |
-
//FB::info('Changing link '.$this->link_id .' to URL "'.$new_url.'"');
|
399 |
-
|
400 |
-
$instances = $this->get_instances();
|
401 |
-
//Fail if there are no instances
|
402 |
-
if (empty($instances)) return false;
|
403 |
-
|
404 |
-
//Load or create a link with the URL = $new_url
|
405 |
-
$new_link = new blcLink($new_url);
|
406 |
-
$was_new = $new_link->is_new;
|
407 |
-
if ($new_link->is_new) {
|
408 |
-
//FB::log($new_link, 'Saving a new link');
|
409 |
-
$new_link->save(); //so that we get a valid link_id
|
410 |
-
}
|
411 |
-
|
412 |
-
if ( empty($new_link->link_id) ){
|
413 |
-
//FB::error("Failed to create a new link record");
|
414 |
-
return false;
|
415 |
-
}
|
416 |
-
|
417 |
-
//Edit each instance.
|
418 |
-
//FB::info('Editing ' . count($instances) . ' instances');
|
419 |
-
$cnt_okay = $cnt_error = 0;
|
420 |
-
foreach ( $instances as $instance ){
|
421 |
-
if ( $instance->edit( $this->url, $new_url ) ){
|
422 |
-
$cnt_okay++;
|
423 |
-
$instance->link_id = $new_link->link_id;
|
424 |
-
$instance->save();
|
425 |
-
//FB::info($instance, 'Successfully edited instance ' . $instance->instance_id);
|
426 |
-
} else {
|
427 |
-
$cnt_error++;
|
428 |
-
//FB::error($instance, 'Failed to edit instance ' . $instance->instance_id);
|
429 |
-
}
|
430 |
-
}
|
431 |
-
|
432 |
-
//If all instances were edited successfully we can delete the old link record.
|
433 |
-
//And copy the new link data into this object. UNLESS this link is equal to the new link
|
434 |
-
//(which should never happen, but whatever)
|
435 |
-
if ( ( $cnt_error == 0 ) && ( $cnt_okay > 0 ) && ( $this->link_id != $new_link->link_id ) ){
|
436 |
-
$this->forget( false );
|
437 |
-
|
438 |
-
$this->link_id = $new_link->link_id;
|
439 |
-
$this->url = $new_link->url;
|
440 |
-
$this->final_url = $new_link->url;
|
441 |
-
$this->log = $new_link->log;
|
442 |
-
$this->http_code = $new_link->http_code;
|
443 |
-
$this->redirect_count = $new_link->redirect_count;
|
444 |
-
$this->timeout = $new_link->timeout;
|
445 |
-
}
|
446 |
-
|
447 |
-
//On the other hand, if no instances could be edited and the $new_link was really new,
|
448 |
-
//then delete it.
|
449 |
-
if ( ( $cnt_okay == 0 ) && $was_new ){
|
450 |
-
$new_link->forget( false );
|
451 |
-
}
|
452 |
-
|
453 |
-
return array(
|
454 |
-
'new_link_id' => $this->link_id,
|
455 |
-
'cnt_okay' => $cnt_okay,
|
456 |
-
'cnt_error' => $cnt_error,
|
457 |
-
);
|
458 |
-
}
|
459 |
-
|
460 |
-
/**
|
461 |
-
* blcLink::deredirect()
|
462 |
-
* Edit all of of this link's instances and replace the URL with the URL that it redirects to.
|
463 |
-
* This method does nothing if the link isn't a redirect.
|
464 |
-
*
|
465 |
-
* @return bool|array An associative array with the new_link_id, the number of successfully edited instances (cnt_okay) and the number of failed edits (cnt_error). Returns False on error or if the link is not a redirect.
|
466 |
-
*/
|
467 |
-
function deredirect(){
|
468 |
-
if ( !$this->valid() ){
|
469 |
-
return false;
|
470 |
-
}
|
471 |
-
|
472 |
-
if ( ($this->redirect_count <= 0) || empty($this->final_url) ){
|
473 |
-
return false;
|
474 |
-
}
|
475 |
-
|
476 |
-
return $this->edit($this->final_url);
|
477 |
-
}
|
478 |
-
|
479 |
-
/**
|
480 |
-
* blcLink::unlink()
|
481 |
-
* Delete (unlink) all instances and the link itself
|
482 |
-
*
|
483 |
-
* @return bool Returns True on success, False on error
|
484 |
-
*/
|
485 |
-
function unlink(){
|
486 |
-
if ( !$this->valid() ){
|
487 |
-
return false;
|
488 |
-
}
|
489 |
-
|
490 |
-
//FB::info($this, 'Removing link');
|
491 |
-
|
492 |
-
$instances = $this->get_instances();
|
493 |
-
//Fail if there are no instances
|
494 |
-
if (empty($instances)) {
|
495 |
-
//FB::warn("This link has no instances. Deleting the link.");
|
496 |
-
return $this->forget( false ) !== false;
|
497 |
-
}
|
498 |
-
|
499 |
-
//Unlink each instance.
|
500 |
-
//FB::info('Unlinking ' . count($instances) . ' instances');
|
501 |
-
$cnt_okay = $cnt_error = 0;
|
502 |
-
foreach ( $instances as $instance ){
|
503 |
-
if ( $instance->unlink( $this->url ) ){
|
504 |
-
$cnt_okay++;
|
505 |
-
//FB::info( $instance, 'Successfully unlinked instance' );
|
506 |
-
} else {
|
507 |
-
$cnt_error++;
|
508 |
-
//FB::error( $instance, 'Failed to unlink instance' );
|
509 |
-
}
|
510 |
-
}
|
511 |
-
|
512 |
-
//If all instances were unlinked successfully we can delete the link record.
|
513 |
-
if ( ( $cnt_error == 0 ) && ( $cnt_okay > 0 ) ){
|
514 |
-
//FB::log('Instances removed, deleting the link.');
|
515 |
-
return $this->forget() !== false;
|
516 |
-
} else {
|
517 |
-
//FB::error("Something went wrong. Unlinked instances : $cnt_okay, errors : $cnt_error");
|
518 |
-
return false;
|
519 |
-
}
|
520 |
-
}
|
521 |
-
|
522 |
-
/**
|
523 |
-
* blcLink::forget()
|
524 |
-
* Remove the link and instance records from the DB. Doesn't alter posts/etc.
|
525 |
-
*
|
526 |
-
* @return mixed 1 on success, 0 if link not found, false on error.
|
527 |
-
*/
|
528 |
-
function forget($remove_instances = true){
|
529 |
-
global $wpdb;
|
530 |
-
if ( !$this->valid() ) return false;
|
531 |
-
|
532 |
-
if ( !empty($this->link_id) ){
|
533 |
-
//FB::info($this, 'Deleting link from DB');
|
534 |
-
|
535 |
-
if ( $remove_instances ){
|
536 |
-
//Remove instances, if any
|
537 |
-
$wpdb->query( $wpdb->prepare("DELETE FROM {$wpdb->prefix}blc_instances WHERE link_id=%d", $this->link_id) );
|
538 |
-
}
|
539 |
-
|
540 |
-
//Remove the link itself
|
541 |
-
$rez = $wpdb->query( $wpdb->prepare("DELETE FROM {$wpdb->prefix}blc_links WHERE link_id=%d", $this->link_id) );
|
542 |
-
$this->link_id = 0;
|
543 |
-
|
544 |
-
return $rez;
|
545 |
-
} else {
|
546 |
-
return false;
|
547 |
-
}
|
548 |
-
|
549 |
-
}
|
550 |
-
|
551 |
-
/**
|
552 |
-
* blcLink::get_instances()
|
553 |
-
* Get a list of the link's instances
|
554 |
-
*
|
555 |
-
* @param integer $max_count The maximum number of instances to return. The default is -1 (no limit)
|
556 |
-
* @return array An array of instance objects or FALSE on failure.
|
557 |
-
*/
|
558 |
-
function get_instances($max_count = -1){
|
559 |
-
global $wpdb;
|
560 |
-
if ( !$this->valid() || empty($this->link_id) ) return false;
|
561 |
-
|
562 |
-
$limit = $max_count > 0 ? "LIMIT $max_count":'';
|
563 |
-
|
564 |
-
//Get all instances of this link
|
565 |
-
$q = $wpdb->prepare("SELECT * FROM {$wpdb->prefix}blc_instances WHERE link_id=%d $limit", $this->link_id);
|
566 |
-
$results = $wpdb->get_results($q, ARRAY_A);
|
567 |
-
|
568 |
-
if ( !empty($results) ) {
|
569 |
-
//Create an object for each instance
|
570 |
-
$instances = array();
|
571 |
-
foreach ($results as $result){
|
572 |
-
//Each source/link type combination has it's own subclass. E.g. _post_image or _blogroll_link.
|
573 |
-
$classname = 'blcLinkInstance_' . $result['source_type'] . '_' . $result['instance_type'];
|
574 |
-
$instances[] = new $classname($result);
|
575 |
-
}
|
576 |
-
return $instances;
|
577 |
-
} else {
|
578 |
-
return false;
|
579 |
-
}
|
580 |
-
}
|
581 |
-
|
582 |
-
/**
|
583 |
-
* blcLink::add_instance()
|
584 |
-
* Record a new instance of the link.
|
585 |
-
*
|
586 |
-
* @param int $source_id
|
587 |
-
* @param string $source_type
|
588 |
-
* @param string $link_text
|
589 |
-
* @param string $instance_type
|
590 |
-
* @return object The created instance or FALSE on error.
|
591 |
-
*/
|
592 |
-
function add_instance($source_id, $source_type, $link_text, $instance_type){
|
593 |
-
|
594 |
-
//The link must be saved before an instance can be added
|
595 |
-
if ($this->is_new) {
|
596 |
-
if ( !$this->save()) return false;
|
597 |
-
}
|
598 |
-
|
599 |
-
//Create a new instance tied to this link
|
600 |
-
$classname = 'blcLinkInstance_' . $source_type . '_' . $instance_type;
|
601 |
-
if ( !class_exists($classname) ){
|
602 |
-
$classname = 'blcLinkInstance';
|
603 |
-
}
|
604 |
-
$inst = new $classname( array(
|
605 |
-
'link_id' => $this->link_id,
|
606 |
-
'source_id' => $source_id,
|
607 |
-
'source_type' => $source_type,
|
608 |
-
'link_text' => $link_text,
|
609 |
-
'instance_type' => $instance_type,
|
610 |
-
) );
|
611 |
-
|
612 |
-
//Save the instance to the DB
|
613 |
-
if ( $inst->save() ){
|
614 |
-
return $inst;
|
615 |
-
} else {
|
616 |
-
return false;
|
617 |
-
};
|
618 |
-
}
|
619 |
-
}
|
620 |
-
} //class_exists
|
621 |
-
|
622 |
-
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
readme.txt
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
=== Broken Link Checker ===
|
2 |
Contributors: whiteshadow
|
3 |
-
Tags: links, broken, maintenance, blogroll, custom fields, admin
|
4 |
-
Requires at least: 2.
|
5 |
-
Tested up to: 3.0-
|
6 |
-
Stable tag: 0.
|
7 |
|
8 |
-
This plugin will check your posts,
|
9 |
|
10 |
== Description ==
|
11 |
This plugin will monitor your blog looking for broken links and let you know if any are found.
|
12 |
|
13 |
**Features**
|
14 |
|
15 |
-
* Monitors links in your posts, pages, the blogroll, and custom fields (optional).
|
16 |
* Detects links that don't work and missing images.
|
17 |
* Notifies you on the Dashboard if any are found.
|
18 |
* Also detects redirected links.
|
@@ -25,26 +25,24 @@ This plugin will monitor your blog looking for broken links and let you know if
|
|
25 |
|
26 |
**Basic Usage**
|
27 |
|
28 |
-
Once installed, the plugin will begin parsing your posts, bookmarks (AKA blogroll), etc and looking for links. Depending on the size of your site this can take a few minutes
|
29 |
|
30 |
-
|
31 |
|
32 |
-
The broken links
|
33 |
|
34 |
-
|
35 |
-
|
36 |
-
There are several actions associated with each link listed -
|
37 |
|
38 |
* "Details" shows more info about the link. You can also toggle link details by clicking on the "link text" cell.
|
39 |
-
* "Edit URL" lets you change the URL of that link. If the link is present in more than one place (e.g. both in a post and in the blogroll) then all
|
40 |
* "Unlink" removes the link but leaves the link text intact.
|
41 |
-
* "
|
42 |
-
* "Discard" lets you manually mark the link as valid. This is useful if you know it was detected as broken only due to a temporary glitch or similar. The link will still be checked normally later.
|
43 |
|
44 |
**Translations**
|
45 |
|
46 |
* Belorussian - [M. Comfi](http://www.comfi.com/)
|
47 |
* Chinese Simplified - [Hank Yang](http://wenzhu.org/)
|
|
|
48 |
* Danish - [Georg S. Adamsen](http://wordpress.blogos.dk/)
|
49 |
* Dutch - [Gideon van Melle](http://www.gvmelle.com/)
|
50 |
* French - [Whiler](http://blogs.wittwer.fr/whiler/)
|
@@ -67,14 +65,35 @@ That's it.
|
|
67 |
|
68 |
To upgrade your installation
|
69 |
|
70 |
-
1.
|
71 |
-
1.
|
72 |
-
1. Reactivate the plugin. Your settings
|
73 |
|
74 |
== Changelog ==
|
75 |
|
76 |
*This is an automatically generated changelog*
|
77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
= 0.8.1 =
|
79 |
* Updated Italian translation.
|
80 |
* Removed the survey link.
|
@@ -220,7 +239,7 @@ To upgrade your installation
|
|
220 |
|
221 |
= 0.5 =
|
222 |
* This is a near-complete rewrite with a lot of new features.
|
223 |
-
* See
|
224 |
|
225 |
= 0.4.14 =
|
226 |
* Fix false positives when the URL contains an #anchor
|
1 |
=== Broken Link Checker ===
|
2 |
Contributors: whiteshadow
|
3 |
+
Tags: links, broken, maintenance, blogroll, custom fields, admin, comments, posts
|
4 |
+
Requires at least: 2.9.0
|
5 |
+
Tested up to: 3.0-beta1
|
6 |
+
Stable tag: 0.9
|
7 |
|
8 |
+
This plugin will check your posts, comments and other places for broken links and missing images and notify you if any are found.
|
9 |
|
10 |
== Description ==
|
11 |
This plugin will monitor your blog looking for broken links and let you know if any are found.
|
12 |
|
13 |
**Features**
|
14 |
|
15 |
+
* Monitors links in your posts, pages, comments, the blogroll, and custom fields (optional).
|
16 |
* Detects links that don't work and missing images.
|
17 |
* Notifies you on the Dashboard if any are found.
|
18 |
* Also detects redirected links.
|
25 |
|
26 |
**Basic Usage**
|
27 |
|
28 |
+
Once installed, the plugin will begin parsing your posts, bookmarks (AKA blogroll), etc and looking for links. Depending on the size of your site this can take from a few minutes to several hours. When parsing is complete, the plugin will start checking each link to see if it works. Again, how long this takes depends on how big your site is and how many links there are. You can monitor the progress and tweak various link checking options in *Settings -> Link Checker*.
|
29 |
|
30 |
+
The broken links, if any are found, will show up in a new tab of the WP admin panel - *Tools -> Broken Links*. A notification will also appear in the "Broken Link Checker" widget on the Dashboard. To save display space, you can keep the widget closed and configure it to expand automatically when problematic links are detected.
|
31 |
|
32 |
+
The "Broken Links" tab will by default display a list of broken links that have been detected so far. However, you can use the links on that page to view redirects or see a listing of all links - working or not - instead. You can also create new link filters by performing a search and clicking the "Create Custom Filter" button. For example, this can be used to create a filter that only shows comment links.
|
33 |
|
34 |
+
There are several actions associated with each link. They show up when you move your mouse over to one of the links listed the aforementioned tab -
|
|
|
|
|
35 |
|
36 |
* "Details" shows more info about the link. You can also toggle link details by clicking on the "link text" cell.
|
37 |
+
* "Edit URL" lets you change the URL of that link. If the link is present in more than one place (e.g. both in a post and in the blogroll) then all occurences of that URL will be changed.
|
38 |
* "Unlink" removes the link but leaves the link text intact.
|
39 |
+
* "Not broken" lets you manually mark a "broken" link as working. This is useful if you know it was incorrectly detected as broken due to a network glitch or a bug. The marked link will still be checked periodically, but the plugin won't consider it broken unless it gets a new result.
|
|
|
40 |
|
41 |
**Translations**
|
42 |
|
43 |
* Belorussian - [M. Comfi](http://www.comfi.com/)
|
44 |
* Chinese Simplified - [Hank Yang](http://wenzhu.org/)
|
45 |
+
* Czech - [Lelkoun](http://lelkoun.cz/)
|
46 |
* Danish - [Georg S. Adamsen](http://wordpress.blogos.dk/)
|
47 |
* Dutch - [Gideon van Melle](http://www.gvmelle.com/)
|
48 |
* French - [Whiler](http://blogs.wittwer.fr/whiler/)
|
65 |
|
66 |
To upgrade your installation
|
67 |
|
68 |
+
1. Deactivate the plugin
|
69 |
+
1. Retrieve and upload the new files (do steps 1. - 3. from "new installation" instructions)
|
70 |
+
1. Reactivate the plugin. Your settings will be retained from the previous version.
|
71 |
|
72 |
== Changelog ==
|
73 |
|
74 |
*This is an automatically generated changelog*
|
75 |
|
76 |
+
= 0.9 =
|
77 |
+
* Masquerade as IE 7 when using the Snoopy library to check links. Should prevent some false positives.
|
78 |
+
* Fixed relative URL handling (yet again). It'll work this time, honest ;)
|
79 |
+
* Fixed post titles being displayed incorrectly on multilingual blogs (props Konstanin Zhilenko)
|
80 |
+
* Misc fixes/comments.
|
81 |
+
* "Unlink" works properly now.
|
82 |
+
* Additional source code comments.
|
83 |
+
* Don't try to display icons in email notifications. It didn't work anyway.
|
84 |
+
* Use AJAX nonces for additional security.
|
85 |
+
* General code cleanup.
|
86 |
+
* Email notifications about broken links.
|
87 |
+
* "Recheck" bulk action.
|
88 |
+
* Check comment links.
|
89 |
+
* Suspend checking if the server is overloaded (on by default).
|
90 |
+
* Icons for broken links and redirects.
|
91 |
+
* Fixed some UI glitches.
|
92 |
+
* "Discard" gone, replaced by "Not broken".
|
93 |
+
* "Exclude" gone from action links.
|
94 |
+
* Better handling of false positives.
|
95 |
+
* FTP, mailto:, javascript: and other links with unsupported protocols now show up in the �All links� list.
|
96 |
+
|
97 |
= 0.8.1 =
|
98 |
* Updated Italian translation.
|
99 |
* Removed the survey link.
|
239 |
|
240 |
= 0.5 =
|
241 |
* This is a near-complete rewrite with a lot of new features.
|
242 |
+
* See http://w-shadow.com/blog/2009/05/22/broken-link-checker-05/ for details.
|
243 |
|
244 |
= 0.4.14 =
|
245 |
* Fix false positives when the URL contains an #anchor
|
uninstall.php
CHANGED
@@ -16,7 +16,7 @@ if( defined( 'ABSPATH') && defined('WP_UNINSTALL_PLUGIN') ) {
|
|
16 |
$mywpdb = $GLOBALS['wpdb'];
|
17 |
if( isset($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" );
|
20 |
}
|
21 |
}
|
22 |
|
16 |
$mywpdb = $GLOBALS['wpdb'];
|
17 |
if( isset($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 |
}
|
22 |
|
utility-class.php
CHANGED
@@ -67,7 +67,7 @@ class blcUtility {
|
|
67 |
if ( ($parts['scheme'] != 'http') && ($parts['scheme'] != 'https') )
|
68 |
return false;
|
69 |
}
|
70 |
-
|
71 |
$url = html_entity_decode($url);
|
72 |
$url = preg_replace(
|
73 |
array('/([\?&]PHPSESSID=\w+)$/i', //remove session ID
|
@@ -103,12 +103,18 @@ class blcUtility {
|
|
103 |
return false;
|
104 |
}
|
105 |
if( isset($p["scheme"]) ) return $relative;
|
|
|
|
|
|
|
|
|
|
|
106 |
|
107 |
$parts=(parse_url($absolute));
|
108 |
-
|
109 |
if(substr($relative,0,1)=='/') {
|
110 |
-
|
111 |
-
|
|
|
112 |
} else {
|
113 |
if(isset($parts['path'])){
|
114 |
$aparts=explode('/',$parts['path']);
|
@@ -117,20 +123,23 @@ class blcUtility {
|
|
117 |
} else {
|
118 |
$aparts=array();
|
119 |
}
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
|
|
|
|
|
|
132 |
}
|
133 |
-
$path = implode("/", $
|
134 |
|
135 |
$url = '';
|
136 |
if($parts['scheme']) {
|
@@ -205,6 +214,147 @@ class blcUtility {
|
|
205 |
return $open_basedir && ( strtolower($open_basedir) != 'none' );
|
206 |
}
|
207 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
208 |
}//class
|
209 |
|
210 |
}//class_exists
|
67 |
if ( ($parts['scheme'] != 'http') && ($parts['scheme'] != 'https') )
|
68 |
return false;
|
69 |
}
|
70 |
+
|
71 |
$url = html_entity_decode($url);
|
72 |
$url = preg_replace(
|
73 |
array('/([\?&]PHPSESSID=\w+)$/i', //remove session ID
|
103 |
return false;
|
104 |
}
|
105 |
if( isset($p["scheme"]) ) return $relative;
|
106 |
+
|
107 |
+
//If the relative URL is just a query string, simply attach it to the absolute URL and return
|
108 |
+
if ( substr($relative, 0, 1) == '?' ){
|
109 |
+
return $absolute . $relative;
|
110 |
+
}
|
111 |
|
112 |
$parts=(parse_url($absolute));
|
113 |
+
|
114 |
if(substr($relative,0,1)=='/') {
|
115 |
+
//Relative URL starts with a slash => ignore the base path and jump straight to the root.
|
116 |
+
$path_segments = explode("/", $relative);
|
117 |
+
array_shift($path_segments);
|
118 |
} else {
|
119 |
if(isset($parts['path'])){
|
120 |
$aparts=explode('/',$parts['path']);
|
123 |
} else {
|
124 |
$aparts=array();
|
125 |
}
|
126 |
+
|
127 |
+
//Merge together the base path & the relative path
|
128 |
+
$aparts = array_merge($aparts, explode("/", $relative));
|
129 |
+
|
130 |
+
//Filter the merged path
|
131 |
+
$path_segments = array();
|
132 |
+
foreach($aparts as $part){
|
133 |
+
if ( $part == '.' ){
|
134 |
+
continue; //. = "this directory". It's basically a no-op, so we skip it.
|
135 |
+
} elseif ( $part == '..' ) {
|
136 |
+
array_pop($path_segments); //.. = one directory up. Remove the last seen path segment.
|
137 |
+
} else {
|
138 |
+
array_push($path_segments, $part); //Normal directory -> add it to the path.
|
139 |
+
}
|
140 |
+
}
|
141 |
}
|
142 |
+
$path = implode("/", $path_segments);
|
143 |
|
144 |
$url = '';
|
145 |
if($parts['scheme']) {
|
214 |
return $open_basedir && ( strtolower($open_basedir) != 'none' );
|
215 |
}
|
216 |
|
217 |
+
/**
|
218 |
+
* Truncate a string on a specified boundary character.
|
219 |
+
*
|
220 |
+
* @param string $text The text to truncate.
|
221 |
+
* @param integer $max_characters Return no more than $max_characters
|
222 |
+
* @param string $break Break on this character. Defaults to space.
|
223 |
+
* @param string $pad Pad the truncated string with this string. Defaults to an HTML ellipsis.
|
224 |
+
* @return
|
225 |
+
*/
|
226 |
+
function truncate($text, $max_characters = 0, $break = ' ', $pad = '…'){
|
227 |
+
if ( strlen($text) <= $max_characters ){
|
228 |
+
return $text;
|
229 |
+
}
|
230 |
+
|
231 |
+
$text = substr($text, 0, $max_characters);
|
232 |
+
$break_pos = strrpos($text, $break);
|
233 |
+
if ( $break_pos !== false ){
|
234 |
+
$text = substr($text, 0, $break_pos);
|
235 |
+
}
|
236 |
+
|
237 |
+
return $text.$pad;
|
238 |
+
}
|
239 |
+
|
240 |
+
/**
|
241 |
+
* extract_tags()
|
242 |
+
* Extract specific HTML tags and their attributes from a string.
|
243 |
+
*
|
244 |
+
* You can either specify one tag, an array of tag names, or a regular expression that matches the tag name(s).
|
245 |
+
* If multiple tags are specified you must also set the $selfclosing parameter and it must be the same for
|
246 |
+
* all specified tags (so you can't extract both normal and self-closing tags in one go).
|
247 |
+
*
|
248 |
+
* The function returns a numerically indexed array of extracted tags. Each entry is an associative array
|
249 |
+
* with these keys :
|
250 |
+
* tag_name - the name of the extracted tag, e.g. "a" or "img".
|
251 |
+
* offset - the numberic offset of the first character of the tag within the HTML source.
|
252 |
+
* contents - the inner HTML of the tag. This is always empty for self-closing tags.
|
253 |
+
* attributes - a name -> value array of the tag's attributes, or an empty array if the tag has none.
|
254 |
+
* full_tag - the entire matched tag, e.g. '<a href="http://example.com">example.com</a>'. This key
|
255 |
+
* will only be present if you set $return_the_entire_tag to true.
|
256 |
+
*
|
257 |
+
* @param string $html The HTML code to search for tags.
|
258 |
+
* @param string|array $tag The tag(s) to extract.
|
259 |
+
* @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.
|
260 |
+
* @param bool $return_the_entire_tag Return the entire matched tag in 'full_tag' key of the results array.
|
261 |
+
* @param string $charset The character set of the HTML code. Defaults to ISO-8859-1.
|
262 |
+
*
|
263 |
+
* @return array An array of extracted tags, or an empty array if no matching tags were found.
|
264 |
+
*/
|
265 |
+
function extract_tags( $html, $tag, $selfclosing = null, $return_the_entire_tag = false, $charset = 'ISO-8859-1' ){
|
266 |
+
|
267 |
+
if ( is_array($tag) ){
|
268 |
+
$tag = implode('|', $tag);
|
269 |
+
}
|
270 |
+
|
271 |
+
//If the user didn't specify if $tag is a self-closing tag we try to auto-detect it
|
272 |
+
//by checking against a list of known self-closing tags.
|
273 |
+
$selfclosing_tags = array( 'area', 'base', 'basefont', 'br', 'hr', 'input', 'img', 'link', 'meta', 'col', 'param' );
|
274 |
+
if ( is_null($selfclosing) ){
|
275 |
+
$selfclosing = in_array( $tag, $selfclosing_tags );
|
276 |
+
}
|
277 |
+
|
278 |
+
//The regexp is different for normal and self-closing tags because I can't figure out
|
279 |
+
//how to make a sufficiently robust unified one.
|
280 |
+
if ( $selfclosing ){
|
281 |
+
$tag_pattern =
|
282 |
+
'@<(?P<tag>'.$tag.') # <tag
|
283 |
+
(?P<attributes>\s[^>]+)? # attributes, if any
|
284 |
+
\s*/?> # /> or just >, being lenient here
|
285 |
+
@xsi';
|
286 |
+
} else {
|
287 |
+
$tag_pattern =
|
288 |
+
'@<(?P<tag>'.$tag.') # <tag
|
289 |
+
(?P<attributes>\s[^>]+)? # attributes, if any
|
290 |
+
\s*> # >
|
291 |
+
(?P<contents>.*?) # tag contents
|
292 |
+
</(?P=tag)> # the closing </tag>
|
293 |
+
@xsi';
|
294 |
+
}
|
295 |
+
|
296 |
+
$attribute_pattern =
|
297 |
+
'@
|
298 |
+
(?P<name>\w+) # attribute name
|
299 |
+
\s*=\s*
|
300 |
+
(
|
301 |
+
(?P<quote>[\"\'])(?P<value_quoted>.*?)(?P=quote) # a quoted value
|
302 |
+
| # or
|
303 |
+
(?P<value_unquoted>[^\s"\']+?)(?:\s+|$) # an unquoted value (terminated by whitespace or EOF)
|
304 |
+
)
|
305 |
+
@xsi';
|
306 |
+
|
307 |
+
//Find all tags
|
308 |
+
if ( !preg_match_all($tag_pattern, $html, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE ) ){
|
309 |
+
//Return an empty array if we didn't find anything
|
310 |
+
return array();
|
311 |
+
}
|
312 |
+
|
313 |
+
$tags = array();
|
314 |
+
foreach ($matches as $match){
|
315 |
+
|
316 |
+
//Parse tag attributes, if any
|
317 |
+
$attributes = array();
|
318 |
+
if ( !empty($match['attributes'][0]) ){
|
319 |
+
|
320 |
+
if ( preg_match_all( $attribute_pattern, $match['attributes'][0], $attribute_data, PREG_SET_ORDER ) ){
|
321 |
+
//Turn the attribute data into a name->value array
|
322 |
+
foreach($attribute_data as $attr){
|
323 |
+
if( !empty($attr['value_quoted']) ){
|
324 |
+
$value = $attr['value_quoted'];
|
325 |
+
} else if( !empty($attr['value_unquoted']) ){
|
326 |
+
$value = $attr['value_unquoted'];
|
327 |
+
} else {
|
328 |
+
$value = '';
|
329 |
+
}
|
330 |
+
|
331 |
+
//Passing the value through html_entity_decode is handy when you want
|
332 |
+
//to extract link URLs or something like that. You might want to remove
|
333 |
+
//or modify this call if it doesn't fit your situation.
|
334 |
+
$value = html_entity_decode( $value, ENT_QUOTES, $charset );
|
335 |
+
|
336 |
+
$attributes[$attr['name']] = $value;
|
337 |
+
}
|
338 |
+
}
|
339 |
+
|
340 |
+
}
|
341 |
+
|
342 |
+
$tag = array(
|
343 |
+
'tag_name' => $match['tag'][0],
|
344 |
+
'offset' => $match[0][1],
|
345 |
+
'contents' => !empty($match['contents'])?$match['contents'][0]:'', //empty for self-closing tags
|
346 |
+
'attributes' => $attributes,
|
347 |
+
);
|
348 |
+
if ( $return_the_entire_tag ){
|
349 |
+
$tag['full_tag'] = $match[0][0];
|
350 |
+
}
|
351 |
+
|
352 |
+
$tags[] = $tag;
|
353 |
+
}
|
354 |
+
|
355 |
+
return $tags;
|
356 |
+
}
|
357 |
+
|
358 |
}//class
|
359 |
|
360 |
}//class_exists
|