Broken Link Checker - Version 0.9.5

Version Description

  • Added the ability to check scheduled, draft and private posts.
  • Added a way to individually enable/disable the monitoring of posts, pages, comments, the blogroll, and so on.
  • New "Status" column in the "Broken Links" table.
  • Visible table columns and the number of links per page can now be selected in the "Screen Options" panel.
  • Replaced the "Delete sources" action with "Move sources to Trash" (except on blogs where Trash is disabled).
  • New URL editor interface, now more consistent with the look-n-feel of the inline editor for posts.
  • New status icon to help distinguish "maybe broken" and "definitely broken" links.
  • Tweaked table layout - links first, posts/etc last.
  • Added "Compact" and "Detailed" table views (for now, the differences are quite minor).
  • Split the settings page into several tabs.
  • Removed the "Details" links as redundant. To display link details, click the contents of the "Status" or "Link text" columns instead.
  • Added a way to individually enable/disable the monitoring of various link types, e.g. HTML links, images, etc.
Download this release

Release Info

Developer whiteshadow
Plugin Icon 128x128 Broken Link Checker
Version 0.9.5
Comparing to
See all releases

Code changes from version 0.9.4.4-last-non-modular to 0.9.5

Files changed (58) hide show
  1. broken-link-checker.php +12 -388
  2. core.php → core/core.php +785 -1011
  3. core/init.php +337 -0
  4. css/links-page.css +189 -23
  5. css/options-page.css +107 -0
  6. css/{uservoice.css → screen-meta-links.css} +9 -2
  7. images/bullet_cross.png +0 -0
  8. images/bullet_error.png +0 -0
  9. images/bullet_warning.png +0 -0
  10. images/dailymotion-embed.png +0 -0
  11. images/vimeo-embed.png +0 -0
  12. images/youtube-embed.png +0 -0
  13. JSON.php → includes/JSON.php +0 -0
  14. includes/admin/db-schema.php +95 -0
  15. includes/admin/db-upgrade.php +577 -0
  16. includes/admin/links-page-js.php +229 -168
  17. includes/admin/options-page-js.php +122 -0
  18. includes/admin/search-form.php +30 -5
  19. includes/admin/table-printer.php +719 -0
  20. includes/any-post.php +732 -0
  21. includes/checkers.php +35 -51
  22. config-manager.php → includes/config-manager.php +0 -0
  23. includes/containers.php +402 -431
  24. includes/containers/post.php +0 -464
  25. includes/extra-strings.php +18 -0
  26. includes/instances.php +41 -45
  27. includes/link-query.php +764 -0
  28. includes/links.php +132 -623
  29. logger.php → includes/logger.php +0 -0
  30. includes/module-base.php +72 -0
  31. includes/module-manager.php +860 -0
  32. includes/modules.php +31 -0
  33. includes/parsers.php +96 -153
  34. includes/screen-options/screen-options.js +13 -0
  35. includes/screen-options/screen-options.php +282 -0
  36. utility-class.php → includes/utility-class.php +126 -141
  37. js/jquery.cookie.js +96 -0
  38. languages/broken-link-checker-pt_PT.po +404 -416
  39. languages/broken-link-checker.pot +796 -505
  40. {includes → modules}/checkers/http.php +116 -35
  41. {includes → modules}/containers/blogroll.php +28 -11
  42. {includes → modules}/containers/comment.php +117 -30
  43. {includes → modules}/containers/custom_field.php +125 -99
  44. {includes → modules}/containers/dummy.php +13 -2
  45. modules/extras/dailymotion-embed.php +17 -0
  46. modules/extras/mediafire.php +17 -0
  47. modules/extras/megaupload.php +17 -0
  48. modules/extras/plaintext-url.php +17 -0
  49. modules/extras/rapidshare.php +17 -0
  50. modules/extras/vimeo-embed.php +17 -0
  51. modules/extras/youtube-embed.php +17 -0
  52. modules/extras/youtube.php +17 -0
  53. {includes → modules}/parsers/html_link.php +15 -2
  54. {includes → modules}/parsers/image.php +16 -5
  55. {includes → modules}/parsers/metadata.php +39 -3
  56. {includes → modules}/parsers/url_field.php +14 -3
  57. readme.txt +37 -18
  58. uninstall.php +4 -3
broken-link-checker.php CHANGED
@@ -1,403 +1,27 @@
1
  <?php
2
-
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.4.4
8
  Author: Janis Elsts
9
  Author URI: http://w-shadow.com/blog/
10
  Text Domain: broken-link-checker
11
  */
12
 
13
- /*
14
- Created by Janis Elsts (email : whiteshadow@w-shadow.com)
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
- /***********************************************
26
- Constants
27
- ************************************************/
28
-
29
- /*
30
- For performance, some internal APIs used for retrieving multiple links, instances or containers
31
- can take an optional "$purpose" argument. Those APIs will try to use this argument to pre-load
32
- any DB data required for the specified purpose ahead of time.
33
-
34
- For example, if you're loading a bunch of link containers for the purposes of parsing them and
35
- thus set $purpose to BLC_FOR_PARSING, the relevant container managers will (if applicable) precache
36
- the parse-able fields in each returned container object. Still, setting $purpose to any particular
37
- value does not *guarantee* any data will be preloaded - it's only a suggestion that it should.
38
-
39
- The currently supported values for the $purpose argument are :
40
- */
41
- define('BLC_FOR_EDITING', 'edit');
42
- define('BLC_FOR_PARSING', 'parse');
43
- define('BLC_FOR_DISPLAY', 'display');
44
-
45
- /***********************************************
46
- Configuration
47
- ************************************************/
48
-
49
- //Load and initialize the plugin's configuration
50
- global $blc_directory;
51
- $blc_directory = dirname(__FILE__);
52
- require $blc_directory . '/config-manager.php';
53
-
54
- global $blc_config_manager;
55
- $blc_config_manager = new blcConfigurationManager(
56
- //Save the plugin's configuration into this DB option
57
- 'wsblc_options',
58
- //Initialize default settings
59
- array(
60
- 'max_execution_time' => 5*60, //(in seconds) How long the worker instance may run, at most.
61
- 'check_threshold' => 72, //(in hours) Check each link every 72 hours.
62
-
63
- 'recheck_count' => 3, //How many times a broken link should be re-checked.
64
- 'recheck_threshold' => 20*60, //(in seconds) Re-check broken links after 20 minutes.
65
-
66
- 'run_in_dashboard' => true, //Run the link checker algo. continuously while the Dashboard is open.
67
- 'run_via_cron' => true, //Run it hourly via WordPress pseudo-cron.
68
-
69
- 'mark_broken_links' => true, //Whether to add the broken_link class to broken links in posts.
70
- 'broken_link_css' => ".broken_link, a.broken_link {\n\ttext-decoration: line-through;\n}",
71
- 'nofollow_broken_links' => false, //Whether to add rel="nofollow" to broken links in posts.
72
-
73
- 'mark_removed_links' => false, //Whether to add the removed_link class when un-linking a link.
74
- 'removed_link_css' => ".removed_link, a.removed_link {\n\ttext-decoration: line-through;\n}",
75
-
76
- 'exclusion_list' => array(), //Links that contain a substring listed in this array won't be checked.
77
-
78
- 'send_email_notifications' => false,//Whether to send email notifications about broken links
79
- 'notification_schedule' => 'daily', //How often (at most) notifications will be sent. Possible values : 'daily', 'weekly'
80
- 'last_notification_sent' => 0, //When the last email notification was send (Unix timestamp)
81
-
82
- 'server_load_limit' => 4, //Stop parsing stuff & checking links if the 1-minute load average
83
- //goes over this value. Only works on Linux servers. 0 = no limit.
84
- 'enable_load_limit' => true, //Enable/disable load monitoring.
85
-
86
- 'custom_fields' => array(), //List of custom fields that can contain URLs and should be checked.
87
- 'check_comment_links' => true, //Whether to check links found in comments
88
-
89
- 'autoexpand_widget' => true, //Autoexpand the Dashboard widget if broken links are detected
90
- 'show_link_count_bubble' => true, //Display a notification bubble in the menu when broken links are found
91
-
92
- 'need_resynch' => false, //[Internal flag] True if there are unparsed items.
93
- 'current_db_version' => 0, //The currently set-up version of the plugin's tables
94
-
95
- 'custom_tmp_dir' => '', //The lockfile will be stored in this directory.
96
- //If this option is not set, the plugin's own directory or the
97
- //system-wide /tmp directory will be used instead.
98
-
99
- 'timeout' => 30, //(in seconds) Links that take longer than this to respond will be treated as broken.
100
-
101
- 'highlight_permanent_failures' => false,//Highlight links that have appear to be permanently broken (in Tools -> Broken Links).
102
- 'failure_duration_threshold' => 3, //(days) Assume a link is permanently broken if it still hasn't
103
- //recovered after this many days.
104
-
105
- 'highlight_feedback_widget' => true, //Highlight the "Feedback" button in vivid orange
106
-
107
- 'installation_complete' => false,
108
- 'installation_failed' => false,
109
- )
110
- );
111
-
112
- /***********************************************
113
- Logging
114
- ************************************************/
115
-
116
- include 'logger.php';
117
-
118
- global $blclog;
119
- $blclog = new blcDummyLogger;
120
-
121
-
122
- /*
123
- if ( defined('BLC_DEBUG') && constant('BLC_DEBUG') ){
124
- //Load FirePHP for debug logging
125
- if ( !class_exists('FB') ) {
126
- require_once 'FirePHPCore/fb.php4';
127
- }
128
- //FB::setEnabled(false);
129
- }
130
- //to comment out all calls : (^[^\/]*)(FB::) -> $1\/\/$2
131
- //to uncomment : \/\/(\s*FB::) -> $1
132
- //*/
133
-
134
- /***********************************************
135
- Global functions
136
- ************************************************/
137
-
138
- /**
139
- * Initialize link containers.
140
- *
141
- * @uses do_action() on 'blc_init_containers' after all built-in link containers have been loaded.
142
- * @see blcContainer
143
- *
144
- * @return void
145
- */
146
- function blc_init_containers(){
147
- global $blc_directory;
148
-
149
- //Only init once.
150
- static $done = false;
151
- if ( $done ) return;
152
-
153
- //Load the base container classes
154
- require $blc_directory . '/includes/containers.php';
155
-
156
- //Load built-in link containers
157
- require $blc_directory . '/includes/containers/post.php';
158
- require $blc_directory . '/includes/containers/blogroll.php';
159
- require $blc_directory . '/includes/containers/custom_field.php';
160
- require $blc_directory . '/includes/containers/dummy.php';
161
-
162
- $conf = & blc_get_configuration();
163
- if ( $conf->options['check_comment_links'] ){
164
- require $blc_directory . '/includes/containers/comment.php';
165
- }
166
-
167
-
168
- //Notify other plugins that they may register their custom containers now.
169
- do_action('blc_init_containers');
170
-
171
- $done = true;
172
- }
173
-
174
- /**
175
- * Initialize link parsers.
176
- *
177
- * @uses do_action() on 'blc_init_parsers' after all built-in parsers have been loaded.
178
- *
179
- * @return void
180
- */
181
- function blc_init_parsers(){
182
- global $blc_directory;
183
-
184
- //Only init once.
185
- static $done = false;
186
- if ( $done ) return;
187
-
188
- //Load the base parser classes
189
- require $blc_directory . '/includes/parsers.php';
190
-
191
- //Load built-in parsers
192
- require $blc_directory . '/includes/parsers/html_link.php';
193
- require $blc_directory . '/includes/parsers/image.php';
194
- require $blc_directory . '/includes/parsers/metadata.php';
195
- require $blc_directory . '/includes/parsers/url_field.php';
196
-
197
- do_action('blc_init_parsers');
198
- $done = true;
199
- }
200
-
201
- /**
202
- * Initialize link checkers.
203
- *
204
- * @uses do_action() on 'blc_init_checkers' after all built-in checker implementations have been loaded.
205
- *
206
- * @return void
207
- */
208
- function blc_init_checkers(){
209
- global $blc_directory;
210
-
211
- //Only init once.
212
- static $done = false;
213
- if ( $done ) return;
214
-
215
- //Load the base classes for link checker algorithms
216
- require $blc_directory . '/includes/checkers.php';
217
-
218
- //Load built-in checker implementations (only HTTP at the time)
219
- require $blc_directory . '/includes/checkers/http.php';
220
-
221
- do_action('blc_init_checkers');
222
- $done = true;
223
- }
224
-
225
- /**
226
- * Load and register all containers, parsers and checkers.
227
- *
228
- * @return void
229
- */
230
- function blc_init_all_components(){
231
- blc_init_containers();
232
- blc_init_parsers();
233
- blc_init_checkers();
234
- }
235
-
236
- /**
237
- * Get the configuration object used by Broken Link Checker.
238
- *
239
- * @return blcConfigurationManager
240
- */
241
- function &blc_get_configuration(){
242
- return $GLOBALS['blc_config_manager'];
243
- }
244
-
245
- /**
246
- * Notify the link checker that there are unsynched items
247
- * that might contain links (e.g. a new or edited post).
248
- *
249
- * @return void
250
- */
251
- function blc_got_unsynched_items(){
252
- $conf = & blc_get_configuration();
253
-
254
- if ( !$conf->options['need_resynch'] ){
255
- $conf->options['need_resynch'] = true;
256
- $conf->save_options();
257
- }
258
- }
259
-
260
- /**
261
- * (Re)create synchronization records for all containers and mark them all as unparsed.
262
- *
263
- * @param bool $forced If true, the plugin will recreate all synch. records from scratch.
264
- * @return void
265
- */
266
- function blc_resynch( $forced = false ){
267
- global $wpdb, $blclog;
268
-
269
- if ( $forced ){
270
- $blclog->info('... Forced resynchronization initiated');
271
-
272
- //Drop all synchronization records
273
- $wpdb->query("TRUNCATE {$wpdb->prefix}blc_synch");
274
- } else {
275
- $blclog->info('... Resynchronization initiated');
276
- }
277
-
278
- //Delete synch. records for container types that don't exist
279
- $blclog->info('... Deleting invalid container records');
280
- blc_cleanup_containers();
281
-
282
- //(Re)create and update synch. records for all container types.
283
- $blclog->info('... (Re)creating container records');
284
- blc_resynch_containers($forced);
285
-
286
- //Delete invalid instances
287
- $blclog->info('... Deleting invalid link instances');
288
- blc_cleanup_instances();
289
-
290
- //Delete orphaned links
291
- $blclog->info('... Deleting orphaned links');
292
- blc_cleanup_links();
293
-
294
- $blclog->info('... Setting resync. flags');
295
- blc_got_unsynched_items();
296
-
297
- //All done.
298
- $blclog->info('Database resynchronization complete.');
299
- }
300
-
301
- /***********************************************
302
- Utility hooks
303
- ************************************************/
304
-
305
- /**
306
- * Add a weekly Cron schedule for email notifications
307
- * and a bimonthly schedule for database maintenance.
308
- *
309
- * @param array $schedules Existing Cron schedules.
310
- * @return array
311
- */
312
- function blc_cron_schedules($schedules){
313
- if ( !isset($schedules['weekly']) ){
314
- $schedules['weekly'] = array(
315
- 'interval' => 604800, //7 days
316
- 'display' => __('Once Weekly')
317
- );
318
- }
319
- if ( !isset($schedules['bimonthly']) ){
320
- $schedules['bimonthly'] = array(
321
- 'interval' => 15*24*2600, //15 days
322
- 'display' => __('Twice a Month')
323
- );
324
- }
325
-
326
- return $schedules;
327
- }
328
- add_filter('cron_schedules', 'blc_cron_schedules');
329
-
330
- /**
331
- * Display installation errors (if any) on the Dashboard.
332
- *
333
- * @return void
334
- */
335
- function blc_print_installation_errors(){
336
- $conf = & blc_get_configuration();
337
- if ( !$conf->options['installation_failed'] ){
338
- return;
339
- }
340
-
341
- $logger = new blcOptionLogger('blc_installation_log');
342
- $log = $logger->get_messages();
343
-
344
- $message = array(
345
- '<strong>' . __('Broken Link Checker installation failed', 'broken-link-checker') . '</strong>',
346
- '',
347
- '<em>Installation log follows :</em>',
348
- );
349
- foreach($log as $entry){
350
- array_push($message, $entry);
351
- }
352
- $message = implode("<br>\n", $message);
353
-
354
- echo "<div class='error'><p>$message</p></div>";
355
- }
356
- add_action('admin_notices', 'blc_print_installation_errors');
357
-
358
-
359
- /***********************************************
360
- Main functionality
361
- ************************************************/
362
-
363
- //Load the base classes
364
- require $blc_directory . '/includes/links.php';
365
- require $blc_directory . '/includes/instances.php';
366
-
367
- if ( is_admin() || defined('DOING_CRON') ){
368
-
369
- //It's an admin-side or Cron request. Load all plugin components.
370
- add_action('plugins_loaded', 'blc_init_all_components');
371
- require $blc_directory . '/utility-class.php';
372
- require $blc_directory . '/core.php';
373
- $ws_link_checker = new wsBrokenLinkChecker( __FILE__ , $blc_config_manager );
374
-
375
- } else {
376
-
377
- //This is user-side request, so we don't need to load the core.
378
- //We do need to load containers (for the purposes of catching
379
- //new comments and such).
380
- add_action('plugins_loaded', 'blc_init_containers');
381
-
382
- //If broken links need to be marked, we also need to load parsers
383
- //(used to find & modify links) and utilities (used by some parsers).
384
- if ( $blc_config_manager->options['mark_broken_links'] || $blc_config_manager->options['nofollow_broken_links'] ){
385
- require $blc_directory . '/utility-class.php';
386
- add_action('plugins_loaded', 'blc_init_parsers');
387
- }
388
-
389
- //And possibly inject the CSS for removed links
390
- if ( $blc_config_manager->options['mark_removed_links'] && !empty($blc_config_manager->options['removed_link_css']) ){
391
- function blc_print_remove_link_css(){
392
- global $blc_config_manager;
393
- echo '<style type="text/css">',$blc_config_manager->options['removed_link_css'],'</style>';
394
- }
395
- add_action('wp_head', 'blc_print_remove_link_css');
396
  }
397
  }
398
 
399
-
400
-
401
-
402
 
403
  ?>
1
  <?php
 
2
  /*
3
  Plugin Name: Broken Link Checker
4
  Plugin URI: http://w-shadow.com/blog/2007/08/05/broken-link-checker-for-wordpress/
5
  Description: Checks your blog for broken links and missing images and notifies you on the dashboard if any are found.
6
+ Version: 0.9.5
7
  Author: Janis Elsts
8
  Author URI: http://w-shadow.com/blog/
9
  Text Domain: broken-link-checker
10
  */
11
 
12
+ if ( !function_exists('blc_get_plugin_file') ){
13
+ /**
14
+ * Retrieve the fully qualified filename of BLC's main PHP file.
15
+ *
16
+ * @return string
17
+ */
18
+ function blc_get_plugin_file(){
19
+ //You'd be surprised on how useful this can be.
20
+ return __FILE__;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  }
22
  }
23
 
24
+ //Load the actual plugin
25
+ require 'core/init.php';
 
26
 
27
  ?>
core.php → core/core.php RENAMED
@@ -11,6 +11,8 @@ if ( !function_exists( 'microtime_float' ) ) {
11
  }
12
  }
13
 
 
 
14
  if (!class_exists('wsBrokenLinkChecker')) {
15
 
16
  class wsBrokenLinkChecker {
@@ -19,7 +21,7 @@ class wsBrokenLinkChecker {
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;
@@ -39,10 +41,12 @@ class wsBrokenLinkChecker {
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
 
@@ -61,7 +65,6 @@ class wsBrokenLinkChecker {
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
- add_action( 'wp_ajax_blc_save_highlight_settings', array(&$this,'ajax_save_highlight_settings') );
65
  add_action( 'wp_ajax_blc_disable_widget_highlight', array(&$this,'ajax_disable_widget_highlight') );
66
 
67
  //Check if it's possible to create a lockfile and nag the user about it if not.
@@ -81,6 +84,17 @@ class wsBrokenLinkChecker {
81
  add_action('blc_cron_email_notifications', array( &$this, 'send_email_notifications' ));
82
  add_action('blc_cron_check_links', array(&$this, 'cron_check_links'));
83
  add_action('blc_cron_database_maintenance', array(&$this, 'database_maintenance'));
 
 
 
 
 
 
 
 
 
 
 
84
  }
85
 
86
  /**
@@ -145,7 +159,8 @@ class wsBrokenLinkChecker {
145
  $.getJSON(
146
  "<?php echo admin_url('admin-ajax.php'); ?>",
147
  {
148
- 'action' : 'blc_dashboard_status'
 
149
  },
150
  function (data, textStatus){
151
  if ( data && ( typeof(data.text) != 'undefined' ) ) {
@@ -190,7 +205,7 @@ class wsBrokenLinkChecker {
190
  }
191
 
192
  function admin_print_scripts(){
193
- //jQuery is used for AJAX and effects
194
  wp_enqueue_script('jquery');
195
  }
196
 
@@ -198,6 +213,8 @@ class wsBrokenLinkChecker {
198
  //jQuery UI is used on the settings page
199
  wp_enqueue_script('jquery-ui-core'); //Used for background color animation
200
  wp_enqueue_script('jquery-ui-dialog');
 
 
201
  }
202
 
203
  function enqueue_link_page_scripts(){
@@ -326,24 +343,40 @@ class wsBrokenLinkChecker {
326
  $blclog = new blcOptionLogger('blc_installation_log');
327
  $blclog->clear();
328
 
329
- $blclog->info('Plugin activated.');
330
 
331
  $this->conf->options['installation_complete'] = false;
332
  $this->conf->options['installation_failed'] = true;
333
  $this->conf->save_options();
334
  $blclog->info('Installation/update begins.');
335
 
336
- $blclog->info('Initializing components...');
337
- blc_init_all_components();
338
-
 
 
 
 
 
 
 
 
 
 
339
  //Prepare the database.
340
  $blclog->info('Upgrading the database...');
341
  $this->upgrade_database();
 
 
 
 
342
 
343
- //Mark all new posts and other parse-able objects as unsynchronized.
344
- $blclog->info('Updating database entries...');
345
- blc_resynch();
346
-
 
 
347
  //Turn off load limiting if it's not available on this server.
348
  $blclog->info('Updating server load limit settings...');
349
  $load = $this->get_server_load();
@@ -373,6 +406,7 @@ class wsBrokenLinkChecker {
373
  wp_clear_scheduled_hook('blc_cron_check_links');
374
  wp_clear_scheduled_hook('blc_cron_email_notifications');
375
  wp_clear_scheduled_hook('blc_cron_database_maintenance');
 
376
  }
377
 
378
  /**
@@ -381,263 +415,8 @@ class wsBrokenLinkChecker {
381
  * @return bool
382
  */
383
  function upgrade_database($trigger_errors = true){
384
- global $wpdb, $blclog;
385
-
386
- //Do we need to upgrade?
387
- if ( $this->db_version == $this->conf->options['current_db_version'] ) {
388
- //The DB is up to date, but lets make sure all the required tables are present
389
- //in case the user has decided to delete some of them.
390
- $blclog->info( sprintf(
391
- 'The database appears to be up to date (current version : %d).',
392
- $this->conf->options['current_db_version']
393
- ));
394
- return $this->maybe_create_tables();
395
- }
396
-
397
- //Upgrade to DB version 4
398
- if ( $this->db_version == 4 ){
399
- $blclog->info(sprintf(
400
- 'Upgrading the database to version %d',
401
- $this->db_version
402
- ));
403
-
404
- //The 4th version makes a lot of backwards-incompatible changes to the main
405
- //BLC tables (in particular, it adds several required fields to blc_instances).
406
- //While it would be possible to import data from an older version of the DB,
407
- //some things - like link editing - wouldn't work with the old data.
408
-
409
- //So we just drop, recreate and repopulate most tables.
410
- $blclog->info('Deleting old tables');
411
- $tables = array(
412
- $wpdb->prefix . 'blc_linkdata',
413
- $wpdb->prefix . 'blc_postdata',
414
- $wpdb->prefix . 'blc_instances',
415
- $wpdb->prefix . 'blc_synch',
416
- $wpdb->prefix . 'blc_links',
417
- );
418
-
419
- $q = "DROP TABLE IF EXISTS " . implode(', ', $tables);
420
- $rez = $wpdb->query( $q );
421
-
422
- if ( $rez === false ){
423
- $error = sprintf(
424
- __("Failed to delete old DB tables. Database error : %s", 'broken-link-checker'),
425
- $wpdb->last_error
426
- );
427
-
428
- $blclog->error($error);
429
- /*//FIXME: In very rare cases, DROP TABLE IF EXISTS throws an error when the table(s) don't exist.
430
- if ( $trigger_errors ){
431
- trigger_error($error, E_USER_ERROR);
432
- }
433
- return false;
434
- //*/
435
- }
436
- $blclog->info('Done.');
437
-
438
- //Create new DB tables.
439
- if ( !$this->maybe_create_tables($trigger_errors) ){
440
- return false;
441
- };
442
-
443
- } else {
444
- //This should never happen.
445
- $error = sprintf(
446
- __(
447
- "Unexpected error: The plugin doesn't know how to upgrade its database to version '%d'.",
448
- 'broken-link-checker'
449
- ),
450
- $this->db_version
451
- );
452
-
453
- $blclog->error($error);
454
- if ( $trigger_errors ){
455
- trigger_error($error, E_USER_ERROR);
456
- }
457
- return false;
458
- }
459
-
460
- //Upgrade was successful.
461
- $this->conf->options['current_db_version'] = $this->db_version;
462
- $this->conf->save_options();
463
-
464
- $blclog->info('Database successfully upgraded.');
465
- return true;
466
- }
467
-
468
- /**
469
- * Create the plugin's DB tables, unless they already exist.
470
- *
471
- * @return bool
472
- */
473
- function maybe_create_tables($trigger_errors = true){
474
- global $wpdb, $blclog;
475
-
476
- //Use the character set and collation that's configured for WP tables
477
- $charset_collate = '';
478
- if ( !empty($wpdb->charset) ){
479
- //Some German installs use "utf-8" (invalid) instead of "utf8" (valid). None of
480
- //the charset ids supported by MySQL contain dashes, so we can safely strip them.
481
- //See http://dev.mysql.com/doc/refman/5.0/en/charset-charsets.html
482
- $charset = str_replace('-', '', $wpdb->charset);
483
-
484
- $charset_collate = "DEFAULT CHARACTER SET {$charset}";
485
- }
486
- if ( !empty($wpdb->collate) ){
487
- $charset_collate = " COLLATE {$wpdb->collate}";
488
- }
489
-
490
- $blclog->info('Creating database tables');
491
-
492
- //Search filters
493
- $blclog->info('... Creating the search filter table');
494
- $q = <<<EOD
495
- CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}blc_filters` (
496
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
497
- `name` varchar(100) NOT NULL,
498
- `params` text NOT NULL,
499
- PRIMARY KEY (`id`)
500
- ) {$charset_collate}
501
- EOD;
502
- if ( $wpdb->query($q) === false ){
503
- $error = sprintf(
504
- __("Failed to create table '%s'. Database error: %s", 'broken-link-checker'),
505
- $wpdb->prefix . 'blc_filters',
506
- $wpdb->last_error
507
- );
508
-
509
- $blclog->error($error);
510
- if ( $trigger_errors ){
511
- trigger_error(
512
- $error,
513
- E_USER_ERROR
514
- );
515
- }
516
- return false;
517
- }
518
-
519
- //Link instances (i.e. link occurences inside posts and other items)
520
- $blclog->info('... Creating the link instance table');
521
- $q = <<<EOT
522
- CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}blc_instances` (
523
- `instance_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
524
- `link_id` int(10) unsigned NOT NULL,
525
- `container_id` int(10) unsigned NOT NULL,
526
- `container_type` varchar(40) NOT NULL DEFAULT 'post',
527
- `link_text` varchar(250) NOT NULL DEFAULT '',
528
- `parser_type` varchar(40) NOT NULL DEFAULT 'link',
529
- `container_field` varchar(250) NOT NULL DEFAULT '',
530
- `link_context` varchar(250) NOT NULL DEFAULT '',
531
- `raw_url` text NOT NULL,
532
-
533
- PRIMARY KEY (`instance_id`),
534
- KEY `link_id` (`link_id`),
535
- KEY `source_id` (`container_type`, `container_id`),
536
- KEY `parser_type` (`parser_type`)
537
- ) {$charset_collate};
538
- EOT;
539
- if ( $wpdb->query($q) === false ){
540
- $error = sprintf(
541
- __("Failed to create table '%s'. Database error: %s", 'broken-link-checker'),
542
- $wpdb->prefix . 'blc_instances',
543
- $wpdb->last_error
544
- );
545
-
546
- $blclog->error($error);
547
-
548
- if ( $trigger_errors ){
549
- trigger_error(
550
- $error,
551
- E_USER_ERROR
552
- );
553
- }
554
- return false;
555
- }
556
-
557
- //Links themselves. Note : The 'url' and 'final_url' columns must be collated
558
- //in a case-sensitive manner. This is because "http://a.b/cde" may be a page
559
- //very different from "http://a.b/CDe".
560
- $blclog->info('... Creating the link table');
561
- $q = <<<EOS
562
- CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}blc_links` (
563
- `link_id` int(20) unsigned NOT NULL AUTO_INCREMENT,
564
- `url` text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
565
- `first_failure` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
566
- `last_check` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
567
- `last_success` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
568
- `last_check_attempt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
569
- `check_count` int(4) unsigned NOT NULL DEFAULT '0',
570
- `final_url` text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
571
- `redirect_count` smallint(5) unsigned NOT NULL DEFAULT '0',
572
- `log` text NOT NULL,
573
- `http_code` smallint(6) NOT NULL DEFAULT '0',
574
- `request_duration` float NOT NULL DEFAULT '0',
575
- `timeout` tinyint(1) unsigned NOT NULL DEFAULT '0',
576
- `broken` tinyint(1) NOT NULL DEFAULT '0',
577
- `may_recheck` tinyint(1) NOT NULL DEFAULT '1',
578
- `being_checked` tinyint(1) NOT NULL DEFAULT '0',
579
- `result_hash` varchar(200) NOT NULL DEFAULT '',
580
- `false_positive` tinyint(1) NOT NULL DEFAULT '0',
581
-
582
- PRIMARY KEY (`link_id`),
583
- KEY `url` (`url`(150)),
584
- KEY `final_url` (`final_url`(150)),
585
- KEY `http_code` (`http_code`),
586
- KEY `broken` (`broken`)
587
- ) {$charset_collate};
588
- EOS;
589
- if ( $wpdb->query($q) === false ){
590
- $error = sprintf(
591
- __("Failed to create table '%s'. Database error: %s", 'broken-link-checker'),
592
- $wpdb->prefix . 'blc_links',
593
- $wpdb->last_error
594
- );
595
-
596
- $blclog->error($error);
597
- if ( $trigger_errors ){
598
- trigger_error(
599
- $error,
600
- E_USER_ERROR
601
- );
602
- }
603
- return false;
604
- }
605
-
606
- //Synchronization records. This table is used to keep track of if and when various items
607
- //(e.g. posts, comments, etc) were parsed.
608
- $blclog->info('... Creating the synch. record table');
609
- $q = <<<EOZ
610
- CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}blc_synch` (
611
- `container_id` int(20) unsigned NOT NULL,
612
- `container_type` varchar(40) NOT NULL,
613
- `synched` tinyint(3) unsigned NOT NULL,
614
- `last_synch` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
615
-
616
- PRIMARY KEY (`container_type`,`container_id`),
617
- KEY `synched` (`synched`)
618
- ) {$charset_collate};
619
- EOZ;
620
-
621
- if ( $wpdb->query($q) === false ){
622
- $error = sprintf(
623
- __("Failed to create table '%s'. Database error: %s", 'broken-link-checker'),
624
- $wpdb->prefix . 'blc_synch',
625
- $wpdb->last_error
626
- );
627
-
628
- $blclog->error($error);
629
- if ( $trigger_errors ){
630
- trigger_error(
631
- $error,
632
- E_USER_ERROR
633
- );
634
- }
635
- return false;
636
- }
637
-
638
- //All good.
639
- $blclog->info('All database tables successfully created.');
640
- return true;
641
  }
642
 
643
  /**
@@ -660,9 +439,7 @@ EOZ;
660
  * @return void
661
  */
662
  function database_maintenance(){
663
- blc_init_all_components();
664
-
665
- blc_cleanup_containers();
666
  blc_cleanup_instances();
667
  blc_cleanup_links();
668
 
@@ -717,21 +494,6 @@ EOZ;
717
  //Add the UserVoice widget to the plugin's pages
718
  add_action( 'admin_footer-' . $options_page_hook, array(&$this, 'uservoice_widget') );
719
  add_action( 'admin_footer-' . $links_page_hook, array(&$this, 'uservoice_widget') );
720
-
721
- /*
722
- Display a checkbox in "Screen Options" that lets the user highlight links that
723
- have been broken for a long time. The "Screen Options" panel isn't directly
724
- customizable, so we must resort to ugly hacks using add_meta_box() and JavaScript.
725
- */
726
- $input_html = sprintf(
727
- '</label><input style="margin-left: -1em" type="text" name="failure_duration_threshold" id="failure_duration_threshold" value="%d" size="2">',
728
- $this->conf->options['failure_duration_threshold']
729
- );
730
- $title_html = sprintf(
731
- __('Highlight links broken for at least %s days', 'broken-link-checker'),
732
- $input_html
733
- );
734
- add_meta_box('highlight_permanent_failures', $title_html, array(&$this, 'noop'), $links_page_hook);
735
  }
736
 
737
  /**
@@ -761,6 +523,8 @@ EOZ;
761
  function options_page(){
762
  global $blclog, $blc_directory;
763
 
 
 
764
  //Sanity check : make sure the DB is all set up
765
  if ( $this->db_version != $this->conf->options['current_db_version'] ) {
766
  printf(
@@ -775,13 +539,37 @@ EOZ;
775
  return;
776
  }
777
 
778
- if (isset($_GET['recheck']) && ($_GET['recheck'] == 'true')) {
779
  $this->initiate_recheck();
 
 
 
 
 
780
  }
781
 
782
  if(isset($_POST['submit'])) {
783
  check_admin_referer('link-checker-options');
784
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
785
  //The execution time limit must be above zero
786
  $new_execution_time = intval($_POST['max_execution_time']);
787
  if( $new_execution_time > 0 ){
@@ -859,22 +647,6 @@ EOZ;
859
  }
860
  $this->conf->options['send_email_notifications'] = $email_notifications;
861
 
862
- //Comment link checking on/off
863
- $old_setting = $this->conf->options['check_comment_links'];
864
- $this->conf->options['check_comment_links'] = !empty($_POST['check_comment_links']);
865
- //If comment link checking was just turned on we need to load the comment manager
866
- //and re-parse comments for new links. This is quite hack-y.
867
- //TODO: More elegant handling of freshly enabled/disabled container types
868
- if ( !$old_setting && $this->conf->options['check_comment_links'] ){
869
- include $blc_directory . '/includes/containers/comment.php';
870
- $containerRegistry = & blcContainerRegistry::getInstance();
871
- $comment_manager = $containerRegistry->get_manager('comment');
872
- if ( $comment_manager ){
873
- $comment_manager->resynch();
874
- blc_got_unsynched_items();
875
- }
876
- }
877
-
878
  //Make settings that affect our Cron events take effect immediately
879
  $this->setup_cron_events();
880
 
@@ -886,8 +658,7 @@ EOZ;
886
  inefficient.
887
  */
888
  if ( ( count($diff1) > 0 ) || ( count($diff2) > 0 ) ){
889
- $containerRegistry = & blcContainerRegistry::getInstance();
890
- $manager = $containerRegistry->get_manager('custom_field');
891
  if ( !is_null($manager) ){
892
  $manager->resynch();
893
  blc_got_unsynched_items();
@@ -905,20 +676,65 @@ EOZ;
905
 
906
  }
907
 
 
 
 
 
 
 
 
 
 
 
 
 
 
908
  $debug = $this->get_debug_info();
909
 
910
- $this->print_uservoice_widget();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
911
  ?>
912
 
913
- <div class="wrap"><h2><?php _e('Broken Link Checker Options', 'broken-link-checker'); ?></h2>
914
 
915
- <form name="link_checker_options" method="post" action="<?php
916
  echo admin_url('options-general.php?page=link-checker-settings&noheader=1');
917
  ?>">
918
  <?php
919
  wp_nonce_field('link-checker-options');
920
  ?>
 
 
 
 
 
 
 
 
 
 
921
 
 
 
 
922
  <table class="form-table">
923
 
924
  <tr valign="top">
@@ -932,35 +748,6 @@ EOZ;
932
  <div id='wsblc_full_status'>
933
  <br/><br/><br/>
934
  </div>
935
- <script type='text/javascript'>
936
- (function($){
937
-
938
- function blcUpdateStatus(){
939
- $.getJSON(
940
- "<?php echo admin_url('admin-ajax.php'); ?>",
941
- {
942
- 'action' : 'blc_full_status'
943
- },
944
- function (data, textStatus){
945
- if ( data && ( typeof(data['text']) != 'undefined' ) ){
946
- $('#wsblc_full_status').html(data.text);
947
- } else {
948
- $('#wsblc_full_status').html('<?php _e('[ Network error ]', 'broken-link-checker'); ?>');
949
- }
950
-
951
- setTimeout(blcUpdateStatus, 10000); //...update every 10 seconds
952
- }
953
- );
954
- }
955
- blcUpdateStatus();//Call it the first time
956
-
957
- })(jQuery);
958
- </script>
959
- <?php //JHS: Recheck all posts link: ?>
960
- <p><input class="button" type="button" name="recheckbutton"
961
- value="<?php _e('Re-check all pages', 'broken-link-checker'); ?>"
962
- onclick="location.replace('<?php echo basename($_SERVER['PHP_SELF']); ?>?page=link-checker-settings&amp;recheck=true')" />
963
- </p>
964
 
965
  <table id="blc-debug-info">
966
  <?php
@@ -1001,53 +788,157 @@ EOZ;
1001
 
1002
  </td>
1003
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
1004
 
1005
  <tr valign="top">
1006
- <th scope="row"><?php _e('Broken link CSS','broken-link-checker'); ?></th>
1007
  <td>
 
1008
  <label for='mark_broken_links'>
1009
  <input type="checkbox" name="mark_broken_links" id="mark_broken_links"
1010
  <?php if ($this->conf->options['mark_broken_links']) echo ' checked="checked"'; ?>/>
1011
- <?php _e('Apply <em>class="broken_link"</em> to broken links', 'broken-link-checker'); ?>
1012
  </label>
1013
- <br/>
1014
- <textarea name="broken_link_css" id="broken_link_css" cols='45' rows='4'/><?php
1015
- if( isset($this->conf->options['broken_link_css']) )
1016
- echo $this->conf->options['broken_link_css'];
1017
- ?></textarea>
1018
-
1019
- </td>
1020
- </tr>
1021
-
1022
- <tr valign="top">
1023
- <th scope="row"><?php _e('Removed link CSS','broken-link-checker'); ?></th>
1024
- <td>
 
 
 
 
 
 
 
 
 
 
 
1025
  <label for='mark_removed_links'>
1026
  <input type="checkbox" name="mark_removed_links" id="mark_removed_links"
1027
  <?php if ($this->conf->options['mark_removed_links']) echo ' checked="checked"'; ?>/>
1028
- <?php _e('Apply <em>class="removed_link"</em> to unlinked links', 'broken-link-checker'); ?>
1029
  </label>
1030
- <br/>
1031
- <textarea name="removed_link_css" id="removed_link_css" cols='45' rows='4'/><?php
1032
- if( isset($this->conf->options['removed_link_css']) )
1033
- echo $this->conf->options['removed_link_css'];
1034
- ?></textarea>
1035
-
1036
- </td>
1037
- </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
1038
 
1039
- <tr valign="top">
1040
- <th scope="row"><?php _e('Broken link SEO','broken-link-checker'); ?></th>
1041
- <td>
1042
  <label for='nofollow_broken_links'>
1043
  <input type="checkbox" name="nofollow_broken_links" id="nofollow_broken_links"
1044
  <?php if ($this->conf->options['nofollow_broken_links']) echo ' checked="checked"'; ?>/>
1045
- <?php _e('Apply <em>rel="nofollow"</em> to broken links', 'broken-link-checker'); ?>
1046
  </label>
 
 
1047
  </td>
1048
  </tr>
1049
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1050
  <tr valign="top">
 
 
 
 
 
 
 
 
 
 
 
 
 
1051
  <th scope="row"><?php _e('Exclusion list', 'broken-link-checker'); ?></th>
1052
  <td><?php _e("Don't check links where the URL contains any of these words (one per line) :", 'broken-link-checker'); ?><br/>
1053
  <textarea name="exclusion_list" id="exclusion_list" cols='45' rows='4' wrap='off'/><?php
@@ -1058,46 +949,30 @@ EOZ;
1058
  </td>
1059
  </tr>
1060
 
1061
- <tr valign="top">
1062
- <th scope="row"><?php _e('Custom fields', 'broken-link-checker'); ?></th>
1063
- <td><?php _e('Check URLs entered in these custom fields (one per line) :', 'broken-link-checker'); ?><br/>
1064
- <textarea name="blc_custom_fields" id="blc_custom_fields" cols='45' rows='4' /><?php
1065
- if( isset($this->conf->options['custom_fields']) )
1066
- echo implode("\n", $this->conf->options['custom_fields']);
1067
- ?></textarea>
1068
-
1069
- </td>
1070
- </tr>
1071
 
1072
- <tr valign="top">
1073
- <th scope="row"><?php _e('Comment links', 'broken-link-checker'); ?></th>
1074
- <td>
1075
- <p style="margin-top: 0px;">
1076
- <label for='check_comment_links'>
1077
- <input type="checkbox" name="check_comment_links" id="check_comment_links"
1078
- <?php if ($this->conf->options['check_comment_links']) echo ' checked="checked"'; ?>/>
1079
- <?php _e('Check comment links', 'broken-link-checker'); ?>
1080
- </label><br>
1081
- </p>
1082
- </td>
1083
- </tr>
1084
 
1085
  <tr valign="top">
1086
- <th scope="row"><?php _e('E-mail notifications', 'broken-link-checker'); ?></th>
1087
  <td>
1088
- <p style="margin-top: 0px;">
1089
- <label for='send_email_notifications'>
1090
- <input type="checkbox" name="send_email_notifications" id="send_email_notifications"
1091
- <?php if ($this->conf->options['send_email_notifications']) echo ' checked="checked"'; ?>/>
1092
- <?php _e('Send me e-mail notifications about newly detected broken links', 'broken-link-checker'); ?>
1093
- </label><br>
1094
- </p>
1095
- </td>
1096
- </tr>
1097
 
1098
  </table>
 
1099
 
1100
- <h3><?php _e('Advanced','broken-link-checker'); ?></h3>
 
1101
 
1102
  <table class="form-table">
1103
 
@@ -1126,21 +1001,23 @@ EOZ;
1126
  <tr valign="top">
1127
  <th scope="row"><?php _e('Link monitor', 'broken-link-checker'); ?></th>
1128
  <td>
 
 
1129
  <label for='run_in_dashboard'>
1130
- <p>
1131
  <input type="checkbox" name="run_in_dashboard" id="run_in_dashboard"
1132
  <?php if ($this->conf->options['run_in_dashboard']) echo ' checked="checked"'; ?>/>
1133
  <?php _e('Run continuously while the Dashboard is open', 'broken-link-checker'); ?>
1134
- </p>
1135
  </label>
 
1136
 
 
1137
  <label for='run_via_cron'>
1138
- <p>
1139
  <input type="checkbox" name="run_via_cron" id="run_via_cron"
1140
  <?php if ($this->conf->options['run_via_cron']) echo ' checked="checked"'; ?>/>
1141
  <?php _e('Run hourly in the background', 'broken-link-checker'); ?>
1142
- </p>
1143
- </label>
1144
 
1145
  </td>
1146
  </tr>
@@ -1219,30 +1096,7 @@ EOZ;
1219
  $value
1220
  );
1221
 
1222
- ?>
1223
- Current load : <span id='wsblc_current_load'>...</span>
1224
- <script type='text/javascript'>
1225
- (function($){
1226
-
1227
- function blcUpdateLoad(){
1228
- $.get(
1229
- "<?php echo admin_url('admin-ajax.php'); ?>",
1230
- {
1231
- 'action' : 'blc_current_load'
1232
- },
1233
- function (data, textStatus){
1234
- $('#wsblc_current_load').html(data);
1235
-
1236
- setTimeout(blcUpdateLoad, 10000); //...update every 10 seconds
1237
- }
1238
- );
1239
- }
1240
- blcUpdateLoad();//Call it the first time
1241
-
1242
- })(jQuery);
1243
- </script>
1244
- <?php
1245
-
1246
  echo '<br/><span class="description">';
1247
  printf(
1248
  __(
@@ -1254,7 +1108,7 @@ EOZ;
1254
  echo '</span>';
1255
 
1256
  } else {
1257
- echo '<input type="text" disabled="disabled" value="Not available" size="13"/><br>';
1258
  echo '<span class="description">';
1259
  _e('Load limiting only works on Linux-like systems where <code>/proc/loadavg</code> is present and accessible.', 'broken-link-checker');
1260
  echo '</span>';
@@ -1263,40 +1117,194 @@ EOZ;
1263
  </td>
1264
  </tr>
1265
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1266
  </table>
 
 
 
1267
 
1268
  <p class="submit"><input type="submit" name="submit" class='button-primary' value="<?php _e('Save Changes') ?>" /></p>
1269
  </form>
1270
  </div>
1271
 
1272
- <script type='text/javascript'>
1273
- jQuery(function($){
1274
- var toggleButton = $('#blc-debug-info-toggle');
1275
-
1276
- toggleButton.click(function(){
1277
-
1278
- var box = $('#blc-debug-info');
1279
- box.toggle();
1280
- if( box.is(':visible') ){
1281
- toggleButton.text('<?php _e('Hide debug info', 'broken-link-checker'); ?>');
1282
- } else {
1283
- toggleButton.text('<?php _e('Show debug info', 'broken-link-checker'); ?>');
1284
- }
1285
-
1286
- });
1287
- });
1288
- </script>
1289
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1290
  }
1291
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1292
  function options_page_css(){
1293
- wp_enqueue_style('blc-links-page', plugin_dir_url($this->loader) . 'css/options-page.css' );
1294
- wp_enqueue_style('blc-uservoice', plugin_dir_url($this->loader) . 'css/uservoice.css' );
1295
  }
1296
 
1297
 
 
 
 
 
 
1298
  function links_page(){
1299
  global $wpdb, $blclog;
 
1300
  $blc_link_query = & blcLinkQuery::getInstance();
1301
 
1302
  //Sanity check : Make sure the plugin's tables are all set up.
@@ -1313,6 +1321,17 @@ EOZ;
1313
  echo '<p>', implode('<br>', $blclog->get_messages()), '</p>';
1314
  return;
1315
  }
 
 
 
 
 
 
 
 
 
 
 
1316
 
1317
  $action = !empty($_POST['action'])?$_POST['action']:'';
1318
  if ( intval($action) == -1 ){
@@ -1333,371 +1352,115 @@ EOZ;
1333
  $msg_class = 'updated';
1334
 
1335
  //Run the selected bulk action, if any
1336
- if ( $action == 'create-custom-filter' ){
1337
- list($message, $msg_class) = $this->do_create_custom_filter();
1338
- } elseif ( $action == 'delete-custom-filter' ){
1339
- list($message, $msg_class) = $this->do_delete_custom_filter();
1340
- } elseif ($action == 'bulk-delete-sources') {
1341
- list($message, $msg_class) = $this->do_bulk_delete_sources($selected_links);
1342
- } elseif ($action == 'bulk-unlink') {
1343
- list($message, $msg_class) = $this->do_bulk_unlink($selected_links);
1344
- } elseif ($action == 'bulk-deredirect') {
1345
- list($message, $msg_class) = $this->do_bulk_deredirect($selected_links);
1346
- } elseif ($action == 'bulk-recheck') {
1347
- list($message, $msg_class) = $this->do_bulk_recheck($selected_links);
1348
- } elseif ($action == 'bulk-not-broken') {
1349
- list($message, $msg_class) = $this->do_bulk_discard($selected_links);
1350
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1351
 
1352
  if ( !empty($message) ){
1353
  echo '<div id="message" class="'.$msg_class.' fade"><p>'.$message.'</p></div>';
1354
  }
1355
 
 
 
1356
  //Load custom filters, if any
1357
  $blc_link_query->load_custom_filters();
1358
 
1359
  //Calculate the number of links matching each filter
1360
  $blc_link_query->count_filter_results();
1361
 
1362
- $filters = $blc_link_query->get_filters();
1363
-
1364
- //Get the selected filter (defaults to displaying broken links)
1365
- $filter_id = isset($_GET['filter_id'])?$_GET['filter_id']:'broken';
1366
- $current_filter = $blc_link_query->get_filter($filter_id);
1367
- if ( empty($current_filter) ){
1368
- $filter_id = 'broken';
1369
- $current_filter = $blc_link_query->get_filter('broken');
1370
-
1371
- }
1372
-
1373
- //Get the desired page number (must be > 0)
1374
- $page = isset($_GET['paged'])?intval($_GET['paged']):'1';
1375
- if ($page < 1) $page = 1;
1376
-
1377
- //Links per page [1 - 200]
1378
- $per_page = isset($_GET['per_page'])?intval($_GET['per_page']):'30';
1379
- if ($per_page < 1){
1380
- $per_page = 30;
1381
- } else if ($per_page > 200){
1382
- $per_page = 200;
1383
- }
1384
-
1385
- //Calculate the maximum number of pages.
1386
- $max_pages = ceil($current_filter['count'] / $per_page);
1387
-
1388
- //Select the required links
1389
- $extra_params = array(
1390
- 'offset' => ( ($page-1) * $per_page ),
1391
- 'max_results' => $per_page,
1392
- 'purpose' => BLC_FOR_DISPLAY,
1393
  );
1394
- $links = $blc_link_query->get_filter_links($current_filter, $extra_params);
 
 
1395
 
1396
  //Error?
1397
- if ( empty($links) && !empty($wpdb->last_error) ){
1398
  printf( __('Database error : %s', 'broken-link-checker'), $wpdb->last_error);
1399
  }
1400
 
1401
- //If the current request is a user-initiated search query (either directly or
1402
- //via a custom filter), save the search params. They can later be used to pre-fill
1403
- //the search form or build a new/modified custom filter.
1404
- if ( !empty($current_filter['custom']) || ($filter_id == 'search') ){
1405
- $search_params = $blc_link_query->get_search_params($current_filter);
1406
- }
1407
-
1408
- //Figure out what the "safe" URL to acccess the current page would be.
1409
- //This is used by the bulk action form.
1410
- $special_args = array('_wpnonce', '_wp_http_referer', 'action', 'selected_links');
1411
- $neutral_current_url = remove_query_arg($special_args);
1412
-
1413
  //Add the "Feedback" widget to the screen meta bar
1414
  $this->print_uservoice_widget();
 
1415
  ?>
1416
 
1417
  <script type='text/javascript'>
1418
  var blc_current_filter = '<?php echo $filter_id; ?>';
1419
- var blc_is_broken_filter = <?php
1420
- //TODO: Simplify this. Maybe overhaul the filter system to let us query the effective filter.
1421
- $is_broken_filter =
1422
- ($filter_id == 'broken')
1423
- || ( isset($current_filter['params']['s_filter']) && ($current_filter['params']['s_filter'] == 'broken') )
1424
- || ( isset($_GET['s_filter']) && ($_GET['s_filter'] == 'broken') );
1425
- echo $is_broken_filter ? 'true' : 'false';
1426
- ?>;
1427
  </script>
1428
 
1429
- <div class="wrap">
1430
- <h2><?php
1431
- //Output a header matching the current filter
1432
- if ( $current_filter['count'] > 0 ){
1433
- echo $current_filter['heading'] . " (<span class='current-link-count'>{$current_filter['count']}</span>)";
1434
- } else {
1435
- echo $current_filter['heading_zero'] . "<span class='current-link-count'></span>";
1436
- }
1437
- ?>
1438
- </h2>
1439
- <ul class="subsubsub">
1440
- <?php
1441
- //Construct a submenu of filter types
1442
- $items = array();
1443
- foreach ($filters as $filter => $data){
1444
- if ( !empty($data['hidden']) ) continue; //skip hidden filters
1445
-
1446
- $class = $number_class = '';
1447
-
1448
- if ( $filter_id == $filter ) {
1449
- $class = 'class="current"';
1450
- $number_class = 'current-link-count';
1451
- }
1452
-
1453
- $items[] = "<li><a href='tools.php?page=view-broken-links&filter_id=$filter' $class>
1454
- {$data['name']}</a> <span class='count'>(<span class='$number_class'>{$data['count']}</span>)</span>";
1455
- }
1456
- echo implode(' |</li>', $items);
1457
- unset($items);
1458
- ?>
1459
- </ul>
1460
-
1461
- <?php
1462
  //Display the "Search" form and associated buttons.
1463
- //The form requires the $filter_id and $search_params variables to be set.
1464
  include dirname($this->loader) . '/includes/admin/search-form.php';
1465
-
1466
-
1467
- //Do we have any links to display?
1468
- if( $links && ( count($links) > 0 ) ) {
1469
- ?>
1470
- <!-- The link list -->
1471
- <form id="blc-bulk-action-form" action="<?php echo $neutral_current_url; ?>" method="post">
1472
- <?php
1473
- wp_nonce_field('bulk-action');
1474
-
1475
- $bulk_actions = array(
1476
- '-1' => __('Bulk Actions', 'broken-link-checker'),
1477
- "bulk-recheck" => __('Recheck', 'broken-link-checker'),
1478
- "bulk-deredirect" => __('Fix redirects', 'broken-link-checker'),
1479
- "bulk-not-broken" => __('Mark as not broken', 'broken-link-checker'),
1480
- "bulk-unlink" => __('Unlink', 'broken-link-checker'),
1481
- "bulk-delete-sources" => __('Delete sources', 'broken-link-checker'),
1482
- );
1483
 
1484
- $bulk_actions_html = '';
1485
- foreach($bulk_actions as $value => $name){
1486
- $bulk_actions_html .= sprintf('<option value="%s">%s</option>', $value, $name);
1487
- }
1488
- ?>
1489
-
1490
- <div class='tablenav'>
1491
- <div class="alignleft actions">
1492
- <select name="action" id="blc-bulk-action">
1493
- <?php echo $bulk_actions_html; ?>
1494
- </select>
1495
- <input type="submit" name="doaction" id="doaction" value="<?php echo esc_attr(__('Apply', 'broken-link-checker')); ?>" class="button-secondary action">
1496
- </div>
1497
- <?php
1498
- //Display pagination links
1499
- $page_links = paginate_links( array(
1500
- 'base' => add_query_arg( 'paged', '%#%' ),
1501
- 'format' => '',
1502
- 'prev_text' => __('&laquo;'),
1503
- 'next_text' => __('&raquo;'),
1504
- 'total' => $max_pages,
1505
- 'current' => $page
1506
- ));
1507
-
1508
- if ( $page_links ) {
1509
- echo '<div class="tablenav-pages">';
1510
- $page_links_text = sprintf( '<span class="displaying-num">' . __( 'Displaying %s&#8211;%s of <span class="current-link-count">%s</span>', 'broken-link-checker' ) . '</span>%s',
1511
- number_format_i18n( ( $page - 1 ) * $per_page + 1 ),
1512
- number_format_i18n( min( $page * $per_page, $current_filter['count'] ) ),
1513
- number_format_i18n( $current_filter['count'] ),
1514
- $page_links
1515
- );
1516
- echo $page_links_text;
1517
- echo '</div>';
1518
- }
1519
- ?>
1520
-
1521
- </div>
1522
- <table class="widefat" id="blc-links">
1523
- <thead>
1524
- <tr>
1525
-
1526
- <th scope="col" id="cb" class="check-column">
1527
- <input type="checkbox">
1528
- </th>
1529
- <th scope="col" class="column-title blc-column-source"><?php _e('Source', 'broken-link-checker'); ?></th>
1530
- <th scope="col" class="blc-column-link-text"><?php _e('Link Text', 'broken-link-checker'); ?></th>
1531
- <th scope="col" class="blc-column-url"><?php _e('URL', 'broken-link-checker'); ?></th>
1532
- </tr>
1533
- </thead>
1534
- <tbody id="the-list">
1535
- <?php
1536
- $rowclass = ''; $rownum = 0;
1537
- foreach ($links as $link) {
1538
- $rownum++;
1539
-
1540
- $rowclass = ($rownum % 2)? 'alternate' : '';
1541
- $excluded = $this->is_excluded( $link->url );
1542
- if ( $excluded ) $rowclass .= ' blc-excluded-link';
1543
-
1544
- if ( $link->redirect_count > 0){
1545
- $rowclass .= ' blc-redirect';
1546
- }
1547
-
1548
- $days_broken = 0;
1549
- if ( $link->broken ){
1550
- $rowclass .= ' blc-broken-link';
1551
-
1552
- //Add a highlight to broken links that appear to be permanently broken
1553
- $days_broken = intval( (time() - $link->first_failure) / (3600*24) );
1554
- if ( $days_broken >= $this->conf->options['failure_duration_threshold'] ){
1555
- $rowclass .= ' blc-permanently-broken';
1556
- if ( $this->conf->options['highlight_permanent_failures'] ){
1557
- $rowclass .= ' blc-permanently-broken-hl';
1558
- }
1559
- }
1560
- }
1561
-
1562
-
1563
- ?>
1564
- <tr id='<?php echo "blc-row-" . $link->link_id; ?>' class='blc-row <?php echo $rowclass; ?>' days_broken="<?php echo $days_broken; ?>">
1565
-
1566
- <th class="check-column" scope="row">
1567
- <input type="checkbox" name="selected_links[]" value="<?php echo $link->link_id; ?>">
1568
- </th>
1569
-
1570
- <td class='post-title column-title'>
1571
- <span class='blc-link-id' style='display:none;'><?php echo $link->link_id; ?></span>
1572
- <?php
1573
-
1574
- //Pick one link instance to display in the table
1575
- $instance = null;
1576
- $instances = $link->get_instances();
1577
-
1578
- if ( !empty($instances) ){
1579
- //Try to find one that matches the selected link type, if any
1580
- if( !empty($search_params['s_link_type']) ){
1581
- foreach($instances as $candidate){
1582
- if ( ($candidate->container_type == $search_params['s_link_type']) || ($candidate->parser_type == $search_params['s_link_type']) ){
1583
- $instance = $candidate;
1584
- break;
1585
- }
1586
- }
1587
- }
1588
- //If there's no specific link type set, or no suitable instances were found,
1589
- //just use the first one.
1590
- if ( is_null($instance) ){
1591
- $instance = $instances[0];
1592
- }
1593
-
1594
- }
1595
-
1596
- //Print the contents of the "Source" column
1597
- if ( !is_null($instance) ){
1598
- echo $instance->ui_get_source();
1599
-
1600
- $actions = $instance->ui_get_action_links();
1601
-
1602
- echo '<div class="row-actions">';
1603
- echo implode(' | </span>', $actions);
1604
- echo '</div>';
1605
-
1606
- } else {
1607
- _e("[An orphaned link! This is a bug.]", 'broken-link-checker');
1608
- }
1609
-
1610
- ?>
1611
- </td>
1612
- <td class='blc-link-text'><?php
1613
- //The "Link text" column
1614
- if ( !is_null($instance) ){
1615
- echo $instance->ui_get_link_text();
1616
- } else {
1617
- echo '<em>N/A</em>';
1618
- }
1619
- ?>
1620
- </td>
1621
- <td class='column-url'>
1622
- <a href="<?php print esc_attr($link->url); ?>" target='_blank' class='blc-link-url' title="<?php echo esc_attr($link->url); ?>">
1623
- <?php print blcUtility::truncate($link->url, 50, ''); ?></a>
1624
- <input type='text' id='link-editor-<?php print $rownum; ?>'
1625
- value="<?php print esc_attr($link->url); ?>"
1626
- class='blc-link-editor' style='display:none' />
1627
- <?php
1628
- //Output inline action links for the link/URL
1629
- $actions = array();
1630
-
1631
- $actions['details'] = "<span class='view'><a class='blc-details-button' href='javascript:void(0)' title='". esc_attr(__('Show more info about this link', 'broken-link-checker')) . "'>". __('Details', 'broken-link-checker') ."</a>";
1632
-
1633
- $actions['delete'] = "<span class='delete'><a class='submitdelete blc-unlink-button' title='" . esc_attr( __('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 ( $link->broken ){
1637
- $actions['discard'] = sprintf(
1638
- '<span><a href="#" title="%s" class="blc-discard-button">%s</a>',
1639
- esc_attr(__('Remove this link from the list of broken links and mark it as valid', 'broken-link-checker')),
1640
- __('Not broken', 'broken-link-checker')
1641
- );
1642
- }
1643
-
1644
- $actions['edit'] = "<span class='edit'><a href='javascript:void(0)' class='blc-edit-button' title='" . esc_attr( __('Edit link URL' , 'broken-link-checker') ) . "'>". __('Edit URL' , 'broken-link-checker') ."</a>";
1645
-
1646
- echo '<div class="row-actions">';
1647
- echo implode(' | </span>', $actions);
1648
-
1649
- echo "<span style='display:none' class='blc-cancel-button-container'> " .
1650
- "| <a href='javascript:void(0)' class='blc-cancel-button' title='". esc_attr(__('Cancel URL editing' , 'broken-link-checker')) ."'>". __('Cancel' , 'broken-link-checker') ."</a></span>";
1651
-
1652
- echo '</div>';
1653
- ?>
1654
- </td>
1655
 
1656
- </tr>
1657
- <!-- Link details -->
1658
- <tr id='<?php print "link-details-$rownum"; ?>' style='display:none;' class='blc-link-details'>
1659
- <td colspan='4'><?php $this->link_details_row($link); ?></td>
1660
- </tr><?php
1661
- }
1662
- ?></tbody></table>
1663
-
1664
- <div class="tablenav">
1665
- <div class="alignleft actions">
1666
- <select name="action2" id="blc-bulk-action2">
1667
- <?php echo $bulk_actions_html; ?>
1668
- </select>
1669
- <input type="submit" name="doaction2" id="doaction2" value="<?php echo esc_attr(__('Apply', 'broken-link-checker')); ?>" class="button-secondary action">
1670
- </div><?php
1671
-
1672
- //Also display pagination links at the bottom
1673
- if ( $page_links ) {
1674
- echo '<div class="tablenav-pages">';
1675
- $page_links_text = sprintf( '<span class="displaying-num">' . __( 'Displaying %s&#8211;%s of <span class="current-link-count">%s</span>', 'broken-link-checker' ) . '</span>%s',
1676
- number_format_i18n( ( $page - 1 ) * $per_page + 1 ),
1677
- number_format_i18n( min( $page * $per_page, $current_filter['count'] ) ),
1678
- number_format_i18n( $current_filter['count'] ),
1679
- $page_links
1680
- );
1681
- echo $page_links_text;
1682
- echo '</div>';
1683
- }
1684
- ?>
1685
- </div>
1686
-
1687
- </form>
1688
- <?php
1689
 
1690
- }; //End of the links table & assorted nav stuff
 
1691
 
1692
- ?>
1693
-
1694
- <?php
1695
- //Load assorted JS event handlers and other shinies
1696
- include dirname($this->loader) . '/includes/admin/links-page-js.php';
1697
- ?>
1698
- </div>
1699
- <?php
1700
- } //Function ends
1701
 
1702
  /**
1703
  * Create a custom link filter using params passed in $_POST.
@@ -1903,14 +1666,16 @@ EOZ;
1903
  }
1904
 
1905
  /**
1906
- * Delete posts, bookmarks and other items that contain any of the specified links.
 
 
 
1907
  *
1908
  * @param array $selected_links An array of link IDs
 
1909
  * @return array Confirmation message and its CSS class.
1910
  */
1911
- function do_bulk_delete_sources($selected_links){
1912
- $blc_container_registry = & blcContainerRegistry::getInstance();
1913
-
1914
  $message = '';
1915
  $msg_class = 'updated';
1916
 
@@ -1944,14 +1709,26 @@ EOZ;
1944
  }
1945
 
1946
  //Instantiate the containers
1947
- $containers = blc_get_containers($containers);
1948
 
1949
- //Delete their associated entities
1950
  $deleted = array();
 
1951
  foreach($containers as $container){
1952
- $container_type = $container->container_type;
 
 
1953
 
1954
- $rez = $container->delete_wrapped_object();
 
 
 
 
 
 
 
 
 
1955
 
1956
  if ( is_wp_error($rez) ){
1957
  //Record error messages for later display
@@ -1959,6 +1736,7 @@ EOZ;
1959
  $msg_class = 'error';
1960
  } else {
1961
  //Keep track of how many of each type were deleted.
 
1962
  if ( isset($deleted[$container_type]) ){
1963
  $deleted[$container_type]++;
1964
  } else {
@@ -1969,11 +1747,38 @@ EOZ;
1969
 
1970
  //Generate delete confirmation messages
1971
  foreach($deleted as $container_type => $number){
1972
- $messages[] = $blc_container_registry->ui_bulk_delete_message($container_type, $number);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1973
  }
1974
 
1975
  if ( count($messages) > 0 ){
1976
- $message = implode('<br>', $messages);
1977
  } else {
1978
  $message = __("Didn't find anything to delete!", 'broken-link-checker');
1979
  $msg_class = 'error';
@@ -2079,194 +1884,123 @@ EOZ;
2079
  }
2080
 
2081
 
 
 
 
 
 
2082
  function links_page_css(){
2083
- wp_enqueue_style('blc-links-page', plugin_dir_url($this->loader) . 'css/links-page.css' );
2084
- wp_enqueue_style('blc-uservoice', plugin_dir_url($this->loader) . 'css/uservoice.css' );
2085
- }
2086
-
2087
- function link_details_row($link){
2088
- ?>
2089
- <div class="blc-detail-container">
2090
- <div class="blc-detail-block" style="float: left; width: 49%;">
2091
- <ol style='list-style-type: none;'>
2092
- <?php if ( !empty($link->post_date) ) { ?>
2093
- <li><strong><?php _e('Post published on', 'broken-link-checker'); ?> :</strong>
2094
- <span class='post_date'><?php
2095
- echo date_i18n(get_option('date_format'),strtotime($link->post_date));
2096
- ?></span></li>
2097
- <?php } ?>
2098
- <li><strong><?php _e('Link last checked', 'broken-link-checker'); ?> :</strong>
2099
- <span class='check_date'><?php
2100
- $last_check = $link->last_check;
2101
- if ( $last_check < strtotime('-10 years') ){
2102
- _e('Never', 'broken-link-checker');
2103
- } else {
2104
- echo date_i18n(get_option('date_format'), $last_check);
2105
- }
2106
- ?></span></li>
2107
-
2108
- <li><strong><?php _e('HTTP code', 'broken-link-checker'); ?> :</strong>
2109
- <span class='http_code'><?php
2110
- print $link->http_code;
2111
- ?></span></li>
2112
-
2113
- <li><strong><?php _e('Response time', 'broken-link-checker'); ?> :</strong>
2114
- <span class='request_duration'><?php
2115
- printf( __('%2.3f seconds', 'broken-link-checker'), $link->request_duration);
2116
- ?></span></li>
2117
-
2118
- <li><strong><?php _e('Final URL', 'broken-link-checker'); ?> :</strong>
2119
- <span class='final_url'><?php
2120
- print $link->final_url;
2121
- ?></span></li>
2122
-
2123
- <li><strong><?php _e('Redirect count', 'broken-link-checker'); ?> :</strong>
2124
- <span class='redirect_count'><?php
2125
- print $link->redirect_count;
2126
- ?></span></li>
2127
-
2128
- <li><strong><?php _e('Instance count', 'broken-link-checker'); ?> :</strong>
2129
- <span class='instance_count'><?php
2130
- print count($link->get_instances());
2131
- ?></span></li>
2132
-
2133
- <?php if ( $link->broken && (intval( $link->check_count ) > 0) ){ ?>
2134
- <li><br/>
2135
- <?php
2136
- printf(
2137
- _n('This link has failed %d time.', 'This link has failed %d times.', $link->check_count, 'broken-link-checker'),
2138
- $link->check_count
2139
- );
2140
-
2141
- echo '<br>';
2142
-
2143
- $delta = time() - $link->first_failure;
2144
- printf(
2145
- __('This link has been broken for %s.', 'broken-link-checker'),
2146
- $this->fuzzy_delta($delta)
2147
- );
2148
- ?>
2149
- </li>
2150
- <?php } ?>
2151
- </ol>
2152
- </div>
2153
-
2154
- <div class="blc-detail-block" style="float: right; width: 50%;">
2155
- <ol style='list-style-type: none;'>
2156
- <li><strong><?php _e('Log', 'broken-link-checker'); ?> :</strong>
2157
- <span class='blc_log'><?php
2158
- print nl2br($link->log);
2159
- ?></span></li>
2160
- </ol>
2161
- </div>
2162
-
2163
- <div style="clear:both;"> </div>
2164
- </div>
2165
- <?php
2166
  }
2167
 
2168
- /**
2169
- * Format a time delta using a fuzzy format, e.g. 'less than a minute', '2 days', etc.
2170
- *
2171
- * @param int $delta Time period in seconds.
2172
- * @return string
2173
- */
2174
- function fuzzy_delta($delta){
2175
- $ONE_MINUTE = 60;
2176
- $ONE_HOUR = 60 * $ONE_MINUTE;
2177
- $ONE_DAY = 24 * $ONE_HOUR;
2178
- $ONE_MONTH = $ONE_DAY * 3652425 / 120000;
2179
- $ONE_YEAR = $ONE_DAY * 3652425 / 10000;
2180
-
2181
- if ( $delta < $ONE_MINUTE ){
2182
- return __('less than a minute', 'broken-link-checker');
2183
  }
2184
 
2185
- if ( $delta < $ONE_HOUR ){
2186
- $minutes = intval($delta / $ONE_MINUTE);
2187
-
2188
- return sprintf(
2189
- _n(
2190
- '%d minute',
2191
- '%d minutes',
2192
- $minutes,
2193
- 'broken-link-checker'
2194
- ),
2195
- $minutes
2196
- );
2197
- }
2198
 
2199
- if ( $delta < $ONE_DAY ){
2200
- $hours = intval($delta / $ONE_HOUR);
2201
-
2202
- return sprintf(
2203
- _n(
2204
- '%d hour',
2205
- '%d hours',
2206
- $hours,
2207
- 'broken-link-checker'
2208
- ),
2209
- $hours
2210
- );
2211
- }
2212
 
2213
- if ( $delta < $ONE_MONTH ){
2214
- $days = intval($delta / $ONE_DAY);
2215
- $hours = intval( ($delta - $days * $ONE_DAY)/$ONE_HOUR );
2216
-
2217
- $ret = sprintf(
2218
- _n(
2219
- '%d day',
2220
- '%d days',
2221
- $days,
2222
- 'broken-link-checker'
2223
- ),
2224
- $days
2225
  );
2226
-
2227
-
2228
- if ( ($days < 2) && ($hours > 0) ){
2229
- $ret .= ' ' . sprintf(
2230
- _n(
2231
- '%d hour',
2232
- '%d hours',
2233
- $hours,
2234
- 'broken-link-checker'
2235
- ),
2236
- $hours
2237
- );
2238
- }
2239
-
2240
- return $ret;
2241
- }
2242
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2243
 
2244
- $months = intval( $delta / $ONE_MONTH );
2245
- $days = intval( ($delta - $months * $ONE_MONTH)/$ONE_DAY );
2246
-
2247
- $ret = sprintf(
2248
- _n(
2249
- '%d month',
2250
- '%d months',
2251
- $months,
2252
- 'broken-link-checker'
2253
- ),
2254
- $months
 
 
 
 
 
 
2255
  );
 
2256
 
2257
- if ( $days > 0 ){
2258
- $ret .= ' ' . sprintf(
2259
- _n(
2260
- '%d day',
2261
- '%d days',
2262
- $days,
2263
- 'broken-link-checker'
2264
- ),
2265
- $days
2266
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2267
  }
2268
 
2269
- return $ret;
 
2270
  }
2271
 
2272
  function start_timer(){
@@ -2326,7 +2060,7 @@ EOZ;
2326
  //This reduces resource usage and may solve the mysterious slowdowns certain users have
2327
  //encountered when activating the plugin.
2328
  //(Disable when debugging or you won't get the FirePHP output)
2329
- if ( !constant('BLC_DEBUG') ){
2330
  @ob_end_clean(); //Discard the existing buffer, if any
2331
  header("Connection: close");
2332
  ob_start();
@@ -2337,18 +2071,23 @@ EOZ;
2337
  flush(); // Unless both are called !
2338
  }
2339
 
2340
- $orphans_possible = false;
2341
- $still_need_resynch = $this->conf->options['need_resynch'];
2342
-
 
 
2343
  /*****************************************
2344
  Parse posts and bookmarks
2345
  ******************************************/
2346
 
 
 
 
2347
  if ( $still_need_resynch ) {
2348
 
2349
  //FB::log("Looking for containers that need parsing...");
2350
 
2351
- while( $containers = blc_get_unsynched_containers(50) ){
2352
  //FB::log($containers, 'Found containers');
2353
 
2354
  foreach($containers as $container){
@@ -2489,15 +2228,9 @@ EOZ;
2489
 
2490
  //Only check links that have at least one valid instance (i.e. an instance exists and
2491
  //it corresponds to one of the currently loaded container/parser types).
2492
- $containerRegistry = & blcContainerRegistry::getInstance();
2493
- $loaded_containers = array_keys($containerRegistry->get_registered_containers());
2494
- $loaded_containers = array_map(array(&$wpdb, 'escape'), $loaded_containers);
2495
- $loaded_containers = "'" . implode("', '", $loaded_containers) . "'";
2496
-
2497
- $parserRegistry = & blcParserRegistry::getInstance();
2498
- $loaded_parsers = array_keys($parserRegistry->get_registered_parsers());
2499
- $loaded_parsers = array_map(array(&$wpdb, 'escape'), $loaded_parsers);
2500
- $loaded_parsers = "'" . implode("', '", $loaded_parsers) . "'";
2501
 
2502
  //Note : This is a slow query, but AFAIK there is no way to speed it up.
2503
  //I could put an index on last_check_attempt, but that value is almost
@@ -2654,7 +2387,7 @@ EOZ;
2654
  function ajax_current_load(){
2655
  $load = $this->get_server_load();
2656
  if ( empty($load) ){
2657
- die('Unknown');
2658
  }
2659
 
2660
  $one_minute = reset($load);
@@ -2875,7 +2608,10 @@ EOZ;
2875
 
2876
  if ( !$link->is_new ){
2877
  //FB::info($link, 'Link loaded');
2878
- $this->link_details_row($link);
 
 
 
2879
  die();
2880
  } else {
2881
  printf( __('Failed to load link details (%s)', 'broken-link-checker'), $wpdb->last_error );
@@ -2883,29 +2619,6 @@ EOZ;
2883
  }
2884
  }
2885
 
2886
- /**
2887
- * AJAX hook for saving the settings from the "Screen Options" panel in Tools -> Broken Links.
2888
- *
2889
- * @return void
2890
- */
2891
- function ajax_save_highlight_settings(){
2892
- if (!current_user_can('edit_others_posts') || !check_ajax_referer('blc_save_highlight_settings', false, false)){
2893
- die( json_encode( array(
2894
- 'error' => __("You're not allowed to do that!", 'broken-link-checker')
2895
- )));
2896
- }
2897
-
2898
- $this->conf->options['highlight_permanent_failures'] = !empty($_POST['highlight_permanent_failures']);
2899
-
2900
- $failure_duration_threshold = intval($_POST['failure_duration_threshold']);
2901
- if ( $failure_duration_threshold >=1 ){
2902
- $this->conf->options['failure_duration_threshold'] = $failure_duration_threshold;
2903
- }
2904
-
2905
- $this->conf->save_options();
2906
- die('1');
2907
- }
2908
-
2909
  /**
2910
  * Create and lock a temporary file.
2911
  *
@@ -2981,8 +2694,8 @@ EOZ;
2981
  }
2982
 
2983
  //Try the plugin's own directory.
2984
- if ( @is_writable( dirname(__FILE__) ) ){
2985
- return dirname(__FILE__) . '/wp_blc_lock';
2986
  } else {
2987
 
2988
  //Try the system-wide temp directory
@@ -3071,7 +2784,7 @@ EOZ;
3071
  }
3072
 
3073
  function lockfile_warning(){
3074
- $my_dir = '/plugins/' . basename(dirname(__FILE__)) . '/';
3075
  $settings_page = admin_url( 'options-general.php?page=link-checker-settings#lockfile_directory' );
3076
 
3077
  //Make the notice customized to the current settings
@@ -3407,6 +3120,11 @@ EOZ;
3407
  if ( !wp_next_scheduled('blc_cron_database_maintenance') ){
3408
  wp_schedule_event(time(), 'bimonthly', 'blc_cron_database_maintenance');
3409
  }
 
 
 
 
 
3410
  }
3411
 
3412
  /**
@@ -3417,6 +3135,62 @@ EOZ;
3417
  function load_language(){
3418
  load_plugin_textdomain( 'broken-link-checker', false, basename(dirname($this->loader)) . '/languages' );
3419
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3420
 
3421
  }//class ends here
3422
 
11
  }
12
  }
13
 
14
+ require dirname(blc_get_plugin_file()) . '/includes/screen-options/screen-options.php';
15
+
16
  if (!class_exists('wsBrokenLinkChecker')) {
17
 
18
  class wsBrokenLinkChecker {
21
  var $loader;
22
  var $my_basename = '';
23
 
24
+ var $db_version = 5; //The required version of the plugin's DB schema.
25
 
26
  var $execution_start_time; //Used for a simple internal execution timer in start_timer()/execution_time()
27
  var $lockfile_handle = null;
41
  $this->loader = $loader;
42
  $this->my_basename = plugin_basename( $this->loader );
43
 
44
+ $this->load_language();
 
45
 
46
+ //Unlike the activation hook, the deactivation callback *can* be registered in this file
47
+ //because deactivation happens after this class has already been instantiated (durinng the
48
+ //'init' action).
49
+ register_deactivation_hook($loader, array(&$this, 'deactivation'));
50
 
51
  add_action('admin_menu', array(&$this,'admin_menu'));
52
 
65
  add_action( 'wp_ajax_blc_link_details', array(&$this,'ajax_link_details') );
66
  add_action( 'wp_ajax_blc_unlink', array(&$this,'ajax_unlink') );
67
  add_action( 'wp_ajax_blc_current_load', array(&$this,'ajax_current_load') );
 
68
  add_action( 'wp_ajax_blc_disable_widget_highlight', array(&$this,'ajax_disable_widget_highlight') );
69
 
70
  //Check if it's possible to create a lockfile and nag the user about it if not.
84
  add_action('blc_cron_email_notifications', array( &$this, 'send_email_notifications' ));
85
  add_action('blc_cron_check_links', array(&$this, 'cron_check_links'));
86
  add_action('blc_cron_database_maintenance', array(&$this, 'database_maintenance'));
87
+ add_action('blc_cron_check_news', array(&$this, 'check_news'));
88
+
89
+ //Add a "Screen Options" panel to the "Broken Links" page
90
+ add_screen_options_panel(
91
+ 'blc-screen-options',
92
+ '',
93
+ array(&$this, 'screen_options_html'),
94
+ 'tools_page_view-broken-links',
95
+ array(&$this, 'ajax_save_screen_options'),
96
+ true
97
+ );
98
  }
99
 
100
  /**
159
  $.getJSON(
160
  "<?php echo admin_url('admin-ajax.php'); ?>",
161
  {
162
+ 'action' : 'blc_dashboard_status',
163
+ 'random' : Math.random()
164
  },
165
  function (data, textStatus){
166
  if ( data && ( typeof(data.text) != 'undefined' ) ) {
205
  }
206
 
207
  function admin_print_scripts(){
208
+ //jQuery is used for triggering the link monitor via AJAX when any admin page is open.
209
  wp_enqueue_script('jquery');
210
  }
211
 
213
  //jQuery UI is used on the settings page
214
  wp_enqueue_script('jquery-ui-core'); //Used for background color animation
215
  wp_enqueue_script('jquery-ui-dialog');
216
+ wp_enqueue_script('jquery-ui-tabs');
217
+ wp_enqueue_script('jquery-cookie', WP_PLUGIN_URL . '/' . dirname($this->my_basename) . '/js/jquery.cookie.js'); //Used for storing last widget states, etc
218
  }
219
 
220
  function enqueue_link_page_scripts(){
343
  $blclog = new blcOptionLogger('blc_installation_log');
344
  $blclog->clear();
345
 
346
+ $blclog->info( sprintf('Plugin activated %s.', date('Y-m-d H:i:s')) );
347
 
348
  $this->conf->options['installation_complete'] = false;
349
  $this->conf->options['installation_failed'] = true;
350
  $this->conf->save_options();
351
  $blclog->info('Installation/update begins.');
352
 
353
+ $moduleManager = & blcModuleManager::getInstance();
354
+
355
+ //If upgrading, activate/deactivate custom field and comment containers based on old ver. settings
356
+ if ( isset($this->conf->options['check_comment_links']) ){
357
+ if ( !$this->conf->options['check_comment_links'] ){
358
+ $moduleManager->deactivate('comment');
359
+ }
360
+ unset($this->conf->options['check_comment_links']);
361
+ }
362
+ if ( empty($this->conf->options['custom_fields']) ){
363
+ $moduleManager->deactivate('custom_field');
364
+ }
365
+
366
  //Prepare the database.
367
  $blclog->info('Upgrading the database...');
368
  $this->upgrade_database();
369
+
370
+ //Remove invalid DB entries
371
+ $blclog->info('Cleaning up the database...');
372
+ blc_cleanup_database();
373
 
374
+ //Notify modules that the plugin has been activated. This will cause container
375
+ //modules to create and update synch. records for all new/modified posts and other items.
376
+ $blclog->info('Notifying modules...');
377
+ $moduleManager->plugin_activated();
378
+ blc_got_unsynched_items();
379
+
380
  //Turn off load limiting if it's not available on this server.
381
  $blclog->info('Updating server load limit settings...');
382
  $load = $this->get_server_load();
406
  wp_clear_scheduled_hook('blc_cron_check_links');
407
  wp_clear_scheduled_hook('blc_cron_email_notifications');
408
  wp_clear_scheduled_hook('blc_cron_database_maintenance');
409
+ wp_clear_scheduled_hook('blc_cron_check_news');
410
  }
411
 
412
  /**
415
  * @return bool
416
  */
417
  function upgrade_database($trigger_errors = true){
418
+ require_once dirname($this->loader) . '/includes/admin/db-upgrade.php';
419
+ return blcDatabaseUpgrader::upgrade_database();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
  }
421
 
422
  /**
439
  * @return void
440
  */
441
  function database_maintenance(){
442
+ blcContainerHelper::cleanup_containers();
 
 
443
  blc_cleanup_instances();
444
  blc_cleanup_links();
445
 
494
  //Add the UserVoice widget to the plugin's pages
495
  add_action( 'admin_footer-' . $options_page_hook, array(&$this, 'uservoice_widget') );
496
  add_action( 'admin_footer-' . $links_page_hook, array(&$this, 'uservoice_widget') );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
497
  }
498
 
499
  /**
523
  function options_page(){
524
  global $blclog, $blc_directory;
525
 
526
+ $moduleManager = &blcModuleManager::getInstance();
527
+
528
  //Sanity check : make sure the DB is all set up
529
  if ( $this->db_version != $this->conf->options['current_db_version'] ) {
530
  printf(
539
  return;
540
  }
541
 
542
+ if (isset($_POST['recheck']) && !empty($_POST['recheck']) ){
543
  $this->initiate_recheck();
544
+
545
+ //Redirect back to the settings page
546
+ $base_url = remove_query_arg( array('_wpnonce', 'noheader', 'updated', 'error', 'action', 'message') );
547
+ wp_redirect( add_query_arg( array( 'recheck-initiated' => true), $base_url ) );
548
+ die();
549
  }
550
 
551
  if(isset($_POST['submit'])) {
552
  check_admin_referer('link-checker-options');
553
 
554
+ //Activate/deactivate modules
555
+ if ( !empty($_POST['module']) ){
556
+ $active = array_keys($_POST['module']);
557
+ $moduleManager->set_active_modules($active);
558
+ }
559
+
560
+ //Only post statuses that actually exist can be selected
561
+ if ( isset($_POST['enabled_post_statuses']) && is_array($_POST['enabled_post_statuses']) ){
562
+ $available_statuses = get_post_stati();
563
+ $enabled_post_statuses = array_intersect($_POST['enabled_post_statuses'], $available_statuses);
564
+ } else {
565
+ $enabled_post_statuses = array();
566
+ }
567
+ //At least one status must be enabled; defaults to "Published".
568
+ if ( empty($enabled_post_statuses) ){
569
+ $enabled_post_statuses = array('publish');
570
+ }
571
+ $this->conf->options['enabled_post_statuses'] = $enabled_post_statuses;
572
+
573
  //The execution time limit must be above zero
574
  $new_execution_time = intval($_POST['max_execution_time']);
575
  if( $new_execution_time > 0 ){
647
  }
648
  $this->conf->options['send_email_notifications'] = $email_notifications;
649
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
650
  //Make settings that affect our Cron events take effect immediately
651
  $this->setup_cron_events();
652
 
658
  inefficient.
659
  */
660
  if ( ( count($diff1) > 0 ) || ( count($diff2) > 0 ) ){
661
+ $manager = & blcContainerHelper::get_manager('custom_field');
 
662
  if ( !is_null($manager) ){
663
  $manager->resynch();
664
  blc_got_unsynched_items();
676
 
677
  }
678
 
679
+ //Show one when recheck is started, too.
680
+ if ( !empty($_GET['recheck-initiated']) ){
681
+ echo '<div id="message" class="updated fade"><p><strong>',
682
+ __('Complete site recheck started.', 'broken-link-checker'), // -- Yoda
683
+ '</strong></p></div>';
684
+ }
685
+
686
+ //Cull invalid and missing modules
687
+ $moduleManager->validate_active_modules();
688
+
689
+ //Output the "Feedback" button that links to the plugin's UserVoice forum
690
+ $this->print_uservoice_widget();
691
+
692
  $debug = $this->get_debug_info();
693
 
694
+ $details_text = __('Details', 'broken-link-checker');
695
+ add_filter('blc-module-settings-custom_field', array(&$this, 'make_custom_field_input'), 10, 2);
696
+
697
+ //Translate and markup-ify module headers for display
698
+ $modules = $moduleManager->get_modules_by_category('', true, true);
699
+
700
+ //Output the custom broken link/removed link styles for example links
701
+ printf(
702
+ '<style type="text/css">%s %s</style>',
703
+ $this->conf->options['broken_link_css'],
704
+ $this->conf->options['removed_link_css']
705
+ );
706
+
707
+ $section_names = array(
708
+ 'general' => __('General', 'broken-link-checker'),
709
+ 'where' => __('Look For Links In', 'broken-link-checker'),
710
+ 'which' => __('Which Links To Check', 'broken-link-checker'),
711
+ 'how' => __('Protocols & APIs', 'broken-link-checker'),
712
+ 'advanced' => __('Advanced', 'broken-link-checker'),
713
+ );
714
  ?>
715
 
716
+ <div class="wrap"><?php screen_icon(); ?><h2><?php _e('Broken Link Checker Options', 'broken-link-checker'); ?></h2>
717
 
718
+ <form name="link_checker_options" id="link_checker_options" method="post" action="<?php
719
  echo admin_url('options-general.php?page=link-checker-settings&noheader=1');
720
  ?>">
721
  <?php
722
  wp_nonce_field('link-checker-options');
723
  ?>
724
+
725
+ <div id="blc-tabs">
726
+
727
+ <ul class="hide-if-no-js">
728
+ <?php
729
+ foreach($section_names as $section_id => $section_name){
730
+ printf('<li><a href="#section-%s">%s</a></li>', esc_attr($section_id), $section_name);
731
+ }
732
+ ?>
733
+ </ul>
734
 
735
+ <div id="section-general" class="blc-section">
736
+ <h3 class="hide-if-js"><?php echo $section_names['general']; ?></h3>
737
+
738
  <table class="form-table">
739
 
740
  <tr valign="top">
748
  <div id='wsblc_full_status'>
749
  <br/><br/><br/>
750
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
751
 
752
  <table id="blc-debug-info">
753
  <?php
788
 
789
  </td>
790
  </tr>
791
+
792
+ <tr valign="top">
793
+ <th scope="row"><?php _e('E-mail notifications', 'broken-link-checker'); ?></th>
794
+ <td>
795
+ <p style="margin-top: 0px;">
796
+ <label for='send_email_notifications'>
797
+ <input type="checkbox" name="send_email_notifications" id="send_email_notifications"
798
+ <?php if ($this->conf->options['send_email_notifications']) echo ' checked="checked"'; ?>/>
799
+ <?php _e('Send me e-mail notifications about newly detected broken links', 'broken-link-checker'); ?>
800
+ </label><br />
801
+ </p>
802
+ </td>
803
+ </tr>
804
 
805
  <tr valign="top">
806
+ <th scope="row"><?php _e('Link tweaks','broken-link-checker'); ?></th>
807
  <td>
808
+ <p style="margin-top: 0; margin-bottom: 0.5em;">
809
  <label for='mark_broken_links'>
810
  <input type="checkbox" name="mark_broken_links" id="mark_broken_links"
811
  <?php if ($this->conf->options['mark_broken_links']) echo ' checked="checked"'; ?>/>
812
+ <?php _e('Apply custom formatting to broken links', 'broken-link-checker'); ?>
813
  </label>
814
+ |
815
+ <a id="toggle-broken-link-css-editor" href="#" class="blc-toggle-link"><?php
816
+ _e('Edit CSS', 'broken-link-checker');
817
+ ?></a>
818
+ </p>
819
+
820
+ <div id="broken-link-css-wrap"<?php
821
+ if ( !blcUtility::get_cookie('broken-link-css-wrap', false) ){
822
+ echo ' class="hidden"';
823
+ }
824
+ ?>>
825
+ <textarea name="broken_link_css" id="broken_link_css" cols='45' rows='4'/><?php
826
+ if( isset($this->conf->options['broken_link_css']) )
827
+ echo $this->conf->options['broken_link_css'];
828
+ ?></textarea>
829
+ <p class="description">
830
+ Example : Lorem ipsum <a href="#" class="broken_link" onclick="return false;">broken link</a>,
831
+ dolor sit amet.
832
+ Click "Save Changes" to update example output.
833
+ </p>
834
+ </div>
835
+
836
+ <p style="margin-bottom: 0.5em;">
837
  <label for='mark_removed_links'>
838
  <input type="checkbox" name="mark_removed_links" id="mark_removed_links"
839
  <?php if ($this->conf->options['mark_removed_links']) echo ' checked="checked"'; ?>/>
840
+ <?php _e('Apply custom formatting to removed links', 'broken-link-checker'); ?>
841
  </label>
842
+ |
843
+ <a id="toggle-removed-link-css-editor" href="#" class="blc-toggle-link"><?php
844
+ _e('Edit CSS', 'broken-link-checker');
845
+ ?></a>
846
+ </p>
847
+
848
+ <div id="removed-link-css-wrap" <?php
849
+ if ( !blcUtility::get_cookie('removed-link-css-wrap', false) ){
850
+ echo ' class="hidden"';
851
+ }
852
+ ?>>
853
+ <textarea name="removed_link_css" id="removed_link_css" cols='45' rows='4'/><?php
854
+ if( isset($this->conf->options['removed_link_css']) )
855
+ echo $this->conf->options['removed_link_css'];
856
+ ?></textarea>
857
+
858
+ <p class="description">
859
+ Example : Lorem ipsum <span class="removed_link">removed link</span>, dolor sit amet.
860
+ Click "Save Changes" to update example output.
861
+ </p>
862
+ </div>
863
 
864
+ <p>
 
 
865
  <label for='nofollow_broken_links'>
866
  <input type="checkbox" name="nofollow_broken_links" id="nofollow_broken_links"
867
  <?php if ($this->conf->options['nofollow_broken_links']) echo ' checked="checked"'; ?>/>
868
+ <?php _e('Stop search engines from following broken links', 'broken-link-checker'); ?>
869
  </label>
870
+ </p>
871
+
872
  </td>
873
  </tr>
874
+
875
+ </table>
876
+
877
+ </div>
878
+
879
+ <div id="section-where" class="blc-section">
880
+ <h3 class="hide-if-js"><?php echo $section_names['where']; ?></h3>
881
+
882
+ <table class="form-table">
883
+
884
+ <tr valign="top">
885
+ <th scope="row"><?php _e('Look for links in', 'broken-link-checker'); ?></th>
886
+ <td>
887
+ <?php
888
+ if ( !empty($modules['container']) ){
889
+ uasort($modules['container'], create_function('$a, $b', 'return strcasecmp($a["Name"], $b["Name"]);'));
890
+ $this->print_module_list($modules['container'], $this->conf->options);
891
+ }
892
+ ?>
893
+ </td></tr>
894
+
895
+ <tr valign="top">
896
+ <th scope="row"><?php _e('Post statuses', 'broken-link-checker'); ?></th>
897
+ <td>
898
+ <?php
899
+ $available_statuses = get_post_stati(array('internal' => false), 'objects');
900
+
901
+ if ( isset($this->conf->options['enabled_post_statuses']) ){
902
+ $enabled_post_statuses = $this->conf->options['enabled_post_statuses'];
903
+ } else {
904
+ $enabled_post_statuses = array();
905
+ }
906
+
907
+ foreach($available_statuses as $status => $status_object){
908
+ printf(
909
+ '<p><label><input type="checkbox" name="enabled_post_statuses[]" value="%s"%s> %s</label></p>',
910
+ esc_attr($status),
911
+ in_array($status, $enabled_post_statuses)?' checked="checked"':'',
912
+ $status_object->label
913
+ );
914
+ }
915
+ ?>
916
+ </td></tr>
917
+
918
+ </table>
919
+
920
+ </div>
921
+
922
+
923
+ <div id="section-which" class="blc-section">
924
+ <h3 class="hide-if-js"><?php echo $section_names['which']; ?></h3>
925
+
926
+ <table class="form-table">
927
+
928
  <tr valign="top">
929
+ <th scope="row"><?php _e('Link types', 'broken-link-checker'); ?></th>
930
+ <td>
931
+ <?php
932
+ if ( !empty($modules['parser']) ){
933
+ $this->print_module_list($modules['parser'], $this->conf->options);
934
+ } else {
935
+ echo __('Error : All link parsers missing!', 'broken-link-checker');
936
+ }
937
+ ?>
938
+ </td>
939
+ </tr>
940
+
941
+ <tr valign="top">
942
  <th scope="row"><?php _e('Exclusion list', 'broken-link-checker'); ?></th>
943
  <td><?php _e("Don't check links where the URL contains any of these words (one per line) :", 'broken-link-checker'); ?><br/>
944
  <textarea name="exclusion_list" id="exclusion_list" cols='45' rows='4' wrap='off'/><?php
949
  </td>
950
  </tr>
951
 
952
+ </table>
953
+ </div>
 
 
 
 
 
 
 
 
954
 
955
+ <div id="section-how" class="blc-section">
956
+ <h3 class="hide-if-js"><?php echo $section_names['how']; ?></h3>
957
+
958
+ <table class="form-table">
 
 
 
 
 
 
 
 
959
 
960
  <tr valign="top">
961
+ <th scope="row"><?php _e('Check links using', 'broken-link-checker'); ?></th>
962
  <td>
963
+ <?php
964
+ if ( !empty($modules['checker']) ){
965
+ $modules['checker'] = array_reverse($modules['checker']);
966
+ $this->print_module_list($modules['checker'], $this->conf->options);
967
+ }
968
+ ?>
969
+ </td></tr>
 
 
970
 
971
  </table>
972
+ </div>
973
 
974
+ <div id="section-advanced" class="blc-section">
975
+ <h3 class="hide-if-js"><?php echo $section_names['advanced']; ?></h3>
976
 
977
  <table class="form-table">
978
 
1001
  <tr valign="top">
1002
  <th scope="row"><?php _e('Link monitor', 'broken-link-checker'); ?></th>
1003
  <td>
1004
+
1005
+ <p>
1006
  <label for='run_in_dashboard'>
1007
+
1008
  <input type="checkbox" name="run_in_dashboard" id="run_in_dashboard"
1009
  <?php if ($this->conf->options['run_in_dashboard']) echo ' checked="checked"'; ?>/>
1010
  <?php _e('Run continuously while the Dashboard is open', 'broken-link-checker'); ?>
 
1011
  </label>
1012
+ </p>
1013
 
1014
+ <p>
1015
  <label for='run_via_cron'>
 
1016
  <input type="checkbox" name="run_via_cron" id="run_via_cron"
1017
  <?php if ($this->conf->options['run_via_cron']) echo ' checked="checked"'; ?>/>
1018
  <?php _e('Run hourly in the background', 'broken-link-checker'); ?>
1019
+ </label>
1020
+ </p>
1021
 
1022
  </td>
1023
  </tr>
1096
  $value
1097
  );
1098
 
1099
+ echo 'Current load : <span id="wsblc_current_load">...</span>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1100
  echo '<br/><span class="description">';
1101
  printf(
1102
  __(
1108
  echo '</span>';
1109
 
1110
  } else {
1111
+ echo '<input type="text" disabled="disabled" value="', esc_attr(__('Not available', 'broken-link-checker')), '" size="13"/><br>';
1112
  echo '<span class="description">';
1113
  _e('Load limiting only works on Linux-like systems where <code>/proc/loadavg</code> is present and accessible.', 'broken-link-checker');
1114
  echo '</span>';
1117
  </td>
1118
  </tr>
1119
 
1120
+ <tr valign="top">
1121
+ <th scope="row"><?php _e('Forced recheck', 'broken-link-checker'); ?></th>
1122
+ <td>
1123
+ <input class="button" type="button" name="start-recheck" id="start-recheck"
1124
+ value="<?php _e('Re-check all pages', 'broken-link-checker'); ?>" />
1125
+ <input type="hidden" name="recheck" value="" id="recheck" />
1126
+ <br />
1127
+ <span class="description"><?php
1128
+ _e('The "Nuclear Option". Click this button to make the plugin empty its link database and recheck the entire site from scratch.', 'broken-link-checker');
1129
+
1130
+ ?></span>
1131
+ </td>
1132
+ </tr>
1133
+
1134
  </table>
1135
+ </div>
1136
+
1137
+ </div>
1138
 
1139
  <p class="submit"><input type="submit" name="submit" class='button-primary' value="<?php _e('Save Changes') ?>" /></p>
1140
  </form>
1141
  </div>
1142
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1143
  <?php
1144
+ //The various JS for this page is stored in a separate file for the purposes readability.
1145
+ include dirname($this->loader) . '/includes/admin/options-page-js.php';
1146
+ }
1147
+
1148
+ /**
1149
+ * Output a list of modules and their settings.
1150
+ *
1151
+ * Each list entry will contain a checkbox that is checked if the module is
1152
+ * currently active.
1153
+ *
1154
+ * @param array $modules Array of modules to display
1155
+ * @param array $current_settings
1156
+ * @return void
1157
+ */
1158
+ function print_module_list($modules, $current_settings){
1159
+ $moduleManager = &blcModuleManager::getInstance();
1160
+
1161
+ foreach($modules as $module_id => $module_data){
1162
+ $module_id = $module_data['ModuleID'];
1163
+
1164
+ $style = $module_data['ModuleHidden']?' style="display:none;"':'';
1165
+
1166
+ printf(
1167
+ '<div class="module-container" id="module-container-%s"%s>',
1168
+ $module_id,
1169
+ $style
1170
+ );
1171
+ $this->print_module_checkbox($module_id, $module_data, $moduleManager->is_active($module_id));
1172
+
1173
+ $extra_settings = apply_filters(
1174
+ 'blc-module-settings-'.$module_id,
1175
+ '',
1176
+ $current_settings
1177
+ );
1178
+
1179
+ if ( !empty($extra_settings) ){
1180
+
1181
+ printf(
1182
+ ' | <a class="blc-toggle-link toggle-module-settings" id="toggle-module-settings-%s" href="#">%s</a>',
1183
+ $module_id,
1184
+ __('Configure', 'broken-link-checker')
1185
+ );
1186
+
1187
+ //The plugin remembers the last open/closed state of module configuration boxes
1188
+ $box_id = 'module-extra-settings-' . $module_id;
1189
+ $show = blcUtility::get_cookie(
1190
+ $box_id,
1191
+ $moduleManager->is_active($module_id)
1192
+ );
1193
+
1194
+ printf(
1195
+ '<div class="module-extra-settings%s" id="%s">%s</div>',
1196
+ $show?'':' hidden',
1197
+ $box_id,
1198
+ $extra_settings
1199
+ );
1200
+ }
1201
+
1202
+ echo '</div>';
1203
+ }
1204
+ }
1205
+
1206
+ /**
1207
+ * Output a checkbox for a module.
1208
+ *
1209
+ * Generates a simple checkbox that can be used to mark a module as active/inactive.
1210
+ * If the specified module can't be deactivated (ModuleAlwaysActive = true), the checkbox
1211
+ * will be displayed in a disabled state and a hidden field will be created to make
1212
+ * form submissions work correctly.
1213
+ *
1214
+ * @param string $module_id Module ID.
1215
+ * @param array $module_data Associative array of module data.
1216
+ * @param bool $active If true, the newly created checkbox will start out checked.
1217
+ * @return void
1218
+ */
1219
+ function print_module_checkbox($module_id, $module_data, $active = false){
1220
+ $disabled = false;
1221
+ $name_prefix = 'module';
1222
+ $label_class = '';
1223
+ $active = $active || $module_data['ModuleAlwaysActive'];
1224
+
1225
+ if ( $module_data['ModuleRequiresPro'] && !defined('BLC_PRO_VERSION') ){
1226
+ $active = false;
1227
+ $disabled = true;
1228
+ $label_class .= ' module-requires-pro';
1229
+ }
1230
+
1231
+ if ( $module_data['ModuleAlwaysActive'] ){
1232
+ $disabled = true;
1233
+ $name_prefix = 'module-always-active';
1234
+ }
1235
+
1236
+ $checked = $active ? ' checked="checked"':'';
1237
+ if ( $disabled ){
1238
+ $checked .= ' disabled="disabled"';
1239
+ }
1240
+
1241
+ $pro_notice = sprintf(
1242
+ '<span class="pro-notice"><a href="%s" title="%s">Pro</a></span>',
1243
+ esc_attr('http://wpplugins.com/plugin/173/broken-link-checker-pro'),
1244
+ esc_attr(__('Upgrade to Pro to enable this feature', 'broken-link-checker'))
1245
+ );
1246
+
1247
+ printf(
1248
+ '<label class="%s">
1249
+ <input type="checkbox" name="%s[%s]" id="module-checkbox-%s"%s /> %s %s
1250
+ </label>',
1251
+ esc_attr($label_class),
1252
+ $name_prefix,
1253
+ esc_attr($module_id),
1254
+ esc_attr($module_id),
1255
+ $checked,
1256
+ $module_data['Name'],
1257
+ ($module_data['ModuleRequiresPro'] && !defined('BLC_PRO_VERSION')) ? $pro_notice : ''
1258
+ );
1259
+
1260
+ if ( $module_data['ModuleAlwaysActive'] ){
1261
+ printf(
1262
+ '<input type="hidden" name="module[%s]" value="on">',
1263
+ esc_attr($module_id)
1264
+ );
1265
+ }
1266
  }
1267
 
1268
+ /**
1269
+ * Add extra settings to the "Custom fields" entry on the plugin's config. page.
1270
+ *
1271
+ * Callback for the 'blc-module-settings-custom_field' filter.
1272
+ *
1273
+ * @param string $html Current extra HTML
1274
+ * @param array $current_settings The current plugin configuration.
1275
+ * @return string New extra HTML.
1276
+ */
1277
+ function make_custom_field_input($html, $current_settings){
1278
+ $html .= '<span class="description">' .
1279
+ __('Check URLs entered in these custom fields (one per line) :', 'broken-link-checker') .
1280
+ '</span>';
1281
+ $html .= '<br><textarea name="blc_custom_fields" id="blc_custom_fields" cols="45" rows="4" />';
1282
+ if( isset($current_settings['custom_fields']) )
1283
+ $html .= implode("\n", $current_settings['custom_fields']);
1284
+ $html .= '</textarea>';
1285
+
1286
+ return $html;
1287
+ }
1288
+
1289
+ /**
1290
+ * Enqueue CSS file for the plugin's Settings page.
1291
+ *
1292
+ * @return void
1293
+ */
1294
  function options_page_css(){
1295
+ wp_enqueue_style('blc-options-page', plugin_dir_url($this->loader) . 'css/options-page.css', array(), '0.9.5' );
1296
+ wp_enqueue_style('blc-screen-meta-links', plugin_dir_url($this->loader) . 'css/screen-meta-links.css' );
1297
  }
1298
 
1299
 
1300
+ /**
1301
+ * Display the "Broken Links" page, listing links detected by the plugin and their status.
1302
+ *
1303
+ * @return void
1304
+ */
1305
  function links_page(){
1306
  global $wpdb, $blclog;
1307
+
1308
  $blc_link_query = & blcLinkQuery::getInstance();
1309
 
1310
  //Sanity check : Make sure the plugin's tables are all set up.
1321
  echo '<p>', implode('<br>', $blclog->get_messages()), '</p>';
1322
  return;
1323
  }
1324
+
1325
+ //Cull invalid and missing modules so that we don't get dummy links/instances showing up.
1326
+ $moduleManager = &blcModuleManager::getInstance();
1327
+ $moduleManager->validate_active_modules();
1328
+
1329
+ if ( defined('BLC_DEBUG') && constant('BLC_DEBUG') ){
1330
+ //Make module headers translatable. They need to be formatted corrrectly and
1331
+ //placed in a .php file to be visible to the script(s) that generate .pot files.
1332
+ $code = $moduleManager->_build_header_translation_code();
1333
+ file_put_contents( dirname($this->loader) . '/includes/extra-strings.php', $code );
1334
+ }
1335
 
1336
  $action = !empty($_POST['action'])?$_POST['action']:'';
1337
  if ( intval($action) == -1 ){
1352
  $msg_class = 'updated';
1353
 
1354
  //Run the selected bulk action, if any
1355
+ $force_delete = false;
1356
+ switch ( $action ){
1357
+ case 'create-custom-filter':
1358
+ list($message, $msg_class) = $this->do_create_custom_filter();
1359
+ break;
1360
+
1361
+ case 'delete-custom-filter':
1362
+ list($message, $msg_class) = $this->do_delete_custom_filter();
1363
+ break;
1364
+
1365
+ case 'bulk-delete-sources':
1366
+ $force_delete = true;
1367
+ case 'bulk-trash-sources':
1368
+ list($message, $msg_class) = $this->do_bulk_delete_sources($selected_links, $force_delete);
1369
+ break;
1370
+
1371
+ case 'bulk-unlink':
1372
+ list($message, $msg_class) = $this->do_bulk_unlink($selected_links);
1373
+ break;
1374
+
1375
+ case 'bulk-deredirect':
1376
+ list($message, $msg_class) = $this->do_bulk_deredirect($selected_links);
1377
+ break;
1378
+
1379
+ case 'bulk-recheck':
1380
+ list($message, $msg_class) = $this->do_bulk_recheck($selected_links);
1381
+ break;
1382
+
1383
+ case 'bulk-not-broken':
1384
+ list($message, $msg_class) = $this->do_bulk_discard($selected_links);
1385
+ break;
1386
+ }
1387
+
1388
 
1389
  if ( !empty($message) ){
1390
  echo '<div id="message" class="'.$msg_class.' fade"><p>'.$message.'</p></div>';
1391
  }
1392
 
1393
+ $start_time = microtime_float();
1394
+
1395
  //Load custom filters, if any
1396
  $blc_link_query->load_custom_filters();
1397
 
1398
  //Calculate the number of links matching each filter
1399
  $blc_link_query->count_filter_results();
1400
 
1401
+ //Run the selected filter (defaults to displaying broken links)
1402
+ $selected_filter_id = isset($_GET['filter_id'])?$_GET['filter_id']:'broken';
1403
+ $current_filter = $blc_link_query->exec_filter(
1404
+ $selected_filter_id,
1405
+ isset($_GET['paged']) ? intval($_GET['paged']) : 1,
1406
+ $this->conf->options['table_links_per_page'],
1407
+ 'broken'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1408
  );
1409
+
1410
+ //exec_filter() returns an array with filter data, including the actual filter ID that was used.
1411
+ $filter_id = $current_filter['filter_id'];
1412
 
1413
  //Error?
1414
+ if ( empty($current_filter['links']) && !empty($wpdb->last_error) ){
1415
  printf( __('Database error : %s', 'broken-link-checker'), $wpdb->last_error);
1416
  }
1417
 
 
 
 
 
 
 
 
 
 
 
 
 
1418
  //Add the "Feedback" widget to the screen meta bar
1419
  $this->print_uservoice_widget();
1420
+ $this->display_plugin_news_link();
1421
  ?>
1422
 
1423
  <script type='text/javascript'>
1424
  var blc_current_filter = '<?php echo $filter_id; ?>';
1425
+ var blc_is_broken_filter = <?php echo $current_filter['is_broken_filter'] ? 'true' : 'false'; ?>;
 
 
 
 
 
 
 
1426
  </script>
1427
 
1428
+ <div class="wrap"><?php screen_icon(); ?>
1429
+ <?php
1430
+ $blc_link_query->print_filter_heading($current_filter);
1431
+ $blc_link_query->print_filter_menu($filter_id);
1432
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1433
  //Display the "Search" form and associated buttons.
1434
+ //The form requires the $filter_id and $current_filter variables to be set.
1435
  include dirname($this->loader) . '/includes/admin/search-form.php';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1436
 
1437
+ //If the user has decided to switch the table to a different mode (compact/full),
1438
+ //save the new setting.
1439
+ if ( isset($_GET['compact']) ){
1440
+ $this->conf->options['table_compact'] = (bool)$_GET['compact'];
1441
+ $this->conf->save_options();
1442
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1443
 
1444
+ //Display the links, if any
1445
+ if( $current_filter['links'] && ( count($current_filter['links']) > 0 ) ) {
1446
+
1447
+ include dirname($this->loader) . '/includes/admin/table-printer.php';
1448
+ $table = new blcTablePrinter($this);
1449
+ $table->print_table(
1450
+ $current_filter,
1451
+ $this->conf->options['table_layout'],
1452
+ $this->conf->options['table_visible_columns'],
1453
+ $this->conf->options['table_compact']
1454
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1455
 
1456
+ };
1457
+ printf('<!-- Total elapsed : %.4f seconds -->', microtime_float() - $start_time);
1458
 
1459
+ //Load assorted JS event handlers and other shinies
1460
+ include dirname($this->loader) . '/includes/admin/links-page-js.php';
1461
+
1462
+ ?></div><?php
1463
+ }
 
 
 
 
1464
 
1465
  /**
1466
  * Create a custom link filter using params passed in $_POST.
1666
  }
1667
 
1668
  /**
1669
+ * Delete or trash posts, bookmarks and other items that contain any of the specified links.
1670
+ *
1671
+ * Will prefer moving stuff to trash to permanent deletion. If it encounters an item that
1672
+ * can't be moved to the trash, it will skip that item by default.
1673
  *
1674
  * @param array $selected_links An array of link IDs
1675
+ * @param bool $force_delete Whether to bypass trash and force deletion. Defaults to false.
1676
  * @return array Confirmation message and its CSS class.
1677
  */
1678
+ function do_bulk_delete_sources($selected_links, $force_delete = false){
 
 
1679
  $message = '';
1680
  $msg_class = 'updated';
1681
 
1709
  }
1710
 
1711
  //Instantiate the containers
1712
+ $containers = blcContainerHelper::get_containers($containers);
1713
 
1714
+ //Delete/trash their associated entities
1715
  $deleted = array();
1716
+ $skipped = array();
1717
  foreach($containers as $container){
1718
+ if ( !$container->current_user_can_delete() ){
1719
+ continue;
1720
+ }
1721
 
1722
+ if ( $force_delete ){
1723
+ $rez = $container->delete_wrapped_object();
1724
+ } else {
1725
+ if ( $container->can_be_trashed() ){
1726
+ $rez = $container->trash_wrapped_object();
1727
+ } else {
1728
+ $skipped[] = $container;
1729
+ continue;
1730
+ }
1731
+ }
1732
 
1733
  if ( is_wp_error($rez) ){
1734
  //Record error messages for later display
1736
  $msg_class = 'error';
1737
  } else {
1738
  //Keep track of how many of each type were deleted.
1739
+ $container_type = $container->container_type;
1740
  if ( isset($deleted[$container_type]) ){
1741
  $deleted[$container_type]++;
1742
  } else {
1747
 
1748
  //Generate delete confirmation messages
1749
  foreach($deleted as $container_type => $number){
1750
+ if ( $force_delete ){
1751
+ $messages[] = blcContainerHelper::ui_bulk_delete_message($container_type, $number);
1752
+ } else {
1753
+ $messages[] = blcContainerHelper::ui_bulk_trash_message($container_type, $number);
1754
+ }
1755
+
1756
+ }
1757
+
1758
+ //If some items couldn't be trashed, let the user know
1759
+ if ( count($skipped) > 0 ){
1760
+ $message = sprintf(
1761
+ _n(
1762
+ "%d item was skipped because it can't be moved to the Trash. You need to delete it manually.",
1763
+ "%d items were skipped because they can't be moved to the Trash. You need to delete them manually.",
1764
+ count($skipped)
1765
+ ),
1766
+ count($skipped)
1767
+ );
1768
+ $message .= '<br><ul>';
1769
+ foreach($skipped as $container){
1770
+ $message .= sprintf(
1771
+ '<li>%s</li>',
1772
+ $container->ui_get_source()
1773
+ );
1774
+ }
1775
+ $message .= '</ul>';
1776
+
1777
+ $messages[] = $message;
1778
  }
1779
 
1780
  if ( count($messages) > 0 ){
1781
+ $message = implode('<p>', $messages);
1782
  } else {
1783
  $message = __("Didn't find anything to delete!", 'broken-link-checker');
1784
  $msg_class = 'error';
1884
  }
1885
 
1886
 
1887
+ /**
1888
+ * Enqueue CSS files for the "Broken Links" page
1889
+ *
1890
+ * @return void
1891
+ */
1892
  function links_page_css(){
1893
+ wp_enqueue_style('blc-links-page', plugin_dir_url($this->loader) . 'css/links-page.css', array(), '0.9.5' );
1894
+ wp_enqueue_style('blc-screen-meta-links', plugin_dir_url($this->loader) . 'css/screen-meta-links.css' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1895
  }
1896
 
1897
+ /**
1898
+ * Generate the HTML for the plugin's Screen Options panel.
1899
+ *
1900
+ * @return string
1901
+ */
1902
+ function screen_options_html(){
1903
+ //Update the links-per-page setting when "Apply" is clicked
1904
+ if ( isset($_POST['per_page']) && is_numeric($_POST['per_page']) ) {
1905
+ check_admin_referer( 'screen-options-nonce', 'screenoptionnonce' );
1906
+ $per_page = intval($_POST['per_page']);
1907
+ if ( ($per_page >= 1) && ($per_page <= 500) ){
1908
+ $this->conf->options['table_links_per_page'] = $per_page;
1909
+ $this->conf->save_options();
1910
+ }
 
1911
  }
1912
 
1913
+ //Let the user show/hide individual table columns
1914
+ $html = '<h5>' . __('Table columns', 'broken-link-checker') . '</h5>';
 
 
 
 
 
 
 
 
 
 
 
1915
 
1916
+ include dirname($this->loader) . '/includes/admin/table-printer.php';
1917
+ $table = new blcTablePrinter($this);
1918
+ $available_columns = $table->get_layout_columns($this->conf->options['table_layout']);
 
 
 
 
 
 
 
 
 
 
1919
 
1920
+ $html .= '<div id="blc-column-selector" class="metabox-prefs">';
1921
+
1922
+ foreach( $available_columns as $column_id => $data ){
1923
+ $html .= sprintf(
1924
+ '<label><input type="checkbox" name="visible_columns[%s]"%s>%s</label>',
1925
+ esc_attr($column_id),
1926
+ in_array($column_id, $this->conf->options['table_visible_columns']) ? ' checked="checked"' : '',
1927
+ $data['heading']
 
 
 
 
1928
  );
1929
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1930
 
1931
+ $html .= '</div>';
1932
+
1933
+ $html .= '<h5>' . __('Show on screen') . '</h5>';
1934
+ $html .= '<div class="screen-options">';
1935
+ $html .= sprintf(
1936
+ '<input type="text" name="per_page" maxlength="3" value="%d" class="screen-per-page" id="blc_links_per_page" />
1937
+ <label for="blc_links_per_page">%s</label>
1938
+ <input type="button" class="button" value="%s" id="blc-per-page-apply-button" /><br />',
1939
+ $this->conf->options['table_links_per_page'],
1940
+ __('links', 'broken-link-checker'),
1941
+ __('Apply')
1942
+ );
1943
+ $html .= '</div>';
1944
 
1945
+ $html .= '<h5>' . __('Misc', 'broken-link-checker') . '</h5>';
1946
+ $html .= '<div class="screen-options">';
1947
+ /*
1948
+ Display a checkbox in "Screen Options" that lets the user highlight links that
1949
+ have been broken for at least X days.
1950
+ */
1951
+ $html .= sprintf(
1952
+ '<label><input type="checkbox" id="highlight_permanent_failures" name="highlight_permanent_failures"%s> ',
1953
+ $this->conf->options['highlight_permanent_failures'] ? ' checked="checked"' : ''
1954
+ );
1955
+ $input_box = sprintf(
1956
+ '</label><input type="text" name="failure_duration_threshold" id="failure_duration_threshold" value="%d" size="2"><label for="highlight_permanent_failures">',
1957
+ $this->conf->options['failure_duration_threshold']
1958
+ );
1959
+ $html .= sprintf(
1960
+ __('Highlight links broken for at least %s days', 'broken-link-checker'),
1961
+ $input_box
1962
  );
1963
+ $html .= '</label>';
1964
 
1965
+ //Display a checkbox for turning colourful link status messages on/off
1966
+ $html .= sprintf(
1967
+ '<br/><label><input type="checkbox" id="table_color_code_status" name="table_color_code_status"%s> %s</label>',
1968
+ $this->conf->options['table_color_code_status'] ? ' checked="checked"' : '',
1969
+ __('Color-code status codes', 'broken-link-checker')
1970
+ );
1971
+
1972
+ $html .= '</div>';
1973
+
1974
+ return $html;
1975
+ }
1976
+
1977
+ /**
1978
+ * AJAX callback for saving the "Screen Options" panel settings
1979
+ *
1980
+ * @param array $form
1981
+ * @return void
1982
+ */
1983
+ function ajax_save_screen_options($form){
1984
+ if ( !current_user_can('edit_others_posts') ){
1985
+ die( json_encode( array(
1986
+ 'error' => __("You're not allowed to do that!", 'broken-link-checker')
1987
+ )));
1988
+ }
1989
+
1990
+ $this->conf->options['highlight_permanent_failures'] = !empty($form['highlight_permanent_failures']);
1991
+ $this->conf->options['table_color_code_status'] = !empty($form['table_color_code_status']);
1992
+
1993
+ $failure_duration_threshold = intval($form['failure_duration_threshold']);
1994
+ if ( $failure_duration_threshold >=1 ){
1995
+ $this->conf->options['failure_duration_threshold'] = $failure_duration_threshold;
1996
+ }
1997
+
1998
+ if ( isset($form['visible_columns']) && is_array($form['visible_columns']) ){
1999
+ $this->conf->options['table_visible_columns'] = array_keys($form['visible_columns']);
2000
  }
2001
 
2002
+ $this->conf->save_options();
2003
+ die('1');
2004
  }
2005
 
2006
  function start_timer(){
2060
  //This reduces resource usage and may solve the mysterious slowdowns certain users have
2061
  //encountered when activating the plugin.
2062
  //(Disable when debugging or you won't get the FirePHP output)
2063
+ if ( !defined('BLC_DEBUG') || !constant('BLC_DEBUG')){
2064
  @ob_end_clean(); //Discard the existing buffer, if any
2065
  header("Connection: close");
2066
  ob_start();
2071
  flush(); // Unless both are called !
2072
  }
2073
 
2074
+ //Load modules for this context
2075
+ $moduleManager = & blcModuleManager::getInstance();
2076
+ $moduleManager->load_modules('work');
2077
+
2078
+
2079
  /*****************************************
2080
  Parse posts and bookmarks
2081
  ******************************************/
2082
 
2083
+ $orphans_possible = false;
2084
+ $still_need_resynch = $this->conf->options['need_resynch'];
2085
+
2086
  if ( $still_need_resynch ) {
2087
 
2088
  //FB::log("Looking for containers that need parsing...");
2089
 
2090
+ while( $containers = blcContainerHelper::get_unsynched_containers(50) ){
2091
  //FB::log($containers, 'Found containers');
2092
 
2093
  foreach($containers as $container){
2228
 
2229
  //Only check links that have at least one valid instance (i.e. an instance exists and
2230
  //it corresponds to one of the currently loaded container/parser types).
2231
+ $manager = & blcModuleManager::getInstance();
2232
+ $loaded_containers = $manager->get_escaped_ids('container');
2233
+ $loaded_parsers = $manager->get_escaped_ids('parser');
 
 
 
 
 
 
2234
 
2235
  //Note : This is a slow query, but AFAIK there is no way to speed it up.
2236
  //I could put an index on last_check_attempt, but that value is almost
2387
  function ajax_current_load(){
2388
  $load = $this->get_server_load();
2389
  if ( empty($load) ){
2390
+ die( _x('Unknown', 'current load', 'broken-link-checker') );
2391
  }
2392
 
2393
  $one_minute = reset($load);
2608
 
2609
  if ( !$link->is_new ){
2610
  //FB::info($link, 'Link loaded');
2611
+ if ( !class_exists('blcTablePrinter') ){
2612
+ require dirname($this->loader) . '/includes/admin/table-printer.php';
2613
+ }
2614
+ blcTablePrinter::details_row_contents($link);
2615
  die();
2616
  } else {
2617
  printf( __('Failed to load link details (%s)', 'broken-link-checker'), $wpdb->last_error );
2619
  }
2620
  }
2621
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2622
  /**
2623
  * Create and lock a temporary file.
2624
  *
2694
  }
2695
 
2696
  //Try the plugin's own directory.
2697
+ if ( @is_writable( dirname( blc_get_plugin_file() ) ) ){
2698
+ return dirname( blc_get_plugin_file() ) . '/wp_blc_lock';
2699
  } else {
2700
 
2701
  //Try the system-wide temp directory
2784
  }
2785
 
2786
  function lockfile_warning(){
2787
+ $my_dir = '/plugins/' . basename(dirname(blc_get_plugin_file())) . '/';
2788
  $settings_page = admin_url( 'options-general.php?page=link-checker-settings#lockfile_directory' );
2789
 
2790
  //Make the notice customized to the current settings
3120
  if ( !wp_next_scheduled('blc_cron_database_maintenance') ){
3121
  wp_schedule_event(time(), 'bimonthly', 'blc_cron_database_maintenance');
3122
  }
3123
+
3124
+ //Check for news notices related to this plugin
3125
+ if ( !wp_next_scheduled('blc_cron_check_news') ){
3126
+ wp_schedule_event(time(), 'daily', 'blc_cron_check_news');
3127
+ }
3128
  }
3129
 
3130
  /**
3135
  function load_language(){
3136
  load_plugin_textdomain( 'broken-link-checker', false, basename(dirname($this->loader)) . '/languages' );
3137
  }
3138
+
3139
+ /**
3140
+ * Check if there's a "news" link to display on the plugin's pages.
3141
+ *
3142
+ * @return void
3143
+ */
3144
+ function check_news(){
3145
+ $url = 'http://w-shadow.com/plugin-news/';
3146
+ if ( defined('BLC_PRO_VERSION') && BLC_PRO_VERSION ){
3147
+ $url .= 'broken-link-checker-pro-news.txt';
3148
+ } else {
3149
+ $url .= 'broken-link-checker-news.txt';
3150
+ }
3151
+
3152
+ //Retrieve the appropriate "news" file
3153
+ $res = wp_remote_get($url);
3154
+ if ( is_wp_error($res) ){
3155
+ return;
3156
+ }
3157
+
3158
+ //Anything there?
3159
+ if ( isset($res['response']['code']) && ($res['response']['code'] == 200) && isset($res['body']) ) {
3160
+ //The file should contain two lines - a title and an URL
3161
+ $news = explode("\n", trim($res['body']));
3162
+ if ( count($news) == 2 ){
3163
+ //Save for later.
3164
+ $this->conf->options['plugin_news'] = $news;
3165
+ } else {
3166
+ $this->conf->options['plugin_news'] = null;
3167
+ }
3168
+ $this->conf->save_options();
3169
+ }
3170
+ }
3171
+
3172
+ /**
3173
+ * Display a link to the latest blog post/whatever about this plugin, if any.
3174
+ *
3175
+ * @return void
3176
+ */
3177
+ function display_plugin_news_link(){
3178
+ if ( !isset($this->conf->options['plugin_news']) || empty($this->conf->options['plugin_news']) ){
3179
+ return;
3180
+ }
3181
+ $news = $this->conf->options['plugin_news'];
3182
+ ?>
3183
+ <script type="text/javascript">
3184
+ (function($){
3185
+ var wrapper = $('<div id="blc-news-link-wrap" class="hide-if-no-js screen-meta-toggle"></div>').appendTo('#screen-meta-links');
3186
+ $('<a id="blc-plugin-news-link" class="show-settings"></a>')
3187
+ .attr('href', '<?php echo esc_js($news[1]); ?>')
3188
+ .html('<?php echo esc_js($news[0]) ?>')
3189
+ .appendTo(wrapper);
3190
+ })(jQuery);
3191
+ </script>
3192
+ <?php
3193
+ }
3194
 
3195
  }//class ends here
3196
 
core/init.php ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //To prevent conflicts, only one version of the plugin can be activated at any given time.
3
+ if ( defined('BLC_ACTIVE') ){
4
+ trigger_error(
5
+ 'Another version of Broken Link Checker is already active. Please deactivate it before activating this one.',
6
+ E_USER_ERROR
7
+ );
8
+ } else {
9
+
10
+ define('BLC_ACTIVE', true);
11
+
12
+ /***********************************************
13
+ Debugging stuff
14
+ ************************************************/
15
+
16
+ //define('BLC_DEBUG', true);
17
+
18
+
19
+
20
+ /***********************************************
21
+ Constants
22
+ ************************************************/
23
+
24
+ /*
25
+ For performance, some internal APIs used for retrieving multiple links, instances or containers
26
+ can take an optional "$purpose" argument. Those APIs will try to use this argument to pre-load
27
+ any DB data required for the specified purpose ahead of time.
28
+
29
+ For example, if you're loading a bunch of link containers for the purposes of parsing them and
30
+ thus set $purpose to BLC_FOR_PARSING, the relevant container managers will (if applicable) precache
31
+ the parse-able fields in each returned container object. Still, setting $purpose to any particular
32
+ value does not *guarantee* any data will be preloaded - it's only a suggestion that it should.
33
+
34
+ The currently supported values for the $purpose argument are :
35
+ */
36
+ define('BLC_FOR_EDITING', 'edit');
37
+ define('BLC_FOR_PARSING', 'parse');
38
+ define('BLC_FOR_DISPLAY', 'display');
39
+
40
+ /***********************************************
41
+ Configuration
42
+ ************************************************/
43
+
44
+ //Load and initialize the plugin's configuration
45
+ global $blc_directory;
46
+ $blc_directory = dirname( blc_get_plugin_file() );
47
+ require $blc_directory . '/includes/config-manager.php';
48
+
49
+ global $blc_config_manager;
50
+ $blc_config_manager = new blcConfigurationManager(
51
+ //Save the plugin's configuration into this DB option
52
+ 'wsblc_options',
53
+ //Initialize default settings
54
+ array(
55
+ 'max_execution_time' => 5*60, //(in seconds) How long the worker instance may run, at most.
56
+ 'check_threshold' => 72, //(in hours) Check each link every 72 hours.
57
+
58
+ 'recheck_count' => 3, //How many times a broken link should be re-checked.
59
+ 'recheck_threshold' => 30*60, //(in seconds) Re-check broken links after 30 minutes.
60
+
61
+ 'run_in_dashboard' => true, //Run the link checker algo. continuously while the Dashboard is open.
62
+ 'run_via_cron' => true, //Run it hourly via WordPress pseudo-cron.
63
+
64
+ 'mark_broken_links' => true, //Whether to add the broken_link class to broken links in posts.
65
+ 'broken_link_css' => ".broken_link, a.broken_link {\n\ttext-decoration: line-through;\n}",
66
+ 'nofollow_broken_links' => false, //Whether to add rel="nofollow" to broken links in posts.
67
+
68
+ 'mark_removed_links' => false, //Whether to add the removed_link class when un-linking a link.
69
+ 'removed_link_css' => ".removed_link, a.removed_link {\n\ttext-decoration: line-through;\n}",
70
+
71
+ 'exclusion_list' => array(), //Links that contain a substring listed in this array won't be checked.
72
+
73
+ 'send_email_notifications' => false,//Whether to send email notifications about broken links
74
+ 'notification_schedule' => 'daily', //How often (at most) notifications will be sent. Possible values : 'daily', 'weekly'
75
+ 'last_notification_sent' => 0, //When the last email notification was send (Unix timestamp)
76
+
77
+ 'server_load_limit' => 4, //Stop parsing stuff & checking links if the 1-minute load average
78
+ //goes over this value. Only works on Linux servers. 0 = no limit.
79
+ 'enable_load_limit' => true, //Enable/disable load monitoring.
80
+
81
+ 'custom_fields' => array(), //List of custom fields that can contain URLs and should be checked.
82
+ 'enabled_post_statuses' => array('publish'), //Only check posts that match one of these statuses
83
+
84
+ 'autoexpand_widget' => true, //Autoexpand the Dashboard widget if broken links are detected
85
+ 'show_link_count_bubble' => true, //Display a notification bubble in the menu when broken links are found
86
+
87
+ 'table_layout' => 'flexible', //The layout of the link table. Possible values : 'classic', 'flexible'
88
+ 'table_compact' => true, //Compact table mode on/off
89
+ 'table_visible_columns' => array('new-url', 'status', 'used-in', 'new-link-text',),
90
+ 'table_links_per_page' => 30,
91
+ 'table_color_code_status' => true, //Color-code link status text
92
+
93
+ 'need_resynch' => false, //[Internal flag] True if there are unparsed items.
94
+ 'current_db_version' => 0, //The currently set-up version of the plugin's tables
95
+
96
+ 'custom_tmp_dir' => '', //The lockfile will be stored in this directory.
97
+ //If this option is not set, the plugin's own directory or the
98
+ //system-wide /tmp directory will be used instead.
99
+
100
+ 'timeout' => 30, //(in seconds) Links that take longer than this to respond will be treated as broken.
101
+
102
+ 'highlight_permanent_failures' => false,//Highlight links that have appear to be permanently broken (in Tools -> Broken Links).
103
+ 'failure_duration_threshold' => 3, //(days) Assume a link is permanently broken if it still hasn't
104
+ //recovered after this many days.
105
+
106
+ 'highlight_feedback_widget' => true, //Highlight the "Feedback" button in vivid orange
107
+
108
+ 'installation_complete' => false,
109
+ 'installation_failed' => false,
110
+ )
111
+ );
112
+
113
+ /***********************************************
114
+ Logging
115
+ ************************************************/
116
+
117
+ include $blc_directory . '/includes/logger.php';
118
+
119
+ global $blclog;
120
+ $blclog = new blcDummyLogger;
121
+
122
+ //*
123
+ if ( defined('BLC_DEBUG') && constant('BLC_DEBUG') ){
124
+ //Load FirePHP for debug logging
125
+ if ( !class_exists('FB') && file_exists($blc_directory . '/FirePHPCore/fb.php4') ) {
126
+ require_once $blc_directory . '/FirePHPCore/fb.php4';
127
+ }
128
+ //FB::setEnabled(false);
129
+ }
130
+ //to comment out all calls : (^[^\/]*)(FB::) -> $1\/\/$2
131
+ //to uncomment : \/\/(\s*FB::) -> $1
132
+ //*/
133
+
134
+ /***********************************************
135
+ Global functions
136
+ ************************************************/
137
+
138
+ /**
139
+ * Get the configuration object used by Broken Link Checker.
140
+ *
141
+ * @return blcConfigurationManager
142
+ */
143
+ function &blc_get_configuration(){
144
+ return $GLOBALS['blc_config_manager'];
145
+ }
146
+
147
+ /**
148
+ * Notify the link checker that there are unsynched items
149
+ * that might contain links (e.g. a new or edited post).
150
+ *
151
+ * @return void
152
+ */
153
+ function blc_got_unsynched_items(){
154
+ $conf = & blc_get_configuration();
155
+
156
+ if ( !$conf->options['need_resynch'] ){
157
+ $conf->options['need_resynch'] = true;
158
+ $conf->save_options();
159
+ }
160
+ }
161
+
162
+ /**
163
+ * (Re)create synchronization records for all containers and mark them all as unparsed.
164
+ *
165
+ * @param bool $forced If true, the plugin will recreate all synch. records from scratch.
166
+ * @return void
167
+ */
168
+ function blc_resynch( $forced = false ){
169
+ global $wpdb, $blclog;
170
+
171
+ if ( $forced ){
172
+ $blclog->info('... Forced resynchronization initiated');
173
+
174
+ //Drop all synchronization records
175
+ $wpdb->query("TRUNCATE {$wpdb->prefix}blc_synch");
176
+ } else {
177
+ $blclog->info('... Resynchronization initiated');
178
+ }
179
+
180
+ //Remove invalid DB entries
181
+ blc_cleanup_database();
182
+
183
+ //(Re)create and update synch. records for all container types.
184
+ $blclog->info('... (Re)creating container records');
185
+ blcContainerHelper::resynch($forced);
186
+
187
+ $blclog->info('... Setting resync. flags');
188
+ blc_got_unsynched_items();
189
+
190
+ //All done.
191
+ $blclog->info('Database resynchronization complete.');
192
+ }
193
+
194
+ /**
195
+ * Delete synch. records, instances and links that refer to missing or invalid items.
196
+ *
197
+ * @return void
198
+ */
199
+ function blc_cleanup_database(){
200
+ global $blclog;
201
+
202
+ //Delete synch. records for container types that don't exist
203
+ $blclog->info('... Deleting invalid container records');
204
+ blcContainerHelper::cleanup_containers();
205
+
206
+ //Delete invalid instances
207
+ $blclog->info('... Deleting invalid link instances');
208
+ blc_cleanup_instances();
209
+
210
+ //Delete orphaned links
211
+ $blclog->info('... Deleting orphaned links');
212
+ blc_cleanup_links();
213
+ }
214
+
215
+ /***********************************************
216
+ Utility hooks
217
+ ************************************************/
218
+
219
+ /**
220
+ * Add a weekly Cron schedule for email notifications
221
+ * and a bimonthly schedule for database maintenance.
222
+ *
223
+ * @param array $schedules Existing Cron schedules.
224
+ * @return array
225
+ */
226
+ function blc_cron_schedules($schedules){
227
+ if ( !isset($schedules['weekly']) ){
228
+ $schedules['weekly'] = array(
229
+ 'interval' => 604800, //7 days
230
+ 'display' => __('Once Weekly')
231
+ );
232
+ }
233
+ if ( !isset($schedules['bimonthly']) ){
234
+ $schedules['bimonthly'] = array(
235
+ 'interval' => 15*24*2600, //15 days
236
+ 'display' => __('Twice a Month')
237
+ );
238
+ }
239
+
240
+ return $schedules;
241
+ }
242
+ add_filter('cron_schedules', 'blc_cron_schedules');
243
+
244
+ /**
245
+ * Display installation errors (if any) on the Dashboard.
246
+ *
247
+ * @return void
248
+ */
249
+ function blc_print_installation_errors(){
250
+ $conf = & blc_get_configuration();
251
+ if ( !$conf->options['installation_failed'] ){
252
+ return;
253
+ }
254
+
255
+ $logger = new blcOptionLogger('blc_installation_log');
256
+ $log = $logger->get_messages();
257
+
258
+ $message = array(
259
+ '<strong>' . __('Broken Link Checker installation failed', 'broken-link-checker') . '</strong>',
260
+ '',
261
+ '<em>Installation log follows :</em>',
262
+ );
263
+ foreach($log as $entry){
264
+ array_push($message, $entry);
265
+ }
266
+ $message = implode("<br>\n", $message);
267
+
268
+ echo "<div class='error'><p>$message</p></div>";
269
+ }
270
+ add_action('admin_notices', 'blc_print_installation_errors');
271
+
272
+ /**
273
+ * A stub function that calls the real activation hook.
274
+ *
275
+ * @return void
276
+ */
277
+ function blc_activation_hook(){
278
+ global $ws_link_checker;
279
+ blc_init();
280
+ $ws_link_checker->activation();
281
+ }
282
+
283
+ //Since the main plugin files load during the 'init' action, any activation hooks
284
+ //set therein would never be executed ('init' runs before activation happens). Instead,
285
+ //we must register the hook(s) immediately after our main plugin file is loaded.
286
+ register_activation_hook(plugin_basename(blc_get_plugin_file()), 'blc_activation_hook');
287
+
288
+
289
+ /***********************************************
290
+ Main functionality
291
+ ************************************************/
292
+
293
+ function blc_init(){
294
+ global $blc_directory, $blc_module_manager, $blc_config_manager, $ws_link_checker;
295
+
296
+ static $init_done = false;
297
+ if ( $init_done ){
298
+ return;
299
+ }
300
+ $init_done = true;
301
+
302
+ //Load the base classes and utilities
303
+ require $blc_directory . '/includes/links.php';
304
+ require $blc_directory . '/includes/link-query.php';
305
+ require $blc_directory . '/includes/instances.php';
306
+ require $blc_directory . '/includes/utility-class.php';
307
+
308
+ //Load the module subsystem
309
+ require $blc_directory . '/includes/modules.php';
310
+
311
+ //Load the modules that want to be executed in all contexts
312
+ $blc_module_manager->load_modules();
313
+
314
+ if ( is_admin() || defined('DOING_CRON') ){
315
+
316
+ //It's an admin-side or Cron request. Load the core.
317
+ require $blc_directory . '/core/core.php';
318
+ $ws_link_checker = new wsBrokenLinkChecker( blc_get_plugin_file() , $blc_config_manager );
319
+
320
+ } else {
321
+
322
+ //This is user-side request, so we don't need to load the core.
323
+ //We might need to inject the CSS for removed links, though.
324
+ if ( $blc_config_manager->options['mark_removed_links'] && !empty($blc_config_manager->options['removed_link_css']) ){
325
+ function blc_print_removed_link_css(){
326
+ global $blc_config_manager;
327
+ echo '<style type="text/css">',$blc_config_manager->options['removed_link_css'],'</style>';
328
+ }
329
+ add_action('wp_head', 'blc_print_removed_link_css');
330
+ }
331
+ }
332
+ }
333
+
334
+ add_action('init', 'blc_init', 2000);
335
+
336
+ }
337
+ ?>
css/links-page.css CHANGED
@@ -5,8 +5,8 @@ table#blc-links {
5
  table-layout: fixed;
6
  }
7
 
8
- td.blc-link-details {
9
- width: 100%;
10
  }
11
 
12
  .blc-detail-container {
@@ -18,34 +18,84 @@ td.blc-link-details {
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 other link states or types */
 
 
 
 
 
 
 
 
 
 
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 {
@@ -61,26 +111,135 @@ td.blc-link-details {
61
  }
62
 
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  /* Misc table styles */
65
 
66
  .blc-link-url {
67
  padding-left: 16px;
 
 
 
 
 
 
 
 
 
 
 
 
68
  }
69
 
70
  .blc-link-editor {
71
  font-size: 1em;
72
  width: 95%;
73
  margin-left: 12px;
 
74
  }
75
 
76
- .column-url .row-actions {
77
- margin-left: 16px;
 
 
 
78
  }
79
 
80
- .blc-link-text {
81
- cursor: pointer;
 
 
82
  }
83
 
 
 
 
84
 
85
  .blc-small-image {
86
  vertical-align: middle;
@@ -92,6 +251,10 @@ td.blc-link-details {
92
  background : white !important;
93
  border: 3px solid #EEEEEE;
94
  padding: 12px;
 
 
 
 
95
  }
96
 
97
  .blc-search-container .ui-dialog-titlebar {
@@ -131,8 +294,11 @@ div.search-box{
131
  margin-left: 0pt;
132
  }
133
 
134
- /* Misc link page styles */
 
 
 
135
 
136
- .tools_page_view-broken-links #screen-options-wrap h5 {
137
- display: none;
138
- }
5
  table-layout: fixed;
6
  }
7
 
8
+ tr.blc-link-details {
9
+ display: none;
10
  }
11
 
12
  .blc-detail-container {
18
  width: 50%;
19
  }
20
 
21
+ /* Column headers */
22
+
23
+ th.column-new-url {
24
+ width: 33%;
25
+ }
26
+
27
+ th.column-status {
28
+ width: 16em;
29
+ }
30
+
31
+ th.column-new-link-text {
32
+
33
+ }
34
+
35
+ th.column-used-in {
36
+
37
+ }
38
+
39
+ th.column-source {
40
  width: 33%;
41
  }
42
 
43
+ th.column-link-text {
44
  width: 24%;
45
  }
46
 
47
+ th.column-url {
48
+ width: 35%;
49
  }
50
 
51
+ th.column-last-checked {
52
+ width: 10em;
53
+ }
54
+
55
+ th.column-broken-for {
56
+ width: 10em;
57
+ }
58
+
59
+ th.column-instance-count {
60
+ width: 10em;
61
+ }
62
 
63
+ /* Cells */
64
+
65
+ td.column-new-url,
66
+ td.column-used-in
67
+ {
68
+ /*
69
+ overflow: hidden;
70
+ white-space: nowrap;
71
+ text-overflow: ellipsis;
72
+ -o-text-overflow: ellipsis;
73
+ */
74
+ }
75
+
76
+ td.column-new-url .row-actions,
77
+ td.column-url .row-actions
78
+ {
79
+ margin-left: 16px;
80
+ }
81
+
82
+ td.column-new-url .mini-status {
83
+ margin-left: 16px;
84
+ color: black;
85
+ }
86
+
87
+ /* Styles for broken links, redirects and other link states or types */
88
 
89
  .blc-redirect .blc-link-url {
90
  background-image: url("../images/bullet_blue.png");
 
 
91
  }
92
 
93
+ .link-status-error .blc-link-url {
 
 
94
  background-image: url("../images/bullet_error.png");
95
+ }
96
+
97
+ .link-status-warning .blc-link-url {
98
+ background-image: url("../images/bullet_warning.png");
99
  }
100
 
101
  .blc-excluded-link {
111
  }
112
 
113
 
114
+ /* The "Status" column */
115
+ td.column-status {
116
+ cursor: pointer;
117
+ }
118
+
119
+ .mini-status, .mini-status th, .mini-status td {
120
+ border: 0;
121
+ font-size: 1em;
122
+ padding: 0;
123
+ color: gray;
124
+ }
125
+
126
+ .mini-status div {
127
+ display: inline-block;
128
+ }
129
+
130
+ .mini-status .status-text {
131
+ color: black;
132
+ }
133
+
134
+ .link-status-unknown td.column-status .http-code {
135
+ display: none;
136
+ }
137
+
138
+
139
+ /* Status colors */
140
+ .color-code-link-status .mini-status .http-code,
141
+ .color-code-link-status .mini-status .status-text
142
+ {
143
+ font-weight: bold;
144
+ }
145
+
146
+ .color-code-link-status .link-status-unknown td.column-status .status-text,
147
+ .color-code-link-status .link-status-unknown td.column-status .http-code
148
+ {
149
+ color: gray;
150
+ font-weight: normal;
151
+ }
152
+
153
+ .color-code-link-status .link-status-ok td.column-status .status-text,
154
+ .color-code-link-status .link-status-ok td.column-status .http-code
155
+ {
156
+ color: green;
157
+ }
158
+
159
+ .color-code-link-status .link-status-info td.column-status .status-text,
160
+ .color-code-link-status .link-status-info td.column-status .http-code
161
+ {
162
+ color: blue;
163
+ }
164
+
165
+ .color-code-link-status .link-status-warning td.column-status .status-text,
166
+ .color-code-link-status .link-status-warning td.column-status .http-code
167
+ {
168
+ color: #FF8C00; /*#FFA500*/
169
+ }
170
+
171
+ .color-code-link-status .link-status-error td.column-status .status-text,
172
+ .color-code-link-status .link-status-error td.column-status .http-code
173
+ {
174
+ color: red;
175
+ }
176
+
177
+
178
+ /* "Compact" view */
179
+
180
+ .compact td.column-url,
181
+ .compact td.column-status,
182
+ .compact td.column-link-text,
183
+ .compact td.column-used-in,
184
+ .compact td.column-new-url,
185
+ .compact td.column-source,
186
+ .compact td.column-new-link-text
187
+ {
188
+ overflow: hidden;
189
+ text-overflow: ellipsis;
190
+ -o-text-overflow: ellipsis;
191
+ white-space: nowrap;
192
+ word-wrap: normal;
193
+ }
194
+
195
+ .compact .link-last-checked,
196
+ .compact .link-broken-for,
197
+ .compact .link-text
198
+ {
199
+ display: none;
200
+ }
201
+
202
  /* Misc table styles */
203
 
204
  .blc-link-url {
205
  padding-left: 16px;
206
+ overflow: hidden;
207
+
208
+ background-image: none;
209
+ background-position: left center;
210
+ background-repeat: no-repeat;
211
+ }
212
+
213
+ td.column-new-url { /* The URL never wraps */
214
+ word-wrap: normal;
215
+ white-space: nowrap;
216
+ text-overflow: ellipsis;
217
+ -o-text-overflow: ellipsis;
218
  }
219
 
220
  .blc-link-editor {
221
  font-size: 1em;
222
  width: 95%;
223
  margin-left: 12px;
224
+ margin-top: -1px;
225
  }
226
 
227
+ .blc-url-editor-buttons {
228
+ margin-left: 12px;
229
+ margin-top: 2px;
230
+ display: none;
231
+ width: 95%;
232
  }
233
 
234
+ img.waiting {
235
+ float:right;
236
+ padding:4px 8px 0;
237
+ vertical-align:top;
238
  }
239
 
240
+ td.column-link-text, td.column-new-link-text {
241
+ cursor: pointer;
242
+ }
243
 
244
  .blc-small-image {
245
  vertical-align: middle;
251
  background : white !important;
252
  border: 3px solid #EEEEEE;
253
  padding: 12px;
254
+
255
+ border-radius: 6px;
256
+ -moz-border-radius: 6px;
257
+ -webkit-border-radius: 6px;
258
  }
259
 
260
  .blc-search-container .ui-dialog-titlebar {
294
  margin-left: 0pt;
295
  }
296
 
297
+ #s_link_type optgroup {
298
+ font-style: normal;
299
+ font-size: 13px;
300
+ }
301
 
302
+ #s_link_type optgroup option {
303
+ margin-left: 1em;
304
+ }
css/options-page.css CHANGED
@@ -35,4 +35,111 @@
35
  border-style: solid;
36
 
37
  border-collapse: collapse;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
35
  border-style: solid;
36
 
37
  border-collapse: collapse;
38
+ }
39
+
40
+ .blc-toggle-link {
41
+ /*padding-left: 20px; */
42
+ }
43
+
44
+ .module-container {
45
+ margin: 1em 0;
46
+ font-size: 12px;
47
+ line-height: 140%;
48
+ }
49
+
50
+ .module-extra-settings {
51
+ margin-top: 0.5em;
52
+ }
53
+
54
+ .form-table td p:first-child, .form-table td .module-container:first-child {
55
+ margin-top: 0.2em;
56
+ }
57
+
58
+ .module-requires-pro {
59
+ color: gray;
60
+ }
61
+
62
+ #blc-tabs {
63
+ margin-top: 0.5em;
64
+ }
65
+
66
+ /* Tab navigation */
67
+ ul.ui-tabs-nav {
68
+ margin-bottom: -1px;
69
+ padding-left: 1.5em;
70
+ }
71
+
72
+ ul.ui-tabs-nav li {
73
+ display: inline-block;
74
+ margin: 0 0.5em 0 0;
75
+
76
+ border: 1px solid #DFDFDF;
77
+
78
+ background: none repeat scroll 0 0 #F4F4F4;
79
+
80
+ border-top-right-radius: 6px;
81
+ border-top-left-radius: 6px;
82
+
83
+ -moz-border-radius-topright: 6px;
84
+ -moz-border-radius-topleft: 6px;
85
+
86
+ -webkit-border-top-right-radius: 6px;
87
+ -webkit-border-top-left-radius: 6px;
88
+
89
+ font-weight: bold;
90
+ text-shadow: 0 1px 0 #FFFFFF;
91
+ }
92
+
93
+ ul.ui-tabs-nav li.ui-tabs-selected {
94
+ background: white;
95
+ color: black;
96
+ border-bottom-color: white;
97
+ }
98
+
99
+ ul.ui-tabs-nav li a {
100
+ display: inline-block;
101
+ padding: 0.5em 1em 0.6em 1em;
102
+ text-decoration: none;
103
+ color: #C1C1C1;
104
+ }
105
+
106
+ ul.ui-tabs-nav li.ui-tabs-selected a {
107
+ color: black;
108
+ }
109
+
110
+ /* Tab panels */
111
+
112
+ .ui-tabs .blc-section {
113
+ border: 1px solid #DFDFDF;
114
+ border-top-width: 1px;
115
+
116
+ padding-bottom: 1em;
117
+
118
+ background: white;
119
+
120
+ border-radius: 6px;
121
+ -moz-border-radius: 6px;
122
+ -webkit-border-radius: 6px;
123
+
124
+ border-top-right-radius: 6px;
125
+ border-bottom-right-radius: 6px;
126
+ border-bottom-left-radius: 6px;
127
+
128
+ -moz-border-radius-topright: 6px;
129
+ -moz-border-radius-bottomright: 6px;
130
+ -moz-border-radius-bottomleft: 6px;
131
+
132
+ -webkit-border-top-right-radius: 6px;
133
+ -webkit-border-bottom-right-radius: 6px;
134
+ -webkit-border-bottom-left-radius: 6px;
135
+ }
136
+
137
+ /* "Upgrade to Pro" stuff */
138
+
139
+ .pro-notice {
140
+
141
+ }
142
+
143
+ .pro-notice a {
144
+ font-style: italic;
145
  }
css/{uservoice.css → screen-meta-links.css} RENAMED
@@ -1,4 +1,6 @@
1
- #blc-feedback-widget-wrap {
 
 
2
  float: right;
3
  height: 22px;
4
  padding: 0;
@@ -18,9 +20,14 @@
18
  -webkit-border-bottom-right-radius: 3px;
19
  }
20
 
21
- #blc-feedback-widget-wrap a.show-settings {
 
 
22
  background-image: none;
23
  padding:0 6px 0 6px;
 
 
 
24
  font-weight: bold;
25
  }
26
 
1
+ #blc-feedback-widget-wrap,
2
+ #blc-news-link-wrap
3
+ {
4
  float: right;
5
  height: 22px;
6
  padding: 0;
20
  -webkit-border-bottom-right-radius: 3px;
21
  }
22
 
23
+ #blc-feedback-widget-wrap a.show-settings,
24
+ #blc-news-link-wrap a.show-settings
25
+ {
26
  background-image: none;
27
  padding:0 6px 0 6px;
28
+ }
29
+
30
+ #blc-feedback-widget-wrap a.show-settings {
31
  font-weight: bold;
32
  }
33
 
images/bullet_cross.png ADDED
Binary file
images/bullet_error.png CHANGED
Binary file
images/bullet_warning.png ADDED
Binary file
images/dailymotion-embed.png ADDED
Binary file
images/vimeo-embed.png ADDED
Binary file
images/youtube-embed.png ADDED
Binary file
JSON.php → includes/JSON.php RENAMED
File without changes
includes/admin/db-schema.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if( !function_exists('blc_get_db_schema') ){
4
+
5
+ function blc_get_db_schema(){
6
+ global $wpdb;
7
+
8
+ //Use the character set and collation that's configured for WP tables
9
+ $charset_collate = '';
10
+ if ( !empty($wpdb->charset) ){
11
+ //Some German installs use "utf-8" (invalid) instead of "utf8" (valid). None of
12
+ //the charset ids supported by MySQL contain dashes, so we can safely strip them.
13
+ //See http://dev.mysql.com/doc/refman/5.0/en/charset-charsets.html
14
+ $charset = str_replace('-', '', $wpdb->charset);
15
+
16
+ $charset_collate = "DEFAULT CHARACTER SET {$charset}";
17
+ }
18
+ if ( !empty($wpdb->collate) ){
19
+ $charset_collate = " COLLATE {$wpdb->collate}";
20
+ }
21
+
22
+ $blc_db_schema = <<<EOM
23
+
24
+ CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}blc_filters` (
25
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
26
+ `name` varchar(100) NOT NULL,
27
+ `params` text NOT NULL,
28
+
29
+ PRIMARY KEY (`id`)
30
+ ) {$charset_collate};
31
+
32
+ CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}blc_instances` (
33
+ `instance_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
34
+ `link_id` int(10) unsigned NOT NULL,
35
+ `container_id` int(10) unsigned NOT NULL,
36
+ `container_type` varchar(40) NOT NULL DEFAULT 'post',
37
+ `link_text` varchar(250) NOT NULL DEFAULT '',
38
+ `parser_type` varchar(40) NOT NULL DEFAULT 'link',
39
+ `container_field` varchar(250) NOT NULL DEFAULT '',
40
+ `link_context` varchar(250) NOT NULL DEFAULT '',
41
+ `raw_url` text NOT NULL,
42
+
43
+ PRIMARY KEY (`instance_id`),
44
+ KEY `link_id` (`link_id`),
45
+ KEY `source_id` (`container_type`, `container_id`),
46
+ KEY `parser_type` (`parser_type`)
47
+ ) {$charset_collate};
48
+
49
+ CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}blc_links` (
50
+ `link_id` int(20) unsigned NOT NULL AUTO_INCREMENT,
51
+ `url` text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
52
+ `first_failure` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
53
+ `last_check` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
54
+ `last_success` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
55
+ `last_check_attempt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
56
+ `check_count` int(4) unsigned NOT NULL DEFAULT '0',
57
+ `final_url` text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
58
+ `redirect_count` smallint(5) unsigned NOT NULL DEFAULT '0',
59
+ `log` text NOT NULL,
60
+ `http_code` smallint(6) NOT NULL DEFAULT '0',
61
+ `status_code` varchar(100) DEFAULT '',
62
+ `status_text` varchar(250) DEFAULT '',
63
+ `request_duration` float NOT NULL DEFAULT '0',
64
+ `timeout` tinyint(1) unsigned NOT NULL DEFAULT '0',
65
+ `broken` tinyint(1) NOT NULL DEFAULT '0',
66
+ `may_recheck` tinyint(1) NOT NULL DEFAULT '1',
67
+ `being_checked` tinyint(1) NOT NULL DEFAULT '0',
68
+ `result_hash` varchar(200) NOT NULL DEFAULT '',
69
+ `false_positive` tinyint(1) NOT NULL DEFAULT '0',
70
+
71
+ PRIMARY KEY (`link_id`),
72
+ KEY `url` (`url`(150)),
73
+ KEY `final_url` (`final_url`(150)),
74
+ KEY `http_code` (`http_code`),
75
+ KEY `broken` (`broken`)
76
+ ) {$charset_collate};
77
+
78
+ CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}blc_synch` (
79
+ `container_id` int(20) unsigned NOT NULL,
80
+ `container_type` varchar(40) NOT NULL,
81
+ `synched` tinyint(3) unsigned NOT NULL,
82
+ `last_synch` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
83
+
84
+ PRIMARY KEY (`container_type`,`container_id`),
85
+ KEY `synched` (`synched`)
86
+ ) {$charset_collate};
87
+
88
+ EOM;
89
+
90
+ return $blc_db_schema;
91
+ }
92
+
93
+ }
94
+
95
+ ?>
includes/admin/db-upgrade.php ADDED
@@ -0,0 +1,577 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class blcDatabaseUpgrader {
4
+
5
+ /**
6
+ * Create and/or upgrade the plugin's database tables.
7
+ *
8
+ * @return bool
9
+ */
10
+ function upgrade_database(){
11
+ global $wpdb, $blclog;
12
+
13
+ $conf = &blc_get_configuration();
14
+ $current = $conf->options['current_db_version'];
15
+
16
+ if ( ($current != 0) && ( $current < 4 ) ){
17
+ //The 4th DB version makes a lot of backwards-incompatible changes to the main
18
+ //BLC tables, so instead of upgrading we just throw them away and recreate.
19
+ if ( !blcDatabaseUpgrader::drop_tables() ){
20
+ return false;
21
+ };
22
+ $current = 0;
23
+ }
24
+
25
+ //Create/update the plugin's tables
26
+ if ( !blcDatabaseUpgrader::make_schema_current() ) {
27
+ return false;
28
+ }
29
+
30
+ if ( $current != 0 ){
31
+
32
+ if ( $current < 5 ){
33
+ blcDatabaseUpgrader::upgrade_095();
34
+ }
35
+
36
+ }
37
+
38
+ $conf->options['current_db_version'] = 5;
39
+ $conf->save_options();
40
+ $blclog->info('Database successfully upgraded.');
41
+
42
+ return true;
43
+ }
44
+
45
+ /**
46
+ * Create or update the plugin's DB tables.
47
+ *
48
+ * @return bool
49
+ */
50
+ function make_schema_current(){
51
+ global $blclog;
52
+
53
+ if ( !function_exists('blc_get_db_schema') ){
54
+ require 'db-schema.php';
55
+ }
56
+ list($dummy, $query_log) = blcTableDelta::delta(blc_get_db_schema());
57
+
58
+ $have_errors = false;
59
+ foreach($query_log as $item){
60
+ if ( $item['success'] ){
61
+ $blclog->info(' [OK] ' . $item['query']);
62
+ } else {
63
+ $blclog->error(' [ ] ' . $item['query']);
64
+ $blclog->error(' Database error : ' . $item['error_message']);
65
+ $have_errors = true;
66
+ }
67
+ }
68
+
69
+ $blclog->info('Database schema updated.');
70
+ return !$have_errors;
71
+ }
72
+
73
+ /**
74
+ * Drop the plugin's tables.
75
+ *
76
+ * @return bool
77
+ */
78
+ function drop_tables(){
79
+ global $wpdb, $blclog;
80
+
81
+ $blclog->info('Deleting the plugin\'s database tables');
82
+ $tables = array(
83
+ $wpdb->prefix . 'blc_linkdata',
84
+ $wpdb->prefix . 'blc_postdata',
85
+ $wpdb->prefix . 'blc_instances',
86
+ $wpdb->prefix . 'blc_synch',
87
+ $wpdb->prefix . 'blc_links',
88
+ );
89
+
90
+ $q = "DROP TABLE IF EXISTS " . implode(', ', $tables);
91
+ $rez = $wpdb->query( $q );
92
+
93
+ if ( $rez === false ){
94
+ $error = sprintf(
95
+ __("Failed to delete old DB tables. Database error : %s", 'broken-link-checker'),
96
+ $wpdb->last_error
97
+ );
98
+
99
+ $blclog->error($error);
100
+ /*
101
+ //FIXME: In very rare cases, DROP TABLE IF EXISTS throws an error when the table(s) don't exist.
102
+ return false;
103
+ //*/
104
+ }
105
+ $blclog->info('Done.');
106
+
107
+ return true;
108
+ }
109
+
110
+ function upgrade_095($trigger_errors = false){
111
+ global $wpdb;
112
+
113
+ //Prior to 0.9.5 all supported post types were internally represented using
114
+ //a common 'post' container type. The current version creates a unique container
115
+ //type to each post type.
116
+
117
+ //Update synch records and instances to reflect this change
118
+ $q = "
119
+ UPDATE
120
+ {$wpdb->prefix}blc_synch AS synch
121
+ LEFT JOIN {$wpdb->posts} AS posts ON (posts.ID = synch.container_id)
122
+ SET
123
+ synch.container_type = posts.post_type
124
+ WHERE
125
+ synch.container_type == 'post' AND posts.post_type IS NOT NULL";
126
+ $wpdb->query($q);
127
+
128
+ $q = "
129
+ UPDATE
130
+ {$wpdb->prefix}blc_instances AS instances
131
+ LEFT JOIN {$wpdb->posts} AS posts ON (posts.ID = instances.container_id)
132
+ SET
133
+ instances.container_type = posts.post_type
134
+ WHERE
135
+ instances.container_type == 'post' AND posts.post_type IS NOT NULL";
136
+ $wpdb->query($q);
137
+ }
138
+
139
+ }
140
+
141
+ class blcTableDelta {
142
+
143
+ /**
144
+ * Parse one or more CREATE TABLE queries and generate a list of SQL queries that need
145
+ * to be executed to make the current database schema match those queries. Will also
146
+ * execute those queries by default.
147
+ *
148
+ * This function returns an array with two items. The first is a list of human-readable
149
+ * messages explaining what database changes were/would be made. The second array item
150
+ * is an array of the generated SQL queries and (if $execute was True) their results.
151
+ *
152
+ * Each item of this second array is itself an associative array with these keys :
153
+ * 'query' - the generated query.
154
+ * 'success' - True if the query was executed successfully, False if it caused an error.
155
+ * 'error_message' - the MySQL error message (only meaningful when 'success' = false).
156
+ *
157
+ * The 'success' and 'error_message' keys will only be present if $execute was set to True.
158
+ *
159
+ * @param string $queries One or more CREATE TABLE queries separated by a semicolon.
160
+ * @param bool $execute Whether to apply the schema changes. Defaults to true.
161
+ * @param bool $drop_columns Whether to drop columns not present in the input. Defaults to true.
162
+ * @param bool $drop_indexes Whether to drop indexes not present in the input. Defaults to true.
163
+ * @return array
164
+ */
165
+ function delta($queries, $execute = true, $drop_columns = true, $drop_indexes = true){
166
+ global $wpdb;
167
+
168
+ // Separate individual queries into an array
169
+ if ( !is_array($queries) ) {
170
+ $queries = explode( ';', $queries );
171
+ if ('' == $queries[count($queries) - 1]) array_pop($queries);
172
+ }
173
+
174
+ $cqueries = array(); // Creation Queries
175
+ $for_update = array();
176
+
177
+ // Create a tablename index for an array ($cqueries) of queries
178
+ foreach($queries as $qry) {
179
+ if (preg_match("|CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?([^\s(]+)|i", $qry, $matches)) {
180
+ $table = trim( strtolower($matches[1]), '`' );
181
+ $cqueries[$table] = $qry;
182
+ $for_update[$table] = 'Create table `'.$table.'`';
183
+ }
184
+ }
185
+
186
+ // Check to see which tables and fields exist
187
+ if ($tables = $wpdb->get_col('SHOW TABLES;')) {
188
+ // For every table in the database
189
+ foreach ($tables as $table) {
190
+ $table = strtolower($table);
191
+
192
+ // If a table query exists for the database table...
193
+ if ( array_key_exists($table, $cqueries) ) {
194
+
195
+ // Clear the field and index arrays
196
+ $cfields = $indices = array();
197
+
198
+ // Get all of the field names in the query from between the parens
199
+ preg_match("|\((.*)\)|ms", $cqueries[$table], $match2);
200
+ $qryline = trim($match2[1]);
201
+
202
+ // Separate field lines into an array
203
+ $flds = preg_split('@[\r\n]+@', $qryline);
204
+
205
+ //echo "<hr/><pre>\n".print_r(strtolower($table), true).":\n".print_r($flds, true)."</pre><hr/>";
206
+
207
+ // For every field line specified in the query
208
+ foreach ($flds as $fld) {
209
+ $definition = blcTableDelta::parse_create_definition($fld);
210
+
211
+ if ( $definition ){
212
+ if ( $definition['index'] ){
213
+ $indices[ $definition['index_definition'] ] = $definition; //Index
214
+ } else {
215
+ $cfields[ $definition['name'] ] = $definition; //Column
216
+ }
217
+ }
218
+ }
219
+
220
+ //echo "Detected fields : <br>"; print_r($cfields);
221
+
222
+ // Fetch the table column structure from the database
223
+ $tablefields = $wpdb->get_results("SHOW FULL COLUMNS FROM {$table};");
224
+
225
+ // For every field in the table
226
+ foreach ($tablefields as $tablefield) {
227
+ $field_name = strtolower($tablefield->Field); //Field names are case-insensitive in MySQL
228
+
229
+ // If the table field exists in the field array...
230
+ if (array_key_exists($field_name, $cfields)) {
231
+ $definition = $cfields[$field_name];
232
+
233
+ // Is actual field definition different from that in the query?
234
+ $different =
235
+ ( $tablefield->Type != $definition['data_type'] ) ||
236
+ ( $definition['collation'] && ($tablefield->Collation != $definition['collation']) ) ||
237
+ ( $definition['null_allowed'] && ($tablefield->Null == 'NO') ) ||
238
+ ( !$definition['null_allowed'] && ($tablefield->Null == 'YES') ) ||
239
+ ( $tablefield->Default !== $definition['default'] );
240
+
241
+ // Add a query to change the column type
242
+ if ( $different ) {
243
+ $cqueries[] = "ALTER TABLE `{$table}` MODIFY COLUMN `{$field_name}` {$definition['column_definition']}";
244
+ $for_update[$table.'.'.$field_name] = "Changed type of {$table}.{$field_name} from {$tablefield->Type} to {$definition['column_definition']}";
245
+ }
246
+
247
+ // Remove the field from the array (so it's not added)
248
+ unset($cfields[$field_name]);
249
+ } else {
250
+ // This field exists in the table, but not in the creation queries? Drop it.
251
+ if ( $drop_columns ){
252
+ $cqueries[] = "ALTER TABLE `{$table}` DROP COLUMN `$field_name`";
253
+ $for_update[$table.'.'.$field_name] = 'Removed column '.$table.'.'.$field_name;
254
+ }
255
+ }
256
+ }
257
+
258
+ // For every remaining field specified for the table
259
+ foreach ($cfields as $field_name => $definition) {
260
+ // Push a query line into $cqueries that adds the field to that table
261
+ $cqueries[] = "ALTER TABLE `{$table}` ADD COLUMN `$field_name` {$definition['column_definition']}";
262
+ $for_update[$table.'.'.$field_name] = 'Added column '.$table.'.'.$field_name;
263
+ }
264
+
265
+ // Index stuff goes here
266
+ //echo 'Detected indexes : <br>'; print_r($indices);
267
+
268
+ // Fetch the table index structure from the database
269
+ $tableindices = $wpdb->get_results("SHOW INDEX FROM `{$table}`;");
270
+
271
+ if ($tableindices) {
272
+ // Clear the index array
273
+ unset($index_ary);
274
+
275
+ // For every index in the table
276
+ foreach ($tableindices as $tableindex) {
277
+ // Add the index to the index data array
278
+ $keyname = strtolower($tableindex->Key_name);
279
+ $index_ary[$keyname]['name'] = $keyname;
280
+
281
+ $index_ary[$keyname]['columns'][] = array(
282
+ 'column_name' => strtolower($tableindex->Column_name),
283
+ 'length' => $tableindex->Sub_part
284
+ );
285
+
286
+ if ( !isset($index_ary[$keyname]['index_modifier']) ){
287
+ if ( $keyname == 'primary' ){
288
+ $index_ary[$keyname]['index_modifier'] = 'primary';
289
+ } else if ( $tableindex->Non_unique == 0 ){
290
+ $index_ary[$keyname]['index_modifier'] = 'unique';
291
+ }
292
+ }
293
+ }
294
+
295
+ // For each actual index in the index array
296
+ foreach ($index_ary as $index_name => $index_data) {
297
+ // Build a create string to compare to the query
298
+ $index_string = blcTableDelta::generate_index_string($index_data);
299
+ if ( array_key_exists($index_string, $indices) ){
300
+ //echo "Found index $index_string<br>";
301
+ unset($indices[$index_string]);
302
+ } else {
303
+ //echo "Didn't find index $index_string<br>";
304
+ if ( $drop_indexes ){
305
+ if ( $index_name == 'primary' ){
306
+ $cqueries[] = "ALTER TABLE `{$table}` DROP PRIMARY KEY";
307
+ } else {
308
+ $cqueries[] = "ALTER TABLE `{$table}` DROP KEY `$index_name`";
309
+ }
310
+ $for_update[$table.'.'.$index_name] = 'Removed index '.$table.'.'.$index_name;
311
+ }
312
+ }
313
+ }
314
+ }
315
+
316
+ // For every remaining index specified for the table
317
+ foreach ( $indices as $index ) {
318
+ // Push a query line into $cqueries that adds the index to that table
319
+ $cqueries[] = "ALTER TABLE `{$table}` ADD {$index['index_definition']}";
320
+ $for_update[$table.'.'.$index['name']] = 'Added index '.$table.' '.$index['index_definition'];
321
+ }
322
+
323
+ // Remove the original table creation query from processing
324
+ unset($cqueries[strtolower($table)]);
325
+ unset($for_update[strtolower($table)]);
326
+ } else {
327
+ // This table exists in the database, but not in the creation queries?
328
+ }
329
+ }
330
+ }
331
+
332
+ //echo "Execute queries : <br>"; print_r($cqueries);
333
+ $query_log = array();
334
+ foreach ($cqueries as $query) {
335
+ $log_item = array('query' => $query,);
336
+ if ( $execute ) {
337
+ $log_item['success'] = ($wpdb->query($query) !== false);
338
+ $log_item['error_message'] = $wpdb->last_error;
339
+ }
340
+ $query_log[] = $log_item;
341
+ }
342
+
343
+ return array($for_update, $query_log);
344
+ }
345
+
346
+ /**
347
+ * Parse a a single column or index definition.
348
+ *
349
+ * This function can parse many (but not all) types of syntax used to define columns
350
+ * and indexes in a "CREATE TABLE" query.
351
+ *
352
+ * @param string $line
353
+ * @return array
354
+ */
355
+ function parse_create_definition($line){
356
+ $line = preg_replace('@[,\r\n\s]+$@', '', $line); //Strip the ", " line separator
357
+
358
+ $pieces = preg_split('@\s+|(?=\()@', $line, -1, PREG_SPLIT_NO_EMPTY);
359
+ if ( empty($pieces) ){
360
+ return null;
361
+ }
362
+
363
+ $token = strtolower(array_shift($pieces));
364
+
365
+ $index_modifier = '';
366
+ $index = false;
367
+
368
+ //Determine if this line defines an index
369
+ if ( in_array($token, array('primary', 'unique', 'fulltext')) ){
370
+ $index_modifier = $token;
371
+ $index = true;
372
+ $token = strtolower(array_shift($pieces));
373
+ }
374
+
375
+ if ( in_array($token, array('index', 'key')) ){
376
+ $index = true;
377
+ $token = strtolower(array_shift($pieces));
378
+ }
379
+
380
+ //Determine column/index name
381
+ $name = '';
382
+ if ( $index ){
383
+ //Names are optional for indexes; the INDEX/etc keyword can be immediately
384
+ //followed by a column list (or index_type, but we're ignoring that possibility).
385
+ if ( strpos($token, '(') === false ){
386
+ $name = $token;
387
+ } else {
388
+ if ( $index_modifier == 'primary' ){
389
+ $name = 'primary';
390
+ }
391
+ array_unshift($pieces, $token);
392
+ }
393
+ } else {
394
+ $name = $token;
395
+ }
396
+ $name = strtolower(trim($name, '`'));
397
+
398
+ $definition = compact('name', 'index', 'index_modifier');
399
+
400
+ //Parse the rest of the line
401
+ $remainder = implode(' ', $pieces);
402
+ if ( $index ){
403
+ $definition['columns'] = blcTableDelta::parse_index_column_list($remainder);
404
+
405
+ //If the index doesn't have a name, use the name of the first column
406
+ //(this is what MySQL does, but only when there isn't already an index with that name).
407
+ if ( empty($definition['name']) ){
408
+ $definition['name'] = $definition['columns'][0]['column_name'];
409
+ }
410
+ //Rebuild the index def. in a normalized form
411
+ $definition['index_definition'] = blcTableDelta::generate_index_string($definition);
412
+
413
+ } else {
414
+ $column_def = blcTableDelta::parse_column_definition($remainder);
415
+ $definition = array_merge($definition, $column_def);
416
+ }
417
+
418
+ return $definition;
419
+ }
420
+
421
+ /**
422
+ * Parse the list of columns included in an index.
423
+ *
424
+ * This function returns a list of column descriptors. Each descriptor is
425
+ * an associative array with the keys 'column_name', 'length' and 'order'.
426
+ *
427
+ * @param string $line
428
+ * @return array Array of index columns
429
+ */
430
+ function parse_index_column_list($line){
431
+ $line = preg_replace('@^\s*\(|\)\s*$@', '', $line); //Strip the braces that surround the column list
432
+ $pieces = preg_split('@\s*,\s*@', $line);
433
+
434
+ $columns = array();
435
+ foreach($pieces as $piece){
436
+ if ( preg_match('@`?(?P<column_name>[^\s`]+)`?(?:\s*\(\s*(?P<length>\d+)\s*\))?(?:\s+(?P<order>ASC|DESC))?@i', $piece, $matches) ){
437
+
438
+ $column = array(
439
+ 'column_name' => strtolower($matches['column_name']),
440
+ 'length' => null,
441
+ 'order' => null //unused; included for completeness
442
+ );
443
+
444
+ if ( isset($matches['length']) && is_numeric($matches['length']) ){
445
+ $column['length'] = intval($matches['length']);
446
+ }
447
+ if ( isset($matches['order']) && !empty($matches['order']) ){
448
+ $column['order'] = strtolower($matches['order']);
449
+ }
450
+
451
+ $columns[] = $column;
452
+ };
453
+ }
454
+
455
+ return $columns;
456
+ }
457
+
458
+ /**
459
+ * Parse column datatype and flags.
460
+ *
461
+ *
462
+ * @param string $line
463
+ * @return array
464
+ */
465
+ function parse_column_definition($line){
466
+ $line = trim($line);
467
+
468
+ //Extract datatype. This regexp is not entirely reliable - for example, it won't work
469
+ //with enum fields where one of values contains brackets "()".
470
+ $data_type = '';
471
+ $regexp = '
472
+ @
473
+ (?P<type_name>^\w+)
474
+
475
+ # followed by an optional length or a list of enum values
476
+ (?:\s*
477
+ \(
478
+ \s* (?P<length>[^()]+) \s*
479
+ \)
480
+ )?
481
+
482
+ # various type modifiers/keywords
483
+ (?P<keywords>
484
+ (?:\s+
485
+ (?: BINARY | UNSIGNED | ZEROFILL )
486
+ )*
487
+ )?
488
+ @xi';
489
+
490
+ if ( preg_match($regexp, $line, $matches) ){
491
+ $data_type = strtolower($matches['type_name']);
492
+ if ( !empty($matches['length']) ){
493
+ $data_type .= '(' . trim($matches['length']) . ')';
494
+ }
495
+ if ( !empty($matches['keywords']) ){
496
+ $data_type .= preg_replace('@\s+@', ' ', $matches['keywords']); //Collapse spaces
497
+ }
498
+ $line = substr($line, strlen($data_type));
499
+ }
500
+
501
+ //Extract flags
502
+ $null_allowed = !preg_match('@\sNOT\s+NULL\b@i', $line);
503
+ $auto_increment = preg_match('@\sAUTO_INCREMENT\b@i', $line);
504
+
505
+ //Got a default value?
506
+ $default = null;
507
+ if ( preg_match("@\sDEFAULT\s+('[^']*'|\"[^\"]*\"|\d+)@i", $line, $matches) ){
508
+ $default = trim($matches[1], '"\'');
509
+ }
510
+
511
+ //Custom character set and/or collation?
512
+ $charset = $collation = null;
513
+ if ( preg_match('@ (?:\s CHARACTER \s+ SET \s+ (?P<charset>[^\s()]+) )? (?:\s COLLATE \s+ (?P<collation>[^\s()]+) )? @xi', $line, $matches) ){
514
+ if ( isset($matches['charset']) ){
515
+ $charset = $matches['charset'];
516
+ }
517
+ if ( isset($matches['collation']) ){
518
+ $collation = $matches['collation'];
519
+ }
520
+ }
521
+
522
+ //Generate the normalized column definition
523
+ $column_definition = $data_type;
524
+ if ( !empty($charset) ){
525
+ $column_definition .= " CHARACTER SET {$charset}";
526
+ }
527
+ if ( !empty($collation) ){
528
+ $column_definition .= " COLLATE {$collation}";
529
+ }
530
+ if ( !$null_allowed ){
531
+ $column_definition .= " NOT NULL";
532
+ }
533
+ if ( !is_null($default) ){
534
+ $column_definition .= " DEFAULT '{$default}'";
535
+ }
536
+ if ( $auto_increment ){
537
+ $column_definition .= " AUTO_INCREMENT";
538
+ }
539
+
540
+ return compact('data_type', 'null_allowed', 'auto_increment', 'default', 'charset', 'collation', 'column_definition');
541
+ }
542
+
543
+ /**
544
+ * Generate an index's definition string from its parsed representation.
545
+ *
546
+ * @param array $definition The return value of blcTableDelta::parse_create_definition()
547
+ * @return string
548
+ */
549
+ function generate_index_string($definition){
550
+
551
+ //Rebuild the index def. in a normalized form
552
+ $index_definition = '';
553
+ if ( !empty($definition['index_modifier']) ){
554
+ $index_definition .= strtoupper($definition['index_modifier']) . ' ';
555
+ }
556
+ $index_definition .= 'KEY';
557
+ if ( $definition['index_modifier'] != 'primary' ){
558
+ $index_definition .= ' `' . $definition['name'].'`';
559
+ }
560
+
561
+ $column_strings = array();
562
+ foreach($definition['columns'] as $column){
563
+ $c = '`' . $column['column_name'] . '`';
564
+ if ( $column['length'] ){
565
+ $c .= '('.$column['length'].')';
566
+ }
567
+ $column_strings[] = $c;
568
+ }
569
+
570
+ $index_definition .= ' (' . implode(', ', $column_strings) . ')';
571
+ return $index_definition;
572
+ }
573
+
574
+ }
575
+
576
+
577
+ ?>
includes/admin/links-page-js.php CHANGED
@@ -23,16 +23,18 @@ function alterLinkCounter(factor){
23
  function replaceLinkId(old_id, new_id){
24
  var master = jQuery('#blc-row-'+old_id);
25
 
26
- //Save the new ID
27
  master.attr('id', 'blc-row-'+new_id);
28
  master.find('.blc-link-id').html(new_id);
 
 
 
29
  }
30
 
31
  function reloadDetailsRow(link_id){
32
- var master = jQuery('#blc-row-'+link_id);
33
 
34
  //Load up the new link info (so sue me)
35
- master.next('.blc-link-details').find('td').html('<center><?php echo esc_js(__('Loading...' , 'broken-link-checker')); ?></center>').load(
36
  "<?php echo admin_url('admin-ajax.php'); ?>",
37
  {
38
  'action' : 'blc_link_details',
@@ -44,16 +46,19 @@ function reloadDetailsRow(link_id){
44
  jQuery(function($){
45
 
46
  //The details button - display/hide detailed info about a link
47
- $(".blc-details-button, .blc-link-text").click(function () {
48
- $(this).parents('.blc-row').next('.blc-link-details').toggle();
 
 
49
  });
50
 
51
- //The discard button - manually mark the link as valid. The link will be checked again later.
52
  $(".blc-discard-button").click(function () {
53
  var me = $(this);
54
  me.html('<?php echo esc_js(__('Wait...', 'broken-link-checker')); ?>');
55
 
56
- var link_id = $(me).parents('.blc-row').find('.blc-link-id').html();
 
57
 
58
  $.post(
59
  "<?php echo admin_url('admin-ajax.php'); ?>",
@@ -64,13 +69,15 @@ jQuery(function($){
64
  },
65
  function (data, textStatus){
66
  if (data == 'OK'){
67
- var master = $(me).parents('.blc-row');
68
- var details = master.next('.blc-link-details');
69
 
70
- //Remove the "Not broken" link
71
  me.parent().remove();
72
 
73
- master.removeClass('blc-broken-link');
 
 
 
74
 
75
  //Flash the main row green to indicate success, then remove it if the current view
76
  //is supposed to show only broken links.
@@ -89,7 +96,7 @@ jQuery(function($){
89
  alterLinkCounter(-1);
90
  }
91
  } else {
92
- $(me).html('<?php echo esc_js(__('Not broken' , 'broken-link-checker')); ?>');
93
  alert(data);
94
  }
95
  }
@@ -98,126 +105,180 @@ jQuery(function($){
98
  return false;
99
  });
100
 
101
- //The edit button - edit/save the link's URL
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  $(".blc-edit-button").click(function () {
103
  var edit_button = $(this);
104
  var master = $(edit_button).parents('.blc-row');
105
- var editor = $(master).find('.blc-link-editor');
106
  var url_el = $(master).find('.blc-link-url');
107
- var cancel_button_container = $(master).find('.blc-cancel-button-container');
108
 
109
  //Find the current/original URL
110
  var orig_url = url_el.attr('href');
111
  //Find the link ID
112
- var link_id = $(master).find('.blc-link-id').html();
113
 
114
- if ( !$(editor).is(':visible') ){
115
- //Dislay the editing UI
116
- url_el.hide();
117
- //Reset the edit box to the actual URL value in case the user has already tried and failed to edit this link.
118
- editor.val( url_el.attr('href') );
119
- editor.show();
120
- cancel_button_container.show();
121
- editor.focus();
122
- editor.select();
123
- edit_button.html('<?php echo esc_js(__('Save URL' , 'broken-link-checker')); ?>');
124
  } else {
125
- //"Save" clicked.
126
- editor.hide();
127
- cancel_button_container.hide();
128
- url_el.show();
129
-
130
- new_url = editor.val();
131
-
132
- if (new_url != orig_url){
133
- //Save the changed link
134
- url_el.html('<?php echo esc_js(__('Saving changes...' , 'broken-link-checker')); ?>');
135
-
136
- $.getJSON(
137
- "<?php echo admin_url('admin-ajax.php'); ?>",
138
- {
139
- 'action' : 'blc_edit',
140
- 'link_id' : link_id,
141
- 'new_url' : new_url,
142
- '_ajax_nonce' : '<?php echo esc_js(wp_create_nonce('blc_edit')); ?>'
143
- },
144
- function (data, textStatus){
145
- var display_url = '';
146
-
147
- if ( data && (typeof(data['error']) != 'undefined') ){
148
- //An internal error occured before the link could be edited.
149
- //data.error is an error message.
150
- alert(data.error);
151
- display_url = orig_url;
152
- } else {
153
- //data contains info about the performed edit
154
- if ( data.errors.length == 0 ){
155
- //Everything went well.
156
-
157
- //Replace the displayed link URL with the new one.
158
- display_url = new_url;
159
- url_el.attr('href', new_url);
160
-
161
- //Save the new ID
162
- replaceLinkId(link_id, data.new_link_id);
163
- //Load up the new link info
164
- reloadDetailsRow(data.new_link_id);
165
- //Remove classes indicating link state - they're probably wrong by now
166
- master.removeClass('blc-broken-link').removeClass('blc-redirect');
167
-
168
- //Flash the row green to indicate success
169
- var oldColor = master.css('background-color');
170
- master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300);
171
-
172
- } else {
173
- display_url = orig_url;
174
-
175
- //Build and display an error message.
176
- var msg = '';
177
-
178
- if ( data.cnt_okay > 0 ){
179
- var msgpiece = sprintf(
180
- '<?php echo esc_js(__('%d instances of the link were successfully modified.', 'broken-link-checker')); ?>',
181
- data.cnt_okay
182
- );
183
- msg = msg + msgpiece + '\n';
184
- if ( data.cnt_error > 0 ){
185
- msgpiece = sprintf(
186
- '<?php echo esc_js(__("However, %d instances couldn't be edited and still point to the old URL.", 'broken-link-checker')); ?>',
187
- data.cnt_error
188
- );
189
- msg = msg + msgpiece + "\n";
190
- }
191
- } else {
192
- msg = msg + '<?php echo esc_js(__('The link could not be modified.', 'broken-link-checker')); ?>\n';
193
- }
194
-
195
- msg = msg + '\n<?php echo esc_js(__("The following error(s) occured :", 'broken-link-checker')); ?>\n* ';
196
- msg = msg + data.errors.join('\n* ');
197
-
198
- alert(msg);
199
- }
200
- };
201
-
202
- //Shorten the displayed URL if it's > 50 characters
203
- if ( display_url.length > 50 ){
204
- display_url = display_url.substr(0, 47) + '...';
205
- }
206
- url_el.html(display_url);
207
- }
208
- );
209
-
210
- } else {
211
- //It's the same URL, so do nothing.
212
- }
213
- edit_button.html('<?php echo esc_js(__('Edit URL', 'broken-link-checker')); ?>');
214
  }
215
  });
216
 
217
- //Let the user use Enter and Esc as shortcuts for "Save URL" and "Cancel"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  $('input.blc-link-editor').keypress(function (e) {
219
  if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
220
- $(this).parents('.blc-row').find('.blc-edit-button').click();
221
  return false;
222
  } else if ((e.which && e.which == 27) || (e.keyCode && e.keyCode == 27)) {
223
  $(this).parents('.blc-row').find('.blc-cancel-button').click();
@@ -227,27 +288,20 @@ jQuery(function($){
227
  }
228
  });
229
 
 
230
  $(".blc-cancel-button").click(function () {
231
  var master = $(this).parents('.blc-row');
232
- var url_el = $(master).find('.blc-link-url');
233
-
234
- //Hide the cancel button
235
- $(this).parent().hide();
236
- //Show the un-editable URL again
237
- url_el.show();
238
- //reset and hide the editor
239
- master.find('.blc-link-editor').hide().val(url_el.attr('href'));
240
- //Set the edit button to say "Edit URL"
241
- master.find('.blc-edit-button').html('<?php echo esc_js(__('Edit URL' , 'broken-link-checker')); ?>');
242
  });
243
 
244
- //The unlink button - remove the link/image from all posts, custom fields, etc.
245
  $(".blc-unlink-button").click(function () {
246
  var me = this;
247
  var master = $(me).parents('.blc-row');
248
  $(me).html('<?php echo esc_js(__('Wait...' , 'broken-link-checker')); ?>');
249
 
250
- var link_id = $(me).parents('.blc-row').find('.blc-link-id').html();
 
251
 
252
  $.post(
253
  "<?php echo admin_url('admin-ajax.php'); ?>",
@@ -266,7 +320,7 @@ jQuery(function($){
266
  } else {
267
  if ( data.errors.length == 0 ){
268
  //The link was successfully removed. Hide its details.
269
- master.next('.blc-link-details').hide();
270
  //Flash the main row green to indicate success, then hide it.
271
  var oldColor = master.css('background-color');
272
  master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300, function(){
@@ -388,28 +442,27 @@ jQuery(function($){
388
  if ( !confirm(message) ){
389
  return false;
390
  }
 
 
 
 
 
 
 
 
 
391
  }
392
  });
393
 
394
  //------------------------------------------------------------
395
  // Manipulate highlight settings for permanently broken links
396
  //------------------------------------------------------------
397
- var highlight_permanent_failures_checkbox = $('#highlight_permanent_failures-hide');
398
  var failure_duration_threshold_input = $('#failure_duration_threshold');
399
 
400
- //Update the checkbox depending on current settings.
401
- <?php
402
- $conf = & blc_get_configuration();
403
- if ( $conf->options['highlight_permanent_failures'] ){
404
- echo 'highlight_permanent_failures_checkbox.attr("checked", "checked");';
405
- } else {
406
- echo 'highlight_permanent_failures_checkbox.removeAttr("checked");';
407
- }
408
- ?>;
409
-
410
  //Apply/remove highlights when the checkbox is (un)checked
411
  highlight_permanent_failures_checkbox.change(function(){
412
- save_highlight_settings();
413
 
414
  if ( this.checked ){
415
  $('#blc-links tr.blc-permanently-broken').addClass('blc-permanently-broken-hl');
@@ -421,7 +474,7 @@ jQuery(function($){
421
  //Apply/remove highlights when the duration threshold is changed.
422
  failure_duration_threshold_input.change(function(){
423
  var new_threshold = parseInt($(this).val());
424
- save_highlight_settings();
425
  if (isNaN(new_threshold) || (new_threshold < 1)) {
426
  return;
427
  }
@@ -441,37 +494,45 @@ jQuery(function($){
441
  });
442
  });
443
 
444
- //Don't let the user manually submit the "Screen Options" form - it wouldn't work properly anyway.
445
- $('#adv-settings').submit(function(){
446
- return false;
447
- });
448
-
449
- //Save highlight settings using AJAX
450
- function save_highlight_settings(){
451
- var $ = jQuery;
452
-
453
- var highlight_permanent_failures = highlight_permanent_failures_checkbox.is(':checked');
454
- var failure_duration_threshold = parseInt(failure_duration_threshold_input.val());
455
-
456
- if ( isNaN(failure_duration_threshold) || ( failure_duration_threshold < 1 ) ){
457
- failure_duration_threshold = 1;
458
  }
459
 
460
- failure_duration_threshold_input.val(failure_duration_threshold);
461
-
462
- $.post(
463
- "<?php echo admin_url('admin-ajax.php'); ?>",
464
- {
465
- 'action' : 'blc_save_highlight_settings',
466
- 'failure_duration_threshold' : failure_duration_threshold,
467
- 'highlight_permanent_failures' : highlight_permanent_failures?1:0,
468
- '_ajax_nonce' : '<?php echo esc_js(wp_create_nonce('blc_save_highlight_settings')); ?>'
469
- }
470
  );
471
- }
472
 
 
 
 
 
 
473
 
 
 
 
 
 
474
 
 
 
 
 
 
 
 
 
 
475
  });
476
 
477
  </script>
23
  function replaceLinkId(old_id, new_id){
24
  var master = jQuery('#blc-row-'+old_id);
25
 
 
26
  master.attr('id', 'blc-row-'+new_id);
27
  master.find('.blc-link-id').html(new_id);
28
+
29
+ var details_row = jQuery('#link-details-'+old_id);
30
+ details_row.attr('id', 'link-details-'+new_id);
31
  }
32
 
33
  function reloadDetailsRow(link_id){
34
+ var details_row = jQuery('#link-details-'+link_id);
35
 
36
  //Load up the new link info (so sue me)
37
+ details_row.find('td').html('<center><?php echo esc_js(__('Loading...' , 'broken-link-checker')); ?></center>').load(
38
  "<?php echo admin_url('admin-ajax.php'); ?>",
39
  {
40
  'action' : 'blc_link_details',
46
  jQuery(function($){
47
 
48
  //The details button - display/hide detailed info about a link
49
+ $(".blc-details-button, td.column-link-text, td.column-status, td.column-new-link-text").click(function () {
50
+ var master = $(this).parents('.blc-row');
51
+ var link_id = master.attr('id').split('-')[2];
52
+ $('#link-details-'+link_id).toggle();
53
  });
54
 
55
+ //The "Not broken" button - manually mark the link as valid. The link will be checked again later.
56
  $(".blc-discard-button").click(function () {
57
  var me = $(this);
58
  me.html('<?php echo esc_js(__('Wait...', 'broken-link-checker')); ?>');
59
 
60
+ var master = me.parents('.blc-row');
61
+ var link_id = master.attr('id').split('-')[2];
62
 
63
  $.post(
64
  "<?php echo admin_url('admin-ajax.php'); ?>",
69
  },
70
  function (data, textStatus){
71
  if (data == 'OK'){
72
+ var details = $('#link-details-'+link_id);
 
73
 
74
+ //Remove the "Not broken" action
75
  me.parent().remove();
76
 
77
+ //Set the displayed link status to OK
78
+ var classNames = master.attr('class');
79
+ classNames = classNames.replace(/(^|\s)link-status-[^\s]+(\s|$)/, ' ') + ' link-status-ok';
80
+ master.attr('class', classNames);
81
 
82
  //Flash the main row green to indicate success, then remove it if the current view
83
  //is supposed to show only broken links.
96
  alterLinkCounter(-1);
97
  }
98
  } else {
99
+ me.html('<?php echo esc_js(__('Not broken' , 'broken-link-checker')); ?>');
100
  alert(data);
101
  }
102
  }
105
  return false;
106
  });
107
 
108
+ /**
109
+ * Display the inline URL editor for a particular link (that's present in the current view).
110
+ *
111
+ * @param link_id Either a link ID (int), or a jQuery object representing the link row.
112
+ */
113
+ function showUrlEditor(link_id){
114
+ if ( isNaN(link_id) ){
115
+ var master = link_id;
116
+ } else {
117
+ var master = $('#blc-row-' + link_id);
118
+ }
119
+
120
+ var url_el = master.find('a.blc-link-url').hide();
121
+
122
+ master.find('div.blc-url-editor-buttons').show();
123
+ master.find('input.blc-link-editor')
124
+ .val( url_el.attr('href') ).show().focus().select()
125
+ .parents('td').find('div.row-actions').hide();
126
+ }
127
+
128
+ /**
129
+ * Hide the URL editor of a particular link.
130
+ *
131
+ * @param link_id Either a link ID (int), or a jQuery object representing the link row.
132
+ */
133
+ function hideUrlEditor(link_id){
134
+ if ( isNaN(link_id) ){
135
+ var master = link_id;
136
+ } else {
137
+ var master = $('#blc-row-' + link_id);
138
+ }
139
+
140
+ master.find('div.blc-url-editor-buttons').hide();
141
+ master.find('input.blc-link-editor').hide();
142
+ master.find('a.blc-link-url').show();
143
+ master.find('div.row-actions').show();
144
+ }
145
+
146
+ /**
147
+ * Call our PHP backend and tell it to edit all occurences of particular link so that they
148
+ * point to a different URL. Updates UI with the new link info and displays any error messages
149
+ * that might be generated.
150
+ *
151
+ * @param link_id Either a link ID (int), or a jQuery object representing the link row.
152
+ * @param new_url The new URL for the link.
153
+ */
154
+ function updateLinkUrl(link_id, new_url){
155
+ if ( isNaN(link_id) ){
156
+ var master = link_id;
157
+ link_id = master.attr('id').split("-")[2]; //id="blc-row-$linkid"
158
+ } else {
159
+ var master = $('#blc-row-' + link_id);
160
+ }
161
+ var url_el = master.find('a.blc-link-url');
162
+ var orig_url = url_el.attr('href');
163
+ var progress_indicator = master.find('.waiting');
164
+
165
+ progress_indicator.show();
166
+
167
+ $.getJSON(
168
+ "<?php echo admin_url('admin-ajax.php'); ?>",
169
+ {
170
+ 'action' : 'blc_edit',
171
+ 'link_id' : link_id,
172
+ 'new_url' : new_url,
173
+ '_ajax_nonce' : '<?php echo esc_js(wp_create_nonce('blc_edit')); ?>'
174
+ },
175
+ function (data, textStatus){
176
+ var display_url = '';
177
+
178
+ if ( data && (typeof(data['error']) != 'undefined') ){
179
+ //An internal error occured before the link could be edited.
180
+ //data.error is an error message.
181
+ alert(data.error);
182
+ display_url = orig_url;
183
+ } else {
184
+ //data contains info about the performed edit
185
+ if ( data.errors.length == 0 ){
186
+ //Everything went well.
187
+
188
+ //Replace the displayed link URL with the new one.
189
+ display_url = new_url;
190
+ url_el.attr('href', new_url);
191
+
192
+ //Save the new ID
193
+ replaceLinkId(link_id, data.new_link_id);
194
+ //Load up the new link info
195
+ reloadDetailsRow(data.new_link_id);
196
+ //Remove classes indicating link state - they're probably wrong by now
197
+ var classNames = master.attr('class').replace(/(^|\s)link-status-[^\s]+(\s|$)/, ' ')+' link-status-unknown';
198
+ master.attr('class', classNames);
199
+ master.removeClass('blc-redirect');
200
+
201
+ //Flash the row green to indicate success
202
+ var oldColor = master.css('background-color');
203
+ master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300);
204
+
205
+ } else {
206
+ display_url = orig_url;
207
+
208
+ //Build and display an error message.
209
+ var msg = '';
210
+
211
+ if ( data.cnt_okay > 0 ){
212
+ var msgpiece = sprintf(
213
+ '<?php echo esc_js(__('%d instances of the link were successfully modified.', 'broken-link-checker')); ?>',
214
+ data.cnt_okay
215
+ );
216
+ msg = msg + msgpiece + '\n';
217
+ if ( data.cnt_error > 0 ){
218
+ msgpiece = sprintf(
219
+ '<?php echo esc_js(__("However, %d instances couldn't be edited and still point to the old URL.", 'broken-link-checker')); ?>',
220
+ data.cnt_error
221
+ );
222
+ msg = msg + msgpiece + "\n";
223
+ }
224
+ } else {
225
+ msg = msg + '<?php echo esc_js(__('The link could not be modified.', 'broken-link-checker')); ?>\n';
226
+ }
227
+
228
+ msg = msg + '\n<?php echo esc_js(__("The following error(s) occured :", 'broken-link-checker')); ?>\n* ';
229
+ msg = msg + data.errors.join('\n* ');
230
+
231
+ alert(msg);
232
+ }
233
+ };
234
+
235
+ url_el.text(display_url);
236
+
237
+ progress_indicator.hide();
238
+ hideUrlEditor(master);
239
+ }
240
+ );
241
+ }
242
+
243
+ //The "Edit URL" button - displays the inline editor
244
  $(".blc-edit-button").click(function () {
245
  var edit_button = $(this);
246
  var master = $(edit_button).parents('.blc-row');
247
+ var editor = $(master).find('input.blc-link-editor');
248
  var url_el = $(master).find('.blc-link-url');
 
249
 
250
  //Find the current/original URL
251
  var orig_url = url_el.attr('href');
252
  //Find the link ID
253
+ var link_id = master.attr('id').split('-')[2];
254
 
255
+ if ( !editor.is(':visible') ){
256
+ showUrlEditor(link_id);
 
 
 
 
 
 
 
 
257
  } else {
258
+ hideUrlEditor(link_id);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  }
260
  });
261
 
262
+ //The "Update URL" button in the inline editor
263
+ $('.blc-update-url-button').click(function(){
264
+ var master = $(this).parents('tr.blc-row');
265
+ var url_el = master.find('.blc-link-url');
266
+ var editor = master.find('input.blc-link-editor');
267
+
268
+ var old_url = url_el.attr('href');
269
+ var new_url = editor.val();
270
+
271
+ if ( (new_url == old_url) || ($.trim(new_url) == '') ){
272
+ hideUrlEditor(master);
273
+ } else {
274
+ updateLinkUrl(master, new_url);
275
+ }
276
+ });
277
+
278
+ //Let the user use Enter and Esc as shortcuts for "Update URL" and "Cancel"
279
  $('input.blc-link-editor').keypress(function (e) {
280
  if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
281
+ $(this).parents('.blc-row').find('.blc-update-url-button').click();
282
  return false;
283
  } else if ((e.which && e.which == 27) || (e.keyCode && e.keyCode == 27)) {
284
  $(this).parents('.blc-row').find('.blc-cancel-button').click();
288
  }
289
  });
290
 
291
+ //The "Cancel" in the inline editor
292
  $(".blc-cancel-button").click(function () {
293
  var master = $(this).parents('.blc-row');
294
+ hideUrlEditor(master);
 
 
 
 
 
 
 
 
 
295
  });
296
 
297
+ //The "Unlink" button - remove the link/image from all posts, custom fields, etc.
298
  $(".blc-unlink-button").click(function () {
299
  var me = this;
300
  var master = $(me).parents('.blc-row');
301
  $(me).html('<?php echo esc_js(__('Wait...' , 'broken-link-checker')); ?>');
302
 
303
+ //Find the link ID
304
+ var link_id = master.attr('id').split('-')[2];
305
 
306
  $.post(
307
  "<?php echo admin_url('admin-ajax.php'); ?>",
320
  } else {
321
  if ( data.errors.length == 0 ){
322
  //The link was successfully removed. Hide its details.
323
+ $('#link-details-'+link_id).hide();
324
  //Flash the main row green to indicate success, then hide it.
325
  var oldColor = master.css('background-color');
326
  master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300, function(){
442
  if ( !confirm(message) ){
443
  return false;
444
  }
445
+ } else if ( action == 'bulk-unlink' ){
446
+ var message = '<?php
447
+ echo esc_js(
448
+ __("Are you sure you want to remove the selected links? This action can't be undone.\n'Cancel' to stop, 'OK' to remove", 'broken-link-checker')
449
+ );
450
+ ?>';
451
+ if ( !confirm(message) ){
452
+ return false;
453
+ }
454
  }
455
  });
456
 
457
  //------------------------------------------------------------
458
  // Manipulate highlight settings for permanently broken links
459
  //------------------------------------------------------------
460
+ var highlight_permanent_failures_checkbox = $('#highlight_permanent_failures');
461
  var failure_duration_threshold_input = $('#failure_duration_threshold');
462
 
 
 
 
 
 
 
 
 
 
 
463
  //Apply/remove highlights when the checkbox is (un)checked
464
  highlight_permanent_failures_checkbox.change(function(){
465
+ //save_highlight_settings();
466
 
467
  if ( this.checked ){
468
  $('#blc-links tr.blc-permanently-broken').addClass('blc-permanently-broken-hl');
474
  //Apply/remove highlights when the duration threshold is changed.
475
  failure_duration_threshold_input.change(function(){
476
  var new_threshold = parseInt($(this).val());
477
+ //save_highlight_settings();
478
  if (isNaN(new_threshold) || (new_threshold < 1)) {
479
  return;
480
  }
494
  });
495
  });
496
 
497
+ //Show/hide table columns dynamically
498
+ $('#blc-column-selector input[type="checkbox"]').change(function(){
499
+ var checkbox = $(this);
500
+ var column_id = checkbox.attr('name').split(/\[|\]/)[1];
501
+ if (checkbox.is(':checked')){
502
+ $('td.column-'+column_id+', th.column-'+column_id, '#blc-links').removeClass('hidden');
503
+ } else {
504
+ $('td.column-'+column_id+', th.column-'+column_id, '#blc-links').addClass('hidden');
 
 
 
 
 
 
505
  }
506
 
507
+ //Recalculate colspan's for detail rows to take into account the changed number of
508
+ //visible columns. Otherwise you can get some ugly layout glitches.
509
+ $('#blc-links tr.blc-link-details td').attr(
510
+ 'colspan',
511
+ $('#blc-column-selector input[type="checkbox"]:checked').length+1
 
 
 
 
 
512
  );
513
+ });
514
 
515
+ //Unlike other fields in "Screen Options", the links-per-page setting
516
+ //is handled using straight form submission (POST), not AJAX.
517
+ $('#blc-per-page-apply-button').click(function(){
518
+ $('#adv-settings').submit();
519
+ });
520
 
521
+ $('#blc_links_per_page').keypress(function(e){
522
+ if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
523
+ $('#adv-settings').submit();
524
+ }
525
+ });
526
 
527
+ //Toggle status code colors when the corresponding checkbox is toggled
528
+ $('#table_color_code_status').click(function(){
529
+ if ( $(this).is(':checked') ){
530
+ $('#blc-links').addClass('color-code-link-status');
531
+ } else {
532
+ $('#blc-links').removeClass('color-code-link-status');
533
+ }
534
+ });
535
+
536
  });
537
 
538
  </script>
includes/admin/options-page-js.php ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script type="text/javascript">
2
+
3
+ jQuery(function($){
4
+ $('#blc-tabs').tabs();
5
+
6
+ //Refresh the "Status" box every 10 seconds
7
+ function blcUpdateStatus(){
8
+ $.getJSON(
9
+ "<?php echo admin_url('admin-ajax.php'); ?>",
10
+ {
11
+ 'action' : 'blc_full_status',
12
+ 'random' : Math.random()
13
+ },
14
+ function (data, textStatus){
15
+ if ( data && ( typeof(data['text']) != 'undefined' ) ){
16
+ $('#wsblc_full_status').html(data.text);
17
+ } else {
18
+ $('#wsblc_full_status').html('<?php _e('[ Network error ]', 'broken-link-checker'); ?>');
19
+ }
20
+
21
+ setTimeout(blcUpdateStatus, 10000);
22
+ }
23
+ );
24
+ }
25
+ blcUpdateStatus();
26
+
27
+ //Refresh the avg. load display every 10 seconds
28
+ function blcUpdateLoad(){
29
+ $.get(
30
+ "<?php echo admin_url('admin-ajax.php'); ?>",
31
+ {
32
+ 'action' : 'blc_current_load'
33
+ },
34
+ function (data, textStatus){
35
+ $('#wsblc_current_load').html(data);
36
+
37
+ setTimeout(blcUpdateLoad, 10000); //...update every 10 seconds
38
+ }
39
+ );
40
+ }
41
+ //Only do it if load limiting is available on this server, though.
42
+ if ( $('#wsblc_current_load').length > 0 ){
43
+ blcUpdateLoad();
44
+ }
45
+
46
+
47
+ var toggleButton = $('#blc-debug-info-toggle');
48
+
49
+ toggleButton.click(function(){
50
+
51
+ var box = $('#blc-debug-info');
52
+ box.toggle();
53
+ if( box.is(':visible') ){
54
+ toggleButton.text('<?php _e('Hide debug info', 'broken-link-checker'); ?>');
55
+ } else {
56
+ toggleButton.text('<?php _e('Show debug info', 'broken-link-checker'); ?>');
57
+ }
58
+
59
+ });
60
+
61
+ $('#toggle-broken-link-css-editor').click(function(){
62
+ var box = $('#broken-link-css-wrap').toggleClass('hidden');
63
+
64
+ $.cookie(
65
+ box.attr('id'),
66
+ box.hasClass('hidden')?'0':'1',
67
+ {
68
+ expires : 365
69
+ }
70
+ );
71
+
72
+ return false;
73
+ });
74
+
75
+ $('#toggle-removed-link-css-editor').click(function(){
76
+ var box = $('#removed-link-css-wrap').toggleClass('hidden');
77
+
78
+ $.cookie(
79
+ box.attr('id'),
80
+ box.hasClass('hidden')?'0':'1',
81
+ {
82
+ expires : 365
83
+ }
84
+ );
85
+
86
+ return false;
87
+ });
88
+
89
+ //Show/hide per-module settings
90
+ $('.toggle-module-settings').click(function(){
91
+ var settingsBox = $(this).parent().find('.module-extra-settings');
92
+ if ( settingsBox.length > 0 ){
93
+ settingsBox.toggleClass('hidden');
94
+ $.cookie(
95
+ settingsBox.attr('id'),
96
+ settingsBox.hasClass('hidden')?'0':'1',
97
+ {
98
+ expires : 365
99
+ }
100
+ );
101
+ }
102
+ return false;
103
+ });
104
+
105
+ //When the user ticks the "Custom fields" box, display the field list input
106
+ //so that they notice that they need to enter the field names.
107
+ $('#module-checkbox-custom_field').click(function(){
108
+ var box = $(this);
109
+ var fieldList = $('#blc_custom_fields');
110
+ if ( box.is(':checked') && ( $.trim(fieldList.val()) == '' ) ){
111
+ $('#module-extra-settings-custom_field').removeClass('hidden');
112
+ }
113
+ });
114
+
115
+ //Handle the "Recheck" button
116
+ $('#start-recheck').click(function(){
117
+ $('#recheck').val('1'); //populate the hidden field
118
+ $('#link_checker_options input[name="submit"]').click(); //.submit() didn't work for some reason
119
+ });
120
+ });
121
+
122
+ </script>
includes/admin/search-form.php CHANGED
@@ -1,3 +1,6 @@
 
 
 
1
  <div class="search-box">
2
 
3
  <?php
@@ -64,7 +67,33 @@
64
 
65
  <label for="s_link_type"><?php _e('Link type', 'broken-link-checker'); ?></label>
66
  <select name="s_link_type" id="s_link_type">
 
67
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  $link_types = array(
69
  __('Any', 'broken-link-checker') => '',
70
  __('Normal link', 'broken-link-checker') => 'link',
@@ -73,11 +102,7 @@
73
  __('Bookmark', 'broken-link-checker') => 'blogroll',
74
  __('Comment', 'broken-link-checker') => 'comment',
75
  );
76
-
77
- foreach ($link_types as $name => $value){
78
- $selected = ( isset($search_params['s_link_type']) && $search_params['s_link_type'] == $value )?' selected="selected"':'';
79
- printf('<option value="%s"%s>%s</option>', $value, $selected, $name);
80
- }
81
  ?>
82
  </select>
83
 
1
+ <?php
2
+ $search_params = $current_filter['search_params'];
3
+ ?>
4
  <div class="search-box">
5
 
6
  <?php
67
 
68
  <label for="s_link_type"><?php _e('Link type', 'broken-link-checker'); ?></label>
69
  <select name="s_link_type" id="s_link_type">
70
+ <option value=""><?php _e('Any', 'broken-link-checker'); ?></option>
71
  <?php
72
+ $moduleManager = &blcModuleManager::getInstance();
73
+
74
+ printf('<optgroup label="%s">', esc_attr(__('Links used in', 'broken-link-checker')));
75
+ $containers = $moduleManager->get_modules_by_category('container', false, true);
76
+ foreach($containers as $container_type => $module_data){
77
+ if ( !empty($module_data['ModuleHidden']) || !$moduleManager->is_active($container_type) ){
78
+ continue;
79
+ }
80
+ $selected = ( isset($search_params['s_link_type']) && $search_params['s_link_type'] == $container_type )?' selected="selected"':'';
81
+ printf('<option value="%s"%s>%s</option>', $container_type, $selected, $module_data['Name']);
82
+ }
83
+ echo '</optgroup>';
84
+ //TODO: Better group labels
85
+ printf('<optgroup label="%s">', esc_attr(__('Link type', 'broken-link-checker')));
86
+ $parsers = $moduleManager->get_modules_by_category('parser', false, true);
87
+ foreach($parsers as $parser_type => $module_data){
88
+ if ( !empty($module_data['ModuleHidden']) || !$moduleManager->is_active($parser_type) ){
89
+ continue;
90
+ }
91
+ $selected = ( isset($search_params['s_link_type']) && $search_params['s_link_type'] == $parser_type )?' selected="selected"':'';
92
+ printf('<option value="%s"%s>%s</option>', $parser_type, $selected, $module_data['Name']);
93
+ }
94
+ echo '</optgroup>';
95
+
96
+ /*
97
  $link_types = array(
98
  __('Any', 'broken-link-checker') => '',
99
  __('Normal link', 'broken-link-checker') => 'link',
102
  __('Bookmark', 'broken-link-checker') => 'blogroll',
103
  __('Comment', 'broken-link-checker') => 'comment',
104
  );
105
+ */
 
 
 
 
106
  ?>
107
  </select>
108
 
includes/admin/table-printer.php ADDED
@@ -0,0 +1,719 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( !class_exists('blcTablePrinter') ) {
4
+
5
+ /**
6
+ * Utility class for printing the link listing table.
7
+ *
8
+ * @package Broken Link Checker
9
+ * @access public
10
+ */
11
+ class blcTablePrinter {
12
+
13
+ var $current_filter; //The current search filter. Also contains the list of links to display.
14
+ var $page; //The current page number
15
+ var $per_page; //Max links per page
16
+ var $core; //A reference to the main plugin object
17
+ var $neutral_current_url; //The "safe" version of the current URL, for use in the bulk action form.
18
+
19
+ var $bulk_actions_html = '';
20
+ var $pagination_html = '';
21
+ var $searched_link_type = '';
22
+
23
+ var $columns;
24
+ var $layouts;
25
+
26
+
27
+ function blcTablePrinter(&$core){
28
+ $this->core = &$core;
29
+
30
+ //Initialize layout and column definitions
31
+ $this->setup_columns();
32
+ $this->setup_layouts();
33
+
34
+ //Figure out what the "safe" URL to acccess the current page would be.
35
+ //This is used by the bulk action form.
36
+ $special_args = array('_wpnonce', '_wp_http_referer', 'action', 'selected_links');
37
+ $this->neutral_current_url = remove_query_arg($special_args);
38
+ }
39
+
40
+
41
+ /**
42
+ * Print the entire link table and associated navigation elements.
43
+ *
44
+ * @param array $current_filter
45
+ * @param string $layout
46
+ * @param array $visible_columns
47
+ * @param bool $compact
48
+ * @return void
49
+ */
50
+ function print_table($current_filter, $layout = 'flexible', $visible_columns = null, $compact = false){
51
+ $this->current_filter = $current_filter;
52
+ $this->page = $current_filter['page'];
53
+ $this->per_page = $current_filter['per_page'];
54
+
55
+ $layout = $this->layouts[$layout];
56
+ if ( empty($visible_columns) ){
57
+ $visible_columns = $layout;
58
+ }
59
+ //Only allow columns actually present in this layout
60
+ $visible_columns = array_intersect($visible_columns, $layout);
61
+
62
+ echo '<form id="blc-bulk-action-form" action="', $this->neutral_current_url, '" method="post">';
63
+ wp_nonce_field('bulk-action');
64
+
65
+ //Top navigation
66
+ $this->prepare_nav_html();
67
+ $this->navigation($compact);
68
+
69
+ //Table header
70
+ $table_classes = array('widefat');
71
+ if ( $compact ) {
72
+ $table_classes[] = 'compact';
73
+ };
74
+ if ( $this->core->conf->options['table_color_code_status'] ) {
75
+ $table_classes[] = 'color-code-link-status';
76
+ };
77
+ printf(
78
+ '<table class="%s" id="blc-links"><thead><tr>',
79
+ implode(' ', $table_classes)
80
+ );
81
+
82
+ //The select-all checkbox
83
+ echo '<th scope="col" class="column-checkbox check-column" id="cb"><input type="checkbox" /></th>';
84
+
85
+ foreach($layout as $column_id){
86
+ $column = $this->columns[$column_id];
87
+
88
+ $column_classes = array('column-'.$column_id);
89
+ if ( isset($column['class']) ){
90
+ $column_classes[] = $column['class'];
91
+ }
92
+ if ( !in_array($column_id, $visible_columns) ) {
93
+ $column_classes[] = 'hidden';
94
+ }
95
+
96
+ printf(
97
+ '<th scope="col" class="%s"%s>%s</th>',
98
+ implode(' ', $column_classes),
99
+ isset($column['id']) ? ' id="' . $column['id'] . '"' : '',
100
+ $column['heading']
101
+ );
102
+ }
103
+ echo '</tr></thead>';
104
+
105
+ //Table body
106
+ echo '<tbody id="the-list">';
107
+ $rownum = 0;
108
+ foreach ($this->current_filter['links'] as $link) {
109
+ $rownum++;
110
+ $this->link_row($link, $layout, $visible_columns, $rownum);
111
+ $this->link_details_row($link, $visible_columns, $rownum);
112
+ }
113
+ echo '</tbody></table>';
114
+
115
+ //Bottom navigation
116
+ $this->navigation($compact, '2');
117
+ echo '</form>';
118
+ }
119
+
120
+ /**
121
+ * Print the "Bulk Actions" dropdown and navigation links
122
+ *
123
+ * @param string $suffix Optional. Appended to ID and name attributes of the bulk action dropdown.
124
+ * @return void
125
+ */
126
+ function navigation($table_compact = false, $suffix = ''){
127
+ //Display the "Bulk Actions" dropdown
128
+ echo '<div class="tablenav">',
129
+ '<div class="alignleft actions">',
130
+ '<select name="action', $suffix ,'" id="blc-bulk-action', $suffix ,'">',
131
+ $this->bulk_actions_html,
132
+ '</select>',
133
+ ' <input type="submit" name="doaction', $suffix ,'" id="doaction',$suffix,'" value="',
134
+ esc_attr(__('Apply', 'broken-link-checker')),
135
+ '" class="button-secondary action">',
136
+ '</div>';
137
+
138
+ //Display pagination links
139
+ if ( !empty($this->pagination_html) ){
140
+ echo $this->pagination_html;
141
+ }
142
+
143
+ //Display the view switch (only in the top nav. area)
144
+ if ( empty($suffix) ){
145
+ ?>
146
+
147
+ <div class="view-switch">
148
+ <a href="<?php echo esc_url(add_query_arg('compact', '1', $_SERVER['REQUEST_URI'])) ?>"><img <?php if ( $table_compact ) echo 'class="current"'; ?> id="view-switch-list" src="<?php echo esc_url( includes_url( 'images/blank.gif' ) ); ?>" width="20" height="20" title="<?php _e('Compact View', 'broken-link-checker') ?>" alt="<?php _e('Compact View', 'broken-link-checker') ?>" /></a>
149
+ <a href="<?php echo esc_url(add_query_arg('compact', '0', $_SERVER['REQUEST_URI'])) ?>"><img <?php if ( !$table_compact ) echo 'class="current"'; ?> id="view-switch-excerpt" src="<?php echo esc_url( includes_url( 'images/blank.gif' ) ); ?>" width="20" height="20" title="<?php _e('Detailed View', 'broken-link-checker') ?>" alt="<?php _e('Detailed View', 'broken-link-checker') ?>" /></a>
150
+ </div>
151
+
152
+ <?php
153
+ }
154
+
155
+ echo '</div>';
156
+ }
157
+
158
+ /**
159
+ * Initialize the internal list of available table columns.
160
+ *
161
+ * @return void
162
+ */
163
+ function setup_columns(){
164
+ $this->columns = array(
165
+ 'source' => array(
166
+ 'heading' => __('Source', 'broken-link-checker'),
167
+ 'class' => 'column-title',
168
+ 'content' => array(&$this, 'column_source'),
169
+ ),
170
+
171
+ 'link-text' => array(
172
+ 'heading' => __('Link Text', 'broken-link-checker'),
173
+ 'content' => array(&$this, 'column_link_text'),
174
+ ),
175
+
176
+ 'url' => array(
177
+ 'heading' => __('URL', 'broken-link-checker'),
178
+ 'content' => array(&$this, 'column_url'),
179
+ ),
180
+
181
+ 'status' => array(
182
+ 'heading' => __('Status', 'broken-link-checker'),
183
+ 'content' => array(&$this, 'column_status'),
184
+ ),
185
+
186
+ 'new-url' => array(
187
+ 'heading' => __('URL', 'broken-link-checker'),
188
+ 'content' => array(&$this, 'column_new_url'),
189
+ ),
190
+
191
+ 'used-in' => array(
192
+ 'heading' => __('Source', 'broken-link-checker'),
193
+ 'class' => 'column-title',
194
+ 'content' => array(&$this, 'column_used_in'),
195
+ ),
196
+
197
+ 'new-link-text' => array(
198
+ 'heading' => __('Link Text', 'broken-link-checker'),
199
+ 'content' => array(&$this, 'column_new_link_text'),
200
+ ),
201
+ );
202
+ }
203
+
204
+ /**
205
+ * Initialize the list of available layouts
206
+ *
207
+ * @return void
208
+ */
209
+ function setup_layouts(){
210
+ $this->layouts = array(
211
+ 'classic' => array('used-in', 'new-link-text', 'new-url'),
212
+ 'flexible' => array('new-url', 'status', 'new-link-text', 'used-in',),
213
+ );
214
+ }
215
+
216
+ /**
217
+ * Get a list of columns available in a specific table layout.
218
+ *
219
+ * @param string $layout Layout ID.
220
+ * @return array Associative array of column data indexed by column ID.
221
+ */
222
+ function get_layout_columns($layout){
223
+ if ( isset($this->layouts[$layout]) ){
224
+
225
+ $result = array();
226
+ foreach($this->layouts[$layout] as $column_id){
227
+ if ( isset($this->columns[$column_id]) )
228
+ $result[$column_id] = $this->columns[$column_id];
229
+ }
230
+ return $result;
231
+
232
+ } else {
233
+ return null;
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Pre-generate some HTML fragments used for both the top and bottom navigation/bulk action boxes.
239
+ *
240
+ * @return void
241
+ */
242
+ function prepare_nav_html(){
243
+ //Generate an <option> element for each possible bulk action. The list doesn't change,
244
+ //so we can do it once and reuse the generated HTML.
245
+ $bulk_actions = array(
246
+ '-1' => __('Bulk Actions', 'broken-link-checker'),
247
+ "bulk-recheck" => __('Recheck', 'broken-link-checker'),
248
+ "bulk-deredirect" => __('Fix redirects', 'broken-link-checker'),
249
+ "bulk-not-broken" => __('Mark as not broken', 'broken-link-checker'),
250
+ "bulk-unlink" => __('Unlink', 'broken-link-checker'),
251
+ );
252
+ if ( EMPTY_TRASH_DAYS ){
253
+ $bulk_actions["bulk-trash-sources"] = __('Move sources to Trash', 'broken-link-checker');
254
+ } else {
255
+ $bulk_actions["bulk-delete-sources"] = __('Delete sources', 'broken-link-checker');
256
+ }
257
+
258
+ $bulk_actions_html = '';
259
+ foreach($bulk_actions as $value => $name){
260
+ $bulk_actions_html .= sprintf('<option value="%s">%s</option>', $value, $name);
261
+ }
262
+
263
+ $this->bulk_actions_html = $bulk_actions_html;
264
+
265
+ //Pagination links can also be pre-generated.
266
+ //WP has a built-in function for pagination :)
267
+ $page_links = paginate_links( array(
268
+ 'base' => add_query_arg( 'paged', '%#%' ),
269
+ 'format' => '',
270
+ 'prev_text' => __('&laquo;'),
271
+ 'next_text' => __('&raquo;'),
272
+ 'total' => $this->current_filter['max_pages'],
273
+ 'current' => $this->page
274
+ ));
275
+
276
+ if ( $page_links ) {
277
+ $this->pagination_html = '<div class="tablenav-pages">';
278
+ $this->pagination_html .= sprintf(
279
+ '<span class="displaying-num">' . __( 'Displaying %s&#8211;%s of <span class="current-link-count">%s</span>', 'broken-link-checker' ) . '</span>%s',
280
+ number_format_i18n( ( $this->page - 1 ) * $this->per_page + 1 ),
281
+ number_format_i18n( min( $this->page * $this->per_page, $this->current_filter['count'] ) ),
282
+ number_format_i18n( $this->current_filter['count'] ),
283
+ $page_links
284
+ );
285
+ $this->pagination_html .= '</div>';
286
+ } else {
287
+ $this->pagination_html = '';
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Print the link row.
293
+ *
294
+ * @param object $link The link to display.
295
+ * @param array $layout List of columns to output.
296
+ * @param array $visible_columns List of visible columns.
297
+ * @param integer $rownum Table row number.
298
+ * @return void
299
+ */
300
+ function link_row(&$link, $layout, $visible_columns, $rownum = 0){
301
+
302
+ //Figure out what CSS classes the link row should have
303
+ $rowclass = ($rownum % 2)? 'alternate' : '';
304
+
305
+ $excluded = $this->core->is_excluded( $link->url );
306
+ if ( $excluded ) $rowclass .= ' blc-excluded-link';
307
+
308
+ if ( $link->redirect_count > 0){
309
+ $rowclass .= ' blc-redirect';
310
+ }
311
+
312
+ $days_broken = 0;
313
+ if ( $link->broken ){
314
+ //Add a highlight to broken links that appear to be permanently broken
315
+ $days_broken = intval( (time() - $link->first_failure) / (3600*24) );
316
+ if ( $days_broken >= $this->core->conf->options['failure_duration_threshold'] ){
317
+ $rowclass .= ' blc-permanently-broken';
318
+ if ( $this->core->conf->options['highlight_permanent_failures'] ){
319
+ $rowclass .= ' blc-permanently-broken-hl';
320
+ }
321
+ }
322
+ }
323
+
324
+ $status = $link->analyse_status();
325
+ $rowclass .= ' link-status-' . $status['code'];
326
+
327
+ //Retrieve link instances to display in the table
328
+ $instances = $link->get_instances();
329
+
330
+ if ( !empty($instances) ){
331
+ //Put instances that match the selected link type at the top. Makes search results look better.
332
+ if ( !empty($this->current_filter['search_params']['s_link_type']) ){
333
+ $s_link_type = $this->current_filter['search_params']['s_link_type'];
334
+ } else {
335
+ $s_link_type = '';
336
+ }
337
+ $instances = $this->sort_instances_for_display($instances, $s_link_type);
338
+ }
339
+
340
+ printf(
341
+ '<tr id="blc-row-%s" class="blc-row %s" days_broken="%d">',
342
+ $link->link_id,
343
+ $rowclass,
344
+ $days_broken
345
+ );
346
+
347
+ //The checkbox used to select links is automatically printed in all layouts
348
+ //and can't be disabled. Without it, bulk actions wouldn't work.
349
+ $this->column_checkbox($link);
350
+
351
+ foreach($layout as $column_id){
352
+ $column = $this->columns[$column_id];
353
+
354
+ printf(
355
+ '<td class="column-%s%s">',
356
+ $column_id,
357
+ in_array($column_id, $visible_columns) ? '' : ' hidden'
358
+ );
359
+
360
+ if ( isset($column['content']) ){
361
+ if ( is_callable($column['content']) ){
362
+ call_user_func($column['content'], $link, $instances);
363
+ } else {
364
+ echo $column['content'];
365
+ }
366
+ } else {
367
+ echo '[', $column_id, ']';
368
+ }
369
+
370
+ echo '</td>';
371
+ }
372
+
373
+ echo '</tr>';
374
+ }
375
+
376
+ /**
377
+ * Print the details row for a specific link.
378
+ *
379
+ * @uses blcTablePrinter::details_row_contents()
380
+ *
381
+ * @param object $link The link to display.
382
+ * @param array $visible_columns List of visible columns.
383
+ * @param integer $rownum Table row number.
384
+ * @return void
385
+ */
386
+ function link_details_row(&$link, $visible_columns, $rownum = 0){
387
+ printf(
388
+ '<tr id="link-details-%d" class="blc-link-details"><td colspan="%d">',
389
+ $link->link_id,
390
+ count($visible_columns)+1
391
+ );
392
+ $this->details_row_contents($link);
393
+ echo '</td></tr>';
394
+ }
395
+
396
+ /**
397
+ * Print the contents of the details row for a specific link.
398
+ *
399
+ * @param object $link
400
+ * @return void
401
+ */
402
+ function details_row_contents(&$link){
403
+ ?>
404
+ <div class="blc-detail-container">
405
+ <div class="blc-detail-block" style="float: left; width: 49%;">
406
+ <ol style='list-style-type: none;'>
407
+ <?php if ( !empty($link->post_date) ) { ?>
408
+ <li><strong><?php _e('Post published on', 'broken-link-checker'); ?> :</strong>
409
+ <span class='post_date'><?php
410
+ echo date_i18n(get_option('date_format'),strtotime($link->post_date));
411
+ ?></span></li>
412
+ <?php } ?>
413
+ <li><strong><?php _e('Link last checked', 'broken-link-checker'); ?> :</strong>
414
+ <span class='check_date'><?php
415
+ $last_check = $link->last_check;
416
+ if ( $last_check < strtotime('-10 years') ){
417
+ _e('Never', 'broken-link-checker');
418
+ } else {
419
+ echo date_i18n(get_option('date_format'), $last_check);
420
+ }
421
+ ?></span></li>
422
+
423
+ <li><strong><?php _e('HTTP code', 'broken-link-checker'); ?> :</strong>
424
+ <span class='http_code'><?php
425
+ print $link->http_code;
426
+ ?></span></li>
427
+
428
+ <li><strong><?php _e('Response time', 'broken-link-checker'); ?> :</strong>
429
+ <span class='request_duration'><?php
430
+ printf( __('%2.3f seconds', 'broken-link-checker'), $link->request_duration);
431
+ ?></span></li>
432
+
433
+ <li><strong><?php _e('Final URL', 'broken-link-checker'); ?> :</strong>
434
+ <span class='final_url'><?php
435
+ print $link->final_url;
436
+ ?></span></li>
437
+
438
+ <li><strong><?php _e('Redirect count', 'broken-link-checker'); ?> :</strong>
439
+ <span class='redirect_count'><?php
440
+ print $link->redirect_count;
441
+ ?></span></li>
442
+
443
+ <li><strong><?php _e('Instance count', 'broken-link-checker'); ?> :</strong>
444
+ <span class='instance_count'><?php
445
+ print count($link->get_instances());
446
+ ?></span></li>
447
+
448
+ <?php if ( $link->broken && (intval( $link->check_count ) > 0) ){ ?>
449
+ <li><br/>
450
+ <?php
451
+ printf(
452
+ _n('This link has failed %d time.', 'This link has failed %d times.', $link->check_count, 'broken-link-checker'),
453
+ $link->check_count
454
+ );
455
+
456
+ echo '<br>';
457
+
458
+ $delta = time() - $link->first_failure;
459
+ printf(
460
+ __('This link has been broken for %s.', 'broken-link-checker'),
461
+ blcUtility::fuzzy_delta($delta)
462
+ );
463
+ ?>
464
+ </li>
465
+ <?php } ?>
466
+ </ol>
467
+ </div>
468
+
469
+ <div class="blc-detail-block" style="float: right; width: 50%;">
470
+ <ol style='list-style-type: none;'>
471
+ <li><strong><?php _e('Log', 'broken-link-checker'); ?> :</strong>
472
+ <span class='blc_log'><?php
473
+ print nl2br($link->log);
474
+ ?></span></li>
475
+ </ol>
476
+ </div>
477
+
478
+ <div style="clear:both;"> </div>
479
+ </div>
480
+ <?php
481
+ }
482
+
483
+ function column_checkbox(&$link){
484
+ ?>
485
+ <th scope="row" class="check-column"><input type="checkbox" name="selected_links[]" value="<?php echo $link->link_id; ?>" /></th>
486
+ <?php
487
+ }
488
+
489
+ function column_source(&$link, $instances){
490
+ echo '<span class="blc-link-id" style="display:none;">',
491
+ $link->link_id,
492
+ '</span>';
493
+
494
+ //Print the contents of the "Source" column
495
+ if ( !empty($instances) ){
496
+ $instance = reset($instances);
497
+
498
+ echo $instance->ui_get_source();
499
+
500
+ $actions = $instance->ui_get_action_links();
501
+
502
+ echo '<div class="row-actions">';
503
+ echo implode(' | </span>', $actions);
504
+ echo '</div>';
505
+
506
+ } else {
507
+ _e("[An orphaned link! This is a bug.]", 'broken-link-checker');
508
+ }
509
+ }
510
+
511
+ function column_url(&$link){
512
+ ?>
513
+ <a href="<?php print esc_attr($link->url); ?>" target='_blank' class='blc-link-url' title="<?php echo esc_attr($link->url); ?>">
514
+ <?php print $link->url; ?></a>
515
+ <input type='text' id='link-editor-<?php print $link->link_id; ?>'
516
+ value="<?php print esc_attr($link->url); ?>"
517
+ class='blc-link-editor' style='display:none' />
518
+ <?php
519
+ //Output inline action links for the link/URL
520
+ $actions = array();
521
+
522
+ $actions['details'] = "<span class='view'><a class='blc-details-button' href='javascript:void(0)' title='". esc_attr(__('Show more info about this link', 'broken-link-checker')) . "'>". __('Details', 'broken-link-checker') ."</a>";
523
+
524
+ $actions['delete'] = "<span class='delete'><a class='submitdelete blc-unlink-button' title='" . esc_attr( __('Remove this link from all posts', 'broken-link-checker') ). "' ".
525
+ "id='unlink-button-$rownum' href='javascript:void(0);'>" . __('Unlink', 'broken-link-checker') . "</a>";
526
+
527
+ if ( $link->broken ){
528
+ $actions['discard'] = sprintf(
529
+ '<span><a href="#" title="%s" class="blc-discard-button">%s</a>',
530
+ esc_attr(__('Remove this link from the list of broken links and mark it as valid', 'broken-link-checker')),
531
+ __('Not broken', 'broken-link-checker')
532
+ );
533
+ }
534
+
535
+ $actions['edit'] = "<span class='edit'><a href='javascript:void(0)' class='blc-edit-button' title='" . esc_attr( __('Edit link URL' , 'broken-link-checker') ) . "'>". __('Edit URL' , 'broken-link-checker') ."</a>";
536
+
537
+ echo '<div class="row-actions">';
538
+ echo implode(' | </span>', $actions);
539
+
540
+ echo "<span style='display:none' class='blc-cancel-button-container'> " .
541
+ "| <a href='javascript:void(0)' class='blc-cancel-button' title='". esc_attr(__('Cancel URL editing' , 'broken-link-checker')) ."'>". __('Cancel' , 'broken-link-checker') ."</a></span>";
542
+
543
+ echo '</div>';
544
+ }
545
+
546
+ function column_link_text(&$link, $instances){
547
+ if ( empty($instances) ){
548
+ echo '<em>N/A</em>';
549
+ } else {
550
+ $instance = reset($instances);
551
+ echo $instance->ui_get_link_text();
552
+ }
553
+ }
554
+
555
+ function column_status(&$link, $instances){
556
+ printf(
557
+ '<table class="mini-status" title="%s">',
558
+ esc_attr(__('Show more info about this link', 'broken-link-checker'))
559
+ );
560
+
561
+ $status = $link->analyse_status();
562
+
563
+ printf(
564
+ '<tr class="link-status-row link-status-%s">
565
+ <td>
566
+ <span class="http-code">%s</span> <span class="status-text">%s</span>
567
+ </td>
568
+ </tr>',
569
+ $status['code'],
570
+ empty($link->http_code)?'':$link->http_code,
571
+ $status['text']
572
+ );
573
+
574
+ //Last checked...
575
+ if ( $link->last_check != 0 ){
576
+ $last_check = _x('Checked', 'checked how long ago', 'broken-link-checker') . ' ';
577
+ $last_check .= blcUtility::fuzzy_delta(time() - $link->last_check, 'ago');
578
+
579
+ printf(
580
+ '<tr class="link-last-checked"><td>%s</td></tr>',
581
+ $last_check
582
+ );
583
+ }
584
+
585
+
586
+ //Broken for...
587
+ if ( $link->broken ){
588
+ $delta = time() - $link->first_failure;
589
+ $broken_for = blcUtility::fuzzy_delta($delta);
590
+ printf(
591
+ '<tr class="link-broken-for"><td>%s %s</td></tr>',
592
+ __('Broken for', 'broken-link-checker'),
593
+ $broken_for
594
+ );
595
+ }
596
+
597
+ echo '</table>';
598
+ }
599
+
600
+
601
+ function column_new_url(&$link){
602
+ ?>
603
+ <a href="<?php print esc_attr($link->url); ?>" target='_blank' class='blc-link-url' title="<?php echo esc_attr($link->url); ?>">
604
+ <?php print $link->url; ?></a>
605
+ <input type='text' id='link-editor-<?php print $link->link_id; ?>'
606
+ value="<?php print esc_attr($link->url); ?>"
607
+ class='blc-link-editor' style='display:none' />
608
+ <?php
609
+ //Output inline action links for the link/URL
610
+ $actions = array();
611
+
612
+ $actions['edit'] = "<span class='edit'><a href='javascript:void(0)' class='blc-edit-button' title='" . esc_attr( __('Edit link URL' , 'broken-link-checker') ) . "'>". __('Edit URL' , 'broken-link-checker') ."</a>";
613
+
614
+ $actions['delete'] = "<span class='delete'><a class='submitdelete blc-unlink-button' title='" . esc_attr( __('Remove this link from all posts', 'broken-link-checker') ). "' ".
615
+ "id='unlink-button-$rownum' href='javascript:void(0);'>" . __('Unlink', 'broken-link-checker') . "</a>";
616
+
617
+ if ( $link->broken ){
618
+ $actions['discard'] = sprintf(
619
+ '<span><a href="#" title="%s" class="blc-discard-button">%s</a>',
620
+ esc_attr(__('Remove this link from the list of broken links and mark it as valid', 'broken-link-checker')),
621
+ __('Not broken', 'broken-link-checker')
622
+ );
623
+ }
624
+
625
+ echo '<div class="row-actions">';
626
+ echo implode(' | </span>', $actions) .'</span>';
627
+
628
+ echo "<span style='display:none' class='blc-cancel-button-container'> " .
629
+ "| <a href='javascript:void(0)' class='blc-cancel-button' title='". esc_attr(__('Cancel URL editing' , 'broken-link-checker')) ."'>". __('Cancel' , 'broken-link-checker') ."</a></span>";
630
+
631
+ echo '</div>';
632
+
633
+ ?>
634
+ <div class="blc-url-editor-buttons">
635
+ <input type="button" class="button-secondary cancel alignleft blc-cancel-button" value="<?php echo esc_attr(__('Cancel', 'broken-link-checker')); ?>" />
636
+ <input type="button" class="button-primary save alignright blc-update-url-button" value="<?php echo esc_attr(__('Update URL', 'broken-link-checker')); ?>" />
637
+ <img class="waiting" style="display:none;" src="<?php echo esc_url( admin_url( 'images/wpspin_light.gif' ) ); ?>" alt="" />
638
+ </div>
639
+ <?php
640
+ }
641
+
642
+ function column_used_in(&$link, $instances){
643
+ echo '<span class="blc-link-id" style="display:none;">',
644
+ $link->link_id,
645
+ '</span>';
646
+
647
+ if ( !empty($instances) ){
648
+ $instance = reset($instances);
649
+ echo $instance->ui_get_source();
650
+
651
+ $actions = $instance->ui_get_action_links();
652
+
653
+ echo '<div class="row-actions">';
654
+ echo implode(' | </span>', $actions);
655
+ echo '</div>';
656
+
657
+ } else {
658
+ _e("[An orphaned link! This is a bug.]", 'broken-link-checker');
659
+ }
660
+ }
661
+
662
+ function column_new_link_text(&$link, $instances){
663
+ if ( empty($instances) ){
664
+ echo '<em>N/A</em>';
665
+ } else {
666
+ $instance = reset($instances);
667
+ echo $instance->ui_get_link_text();
668
+ }
669
+ }
670
+
671
+ /**
672
+ * Sort a list of link instances to be displayed in the "Broken Links" page.
673
+ *
674
+ * Groups instances by container type and, if $search_link_type is specified,
675
+ * puts instances that have a matching container type or parser type at the
676
+ * beginning.
677
+ *
678
+ * @param array $instances An array of blcLinkInstance objects.
679
+ * @param string $searched_link_type Optional. The required container/parser type.
680
+ * @return array Sorted array.
681
+ */
682
+ function sort_instances_for_display($instances, $searched_link_type = ''){
683
+ $this->searched_link_type = $searched_link_type;
684
+ usort($instances, array(&$this, 'compare_link_instances'));
685
+ return $instances;
686
+ }
687
+
688
+ /**
689
+ * Callback function for sorting link instances.
690
+ *
691
+ * @see blcTablePrinter::sort_instances_for_display()
692
+ *
693
+ * @param blcLinkInstance $a
694
+ * @param blcLinkInstance $b
695
+ * @return int
696
+ */
697
+ function compare_link_instances($a, $b){
698
+ if ( !empty($this->searched_link_type) ){
699
+ if ( ($a->container_type == $this->searched_link_type) || ($a->parser_type == $this->searched_link_type) ){
700
+ if ( ($b->container_type == $this->searched_link_type) || ($b->parser_type == $this->searched_link_type) ){
701
+ return 0;
702
+ } else {
703
+ return -1;
704
+ }
705
+ } else {
706
+ if ( ($b->container_type == $this->searched_link_type) || ($b->parser_type == $this->searched_link_type) ){
707
+ return 1;
708
+ }
709
+ }
710
+ }
711
+
712
+ return strcmp($a->container_type, $b->container_type);
713
+ }
714
+
715
+ }
716
+
717
+ }//class_exists
718
+
719
+ ?>
includes/any-post.php ADDED
@@ -0,0 +1,732 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * The manager to rule all (post) managers.
5
+ *
6
+ * This class dynamically registers container modules for the available post types
7
+ * (including custom post types) and does stuff that pertain to all of them, such
8
+ * as handling save/delete hooks and (re)creating synch records.
9
+ *
10
+ * @package Broken Link Checker
11
+ * @author Janis Elsts
12
+ * @access private
13
+ */
14
+ class blcPostTypeOverlord {
15
+ var $enabled_post_types = array(); //Post types currently selected for link checking
16
+ var $enabled_post_statuses = array('publish'); //Only posts that have one of these statuses shall be checked
17
+
18
+ var $plugin_conf;
19
+ var $resynch_already_done = false;
20
+
21
+ /**
22
+ * Class "constructor". Can't use an actual constructor due to how PHP4 handles object references.
23
+ *
24
+ * Specifically, this class is a singleton. The function needs to pass $this to several other
25
+ * functions (to set up hooks), which will store the reference for later use. However, it appears
26
+ * that in PHP4 the actual value of $this is thrown away right after the constructor finishes, and
27
+ * `new` returns a *copy* of $this. The result is that means getInstance() won't be returning a ref.
28
+ * to the same object as is used for hook callbacks. And that's horrible.
29
+ *
30
+ * Sets up hooks that monitor added/modified/deleted posts and registers
31
+ * virtual modules for all post types.
32
+ *
33
+ * @return void
34
+ */
35
+ function init(){
36
+ $this->plugin_conf = &blc_get_configuration();
37
+
38
+ if ( isset($this->plugin_conf->options['enabled_post_statuses']) ){
39
+ $this->enabled_post_statuses = $this->plugin_conf->options['enabled_post_statuses'];
40
+ }
41
+
42
+ //Register a virtual container module for each enabled post type
43
+ $module_manager = &blcModuleManager::getInstance();
44
+
45
+ $post_types = get_post_types(array(), 'objects');
46
+ $exceptions = array('revision', 'nav_menu_item', 'attachment');
47
+ $built_in = array('post', 'page');
48
+
49
+ foreach($post_types as $post_type => $data){
50
+ if ( in_array($post_type, $exceptions) ){
51
+ continue;
52
+ }
53
+
54
+ $module_manager->register_virtual_module(
55
+ $post_type,
56
+ array(
57
+ 'Name' => $data->labels->name,
58
+ 'ModuleCategory' => 'container',
59
+ 'ModuleContext' => 'all',
60
+ 'ModuleClassName' => 'blcAnyPostContainerManager',
61
+ 'ModuleRequiresPro' => in_array($post_type, $built_in) ? 'false' : 'true',
62
+ )
63
+ );
64
+ }
65
+
66
+ //These hooks update the synch & instance records when posts are added, deleted or modified.
67
+ add_action('delete_post', array(&$this,'post_deleted'));
68
+ add_action('save_post', array(&$this,'post_saved'));
69
+ //We also treat post trashing/untrashing as delete/save.
70
+ add_action('trash_post', array(&$this,'post_deleted'));
71
+ add_action('untrash_post', array(&$this,'post_saved'));
72
+
73
+ //Highlight and nofollow broken links in posts & pages
74
+ if ( $this->plugin_conf->options['mark_broken_links'] || $this->plugin_conf->options['nofollow_broken_links'] ){
75
+ add_filter( 'the_content', array(&$this, 'hook_the_content') );
76
+ if ( $this->plugin_conf->options['mark_broken_links'] && !empty( $this->plugin_conf->options['broken_link_css'] ) ){
77
+ add_action( 'wp_head', array(&$this,'hook_wp_head') );
78
+ }
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Retrieve an instance of the overlord class.
84
+ *
85
+ * @return blcPostTypeOverlord
86
+ */
87
+ function &getInstance(){
88
+ static $instance = null;
89
+ if ( is_null($instance) ){
90
+ $instance = new blcPostTypeOverlord;
91
+ $instance->init();
92
+ }
93
+ return $instance;
94
+ }
95
+
96
+ /**
97
+ * Notify the overlord that a post type is active.
98
+ *
99
+ * Called by individual instances of blcAnyPostContainerManager to let
100
+ * the overlord know that they've been created. Since a module instance
101
+ * is only created if the module is active, this event indicates that
102
+ * the user has enabled the corresponding post type for link checking.
103
+ *
104
+ * @param string $post_type
105
+ * @return void
106
+ */
107
+ function post_type_enabled($post_type){
108
+ if ( !in_array($post_type, $this->enabled_post_types) ){
109
+ $this->enabled_post_types[] = $post_type;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Remove the synch. record and link instances associated with a post when it's deleted
115
+ *
116
+ * @param int $post_id
117
+ * @return void
118
+ */
119
+ function post_deleted($post_id){
120
+ //Get the container type matching the type of the deleted post
121
+ $post = &get_post($post_id);
122
+ if ( !$post ){
123
+ return;
124
+ }
125
+ //Get the associated container object
126
+ $post_container = & blcContainerHelper::get_container( array($post->post_type, intval($post_id)) );
127
+
128
+ if ( $post_container ){
129
+ //Delete it
130
+ $post_container->delete();
131
+ //Clean up any dangling links
132
+ blc_cleanup_links();
133
+ }
134
+ }
135
+
136
+ /**
137
+ * When a post is saved or modified, mark it as unparsed.
138
+ *
139
+ * @param int $post_id
140
+ * @return void
141
+ */
142
+ function post_saved($post_id){
143
+ //Get the container type matching the type of the deleted post
144
+ $post = &get_post($post_id);
145
+ if ( !$post ){
146
+ return;
147
+ }
148
+
149
+ //Only check links in currently enabled post types
150
+ if ( !in_array($post->post_type, $this->enabled_post_types) ) return;
151
+
152
+ //Only check posts that have one of the allowed statuses
153
+ if ( !in_array($post->post_status, $this->enabled_post_statuses) ) return;
154
+
155
+ //Get the container & mark it as unparsed
156
+ $args = array($post->post_type, intval($post_id));
157
+ $post_container = & blcContainerHelper::get_container( $args );
158
+
159
+ $post_container->mark_as_unsynched();
160
+ }
161
+
162
+
163
+ /**
164
+ * Create or update synchronization records for all posts.
165
+ *
166
+ * @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch.
167
+ * @return void
168
+ */
169
+ function resynch($container_type = '', $forced = false){
170
+ global $wpdb;
171
+ //Resynch is expensive in terms of DB performance. Thus we only do it once, processing
172
+ //all post types in one go and ignoring any further resynch requests during this pageload.
173
+ //BUG: This might be a problem if there ever is an actual need to run resynch twice or
174
+ //more per pageload.
175
+ if ( $this->resynch_already_done ){
176
+ return;
177
+ }
178
+
179
+ if ( empty($this->enabled_post_types) ){
180
+ return;
181
+ }
182
+
183
+ $escaped_post_types = array_map(array(&$wpdb, 'escape'), $this->enabled_post_types);
184
+ $escaped_post_statuses = array_map(array(&$wpdb, 'escape'), $this->enabled_post_statuses);
185
+
186
+ if ( $forced ){
187
+ //Create new synchronization records for all posts.
188
+ $q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
189
+ SELECT posts.id, posts.post_type, 0
190
+ FROM {$wpdb->posts} AS posts
191
+ WHERE
192
+ posts.post_status IN (%s)
193
+ AND posts.post_type IN (%s)";
194
+ $q = sprintf(
195
+ $q,
196
+ "'" . implode("', '", $escaped_post_statuses) . "'",
197
+ "'" . implode("', '", $escaped_post_types) . "'"
198
+ );
199
+ $wpdb->query( $q );
200
+ } else {
201
+ //Delete synch records corresponding to posts that no longer exist.
202
+ $q = "DELETE synch.*
203
+ FROM
204
+ {$wpdb->prefix}blc_synch AS synch LEFT JOIN {$wpdb->posts} AS posts
205
+ ON posts.ID = synch.container_id
206
+ WHERE
207
+ synch.container_type IN (%s) AND posts.ID IS NULL";
208
+ $q = sprintf(
209
+ $q,
210
+ "'" . implode("', '", $escaped_post_types) . "'"
211
+ );
212
+ $wpdb->query( $q );
213
+
214
+ //Remove the 'synched' flag from all posts that have been updated
215
+ //since the last time they were parsed/synchronized.
216
+ $q = "UPDATE
217
+ {$wpdb->prefix}blc_synch AS synch
218
+ JOIN {$wpdb->posts} AS posts ON (synch.container_id = posts.ID and synch.container_type=posts.post_type)
219
+ SET
220
+ synched = 0
221
+ WHERE
222
+ synch.last_synch < posts.post_modified";
223
+ $wpdb->query( $q );
224
+
225
+ //Create synch. records for posts that don't have them.
226
+ $q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
227
+ SELECT posts.id, posts.post_type, 0
228
+ FROM
229
+ {$wpdb->posts} AS posts LEFT JOIN {$wpdb->prefix}blc_synch AS synch
230
+ ON (synch.container_id = posts.ID and synch.container_type=posts.post_type)
231
+ WHERE
232
+ posts.post_status IN (%s)
233
+ AND posts.post_type IN (%s)
234
+ AND synch.container_id IS NULL";
235
+ $q = sprintf(
236
+ $q,
237
+ "'" . implode("', '", $escaped_post_statuses) . "'",
238
+ "'" . implode("', '", $escaped_post_types) . "'"
239
+ );
240
+ $wpdb->query($q);
241
+ }
242
+
243
+ $this->resynch_already_done = true;
244
+ }
245
+
246
+ /**
247
+ * Hook for the 'the_content' filter. Scans the current post and adds the 'broken_link'
248
+ * CSS class to all links that are known to be broken. Currently works only on standard
249
+ * HTML links (i.e. the '<a href=...' kind).
250
+ *
251
+ * @param string $content Post content
252
+ * @return string Modified post content.
253
+ */
254
+ function hook_the_content($content){
255
+ global $post, $wpdb;
256
+ if ( empty($post) || !in_array($post->post_type, $this->enabled_post_types)) {
257
+ return $content;
258
+ }
259
+
260
+ //Retrieve info about all occurences of broken links in the current post
261
+ $q = "
262
+ SELECT instances.raw_url
263
+ FROM {$wpdb->prefix}blc_instances AS instances JOIN {$wpdb->prefix}blc_links AS links
264
+ ON instances.link_id = links.link_id
265
+ WHERE
266
+ instances.container_type = %s
267
+ AND instances.container_id = %d
268
+ AND links.broken = 1
269
+ AND parser_type = 'link'
270
+ ";
271
+ $q = $wpdb->prepare($q, $post->post_type, $post->ID);
272
+ $links = $wpdb->get_results($q, ARRAY_A);
273
+
274
+ //Return the content unmodified if there are no broken links in this post.
275
+ if ( empty($links) || !is_array($links) ){
276
+ return $content;
277
+ }
278
+
279
+ //Put the broken link URLs in an array
280
+ $broken_link_urls = array();
281
+ foreach($links as $link){
282
+ $broken_link_urls[] = $link['raw_url'];
283
+ }
284
+
285
+ //Iterate over all HTML links and modify the broken ones
286
+ if ( $parser = & blcParserHelper::get_parser('link') ){
287
+ $content = $parser->multi_edit($content, array(&$this, 'highlight_broken_link'), $broken_link_urls);
288
+ }
289
+
290
+ return $content;
291
+ }
292
+
293
+ /**
294
+ * Analyse a link and add 'broken_link' CSS class if the link is broken.
295
+ *
296
+ * @see blcHtmlLink::multi_edit()
297
+ *
298
+ * @param array $link Associative array of link data.
299
+ * @param array $broken_link_urls List of broken link URLs present in the current post.
300
+ * @return array|string The modified link
301
+ */
302
+ function highlight_broken_link($link, $broken_link_urls){
303
+ if ( !in_array($link['href'], $broken_link_urls) ){
304
+ //Link not broken = return the original link tag
305
+ return $link['#raw'];
306
+ }
307
+
308
+ //Add 'broken_link' to the 'class' attribute (unless already present).
309
+ if ( $this->plugin_conf->options['mark_broken_links'] ){
310
+ if ( isset($link['class']) ){
311
+ $classes = explode(' ', $link['class']);
312
+ if ( !in_array('broken_link', $classes) ){
313
+ $classes[] = 'broken_link';
314
+ $link['class'] = implode(' ', $classes);
315
+ }
316
+ } else {
317
+ $link['class'] = 'broken_link';
318
+ }
319
+ }
320
+
321
+ //Nofollow the link (unless it's already nofollow'ed)
322
+ if ( $this->plugin_conf->options['nofollow_broken_links'] ){
323
+ if ( isset($link['rel']) ){
324
+ $relations = explode(' ', $link['rel']);
325
+ if ( !in_array('nofollow', $relations) ){
326
+ $relations[] = 'nofollow';
327
+ $link['rel'] = implode(' ', $relations);
328
+ }
329
+ } else {
330
+ $link['rel'] = 'nofollow';
331
+ }
332
+ }
333
+
334
+ return $link;
335
+ }
336
+
337
+ /**
338
+ * A hook for the 'wp_head' action. Outputs the user-defined broken link CSS.
339
+ *
340
+ * @return void
341
+ */
342
+ function hook_wp_head(){
343
+ echo '<style type="text/css">',$this->plugin_conf->options['broken_link_css'],'</style>';
344
+ }
345
+ }
346
+
347
+ //Start up the post overlord
348
+ blcPostTypeOverlord::getInstance();
349
+
350
+
351
+ /**
352
+ * Universal container item class used for all post types.
353
+ *
354
+ * @package Broken Link Checker
355
+ * @author Janis Elsts
356
+ * @access public
357
+ */
358
+ class blcAnyPostContainer extends blcContainer {
359
+ var $default_field = 'post_content';
360
+
361
+ /**
362
+ * Get action links for this post.
363
+ *
364
+ * @param string $container_field Ignored.
365
+ * @return array of action link HTML.
366
+ */
367
+ function ui_get_action_links($container_field = ''){
368
+ $actions = array();
369
+
370
+ //Fetch the post (it should be cached already)
371
+ $post = &$this->get_wrapped_object();
372
+ if ( !$post ){
373
+ return $actions;
374
+ }
375
+
376
+ $post_type_object = get_post_type_object($post->post_type);
377
+
378
+ //Each post type can have its own cap requirements
379
+ if ( current_user_can( $post_type_object->cap->edit_post, $this->container_id ) ){
380
+ $actions['edit'] = sprintf(
381
+ '<span class="edit"><a href="%s" title="%s">%s</a>',
382
+ $this->get_edit_url(),
383
+ $post_type_object->labels->edit_item,
384
+ __('Edit')
385
+ );
386
+
387
+ //Trash/Delete link
388
+ if ( current_user_can( $post_type_object->cap->delete_post, $this->container_id ) ){
389
+ if ( $this->can_be_trashed() ) {
390
+ $actions['trash'] = sprintf(
391
+ "<span class='trash'><a class='submitdelete' title='%s' href='%s'>%s</a>",
392
+ esc_attr(__('Move this item to the Trash')),
393
+ get_delete_post_link($this->container_id, '', false),
394
+ __('Trash')
395
+ );
396
+ } else {
397
+ $actions['delete'] = sprintf(
398
+ "<span><a class='submitdelete' title='%s' href='%s'>%s</a>",
399
+ esc_attr(__('Delete this item permanently')),
400
+ get_delete_post_link($this->container_id, '', true),
401
+ __('Delete')
402
+ );
403
+ }
404
+ }
405
+ }
406
+
407
+ //View/Preview link
408
+ $title = get_the_title($this->container_id);
409
+ if ( in_array($post->post_status, array('pending', 'draft')) ) {
410
+ if ( current_user_can($post_type_object->cap->edit_post, $this->container_id) ){
411
+ $actions['view'] = sprintf(
412
+ '<span class="view"><a href="%s" title="%s" rel="permalink">%s</a>',
413
+ esc_url( add_query_arg( 'preview', 'true', get_permalink($this->container_id) ) ),
414
+ esc_attr(sprintf(__('Preview &#8220;%s&#8221;'), $title)),
415
+ __('Preview')
416
+ );
417
+ }
418
+ } elseif ( 'trash' != $post->post_status ) {
419
+ $actions['view'] = sprintf(
420
+ '<span class="view"><a href="%s" title="%s" rel="permalink">%s</a>',
421
+ esc_url( get_permalink($this->container_id) ),
422
+ esc_attr(sprintf(__('View &#8220;%s&#8221;'), $title)),
423
+ __('View')
424
+ );
425
+ }
426
+
427
+ return $actions;
428
+ }
429
+
430
+ /**
431
+ * Get the HTML for displaying the post title in the "Source" column.
432
+ *
433
+ * @param string $container_field Ignored.
434
+ * @param string $context How to filter the output. Optional, defaults to 'display'.
435
+ * @return string HTML
436
+ */
437
+ function ui_get_source($container_field = '', $context = 'display'){
438
+ $source = '<a class="row-title" href="%s" title="%s">%s</a>';
439
+ $source = sprintf(
440
+ $source,
441
+ $this->get_edit_url(),
442
+ esc_attr(__('Edit this item')),
443
+ get_the_title($this->container_id)
444
+ );
445
+
446
+ return $source;
447
+ }
448
+
449
+ /**
450
+ * Get edit URL for this container. Returns the URL of the Dashboard page where the item
451
+ * associated with this container can be edited.
452
+ *
453
+ * @access protected
454
+ *
455
+ * @return string
456
+ */
457
+ function get_edit_url(){
458
+ /*
459
+ The below is a near-exact copy of the get_post_edit_link() function.
460
+ Unfortunately we can't just call that function because it has a hardcoded
461
+ caps-check which fails when called from the email notification script
462
+ executed by Cron.
463
+ */
464
+
465
+ if ( !$post = &$this->get_wrapped_object() ){
466
+ return '';
467
+ }
468
+
469
+ $context = 'display';
470
+ $action = '&amp;action=edit';
471
+
472
+ $post_type_object = get_post_type_object( $post->post_type );
473
+ if ( !$post_type_object ){
474
+ return '';
475
+ }
476
+
477
+ return apply_filters( 'get_edit_post_link', admin_url( sprintf($post_type_object->_edit_link . $action, $post->ID) ), $post->ID, $context );
478
+ }
479
+
480
+ /**
481
+ * Retrieve the post associated with this container.
482
+ *
483
+ * @access protected
484
+ *
485
+ * @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).
486
+ * @return object Post data.
487
+ */
488
+ function &get_wrapped_object($ensure_consistency = false){
489
+ if( $ensure_consistency || is_null($this->wrapped_object) ){
490
+ $this->wrapped_object = &get_post($this->container_id);
491
+ }
492
+ return $this->wrapped_object;
493
+ }
494
+
495
+ /**
496
+ * Update the post associated with this container.
497
+ *
498
+ * @access protected
499
+ *
500
+ * @return bool|WP_Error True on success, an error if something went wrong.
501
+ */
502
+ function update_wrapped_object(){
503
+ if ( is_null($this->wrapped_object) ){
504
+ return new WP_Error(
505
+ 'no_wrapped_object',
506
+ __('Nothing to update', 'broken-link-checker')
507
+ );
508
+ }
509
+
510
+ $id = wp_update_post($this->wrapped_object);
511
+ if ( $id != 0 ){
512
+ return true;
513
+ } else {
514
+ return new WP_Error(
515
+ 'update_failed',
516
+ sprintf(__('Updating post %d failed', 'broken-link-checker'), $this->container_id)
517
+ );
518
+ }
519
+ }
520
+
521
+ /**
522
+ * Get the base URL of the container. For posts, the post permalink is used
523
+ * as the base URL when normalizing relative links.
524
+ *
525
+ * @return string
526
+ */
527
+ function base_url(){
528
+ return get_permalink($this->container_id);
529
+ }
530
+
531
+ /**
532
+ * Delete or trash the post corresponding to this container.
533
+ * Will always move to trash instead of deleting if trash is enabled.
534
+ *
535
+ * @return bool|WP_error
536
+ */
537
+ function delete_wrapped_object(){
538
+ //Note that we don't need to delete the synch record and instances here -
539
+ //wp_delete_post()/wp_trash_post() will run the post_delete/trash hook,
540
+ //which will be caught by blcPostContainerManager, which will in turn
541
+ //delete anything that needs to be deleted.
542
+ if ( EMPTY_TRASH_DAYS ){
543
+ return $this->trash_wrapped_object();
544
+ } else {
545
+ if ( wp_delete_post($this->container_id, true) ){
546
+ return true;
547
+ } else {
548
+ return new WP_Error(
549
+ 'delete_failed',
550
+ sprintf(
551
+ __('Failed to delete post "%s" (%d)', 'broken-link-checker'),
552
+ get_the_title($this->container_id),
553
+ $this->container_id
554
+ )
555
+ );
556
+ };
557
+ }
558
+ }
559
+
560
+ /**
561
+ * Move the post corresponding to this container to the Trash.
562
+ *
563
+ * @return bool|WP_Error
564
+ */
565
+ function trash_wrapped_object(){
566
+ if ( !EMPTY_TRASH_DAYS ){
567
+ return new WP_Error(
568
+ 'trash_disabled',
569
+ sprintf(
570
+ __('Can\'t move post "%s" (%d) to the trash because the trash feature is disabled', 'broken-link-checker'),
571
+ get_the_title($this->container_id),
572
+ $this->container_id
573
+ )
574
+ );
575
+ }
576
+
577
+ $post = &get_post($this->container_id);
578
+ if ( $post->post_status == 'trash' ){
579
+ //Prevent conflicts between post and custom field containers trying to trash the same post.
580
+ //BUG: Post and custom field containers shouldn't wrap the same object
581
+ return true;
582
+ }
583
+
584
+ if ( wp_trash_post($this->container_id) ){
585
+ return true;
586
+ } else {
587
+ return new WP_Error(
588
+ 'trash_failed',
589
+ sprintf(
590
+ __('Failed to move post "%s" (%d) to the trash', 'broken-link-checker'),
591
+ get_the_title($this->container_id),
592
+ $this->container_id
593
+ )
594
+ );
595
+ };
596
+ }
597
+
598
+ /**
599
+ * Check if the current user can delete/trash this post.
600
+ *
601
+ * @return bool
602
+ */
603
+ function current_user_can_delete(){
604
+ $post = &$this->get_wrapped_object();
605
+ $post_type_object = get_post_type_object($post->post_type);
606
+ return current_user_can( $post_type_object->cap->delete_post, $this->container_id );
607
+ }
608
+
609
+ function can_be_trashed(){
610
+ return defined('EMPTY_TRASH_DAYS') && EMPTY_TRASH_DAYS;
611
+ }
612
+ }
613
+
614
+
615
+
616
+ /**
617
+ * Universal manager usable for most post types.
618
+ *
619
+ * @package Broken Link Checker
620
+ * @access public
621
+ */
622
+ class blcAnyPostContainerManager extends blcContainerManager {
623
+ var $container_class_name = 'blcAnyPostContainer';
624
+ var $fields = array('post_content' => 'html');
625
+
626
+ function init(){
627
+ parent::init();
628
+
629
+ //Notify the overlord that the post/container type that this instance is
630
+ //responsible for is enabled.
631
+ $overlord = &blcPostTypeOverlord::getInstance();
632
+ $overlord->post_type_enabled($this->container_type);
633
+ }
634
+
635
+ /**
636
+ * Instantiate multiple containers of the container type managed by this class.
637
+ *
638
+ * @param array $containers Array of assoc. arrays containing container data.
639
+ * @param string $purpose An optional code indicating how the retrieved containers will be used.
640
+ * @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
641
+ *
642
+ * @return array of blcPostContainer indexed by "container_type|container_id"
643
+ */
644
+ function get_containers($containers, $purpose = '', $load_wrapped_objects = false){
645
+ $containers = $this->make_containers($containers);
646
+
647
+ //Preload post data if it is likely to be useful later
648
+ $preload = $load_wrapped_objects || in_array($purpose, array(BLC_FOR_DISPLAY, BLC_FOR_PARSING));
649
+ if ( $preload ){
650
+ $post_ids = array();
651
+ foreach($containers as $container){
652
+ $post_ids[] = $container->container_id;
653
+ }
654
+
655
+ $args = array('include' => implode(',', $post_ids));
656
+ $posts = get_posts($args);
657
+
658
+ foreach($posts as $post){
659
+ $key = $this->container_type . '|' . $post->ID;
660
+ if ( isset($containers[$key]) ){
661
+ $containers[$key]->wrapped_object = $post;
662
+ }
663
+ }
664
+ }
665
+
666
+ return $containers;
667
+ }
668
+
669
+ /**
670
+ * Create or update synchronization records for all posts.
671
+ *
672
+ * @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch.
673
+ * @return void
674
+ */
675
+ function resynch($forced = false){
676
+ $overlord = &blcPostTypeOverlord::getInstance();
677
+ $overlord->resynch($this->container_type, $forced);
678
+ }
679
+
680
+ /**
681
+ * Get the message to display after $n posts have been deleted.
682
+ *
683
+ * @param int $n Number of deleted posts.
684
+ * @return string A delete confirmation message, e.g. "5 posts were moved deleted"
685
+ */
686
+ function ui_bulk_delete_message($n){
687
+ //Since the "Trash" feature has been introduced, calling wp_delete_post
688
+ //doesn't actually delete the post (unless you set force_delete to True),
689
+ //just moves it to the trash. So we pick the message accordingly.
690
+ //(If possible, BLC *always* moves to trash instead of deleting permanently.)
691
+ if ( function_exists('wp_trash_post') && EMPTY_TRASH_DAYS ){
692
+ return blcAnyPostContainerManager::ui_bulk_trash_message($n);
693
+ } else {
694
+ $post_type_object = get_post_type_object($this->container_type);
695
+ $type_name = '';
696
+
697
+ if ( $this->container_type == 'post' || is_null($post_type_object) ){
698
+ $delete_msg = _n("%d post deleted.", "%d posts deleted.", $n, 'broken-link-checker');
699
+ } elseif ( $this->container_type == 'page' ){
700
+ $delete_msg = _n("%d page deleted.", "%d pages deleted.", $n, 'broken-link-checker');
701
+ } else {
702
+ $delete_msg = _n('%d "%s" deleted.', '%d "%s" deleted.', $n, 'broken-link-checker');
703
+ $type_name = ($n == 1 ? $post_type_object->labels->singular_name : $post_type_object->labels->name);
704
+ }
705
+ return sprintf($delete_msg, $n, $type_name);
706
+ }
707
+ }
708
+
709
+
710
+ /**
711
+ * Get the message to display after $n posts have been trashed.
712
+ *
713
+ * @param int $n Number of deleted posts.
714
+ * @return string A confirmation message, e.g. "5 posts were moved to trash"
715
+ */
716
+ function ui_bulk_trash_message($n){
717
+ $post_type_object = get_post_type_object($this->container_type);
718
+ $type_name = '';
719
+
720
+ if ( $this->container_type == 'post' || is_null($post_type_object) ){
721
+ $delete_msg = _n("%d post moved to the Trash.", "%d posts moved to the Trash.", $n, 'broken-link-checker');
722
+ } elseif ( $this->container_type == 'page' ){
723
+ $delete_msg = _n("%d page moved to the Trash.", "%d pages moved to the Trash.", $n, 'broken-link-checker');
724
+ } else {
725
+ $delete_msg = _n('%d "%s" moved to the Trash.', '%d "%s" moved to the Trash.', $n, 'broken-link-checker');
726
+ $type_name = ($n == 1 ? $post_type_object->labels->singular_name : $post_type_object->labels->name);
727
+ }
728
+ return sprintf($delete_msg, $n, $type_name);
729
+ }
730
+ }
731
+
732
+ ?>
includes/checkers.php CHANGED
@@ -8,7 +8,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
@@ -63,33 +63,19 @@ class blcChecker {
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
  /**
@@ -101,7 +87,27 @@ class blcCheckerRegistry {
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
  }
@@ -110,27 +116,5 @@ class blcCheckerRegistry {
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
  ?>
8
  * @package Broken Link Checker
9
  * @access public
10
  */
11
+ class blcChecker extends blcModule {
12
 
13
  /**
14
  * Priority determines the order in which the plugin will try all registered checkers
63
  }
64
  }
65
 
66
+ class blcCheckerHelper {
 
67
 
68
+ /**
69
+ * Get a reference to a specific checker.
70
+ *
71
+ * @uses blcModuleManager::get_module()
72
+ *
73
+ * @param string $checker_id
74
+ * @return blcChecker
75
+ */
76
+ function &get_checker($checker_id){
77
+ $manager = & blcModuleManager::getInstance();
78
+ return $manager->get_module($checker_id, true, 'checker');
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  }
80
 
81
  /**
87
  function &get_checker_for($url){
88
  $parsed = @parse_url($url);
89
 
90
+ $manager = & blcModuleManager::getInstance();
91
+ $active_checkers = $manager->get_active_by_category('checker');
92
+
93
+ foreach($active_checkers as $module_id => $module_data){
94
+ //Try the URL pattern in the header first. If it doesn't match,
95
+ //we can avoid loading the module altogether.
96
+ if ( !empty($module_data['ModuleCheckerUrlPattern']) ){
97
+ if ( !preg_match($module_data['ModuleCheckerUrlPattern'], $url) ){
98
+ continue;
99
+ }
100
+ }
101
+
102
+ $checker = & $manager->get_module($module_id);
103
+
104
+ if ( !$checker ){
105
+ continue;
106
+ }
107
+
108
+ //The can_check() method can perform more sophisticated filtering,
109
+ //or just return true if the checker thinks matching the URL regex
110
+ //is sufficient.
111
  if ( $checker->can_check($url, $parsed) ){
112
  return $checker;
113
  }
116
  return null;
117
  }
118
  }
119
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  ?>
config-manager.php → includes/config-manager.php RENAMED
File without changes
includes/containers.php CHANGED
@@ -1,298 +1,145 @@
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
- * Return a singleton instance of this class.
40
- *
41
- * @return blcContainerRegistry
42
- */
43
- function &getInstance(){
44
- static $instance = null;
45
- if ( is_null($instance) ){
46
- $instance = new blcContainerRegistry;
47
- }
48
- return $instance;
49
  }
50
 
51
  /**
52
- * Register a new container type.
53
- *
54
- * A "container type" comprises three things :
55
- * - An alphanumeric container type name, e.g. "post"
56
- * - A class representing an individual container. Must inherit from blcContainer.
57
- * - A "manager" class that builds container objects, knows how to retrieve multiple
58
- * containers and their associated data from the database, and handles all other
59
- * ancillary tasks associated with the particular container type (e.g. WP hooks).
60
  *
61
- * When registering a new container type you only need to provide the container type
62
- * name and the container manager class name.
 
 
63
  *
64
- * @see blcContainer
65
- * @see blcContainerManager
 
66
  *
67
- * @param string $container_type
68
- * @param string $manager_class
69
- * @return bool True on success, false if the container type is already registered.
 
 
70
  */
71
- function register_container( $container_type, $manager_class ){
72
- if ( isset($this->registered_managers[$container_type]) ){
73
- return false;
74
- }
75
-
76
- $this->registered_managers[$container_type] = new $manager_class($container_type);
77
-
78
- return true;
79
- }
80
-
81
- /**
82
- * Retrieve a list of all registered container types and their managers.
83
- *
84
- * @return array An associative array of container manager objects indexed by container type.
85
- */
86
- function get_registered_containers(){
87
- return $this->registered_managers;
88
  }
89
 
90
  /**
91
- * Get the manager associated with a container type.
92
  *
93
- * @param string $container_type
94
- * @param string $fallback If there is no manager associated with $container_type, return the manager of this container type instead.
95
- * @return blcContainerManager|null
96
  */
97
- function &get_manager( $container_type, $fallback = '' ){
98
- if ( isset($this->registered_managers[$container_type]) ){
99
- return $this->registered_managers[$container_type];
100
- } elseif ( !empty($fallback) && isset($this->registered_managers[$fallback]) ) {
101
- return $this->registered_managers[$fallback];
102
- } else {
103
- return null;
104
  }
 
105
  }
106
 
107
  /**
108
- * Retrieve or instantiate a container object.
109
  *
110
- * Pass an array containing the container type (string) and ID (int) to retrieve the container
111
- * from the database. Alternatively, pass an associative array to create a new container object
112
- * from the data in the array.
113
  *
114
- * @param array $container Either [container_type, container_id], or an assoc. array of container data.
115
- * @return blcContainer|null
116
  */
117
- function get_container( $container ){
118
- global $wpdb;
119
-
120
- if ( !is_array($container) || ( count($container) < 2 ) ){
121
- return null;
122
- }
123
-
124
- if ( is_string($container[0]) && is_numeric($container[1]) ){
125
- //The argument is in the [container_type, id] format
126
- //Fetch the container's synch record.
127
- $q = "SELECT * FROM {$wpdb->prefix}blc_synch WHERE container_type = %s AND container_id = %d";
128
- $q = $wpdb->prepare($q, $container[0], $container[1]);
129
- $rez = $wpdb->get_row($q, ARRAY_A);
130
-
131
- if ( empty($rez) ){
132
- //The container wasn't found, so we'll create a new one.
133
- $container = array(
134
- 'container_type' => $container[0],
135
- 'container_id' => $container[1],
136
- );
137
- } else {
138
- $container = $rez;
139
- }
140
- }
141
-
142
- if ( !isset($this->registered_managers[$container['container_type']]) ){
143
- return null;
144
- }
145
-
146
- $manager = $this->registered_managers[$container['container_type']];
147
-
148
- return $manager->get_container($container);
149
  }
150
 
151
- /**
152
- * Retrieve or instantiate multiple link containers.
153
- *
154
- * Takes an array of container specifications and returns an array of container objects.
155
- * Each input array entry should be an array and consist either of a container type (string)
156
- * and container ID (int), or name => value pairs describing a container object.
157
- *
158
- * @see blcContainerRegistry::get_container()
159
- *
160
- * @param array $containers
161
- * @param string $purpose Optional code indicating how the retrieved containers will be used.
162
- * @param string $fallback The fallback container type to use for unrecognized containers.
163
- * @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
164
- * @return array of blcContainer indexed by "container_type|container_id"
165
- */
166
- function get_containers( $containers, $purpose = '', $fallback = '', $load_wrapped_objects = false ){
167
- global $wpdb;
168
-
169
- //If the input is invalid or empty, return an empty array.
170
- if ( !is_array($containers) || (count($containers) < 1) ) {
171
- return array();
172
- }
173
-
174
- $first = reset($containers);
175
- if ( !is_array($first) ){
176
- return array();
177
- }
178
-
179
- if ( isset($first[0]) && is_string($first[0]) && is_numeric($first[1]) ){
180
- //The argument is an array of [container_type, id].
181
- //Divide the container IDs by container type.
182
- $by_type = array();
183
-
184
- foreach($containers as $container){
185
- if ( isset($by_type[$container[0]]) ){
186
- array_push($by_type[$container[0]], intval($container[1]));
187
- } else {
188
- $by_type[$container[0]] = array( intval($container[1]) );
189
- }
190
- }
191
-
192
- //Build the SQL to fetch all the specified containers
193
- $q = "SELECT *
194
- FROM {$wpdb->prefix}blc_synch
195
- WHERE";
196
-
197
- $pieces = array();
198
- foreach($by_type as $container_type => $container_ids){
199
- $pieces[] = '( container_type = "'. $wpdb->escape($container_type) .'" AND container_id IN ('. implode(', ', $container_ids) .') )';
200
- }
201
-
202
- $q .= implode("\n\t OR ", $pieces);
203
-
204
- //Fetch the container synch. records from the DB.
205
- $containers = $wpdb->get_results($q, ARRAY_A);
206
- }
207
-
208
- /*
209
- Divide the inputs into separate arrays by container type (again), then invoke
210
- the appropriate manager for each type to instantiate the container objects.
211
- */
212
-
213
- //At this point, $containers is an array of assoc. arrays comprising container data.
214
- $by_type = array();
215
- foreach($containers as $container){
216
- if ( isset($by_type[$container['container_type']]) ){
217
- array_push($by_type[$container['container_type']], $container);
218
- } else {
219
- $by_type[$container['container_type']] = array($container);
220
- }
221
- }
222
-
223
- $results = array();
224
- foreach($by_type as $container_type => $entries){
225
- $manager = & $this->get_manager($container_type, $fallback);
226
- if ( !is_null($manager) ){
227
- $partial_results = $manager->get_containers($entries, $purpose, $load_wrapped_objects);
228
- $results = array_merge($results, $partial_results);
229
- }
230
- }
231
-
232
- return $results;
233
  }
234
 
235
- /**
236
- * Retrieve link containers that need to be synchronized (parsed).
237
- *
238
- * @param integer $max_results The maximum number of containers to return. Defaults to returning all unsynched containers.
239
- * @return array of blcContainer
240
- */
241
- function get_unsynched_containers($max_results = 0){
242
- global $wpdb;
243
-
244
- $q = "SELECT * FROM {$wpdb->prefix}blc_synch WHERE synched = 0";
245
- if ( $max_results > 0 ){
246
- $q .= " LIMIT $max_results";
247
- }
248
-
249
- $container_data = $wpdb->get_results($q, ARRAY_A);
250
- //FB::log($container_data, "Unsynched containers");
251
- if( empty($container_data) ){
252
- return array();
253
- }
254
-
255
- $containers = $this->get_containers($container_data, BLC_FOR_PARSING, 'dummy');
256
- return $containers;
257
  }
258
 
259
  /**
260
- * (Re)create and update synchronization records for all supported containers.
261
- * Calls the resynch() method of all registered managers.
262
  *
263
- * @param bool $forced If true, assume that no synch. records exist and build all of them from scratch.
264
- * @return void
265
  */
266
- function resynch($forced = false){
267
- global $wpdb;
268
-
269
- foreach($this->registered_managers as $manager){
270
- $manager->resynch($forced);
271
- }
 
 
 
 
 
272
  }
273
 
274
  /**
275
- * Get the message to display after $n containers of a specific type have been deleted.
276
  *
277
- * @param string $container_type
278
- * @param int $n Number of deleted containers.
279
  * @return string A delete confirmation message, e.g. "5 posts were moved to trash"
280
  */
281
- function ui_bulk_delete_message($container_type, $n){
282
- $manager = & $this->get_manager($container_type);
283
- if ( is_null($manager) ){
284
- return sprintf(__("Container type '%s' not recognized", 'broken-link-checker'), $container_type);
285
- } else {
286
- return $manager->ui_bulk_delete_message($n);
287
- }
288
  }
289
  }
290
 
291
- //Init the container registry & make it global
292
- $GLOBALS['blc_container_registry'] = & blcContainerRegistry::getInstance();
293
-
294
-
295
-
296
  /**
297
  * The base class for link containers. All containers should extend this class.
298
  *
@@ -423,7 +270,7 @@ class blcContainer {
423
  //FB::log($name, "Parsing field");
424
 
425
  //Get all parsers applicable to this field
426
- $parsers = blc_get_parsers( $format, $this->container_type );
427
  //FB::log($parsers, "Applicable parsers");
428
 
429
  if ( empty($parsers) ) continue;
@@ -562,7 +409,7 @@ class blcContainer {
562
  }
563
 
564
  /**
565
- * Delete the WP entity corresponding to this container.
566
  * Also remove the synch. record of the container and all associated instances.
567
  *
568
  * Must be over-ridden in a sub-class.
@@ -571,10 +418,43 @@ class blcContainer {
571
  */
572
  function delete_wrapped_object(){
573
  trigger_error('Function blcContainer::delete_wrapped_object() must be over-ridden in a sub-class', E_USER_ERROR);
574
- }
575
 
 
 
 
 
 
 
 
 
 
 
576
 
577
- /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578
  * Change all links with the specified URL to a new URL.
579
  *
580
  * @param string $field_name
@@ -582,7 +462,7 @@ class blcContainer {
582
  * @param string $new_url
583
  * @param string $old_url
584
  * @param string $old_raw_url
585
- * @return string|WP_Error The new value of raw_url on success, or an error object if something went wrong.
586
  */
587
  function edit_link($field_name, $parser, $new_url, $old_url = '', $old_raw_url = ''){
588
  //Ensure we're operating on a consistent copy of the wrapped object.
@@ -614,15 +494,16 @@ class blcContainer {
614
  if ( is_wp_error($edit_result) ){
615
  return $edit_result;
616
  }
617
-
618
  //Update the field with the new value returned by the parser.
619
  $update_result = $this->update_field( $field_name, $edit_result['content'], $old_value );
620
  if ( is_wp_error($update_result) ){
621
  return $update_result;
622
  }
623
 
624
- //Return the new "raw" URL.
625
- return $edit_result['raw_url'];
 
626
  }
627
 
628
  /**
@@ -634,7 +515,7 @@ class blcContainer {
634
  * @param string $raw_url
635
  * @return bool|WP_Error True on success, or an error object if something went wrong.
636
  */
637
- function unlink($field_name, $parser, $url, $raw_url =''){
638
  //Ensure we're operating on a consistent copy of the wrapped object.
639
  $this->get_wrapped_object(true);
640
 
@@ -699,232 +580,322 @@ class blcContainer {
699
  //Should be over-ridden in a sub-class.
700
  return '';
701
  }
 
702
  }
703
 
 
704
  /**
705
- * The base class for link container manager.
706
- *
707
- * Sub-classes should override at least the get_containers() and resynch() methods.
708
- *
709
  * @package Broken Link Checker
710
- * @access public
711
  */
712
- class blcContainerManager {
713
-
714
- var $container_type = '';
715
- var $container_class_name = 'blcContainer';
716
-
717
- function __construct($container_type){
718
- $this->container_type = $container_type;
719
- $this->init();
720
- }
721
 
722
  /**
723
- * blcContainerManager::blcContainerManager()
724
- * Old-style class constructor
725
  *
726
- * @return void
 
 
727
  */
728
- function blcContainerManager($container_type){
729
- $this->__construct($container_type);
 
 
 
 
 
 
 
 
 
730
  }
731
 
732
  /**
733
- * Do whatever setup necessary that wasn't already done in the constructor.
734
  *
735
- * This method was added so that sub-classes would have something "safe" to
736
- * over-ride without having to deal with PHP4/5 constructors and remember to
737
- * call the parent constructor.
738
- *
739
- * @return void
740
- */
741
- function init(){
742
- //Do nothing. Sub-classes might use it to set up hooks, etc.
743
- }
744
-
745
- /**
746
- * Instantiate a link container.
747
  *
748
- * @param array $container An associative array of container data.
749
- * @return blcContainer
750
  */
751
- function get_container($container){
752
- return new $this->container_class_name($container);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
753
  }
754
 
755
  /**
756
- * Instantiate multiple containers of the container type managed by this class and optionally
757
- * pre-load container data used for display/parsing.
758
  *
759
- * Sub-classes should, if possible, use the $purpose argument to pre-load any extra data required for
760
- * the specified task right away, instead of making multiple DB roundtrips later. For example, if
761
- * $purpose is set to the BLC_FOR_DISPLAY constant, you might want to preload any DB data that the
762
- * container will need in blcContainer::ui_get_source().
763
  *
764
- * @see blcContainer::make_containers()
765
- * @see blcContainer::ui_get_source()
766
- * @see blcContainer::ui_get_action_links()
767
  *
768
- * @param array $containers Array of assoc. arrays containing container data.
769
- * @param string $purpose An optional code indicating how the retrieved containers will be used.
770
- * @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
771
- *
772
  * @return array of blcContainer indexed by "container_type|container_id"
773
  */
774
- function get_containers($containers, $purpose = '', $load_wrapped_objects = false){
775
- return $this->make_containers($containers);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
776
  }
777
 
778
  /**
779
- * Instantiate multiple containers of the container type managed by this class
780
  *
781
- * @param array $containers Array of assoc. arrays containing container data.
782
- * @return array of blcContainer indexed by "container_type|container_id"
783
  */
784
- function make_containers($containers){
785
- $results = array();
786
- foreach($containers as $container){
787
- $key = $container['container_type'] . '|' . $container['container_id'];
788
- $results[ $key ] = $this->get_container($container);
 
789
  }
790
- return $results;
 
 
 
 
 
 
 
 
791
  }
792
 
793
  /**
794
- * Create or update synchronization records for all containers managed by this class.
795
- *
796
- * Must be over-ridden in subclasses.
797
  *
798
- * @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch.
799
  * @return void
800
  */
801
  function resynch($forced = false){
802
- trigger_error('Function blcContainerManager::resynch() must be over-ridden in a sub-class', E_USER_ERROR);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
803
  }
804
 
805
  /**
806
- * Get the message to display after $n containers have been deleted.
807
  *
 
808
  * @param int $n Number of deleted containers.
809
  * @return string A delete confirmation message, e.g. "5 posts were moved to trash"
810
  */
811
- function ui_bulk_delete_message($n){
812
- return sprintf(
813
- _n(
814
- "%d '%s' has been deleted",
815
- "%d '%s' have been deleted",
816
- $n,
817
- 'broken-link-checker'
818
- ),
819
- $n,
820
- $this->container_type
821
- );
822
  }
823
- }
824
-
825
- /**
826
- * Register a new link container.
827
- *
828
- * Each container type is implemented by two related classes - the container manager class, and the
829
- * container class itself. The container manager handles tasks like creating new instances of the container
830
- * class, loading & filtering them to the database, handling WordPress hooks relevant to the container
831
- * type, and so on. The container class handles the synchronization, parsing and modification of
832
- * individual link containers (e.g. posts or comments).
833
- *
834
- * @see blcContainer
835
- * @see blcContainerManager
836
- *
837
- * @param string $container_type A unique string identifying the container, e.g. "post" or "comment".
838
- * @param string $manager_class Class name of the container manager corresponding to the container type you want to register.
839
- * @return bool True if the container was successfully registered, false otherwise.
840
- */
841
- function blc_register_container( $container_type, $manager_class ){
842
- $instance = & blcContainerRegistry::getInstance();
843
- return $instance->register_container($container_type, $manager_class);
844
- }
845
-
846
- /**
847
- * Retrieve or create a link container.
848
- *
849
- * @param array $container Either (container type, id), or an assoc. array of container data.
850
- * @return blcContainer|null Returns null if the container type is unrecognized.
851
- */
852
- function blc_get_container($container){
853
- $instance = & blcContainerRegistry::getInstance();
854
- return $instance->get_container($container);
855
- }
856
-
857
- /**
858
- * Retrieve multiple link containers.
859
- *
860
- * If you specify the optional $purpose argument, the relevant container managers might be
861
- * able to use it to (pre)load container data more efficiently - e.g. loading all posts associated
862
- * with the selected batch of containers in one go, instead of running a separate DB query for
863
- * each individual container later.
864
- *
865
- * There are several predefined constants that can be used for the $purpose argument :
866
- * BLC_FOR_EDITING, BLC_FOR_PARSING, BLC_FOR_DISPLAY
867
- *
868
- * For containers not found in the DB, the behaviour of this function depends on the format
869
- * of the $containers argument. If $containers is an array of [container_type, container_id] pairs,
870
- * only existing containers will be returned. If it's an array of assoc. arrays specifying container
871
- * data, the function will create and return container objects for all specified containers.
872
- *
873
- * @see blc_get_container()
874
- *
875
- * @param array $containers Array of (container_type, id) pairs, or assoc. arrays with container data.
876
- * @param string $purpose Optional code indicating how the retrieved containers are going to be used.
877
- * @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
878
- * @return array of blcContainer indexed by 'container_type|container_id'
879
- */
880
- function blc_get_containers( $containers, $purpose = '', $load_wrapped_objects = false ){
881
- $instance = & blcContainerRegistry::getInstance();
882
- return $instance->get_containers($containers, $purpose, '', $load_wrapped_objects);
883
- }
884
-
885
- /**
886
- * Retrieve link containers that need to be synchronized (parsed).
887
- *
888
- * @param integer $max_results The maximum number of containers to return. Defaults to returning all unsynched containers.
889
- * @return array of blcContainer
890
- */
891
- function blc_get_unsynched_containers($max_results = 0){
892
- $instance = & blcContainerRegistry::getInstance();
893
- return $instance->get_unsynched_containers($max_results);
894
- }
895
-
896
- /**
897
- * (Re)create and update synchronization records for all supported containers.
898
- * Calls the resynch() method of all registered managers.
899
- *
900
- * @param bool $forced If true, assume that no synch. records exist and build all of them from scratch.
901
- * @return void
902
- */
903
- function blc_resynch_containers($forced = false){
904
- $instance = & blcContainerRegistry::getInstance();
905
- $instance->resynch($forced);
906
- }
907
-
908
- /**
909
- * Remove synch. records that reference container types not currently loaded
910
- *
911
- * @return bool
912
- */
913
- function blc_cleanup_containers(){
914
- global $wpdb;
915
-
916
- $containerRegistry = & blcContainerRegistry::getInstance();
917
- $loaded_containers = array_keys($containerRegistry->get_registered_containers());
918
- $loaded_containers = array_map(array(&$wpdb, 'escape'), $loaded_containers);
919
- $loaded_containers = "'" . implode("', '", $loaded_containers) . "'";
920
-
921
- $q = "DELETE synch.*
922
- FROM {$wpdb->prefix}blc_synch AS synch
923
- WHERE
924
- synch.container_type NOT IN ({$loaded_containers})";
925
- $rez = $wpdb->query($q);
926
 
927
- return $rez !== false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
928
  }
929
 
930
  ?>
1
  <?php
2
 
3
  /**
4
+ * The base class for link container managers.
5
+ *
6
+ * Sub-classes should override at least the get_containers() and resynch() methods.
 
 
 
 
 
7
  *
8
  * @package Broken Link Checker
9
+ * @access public
10
  */
11
+ class blcContainerManager extends blcModule {
12
 
13
+ var $container_type = '';
14
+ var $fields = array();
15
+ var $container_class_name = 'blcContainer';
16
 
17
  /**
18
+ * Do whatever setup necessary that wasn't already done in the constructor.
19
  *
20
+ * This method was added so that sub-classes would have something "safe" to
21
+ * over-ride without having to deal with PHP4/5 constructors.
22
+ *
23
  * @return void
24
  */
25
+ function init(){
26
+ parent::init();
27
+ $this->container_type = $this->module_id;
28
+ //Sub-classes might also use it to set up hooks, etc.
29
  }
30
 
31
  /**
32
+ * Instantiate a link container.
 
33
  *
34
+ * @param array $container An associative array of container data.
35
+ * @return blcContainer
36
  */
37
+ function &get_container($container){
38
+ $container['fields'] = $this->get_parseable_fields();
39
+ return new $this->container_class_name($container);
 
 
 
 
 
 
 
 
 
 
 
 
40
  }
41
 
42
  /**
43
+ * Instantiate multiple containers of the container type managed by this class and optionally
44
+ * pre-load container data used for display/parsing.
 
 
 
 
 
 
45
  *
46
+ * Sub-classes should, if possible, use the $purpose argument to pre-load any extra data required for
47
+ * the specified task right away, instead of making multiple DB roundtrips later. For example, if
48
+ * $purpose is set to the BLC_FOR_DISPLAY constant, you might want to preload any DB data that the
49
+ * container will need in blcContainer::ui_get_source().
50
  *
51
+ * @see blcContainer::make_containers()
52
+ * @see blcContainer::ui_get_source()
53
+ * @see blcContainer::ui_get_action_links()
54
  *
55
+ * @param array $containers Array of assoc. arrays containing container data.
56
+ * @param string $purpose An optional code indicating how the retrieved containers will be used.
57
+ * @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
58
+ *
59
+ * @return array of blcContainer indexed by "container_type|container_id"
60
  */
61
+ function get_containers($containers, $purpose = '', $load_wrapped_objects = false){
62
+ return $this->make_containers($containers);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  }
64
 
65
  /**
66
+ * Instantiate multiple containers of the container type managed by this class
67
  *
68
+ * @param array $containers Array of assoc. arrays containing container data.
69
+ * @return array of blcContainer indexed by "container_type|container_id"
 
70
  */
71
+ function make_containers($containers){
72
+ $results = array();
73
+ foreach($containers as $container){
74
+ $key = $container['container_type'] . '|' . $container['container_id'];
75
+ $results[ $key ] = & $this->get_container($container);
 
 
76
  }
77
+ return $results;
78
  }
79
 
80
  /**
81
+ * Create or update synchronization records for all containers managed by this class.
82
  *
83
+ * Must be over-ridden in subclasses.
 
 
84
  *
85
+ * @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch.
86
+ * @return void
87
  */
88
+ function resynch($forced = false){
89
+ trigger_error('Function blcContainerManager::resynch() must be over-ridden in a sub-class', E_USER_ERROR);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  }
91
 
92
+ /**
93
+ * Resynch when activated.
94
+ *
95
+ * @uses blcContainerManager::resynch()
96
+ *
97
+ * @return void
98
+ */
99
+ function activated(){
100
+ $this->resynch();
101
+ blc_got_unsynched_items();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  }
103
 
104
+ /**
105
+ * Get a list of the parseable fields and their formats common to all containers of this type.
106
+ *
107
+ * @return array Associative array of formats indexed by field name.
108
+ */
109
+ function get_parseable_fields(){
110
+ return $this->fields;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  }
112
 
113
  /**
114
+ * Get the message to display after $n containers have been deleted.
 
115
  *
116
+ * @param int $n Number of deleted containers.
117
+ * @return string A delete confirmation message, e.g. "5 posts were moved to trash"
118
  */
119
+ function ui_bulk_delete_message($n){
120
+ return sprintf(
121
+ _n(
122
+ "%d '%s' has been deleted",
123
+ "%d '%s' have been deleted",
124
+ $n,
125
+ 'broken-link-checker'
126
+ ),
127
+ $n,
128
+ $this->container_type
129
+ );
130
  }
131
 
132
  /**
133
+ * Get the message to display after $n containers have been moved to the trash.
134
  *
135
+ * @param int $n Number of trashed containers.
 
136
  * @return string A delete confirmation message, e.g. "5 posts were moved to trash"
137
  */
138
+ function ui_bulk_trash_message($n){
139
+ return $this->ui_bulk_delete_message($n);
 
 
 
 
 
140
  }
141
  }
142
 
 
 
 
 
 
143
  /**
144
  * The base class for link containers. All containers should extend this class.
145
  *
270
  //FB::log($name, "Parsing field");
271
 
272
  //Get all parsers applicable to this field
273
+ $parsers = blcParserHelper::get_parsers( $format, $this->container_type );
274
  //FB::log($parsers, "Applicable parsers");
275
 
276
  if ( empty($parsers) ) continue;
409
  }
410
 
411
  /**
412
+ * Delete or trash the WP entity corresponding to this container. Should prefer moving to trash, if possible.
413
  * Also remove the synch. record of the container and all associated instances.
414
  *
415
  * Must be over-ridden in a sub-class.
418
  */
419
  function delete_wrapped_object(){
420
  trigger_error('Function blcContainer::delete_wrapped_object() must be over-ridden in a sub-class', E_USER_ERROR);
421
+ }
422
 
423
+ /**
424
+ * Move the WP entity corresponding to this container to the Trash.
425
+ *
426
+ * Must be over-riden in a subclass.
427
+ *
428
+ * @return bool|WP_Error
429
+ */
430
+ function trash_wrapped_object(){
431
+ trigger_error('Function blcContainer::trash_wrapped_object() must be over-ridden in a sub-class', E_USER_ERROR);
432
+ }
433
 
434
+ /**
435
+ * Check if the current user can delete/trash this container.
436
+ *
437
+ * Should be over-ridden in a subclass.
438
+ *
439
+ * @return bool
440
+ */
441
+ function current_user_can_delete(){
442
+ return false;
443
+ }
444
+
445
+ /**
446
+ * Determine if this container can be moved to the trash.
447
+ *
448
+ * Should be over-ridden in a subclass.
449
+ *
450
+ * @return bool
451
+ */
452
+ function can_be_trashed(){
453
+ return false;
454
+ }
455
+
456
+
457
+ /**
458
  * Change all links with the specified URL to a new URL.
459
  *
460
  * @param string $field_name
462
  * @param string $new_url
463
  * @param string $old_url
464
  * @param string $old_raw_url
465
+ * @return array|WP_Error The new value of raw_url on success, or an error object if something went wrong.
466
  */
467
  function edit_link($field_name, $parser, $new_url, $old_url = '', $old_raw_url = ''){
468
  //Ensure we're operating on a consistent copy of the wrapped object.
494
  if ( is_wp_error($edit_result) ){
495
  return $edit_result;
496
  }
497
+
498
  //Update the field with the new value returned by the parser.
499
  $update_result = $this->update_field( $field_name, $edit_result['content'], $old_value );
500
  if ( is_wp_error($update_result) ){
501
  return $update_result;
502
  }
503
 
504
+ //Return the new values to the instance.
505
+ unset($edit_result['content']); //(Except content, which it doesn't need.)
506
+ return $edit_result;
507
  }
508
 
509
  /**
515
  * @param string $raw_url
516
  * @return bool|WP_Error True on success, or an error object if something went wrong.
517
  */
518
+ function unlink($field_name, &$parser, $url, $raw_url =''){
519
  //Ensure we're operating on a consistent copy of the wrapped object.
520
  $this->get_wrapped_object(true);
521
 
580
  //Should be over-ridden in a sub-class.
581
  return '';
582
  }
583
+
584
  }
585
 
586
+
587
  /**
588
+ * An utility class for working with link container types.
589
+ * All methods of this class should be called statically.
590
+ *
 
591
  * @package Broken Link Checker
 
592
  */
593
+ class blcContainerHelper {
 
 
 
 
 
 
 
 
594
 
595
  /**
596
+ * Get the manager associated with a container type.
 
597
  *
598
+ * @param string $container_type
599
+ * @param string $fallback If there is no manager associated with $container_type, return the manager of this container type instead.
600
+ * @return blcContainerManager|null
601
  */
602
+ function &get_manager( $container_type, $fallback = '' ){
603
+ $module_manager = & blcModuleManager::getInstance();
604
+ $container_manager = null;
605
+
606
+ if ( $container_manager = & $module_manager->get_module($container_type, true, 'container') ){
607
+ return $container_manager;
608
+ } elseif ( !empty($fallback) && ( $container_manager = & $module_manager->get_module($fallback, true, 'container') ) ) {
609
+ return $container_manager;
610
+ } else {
611
+ return null;
612
+ }
613
  }
614
 
615
  /**
616
+ * Retrieve or instantiate a container object.
617
  *
618
+ * Pass an array containing the container type (string) and ID (int) to retrieve the container
619
+ * from the database. Alternatively, pass an associative array to create a new container object
620
+ * from the data in the array.
 
 
 
 
 
 
 
 
 
621
  *
622
+ * @param array $container Either [container_type, container_id], or an assoc. array of container data.
623
+ * @return blcContainer|null
624
  */
625
+ function &get_container( $container ){
626
+ global $wpdb;
627
+
628
+ if ( !is_array($container) || ( count($container) < 2 ) ){
629
+ return null;
630
+ }
631
+
632
+ if ( is_string($container[0]) && is_numeric($container[1]) ){
633
+ //The argument is in the [container_type, id] format
634
+ //Fetch the container's synch record.
635
+ $q = "SELECT * FROM {$wpdb->prefix}blc_synch WHERE container_type = %s AND container_id = %d";
636
+ $q = $wpdb->prepare($q, $container[0], $container[1]);
637
+ $rez = $wpdb->get_row($q, ARRAY_A);
638
+
639
+ if ( empty($rez) ){
640
+ //The container wasn't found, so we'll create a new one.
641
+ $container = array(
642
+ 'container_type' => $container[0],
643
+ 'container_id' => $container[1],
644
+ );
645
+ } else {
646
+ $container = $rez;
647
+ }
648
+ }
649
+
650
+ if ( !($manager = & blcContainerHelper::get_manager($container['container_type'])) ){
651
+ return null;
652
+ }
653
+
654
+ return $manager->get_container($container);
655
  }
656
 
657
  /**
658
+ * Retrieve or instantiate multiple link containers.
 
659
  *
660
+ * Takes an array of container specifications and returns an array of container objects.
661
+ * Each input array entry should be an array and consist either of a container type (string)
662
+ * and container ID (int), or name => value pairs describing a container object.
 
663
  *
664
+ * @see blcContainerHelper::get_container()
 
 
665
  *
666
+ * @param array $containers
667
+ * @param string $purpose Optional code indicating how the retrieved containers will be used.
668
+ * @param string $fallback The fallback container type to use for unrecognized containers.
669
+ * @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
670
  * @return array of blcContainer indexed by "container_type|container_id"
671
  */
672
+ function get_containers( $containers, $purpose = '', $fallback = '', $load_wrapped_objects = false ){
673
+ global $wpdb;
674
+
675
+ //If the input is invalid or empty, return an empty array.
676
+ if ( !is_array($containers) || (count($containers) < 1) ) {
677
+ return array();
678
+ }
679
+
680
+ $first = reset($containers);
681
+ if ( !is_array($first) ){
682
+ return array();
683
+ }
684
+
685
+ if ( isset($first[0]) && is_string($first[0]) && is_numeric($first[1]) ){
686
+ //The argument is an array of [container_type, id].
687
+ //Divide the container IDs by container type.
688
+ $by_type = array();
689
+
690
+ foreach($containers as $container){
691
+ if ( isset($by_type[$container[0]]) ){
692
+ array_push($by_type[$container[0]], intval($container[1]));
693
+ } else {
694
+ $by_type[$container[0]] = array( intval($container[1]) );
695
+ }
696
+ }
697
+
698
+ //Build the SQL to fetch all the specified containers
699
+ $q = "SELECT *
700
+ FROM {$wpdb->prefix}blc_synch
701
+ WHERE";
702
+
703
+ $pieces = array();
704
+ foreach($by_type as $container_type => $container_ids){
705
+ $pieces[] = '( container_type = "'. $wpdb->escape($container_type) .'" AND container_id IN ('. implode(', ', $container_ids) .') )';
706
+ }
707
+
708
+ $q .= implode("\n\t OR ", $pieces);
709
+
710
+ //Fetch the container synch. records from the DB.
711
+ $containers = $wpdb->get_results($q, ARRAY_A);
712
+ }
713
+
714
+ /*
715
+ Divide the inputs into separate arrays by container type (again), then invoke
716
+ the appropriate manager for each type to instantiate the container objects.
717
+ */
718
+
719
+ //At this point, $containers is an array of assoc. arrays comprising container data.
720
+ $by_type = array();
721
+ foreach($containers as $container){
722
+ if ( isset($by_type[$container['container_type']]) ){
723
+ array_push($by_type[$container['container_type']], $container);
724
+ } else {
725
+ $by_type[$container['container_type']] = array($container);
726
+ }
727
+ }
728
+
729
+ $results = array();
730
+ foreach($by_type as $container_type => $entries){
731
+ $manager = & blcContainerHelper::get_manager($container_type, $fallback);
732
+ if ( !is_null($manager) ){
733
+ $partial_results = $manager->get_containers($entries, $purpose, $load_wrapped_objects);
734
+ $results = array_merge($results, $partial_results);
735
+ }
736
+ }
737
+
738
+ return $results;
739
  }
740
 
741
  /**
742
+ * Retrieve link containers that need to be synchronized (parsed).
743
  *
744
+ * @param integer $max_results The maximum number of containers to return. Defaults to returning all unsynched containers.
745
+ * @return array of blcContainer
746
  */
747
+ function get_unsynched_containers($max_results = 0){
748
+ global $wpdb;
749
+
750
+ $q = "SELECT * FROM {$wpdb->prefix}blc_synch WHERE synched = 0";
751
+ if ( $max_results > 0 ){
752
+ $q .= " LIMIT $max_results";
753
  }
754
+
755
+ $container_data = $wpdb->get_results($q, ARRAY_A);
756
+ //FB::log($container_data, "Unsynched containers");
757
+ if( empty($container_data) ){
758
+ return array();
759
+ }
760
+
761
+ $containers = blcContainerHelper::get_containers($container_data, BLC_FOR_PARSING, 'dummy');
762
+ return $containers;
763
  }
764
 
765
  /**
766
+ * (Re)create and update synchronization records for all supported containers.
767
+ * Calls the resynch() method of all registered managers.
 
768
  *
769
+ * @param bool $forced If true, assume that no synch. records exist and build all of them from scratch.
770
  * @return void
771
  */
772
  function resynch($forced = false){
773
+ global $wpdb;
774
+
775
+ $module_manager = & blcModuleManager::getInstance();
776
+ $active_managers = $module_manager->get_active_by_category('container');
777
+ foreach($active_managers as $module_id => $module_data){
778
+ $manager = & $module_manager->get_module($module_id);
779
+ if ( $manager ){
780
+ $manager->resynch($forced);
781
+ }
782
+ }
783
+ }
784
+
785
+ /**
786
+ * Mark as unparsed all containers that match one of the the specified formats or
787
+ * container types and that were last parsed after a specific timestamp.
788
+ *
789
+ * Used by newly activated parsers to force the containers they're interested in
790
+ * to resynchronize and thus let the parser process them.
791
+ *
792
+ * @param array $formats Associative array of timestamps, indexed by format IDs.
793
+ * @param array $container_types Associative array of timestamps, indexed by container types.
794
+ * @return bool
795
+ */
796
+ function mark_as_unsynched_where($formats, $container_types){
797
+ global $wpdb;
798
+
799
+ //Find containers that match any of the specified formats and add them to
800
+ //the list of container types that need to be marked as unsynched.
801
+ $module_manager = &blcModuleManager::getInstance();
802
+ $containers = $module_manager->get_active_by_category('container');
803
+
804
+ foreach($containers as $module_id => $module_data){
805
+ if ( $container_manager = &$module_manager->get_module($module_id) ){
806
+ $fields = $container_manager->get_parseable_fields();
807
+ $container_type = $container_manager->container_type;
808
+ foreach($formats as $format => $timestamp){
809
+ if ( in_array($format, $fields) ){
810
+ //Choose the earliest timestamp
811
+ if ( isset($container_types[$container_type]) ){
812
+ $container_types[$container_type] = min($timestamp, $container_types[$container_type]);
813
+ } else {
814
+ $container_types[$container_type] = $timestamp;
815
+ }
816
+ }
817
+ }
818
+ };
819
+ }
820
+
821
+ if ( empty($container_types) ){
822
+ return true;
823
+ }
824
+
825
+ //Build the query to update all synch. records that match one of the specified
826
+ //container types and have been parsed after the specified time.
827
+ $q = "UPDATE {$wpdb->prefix}blc_synch SET synched = 0 WHERE ";
828
+
829
+ $pieces = array();
830
+ foreach($container_types as $container_type => $timestamp){
831
+ $pieces[] = $wpdb->prepare(
832
+ '(container_type = %s AND last_synch >= %s)',
833
+ $container_type,
834
+ date('Y-m-d H:i:s', $timestamp)
835
+ );
836
+ }
837
+
838
+ $q .= implode(' OR ', $pieces);
839
+
840
+ $rez = ($wpdb->query($q) !== false);
841
+ blc_got_unsynched_items();
842
+
843
+ return $rez;
844
+ }
845
+
846
+ /**
847
+ * Remove synch. records that reference container types not currently loaded
848
+ *
849
+ * @return bool
850
+ */
851
+ function cleanup_containers(){
852
+ global $wpdb;
853
+
854
+ $module_manager = & blcModuleManager::getInstance();
855
+ $active_containers = $module_manager->get_escaped_ids('container');
856
+
857
+ $q = "DELETE synch.*
858
+ FROM {$wpdb->prefix}blc_synch AS synch
859
+ WHERE
860
+ synch.container_type NOT IN ({$active_containers})";
861
+ $rez = $wpdb->query($q);
862
+
863
+ return $rez !== false;
864
  }
865
 
866
  /**
867
+ * Get the message to display after $n containers of a specific type have been deleted.
868
  *
869
+ * @param string $container_type
870
  * @param int $n Number of deleted containers.
871
  * @return string A delete confirmation message, e.g. "5 posts were moved to trash"
872
  */
873
+ function ui_bulk_delete_message($container_type, $n){
874
+ $manager = & blcContainerHelper::get_manager($container_type);
875
+ if ( is_null($manager) ){
876
+ return sprintf(__("Container type '%s' not recognized", 'broken-link-checker'), $container_type);
877
+ } else {
878
+ return $manager->ui_bulk_delete_message($n);
879
+ }
 
 
 
 
880
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
881
 
882
+ /**
883
+ * Get the message to display after $n containers of a specific type have been moved to the trash.
884
+ *
885
+ * @see blcContainerHelper::ui_bulk_delete_message()
886
+ *
887
+ * @param string $container_type
888
+ * @param int $n
889
+ * @return string
890
+ */
891
+ function ui_bulk_trash_message($container_type, $n){
892
+ $manager = & blcContainerHelper::get_manager($container_type);
893
+ if ( is_null($manager) ){
894
+ return sprintf(__("Container type '%s' not recognized", 'broken-link-checker'), $container_type);
895
+ } else {
896
+ return $manager->ui_bulk_trash_message($n);
897
+ }
898
+ }
899
  }
900
 
901
  ?>
includes/containers/post.php DELETED
@@ -1,464 +0,0 @@
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="' . esc_attr(__('Edit this post')) . '">' . __('Edit') . '</a>';
17
-
18
- if ( constant('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&amp;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="' . esc_attr(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
- esc_attr(__('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 string
55
- */
56
- function get_edit_url(){
57
- /*
58
- The below is a near-exact copy of the get_post_edit_link() function.
59
- Unfortunately we can't just call that function because it has a hardcoded
60
- caps-check which fails when called from the email notification script
61
- executed by Cron.
62
- */
63
-
64
- if ( !$post = &get_post( $this->container_id ) ){
65
- return '';
66
- }
67
-
68
- $context = 'display';
69
-
70
- if ( function_exists('get_post_type_object') ){
71
- //WP 3.0
72
- if ( 'display' == $context )
73
- $action = '&amp;action=edit';
74
- else
75
- $action = '&action=edit';
76
-
77
- $post_type_object = get_post_type_object( $post->post_type );
78
- if ( !$post_type_object ){
79
- return '';
80
- }
81
-
82
- return apply_filters( 'get_edit_post_link', admin_url( sprintf($post_type_object->_edit_link . $action, $post->ID) ), $post->ID, $context );
83
-
84
- } else {
85
- //WP 2.9.x
86
- if ( 'display' == $context )
87
- $action = 'action=edit&amp;';
88
- else
89
- $action = 'action=edit&';
90
-
91
- switch ( $post->post_type ) :
92
- case 'page' :
93
- $file = 'page';
94
- $var = 'post';
95
- break;
96
- case 'attachment' :
97
- $file = 'media';
98
- $var = 'attachment_id';
99
- break;
100
- case 'revision' :
101
- $file = 'revision';
102
- $var = 'revision';
103
- $action = '';
104
- break;
105
- default :
106
- $file = 'post';
107
- $var = 'post';
108
- break;
109
- endswitch;
110
-
111
- return apply_filters( 'get_edit_post_link', admin_url("$file.php?{$action}$var=$post->ID"), $post->ID, $context );
112
-
113
- }
114
- }
115
-
116
- /**
117
- * Retrieve the post associated with this container.
118
- *
119
- * @access protected
120
- *
121
- * @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).
122
- * @return object Post data.
123
- */
124
- function &get_wrapped_object($ensure_consistency = false){
125
- if( $ensure_consistency || is_null($this->wrapped_object) ){
126
- $this->wrapped_object = &get_post($this->container_id);
127
- }
128
- return $this->wrapped_object;
129
- }
130
-
131
- /**
132
- * Update the post associated with this container.
133
- *
134
- * @access protected
135
- *
136
- * @return bool|WP_Error True on success, an error if something went wrong.
137
- */
138
- function update_wrapped_object(){
139
- if ( is_null($this->wrapped_object) ){
140
- return new WP_Error(
141
- 'no_wrapped_object',
142
- __('Nothing to update', 'broken-link-checker')
143
- );
144
- }
145
-
146
- $id = wp_update_post($this->wrapped_object);
147
- if ( $id != 0 ){
148
- return true;
149
- } else {
150
- return new WP_Error(
151
- 'update_failed',
152
- sprintf(__('Updating post %d failed', 'broken-link-checker'), $this->container_id)
153
- );
154
- }
155
- }
156
-
157
- /**
158
- * Get the base URL of the container. For posts, the post permalink is used
159
- * as the base URL when normalizing relative links.
160
- *
161
- * @return string
162
- */
163
- function base_url(){
164
- return get_permalink($this->container_id);
165
- }
166
-
167
- /**
168
- * Delete the post corresponding to this container.
169
- *
170
- * @return bool|WP_error
171
- */
172
- function delete_wrapped_object(){
173
- if ( wp_delete_post($this->container_id) ){
174
- //Note that we don't need to delete the synch record and instances here -
175
- //wp_delete_post() will run the post_delete hook, which will be caught
176
- //by blcPostContainerManager, which will delete anything that needs to be
177
- //deleted.
178
- return true;
179
- } else {
180
- return new WP_Error(
181
- 'delete_failed',
182
- sprintf(
183
- __('Failed to delete post "%s" (%d)', 'broken-link-checker'),
184
- get_the_title($this->container_id),
185
- $this->container_id
186
- )
187
- );
188
- };
189
- }
190
- }
191
-
192
- class blcPostContainerManager extends blcContainerManager {
193
- var $container_class_name = 'blcPostContainer';
194
-
195
- var $_conf; //Keep a local reference to the BLC configuration manager. Yields a minor performance benefit.
196
-
197
- /**
198
- * Set up hooks that monitor added/modified/deleted posts.
199
- *
200
- * @return void
201
- */
202
- function init(){
203
- //These hooks update the synch & instance records when posts are added, deleted or modified.
204
- add_action('delete_post', array(&$this,'post_deleted'));
205
- add_action('save_post', array(&$this,'post_saved'));
206
- //We also treat post trashing/untrashing as delete/save.
207
- add_action('trash_post', array(&$this,'post_deleted'));
208
- add_action('untrash_post', array(&$this,'post_saved'));
209
-
210
- //Highlight and nofollow broken links in posts & pages
211
- $this->_conf = & blc_get_configuration();
212
- if ( $this->_conf->options['mark_broken_links'] || $this->_conf->options['nofollow_broken_links'] ){
213
- add_filter( 'the_content', array(&$this,'hook_the_content') );
214
- if ( $this->_conf->options['mark_broken_links'] && !empty( $this->_conf->options['broken_link_css'] ) ){
215
- add_action( 'wp_head', array(&$this,'hook_wp_head') );
216
- }
217
- }
218
- }
219
-
220
- /**
221
- * Remove the synch. record and link instances associated with a post when it's deleted
222
- *
223
- * @param int $post_id
224
- * @return void
225
- */
226
- function post_deleted($post_id){
227
- //Get the associated container object
228
- $post_container = blc_get_container( array($this->container_type, intval($post_id)) );
229
- //Delete it
230
- $post_container->delete();
231
- //Clean up any dangling links
232
- blc_cleanup_links();
233
- }
234
-
235
- /**
236
- * When a post is saved or modified, mark it as unparsed.
237
- *
238
- * @param int $post_id
239
- * @return void
240
- */
241
- function post_saved($post_id){
242
- //Get the container
243
- $args = array($this->container_type, intval($post_id));
244
- $post_container = blc_get_container( $args );
245
-
246
- //Get the post
247
- $post = $post_container->get_wrapped_object();
248
-
249
- //Only check links in posts, not revisions and attachments
250
- if ( ($post->post_type != 'post') && ($post->post_type != 'page') ) return;
251
- //Only check published posts
252
- if ( $post->post_status != 'publish' ) return;
253
-
254
- $post_container->mark_as_unsynched();
255
- }
256
-
257
-
258
- /**
259
- * Instantiate multiple containers of the container type managed by this class.
260
- *
261
- * @param array $containers Array of assoc. arrays containing container data.
262
- * @param string $purpose An optional code indicating how the retrieved containers will be used.
263
- * @param bool $load_wrapped_objects Preload wrapped objects regardless of purpose.
264
- *
265
- * @return array of blcPostContainer indexed by "container_type|container_id"
266
- */
267
- function get_containers($containers, $purpose = '', $load_wrapped_objects = false){
268
- $containers = $this->make_containers($containers);
269
-
270
- //Preload post data if it is likely to be useful later
271
- $preload = $load_wrapped_objects || in_array($purpose, array(BLC_FOR_DISPLAY, BLC_FOR_PARSING));
272
- if ( $preload ){
273
- $post_ids = array();
274
- foreach($containers as $container){
275
- $post_ids[] = $container->container_id;
276
- }
277
-
278
- $args = array('include' => implode(',', $post_ids));
279
- $posts = get_posts($args);
280
-
281
- foreach($posts as $post){
282
- $key = $this->container_type . '|' . $post->ID;
283
- if ( isset($containers[$key]) ){
284
- $containers[$key]->wrapped_object = $post;
285
- }
286
- }
287
- }
288
-
289
- return $containers;
290
- }
291
-
292
- /**
293
- * Create or update synchronization records for all posts.
294
- *
295
- * @param bool $forced If true, assume that all synch. records are gone and will need to be recreated from scratch.
296
- * @return void
297
- */
298
- function resynch($forced = false){
299
- global $wpdb;
300
-
301
- if ( $forced ){
302
- //Create new synchronization records for all posts.
303
- $q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
304
- SELECT id, 'post', 0
305
- FROM {$wpdb->posts}
306
- WHERE
307
- {$wpdb->posts}.post_status = 'publish'
308
- AND {$wpdb->posts}.post_type IN ('post', 'page')";
309
- $wpdb->query( $q );
310
- } else {
311
- //Delete synch records corresponding to posts that no longer exist.
312
- $q = "DELETE synch.*
313
- FROM
314
- {$wpdb->prefix}blc_synch AS synch LEFT JOIN {$wpdb->posts} AS posts
315
- ON posts.ID = synch.container_id
316
- WHERE
317
- synch.container_type = 'post' AND posts.ID IS NULL";
318
- $wpdb->query( $q );
319
-
320
- //Remove the 'synched' flag from all posts that have been updated
321
- //since the last time they were parsed/synchronized.
322
- $q = "UPDATE
323
- {$wpdb->prefix}blc_synch AS synch
324
- JOIN {$wpdb->posts} AS posts ON (synch.container_id = posts.ID and synch.container_type='post')
325
- SET
326
- synched = 0
327
- WHERE
328
- synch.last_synch < posts.post_modified";
329
- $wpdb->query( $q );
330
-
331
- //Create synch. records for posts that don't have them.
332
- $q = "INSERT INTO {$wpdb->prefix}blc_synch(container_id, container_type, synched)
333
- SELECT id, 'post', 0
334
- FROM
335
- {$wpdb->posts} AS posts LEFT JOIN {$wpdb->prefix}blc_synch AS synch
336
- ON (synch.container_id = posts.ID and synch.container_type='post')
337
- WHERE
338
- posts.post_status = 'publish'
339
- AND posts.post_type IN ('post', 'page')
340
- AND synch.container_id IS NULL";
341
- $wpdb->query($q);
342
- }
343
- }
344
-
345
- /**
346
- * Get the message to display after $n posts have been deleted.
347
- *
348
- * @param int $n Number of deleted posts.
349
- * @return string A delete confirmation message, e.g. "5 posts were moved to trash"
350
- */
351
- function ui_bulk_delete_message($n){
352
- //Since the "Trash" feature has been introduced, calling wp_delete_post
353
- //doesn't actually delete the post (unless you set force_delete to True),
354
- //just moves it to the trash. So we pick the message accordingly.
355
- if ( function_exists('wp_trash_post') && EMPTY_TRASH_DAYS ){
356
- $delete_msg = _n("%d post moved to the trash", "%d posts moved to the trash", $n, 'broken-link-checker');
357
- } else {
358
- $delete_msg = _n("%d post deleted", "%d posts deleted", $n, 'broken-link-checker');
359
- }
360
- return sprintf($delete_msg, $n);
361
- }
362
-
363
- /**
364
- * Hook for the 'the_content' filter. Scans the current post and adds the 'broken_link'
365
- * CSS class to all links that are known to be broken. Currently works only on standard
366
- * HTML links (i.e. the '<a href=...' kind).
367
- *
368
- * @param string $content Post content
369
- * @return string Modified post content.
370
- */
371
- function hook_the_content($content){
372
- global $post, $wpdb;
373
- if ( empty($post) ) return $content;
374
-
375
- //Retrieve info about all occurences of broken links in the current post
376
- $q = "
377
- SELECT instances.raw_url
378
- FROM {$wpdb->prefix}blc_instances AS instances JOIN {$wpdb->prefix}blc_links AS links
379
- ON instances.link_id = links.link_id
380
- WHERE
381
- instances.container_type = %s
382
- AND instances.container_id = %d
383
- AND links.broken = 1
384
- AND parser_type = 'link'
385
- ";
386
- $q = $wpdb->prepare($q, $this->container_type, $post->ID);
387
- $links = $wpdb->get_results($q, ARRAY_A);
388
-
389
- //Return the content unmodified if there are no broken links in this post.
390
- if ( empty($links) || !is_array($links) ){
391
- return $content;
392
- }
393
-
394
- //Put the broken link URLs in an array
395
- $broken_link_urls = array();
396
- foreach($links as $link){
397
- $broken_link_urls[] = $link['raw_url'];
398
- }
399
-
400
- //Iterate over all HTML links and modify the broken ones
401
- $parser = &blc_get_parser('link');
402
- $content = $parser->multi_edit($content, array(&$this, 'highlight_broken_link'), $broken_link_urls);
403
-
404
- return $content;
405
- }
406
-
407
- /**
408
- * Analyse a link and add 'broken_link' CSS class if the link is broken.
409
- *
410
- * @see blcHtmlLink::multi_edit()
411
- *
412
- * @param array $link Associative array of link data.
413
- * @param array $broken_link_urls List of broken link URLs present in the current post.
414
- * @return array|string The modified link
415
- */
416
- function highlight_broken_link($link, $broken_link_urls){
417
- if ( !in_array($link['href'], $broken_link_urls) ){
418
- //Link not broken = return the original link tag
419
- return $link['#raw'];
420
- }
421
-
422
- //Add 'broken_link' to the 'class' attribute (unless already present).
423
- if ( $this->_conf->options['mark_broken_links'] ){
424
- if ( isset($link['class']) ){
425
- $classes = explode(' ', $link['class']);
426
- if ( !in_array('broken_link', $classes) ){
427
- $classes[] = 'broken_link';
428
- $link['class'] = implode(' ', $classes);
429
- }
430
- } else {
431
- $link['class'] = 'broken_link';
432
- }
433
- }
434
-
435
- //Nofollow the link (unless it's already nofollow'ed)
436
- if ( $this->_conf->options['nofollow_broken_links'] ){
437
- if ( isset($link['rel']) ){
438
- $relations = explode(' ', $link['rel']);
439
- if ( !in_array('nofollow', $relations) ){
440
- $relations[] = 'nofollow';
441
- $link['rel'] = implode(' ', $relations);
442
- }
443
- } else {
444
- $link['rel'] = 'nofollow';
445
- }
446
- }
447
-
448
- return $link;
449
- }
450
-
451
- /**
452
- * A hook for the 'wp_head' action. Outputs the user-defined broken link CSS.
453
- *
454
- * @return void
455
- */
456
- function hook_wp_head(){
457
- $conf = & blc_get_configuration();
458
- echo '<style type="text/css">',$conf->options['broken_link_css'],'</style>';
459
- }
460
- }
461
-
462
- blc_register_container('post', 'blcPostContainerManager');
463
-
464
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/extra-strings.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ _x("Basic HTTP", "module name", "broken-link-checker");
3
+ _x("Blogroll items", "module name", "broken-link-checker");
4
+ _x("Comments", "module name", "broken-link-checker");
5
+ _x("Custom fields", "module name", "broken-link-checker");
6
+ _x("Embedded DailyMotion videos", "module name", "broken-link-checker");
7
+ _x("Embedded Vimeo videos", "module name", "broken-link-checker");
8
+ _x("Embedded YouTube videos", "module name", "broken-link-checker");
9
+ _x("HTML images", "module name", "broken-link-checker");
10
+ _x("HTML links", "module name", "broken-link-checker");
11
+ _x("MediaFire API", "module name", "broken-link-checker");
12
+ _x("MegaUpload API", "module name", "broken-link-checker");
13
+ _x("Plaintext URLs", "module name", "broken-link-checker");
14
+ _x("RapidShare API", "module name", "broken-link-checker");
15
+ _x("YouTube API", "module name", "broken-link-checker");
16
+ _x("Posts", "module name", "broken-link-checker");
17
+ _x("Pages", "module name", "broken-link-checker");
18
+ ?>
includes/instances.php CHANGED
@@ -95,7 +95,7 @@ class blcLinkInstance {
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',
@@ -104,7 +104,7 @@ class blcLinkInstance {
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',
@@ -125,6 +125,16 @@ class blcLinkInstance {
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.
@@ -141,7 +151,7 @@ class blcLinkInstance {
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',
@@ -150,7 +160,7 @@ class blcLinkInstance {
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',
@@ -296,7 +306,7 @@ class blcLinkInstance {
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;
@@ -312,7 +322,7 @@ class blcLinkInstance {
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;
@@ -325,8 +335,8 @@ class blcLinkInstance {
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
 
@@ -346,7 +356,7 @@ class blcLinkInstance {
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;
@@ -358,8 +368,8 @@ class blcLinkInstance {
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 = '';
@@ -409,7 +419,7 @@ class blcLinkInstance {
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);
@@ -431,7 +441,7 @@ class blcLinkInstance {
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 {
@@ -449,7 +459,7 @@ class blcLinkInstance {
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 {
@@ -482,16 +492,12 @@ function blc_get_instances( $link_ids, $purpose = '', $load_containers = false,
482
 
483
  //Skip instances that reference containers or parsers that aren't currently loaded
484
  if ( !$include_invalid ){
485
- $containerRegistry = & blcContainerRegistry::getInstance();
486
- $loaded_containers = array_keys($containerRegistry->get_registered_containers());
487
- $parserRegistry = & blcParserRegistry::getInstance();
488
- $loaded_parsers = array_keys($parserRegistry->get_registered_parsers());
489
-
490
- $loaded_containers = array_map(array(&$wpdb, 'escape'), $loaded_containers);
491
- $loaded_parsers = array_map(array(&$wpdb, 'escape'), $loaded_parsers);
492
 
493
- $q .= " AND container_type IN ('" . implode("', '", $loaded_containers) . "') ";
494
- $q .= " AND parser_type IN ('" . implode("', '", $loaded_parsers) . "') ";
495
  }
496
 
497
  $results = $wpdb->get_results($q, ARRAY_A);
@@ -513,7 +519,7 @@ function blc_get_instances( $link_ids, $purpose = '', $load_containers = false,
513
  );
514
  }
515
 
516
- $containers = blc_get_containers($container_ids, $purpose, $load_wrapped_objects);
517
  }
518
 
519
  //Create an object for each instance and group them by link ID
@@ -550,16 +556,12 @@ function blc_get_usable_instance_count(){
550
  $q = "SELECT COUNT(instance_id) FROM {$wpdb->prefix}blc_instances WHERE 1";
551
 
552
  //Skip instances that reference containers or parsers that aren't currently loaded
553
- $containerRegistry = & blcContainerRegistry::getInstance();
554
- $loaded_containers = array_keys($containerRegistry->get_registered_containers());
555
- $parserRegistry = & blcParserRegistry::getInstance();
556
- $loaded_parsers = array_keys($parserRegistry->get_registered_parsers());
557
 
558
- $loaded_containers = array_map(array(&$wpdb, 'escape'), $loaded_containers);
559
- $loaded_parsers = array_map(array(&$wpdb, 'escape'), $loaded_parsers);
560
-
561
- $q .= " AND container_type IN ('" . implode("', '", $loaded_containers) . "') ";
562
- $q .= " AND parser_type IN ('" . implode("', '", $loaded_parsers) . "') ";
563
 
564
  return $wpdb->get_var($q);
565
  }
@@ -581,22 +583,16 @@ function blc_cleanup_instances(){
581
  synch.container_id IS NULL";
582
  $rez = $wpdb->query($q);
583
 
584
- $containerRegistry = & blcContainerRegistry::getInstance();
585
- $loaded_containers = array_keys($containerRegistry->get_registered_containers());
586
- $parserRegistry = & blcParserRegistry::getInstance();
587
- $loaded_parsers = array_keys($parserRegistry->get_registered_parsers());
588
-
589
- $loaded_containers = array_map(array(&$wpdb, 'escape'), $loaded_containers);
590
- $loaded_containers = "'" . implode("', '", $loaded_containers) . "'";
591
-
592
- $loaded_parsers = array_map(array(&$wpdb, 'escape'), $loaded_parsers);
593
- $loaded_parsers = "'" . implode("', '", $loaded_parsers) . "'";
594
 
595
  $q = "DELETE instances.*
596
  FROM {$wpdb->prefix}blc_instances AS instances
597
  WHERE
598
- instances.container_type NOT IN ({$loaded_containers}) OR
599
- instances.parser_type NOT IN ({$loaded_parsers})";
600
  $rez2 = $wpdb->query($q);
601
 
602
  return ($rez !== false) && ($rez2 !== false);
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',
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',
125
  //indicating success.
126
  $this->raw_url = $result;
127
  return true;
128
+ } elseif ( is_array($result) ){
129
+ //More advanced containers/parsers may return an array of values to
130
+ //modify several fields at once.
131
+ $allowed_fields = array('raw_url', 'link_text', 'link_context');
132
+ foreach($result as $key => $value){
133
+ if ( in_array($key, $allowed_fields) ){
134
+ $this->$key = $value;
135
+ }
136
+ }
137
+ return true;
138
  } else {
139
  //Otherwise, it will return an error object. In this case we'll
140
  //just pass it back to the caller and let them sort it out.
151
  function unlink( $url = null ) {
152
 
153
  //Get the container that contains this link
154
+ $container = & $this->get_container();
155
  if ( is_null($container) ){
156
  return new WP_Error(
157
  'container_not_found',
160
  }
161
 
162
  //Get the parser.
163
+ $parser = & $this->get_parser();
164
  if ( is_null($parser) ){
165
  return new WP_Error(
166
  'parser_not_found',
306
  * @return string The associated URL, or an empty string if the instance is currently not assigned to any link.
307
  */
308
  function get_url(){
309
+ $link = & $this->get_link();
310
 
311
  if ( !is_null($link) ){
312
  return $link->url;
322
  */
323
  function &get_container(){
324
  if( is_null($this->_container) ){
325
+ $this->_container = & blcContainerHelper::get_container( array($this->container_type, $this->container_id) );
326
  }
327
 
328
  return $this->_container;
335
  * @param string $field
336
  * @return void
337
  */
338
+ function set_container(&$new_container, $field = ''){
339
+ $this->_container = &$new_container;
340
 
341
  $this->container_field = $field;
342
 
356
  */
357
  function &get_parser(){
358
  if ( is_null($this->_parser) ){
359
+ $this->_parser = & blcParserHelper::get_parser($this->parser_type);
360
  }
361
 
362
  return $this->_parser;
368
  * @param blcParser|null $new_parser
369
  * @return void
370
  */
371
+ function set_parser(&$new_parser){
372
+ $this->_parser = &$new_parser;
373
 
374
  if ( is_null($new_parser) ){
375
  $this->parser_type = '';
419
  * @return string HTML
420
  */
421
  function ui_get_link_text($context = 'display'){
422
+ $parser = & $this->get_parser();
423
 
424
  if ( !is_null($parser) ){
425
  $text = $parser->ui_get_link_text($this, $context);
441
  */
442
  function ui_get_action_links(){
443
  //The container is responsible for generating the links.
444
+ $container = & $this->get_container();
445
  if ( !is_null($container) ){
446
  return $container->ui_get_action_links($this->container_field);
447
  } else {
459
  */
460
  function ui_get_source($context = 'display'){
461
  //The container is also responsible for generating the "Source" column HTML.
462
+ $container = & $this->get_container();
463
  if ( !is_null($container) ){
464
  return $container->ui_get_source($this->container_field, $context);
465
  } else {
492
 
493
  //Skip instances that reference containers or parsers that aren't currently loaded
494
  if ( !$include_invalid ){
495
+ $manager = & blcModuleManager::getInstance();
496
+ $active_containers = $manager->get_escaped_ids('container');
497
+ $active_parsers = $manager->get_escaped_ids('parser');
 
 
 
 
498
 
499
+ $q .= " AND container_type IN ({$active_containers}) ";
500
+ $q .= " AND parser_type IN ({$active_parsers}) ";
501
  }
502
 
503
  $results = $wpdb->get_results($q, ARRAY_A);
519
  );
520
  }
521
 
522
+ $containers = blcContainerHelper::get_containers($container_ids, $purpose, $load_wrapped_objects);
523
  }
524
 
525
  //Create an object for each instance and group them by link ID
556
  $q = "SELECT COUNT(instance_id) FROM {$wpdb->prefix}blc_instances WHERE 1";
557
 
558
  //Skip instances that reference containers or parsers that aren't currently loaded
559
+ $manager = & blcModuleManager::getInstance();
560
+ $active_containers = $manager->get_escaped_ids('container');
561
+ $active_parsers = $manager->get_escaped_ids('parser');
 
562
 
563
+ $q .= " AND container_type IN ({$active_containers}) ";
564
+ $q .= " AND parser_type IN ({$active_parsers}) ";
 
 
 
565
 
566
  return $wpdb->get_var($q);
567
  }
583
  synch.container_id IS NULL";
584
  $rez = $wpdb->query($q);
585
 
586
+ //Delete instances that reference containers and parsers that are no longer active
587
+ $manager = & blcModuleManager::getInstance();
588
+ $active_containers = $manager->get_escaped_ids('container');
589
+ $active_parsers = $manager->get_escaped_ids('parser');
 
 
 
 
 
 
590
 
591
  $q = "DELETE instances.*
592
  FROM {$wpdb->prefix}blc_instances AS instances
593
  WHERE
594
+ instances.container_type NOT IN ({$active_containers}) OR
595
+ instances.parser_type NOT IN ({$active_parsers})";
596
  $rez2 = $wpdb->query($q);
597
 
598
  return ($rez !== false) && ($rez2 !== false);
includes/link-query.php ADDED
@@ -0,0 +1,764 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class for querying, sorting and filtering links.
5
+ * Used as a singleton.
6
+ *
7
+ * @package Broken Link Checker
8
+ * @access public
9
+ */
10
+ class blcLinkQuery {
11
+
12
+ var $native_filters;
13
+ var $search_filter;
14
+ var $custom_filters = array();
15
+
16
+ var $valid_url_params = array();
17
+
18
+ function __construct(){
19
+ //Init. the available native filters.
20
+ $this->native_filters = array(
21
+ 'broken' => array(
22
+ 'params' => array(
23
+ 'where_expr' => '( broken = 1 )',
24
+ ),
25
+ 'name' => __('Broken', 'broken-link-checker'),
26
+ 'heading' => __('Broken Links', 'broken-link-checker'),
27
+ 'heading_zero' => __('No broken links found', 'broken-link-checker'),
28
+ 'native' => true,
29
+ ),
30
+ 'redirects' => array(
31
+ 'params' => array(
32
+ 'where_expr' => '( redirect_count > 0 )',
33
+ ),
34
+ 'name' => __('Redirects', 'broken-link-checker'),
35
+ 'heading' => __('Redirected Links', 'broken-link-checker'),
36
+ 'heading_zero' => __('No redirects found', 'broken-link-checker'),
37
+ 'native' => true,
38
+ ),
39
+
40
+ 'all' => array(
41
+ 'params' => array(
42
+ 'where_expr' => '1',
43
+ ),
44
+ 'name' => __('All', 'broken-link-checker'),
45
+ 'heading' => __('Detected Links', 'broken-link-checker'),
46
+ 'heading_zero' => __('No links found (yet)', 'broken-link-checker'),
47
+ 'native' => true,
48
+ ),
49
+ );
50
+
51
+ //Create the special "search" filter
52
+ $this->search_filter = array(
53
+ 'name' => __('Search', 'broken-link-checker'),
54
+ 'heading' => __('Search Results', 'broken-link-checker'),
55
+ 'heading_zero' => __('No links found for your query', 'broken-link-checker'),
56
+ 'params' => array(),
57
+ 'use_url_params' => true,
58
+ 'hidden' => true,
59
+ );
60
+
61
+ //These search arguments may be passed via the URL if the filter's 'use_url_params' field is set to True.
62
+ //They map to the fields of the search form on the Tools -> Broken Links page. Only these arguments
63
+ //can be used in user-defined filters.
64
+ $this->valid_url_params = array(
65
+ 's_link_text',
66
+ 's_link_url',
67
+ 's_parser_type',
68
+ 's_container_type',
69
+ 's_link_type',
70
+ 's_http_code',
71
+ 's_filter',
72
+ );
73
+ }
74
+
75
+ function blcLinkQuery(){
76
+ $this->__construct();
77
+ }
78
+
79
+ function &getInstance(){
80
+ static $instance = null;
81
+ if ( is_null($instance) ){
82
+ $instance = new blcLinkQuery;
83
+ }
84
+ return $instance;
85
+ }
86
+
87
+ /**
88
+ * Load and return the list of user-defined link filters.
89
+ *
90
+ * @return array An array of custom filter definitions. If there are no custom filters defined returns an empty array.
91
+ */
92
+ function load_custom_filters(){
93
+ global $wpdb;
94
+
95
+ $filter_data = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}blc_filters ORDER BY name ASC", ARRAY_A);
96
+ $filters = array();
97
+
98
+ if ( !empty($filter_data) ) {
99
+ foreach($filter_data as $data){
100
+ wp_parse_str($data['params'], $params);
101
+
102
+ $filters[ 'f'.$data['id'] ] = array(
103
+ 'name' => $data['name'],
104
+ 'params' => $params,
105
+ 'heading' => ucwords($data['name']),
106
+ 'heading_zero' => __('No links found for your query', 'broken-link-checker'),
107
+ 'custom' => true,
108
+ );
109
+ }
110
+ }
111
+
112
+ $this->custom_filters = $filters;
113
+
114
+ return $filters;
115
+ }
116
+
117
+ /**
118
+ * Add a custom link filter.
119
+ *
120
+ * @param string $name Filter name.
121
+ * @param string|array $params Filter params. Either as a query string, or an array.
122
+ * @return string|bool The ID of the newly added filter, or False.
123
+ */
124
+ function create_custom_filter($name, $params){
125
+ global $wpdb;
126
+
127
+ if ( is_array($params) ){
128
+ $params = http_build_query($params, null, '&');
129
+ }
130
+
131
+ //Save the new filter
132
+ $q = $wpdb->prepare(
133
+ "INSERT INTO {$wpdb->prefix}blc_filters(name, params) VALUES (%s, %s)",
134
+ $name, $params
135
+ );
136
+
137
+ if ( $wpdb->query($q) !== false ){
138
+ $filter_id = 'f'.$wpdb->insert_id;
139
+ return $filter_id;
140
+ } else {
141
+ return false;
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Delete a custom filter
147
+ *
148
+ * @param string $filter_id
149
+ * @return bool True on success, False if a database error occured.
150
+ */
151
+ function delete_custom_filter($filter_id){
152
+ global $wpdb;
153
+
154
+ //Remove the "f" character from the filter ID to get its database key
155
+ $filter_id = intval(ltrim($_POST['filter_id'], 'f'));
156
+
157
+ //Try to delete the filter
158
+ $q = $wpdb->prepare("DELETE FROM {$wpdb->prefix}blc_filters WHERE id = %d", $filter_id);
159
+ if ( $wpdb->query($q) !== false ){
160
+ return true;
161
+ } else {
162
+ return false;
163
+ }
164
+ }
165
+
166
+ function get_filters(){
167
+ $filters = array_merge($this->native_filters, $this->custom_filters);
168
+ $filters['search'] = $this->search_filter;
169
+ return $filters;
170
+ }
171
+
172
+ /**
173
+ * Get a link search filter by filter ID.
174
+ *
175
+ * @param string $filter_id
176
+ * @return array|null
177
+ */
178
+ function get_filter($filter_id){
179
+ $filters = $this->get_filters();
180
+ if ( isset($filters[$filter_id]) ){
181
+ return $filters[$filter_id];
182
+ } else {
183
+ return null;
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Get link search parameters from the specified filter.
189
+ *
190
+ * @param array $filter
191
+ * @return array An array of parameters suitable for use with blcLinkQuery::get_links()
192
+ */
193
+ function get_search_params( $filter = null ){
194
+ //If present, the filter's parameters may be saved either as an array or a string.
195
+ $params = array();
196
+ if ( !empty($filter) && !empty($filter['params']) ){
197
+ $params = $filter['params'];
198
+ if ( is_string( $params ) ){
199
+ wp_parse_str($params, $params);
200
+ }
201
+ }
202
+
203
+ //Merge in the parameters from the current request, if required
204
+ if ( isset($filter['use_url_params']) && $filter['use_url_params'] ){
205
+ $params = array_merge($params, $this->get_url_search_params());
206
+ }
207
+
208
+ return $params;
209
+ }
210
+
211
+ /**
212
+ * Extract search query parameters from the current URL
213
+ *
214
+ * @return array
215
+ */
216
+ function get_url_search_params(){
217
+ $url_params = array();
218
+ foreach ($_GET as $param => $value){
219
+ if ( in_array($param, $this->valid_url_params) ){
220
+ $url_params[$param] = $value;
221
+ }
222
+ }
223
+ return $url_params;
224
+ }
225
+
226
+
227
+
228
+ /**
229
+ * A helper method for parsing a list of search criteria and generating the parts of the SQL query.
230
+ *
231
+ * @see blcLinkQuery::get_links()
232
+ *
233
+ * @param array $params An array of search criteria.
234
+ * @return array 'where_exprs' - an array of search expressions, 'join_instances' - whether joining the instance table is required.
235
+ */
236
+ function compile_search_params($params){
237
+ global $wpdb;
238
+
239
+ //Track whether we'll need to left-join the instance table to run the query.
240
+ $join_instances = false;
241
+
242
+ //Generate the individual clauses of the WHERE expression and store them in an array.
243
+ $pieces = array();
244
+
245
+ //Convert parser and container type lists to arrays of valid values
246
+ $s_parser_type = array();
247
+ if ( !empty($params['s_parser_type']) ){
248
+ $s_parser_type = $params['s_parser_type'];
249
+ if ( is_string($s_parser_type) ){
250
+ $s_parser_type = preg_split('/[,\s]+/', $s_parser_type);
251
+ }
252
+ }
253
+
254
+ $s_container_type = array();
255
+ if ( !empty($params['s_container_type']) ){
256
+ $s_container_type = $params['s_container_type'];
257
+ if ( is_string($s_container_type) ){
258
+ $s_container_type = preg_split('/[,\s]+/', $s_container_type);
259
+ }
260
+ }
261
+
262
+ //Don't include links with instances that reference invalid (not currently loaded)
263
+ //containers and parsers (unless specifically told to also include invalid links).
264
+ if ( empty($params['include_invalid']) ){
265
+ $join_instances = true;
266
+
267
+ $module_manager = & blcModuleManager::getInstance();
268
+ $loaded_containers = array_keys($module_manager->get_active_by_category('container'));
269
+ $loaded_parsers = array_keys($module_manager->get_active_by_category('parser'));
270
+
271
+ if ( empty($s_parser_type) ){
272
+ $s_parser_type = $loaded_parsers;
273
+ } else {
274
+ $s_parser_type = array_intersect($s_parser_type, $loaded_parsers);
275
+ }
276
+
277
+ if ( empty($s_container_type) ){
278
+ $s_container_type = $loaded_containers;
279
+ } else {
280
+ $s_container_type = array_intersect($s_container_type, $loaded_containers);
281
+ }
282
+ }
283
+
284
+ //Parser type should match the parser_type column in the instance table.
285
+ if ( !empty($s_parser_type) ){
286
+ $s_parser_type = array_map('trim', array_unique($s_parser_type));
287
+ $s_parser_type = array_map(array(&$wpdb, 'escape'), $s_parser_type);
288
+
289
+ if ( count($s_parser_type) == 1 ){
290
+ $pieces[] = sprintf("instances.parser_type = '%s'", reset($s_parser_type));
291
+ } else {
292
+ $pieces[] = "instances.parser_type IN ('" . implode("', '", $s_parser_type) . "')";
293
+ }
294
+
295
+ $join_instances = true;
296
+ }
297
+
298
+ //Container type should match the container_type column in the instance table.
299
+ if ( !empty($s_container_type) ){
300
+ //Sanitize for use in SQL
301
+ $s_container_type = array_map('trim', array_unique($s_container_type));
302
+ $s_container_type = array_map(array(&$wpdb, 'escape'), $s_container_type);
303
+
304
+ if ( count($s_container_type) == 1 ){
305
+ $pieces[] = sprintf("instances.container_type = '%s'", reset($s_container_type));
306
+ } else {
307
+ $pieces[] = "instances.container_type IN ('" . implode("', '", $s_container_type) . "')";
308
+ }
309
+
310
+ $join_instances = true;
311
+ }
312
+
313
+ //A part of the WHERE expression can be specified explicitly
314
+ if ( !empty($params['where_expr']) ){
315
+ $pieces[] = $params['where_expr'];
316
+ $join_instances = $join_instances || ( stripos($params['where_expr'], 'instances') !== false );
317
+ }
318
+
319
+ //List of allowed link ids (either an array or comma-separated)
320
+ if ( !empty($params['link_ids']) ){
321
+ $link_ids = $params['link_ids'];
322
+
323
+ if ( is_string($link_ids) ){
324
+ $link_ids = preg_split('/[,\s]+/', $link_ids);
325
+ }
326
+
327
+ //Only accept non-zero integers
328
+ $sanitized_link_ids = array();
329
+ foreach($link_ids as $id){
330
+ $id = intval($id);
331
+ if ( $id != 0 ){
332
+ $sanitized_link_ids[] = $id;
333
+ }
334
+ }
335
+
336
+ $pieces[] = 'links.link_id IN (' . implode(', ', $sanitized_link_ids) . ')';
337
+ }
338
+
339
+ //Anchor text - use LIKE search
340
+ if ( !empty($params['s_link_text']) ){
341
+ $s_link_text = like_escape($wpdb->escape($params['s_link_text']));
342
+ $s_link_text = str_replace('*', '%', $s_link_text);
343
+
344
+ $pieces[] = '(instances.link_text LIKE "%' . $s_link_text . '%")';
345
+ $join_instances = true;
346
+ }
347
+
348
+ //URL - try to match both the initial URL and the final URL.
349
+ //There is limited wildcard support, e.g. "google.*/search" will match both
350
+ //"google.com/search" and "google.lv/search"
351
+ if ( !empty($params['s_link_url']) ){
352
+ $s_link_url = like_escape($wpdb->escape($params['s_link_url']));
353
+ $s_link_url = str_replace('*', '%', $s_link_url);
354
+
355
+ $pieces[] = '(links.url LIKE "%'. $s_link_url .'%") OR '.
356
+ '(links.final_url LIKE "%'. $s_link_url .'%")';
357
+ }
358
+
359
+ //Container ID should match... you guessed it - container_id
360
+ if ( !empty($params['s_container_id']) ){
361
+ $s_container_id = intval($params['s_container_id']);
362
+ if ( $s_container_id != 0 ){
363
+ $pieces[] = "instances.container_id = $s_container_id";
364
+ $join_instances = true;
365
+ }
366
+ }
367
+
368
+ //Link type can match either the the parser_type or the container_type.
369
+ if ( !empty($params['s_link_type']) ){
370
+ $s_link_type = $wpdb->escape($params['s_link_type']);
371
+ $pieces[] = "instances.parser_type = '$s_link_type' OR instances.container_type='$s_link_type'";
372
+ $join_instances = true;
373
+ }
374
+
375
+ //HTTP code - the user can provide a list of HTTP response codes and code ranges.
376
+ //Example : 201,400-410,500
377
+ if ( !empty($params['s_http_code']) ){
378
+ //Strip spaces.
379
+ $params['s_http_code'] = str_replace(' ', '', $params['s_http_code']);
380
+ //Split by comma
381
+ $codes = explode(',', $params['s_http_code']);
382
+
383
+ $individual_codes = array();
384
+ $ranges = array();
385
+
386
+ //Try to parse each response code or range. Invalid ones are simply ignored.
387
+ foreach($codes as $code){
388
+ if ( is_numeric($code) ){
389
+ //It's a single number
390
+ $individual_codes[] = abs(intval($code));
391
+ } elseif ( strpos($code, '-') !== false ) {
392
+ //Try to parse it as a range
393
+ $range = explode( '-', $code, 2 );
394
+ if ( (count($range) == 2) && is_numeric($range[0]) && is_numeric($range[0]) ){
395
+ //Make sure the smaller code comes first
396
+ $range = array( intval($range[0]), intval($range[1]) );
397
+ $ranges[] = array( min($range), max($range) );
398
+ }
399
+ }
400
+ }
401
+
402
+ $piece = array();
403
+
404
+ //All individual response codes get one "http_code IN (...)" clause
405
+ if ( !empty($individual_codes) ){
406
+ $piece[] = '(links.http_code IN ('. implode(', ', $individual_codes) .'))';
407
+ }
408
+
409
+ //Ranges get a "http_code BETWEEN min AND max" clause each
410
+ if ( !empty($ranges) ){
411
+ $range_strings = array();
412
+ foreach($ranges as $range){
413
+ $range_strings[] = "(links.http_code BETWEEN $range[0] AND $range[1])";
414
+ }
415
+ $piece[] = '( ' . implode(' OR ', $range_strings) . ' )';
416
+ }
417
+
418
+ //Finally, generate a composite WHERE clause for both types of response code queries
419
+ if ( !empty($piece) ){
420
+ $pieces[] = implode(' OR ', $piece);
421
+ }
422
+
423
+ }
424
+
425
+ //Custom filters can optionally call one of the native filters
426
+ //to narrow down the result set.
427
+ if ( !empty($params['s_filter']) && isset($this->native_filters[$params['s_filter']]) ){
428
+ $the_filter = $this->native_filters[$params['s_filter']];
429
+ $extra_criteria = $this->compile_search_params($the_filter['params']);
430
+
431
+ $pieces = array_merge($pieces, $extra_criteria['where_exprs']);
432
+ $join_instances = $join_instances || $extra_criteria['join_instances'];
433
+ }
434
+
435
+ return array(
436
+ 'where_exprs' => $pieces,
437
+ 'join_instances' => $join_instances,
438
+ );
439
+ }
440
+
441
+ /**
442
+ * blcLinkQuery::get_links()
443
+ *
444
+ * @see blc_get_links()
445
+ *
446
+ * @param array $params
447
+ * @param string $purpose
448
+ * @return array|int
449
+ */
450
+ function get_links($params = null){
451
+ global $wpdb;
452
+
453
+ if( !is_array($params) ){
454
+ $params = array();
455
+ }
456
+
457
+ $defaults = array(
458
+ 'offset' => 0,
459
+ 'max_results' => 0,
460
+ 'load_instances' => false,
461
+ 'load_containers' => false,
462
+ 'load_wrapped_objects' => false,
463
+ 'count_only' => false,
464
+ 'purpose' => '',
465
+ 'include_invalid' => false,
466
+ );
467
+
468
+ $params = array_merge($defaults, $params);
469
+
470
+ //Compile the search-related params into search expressions usable in a WHERE clause
471
+ $criteria = $this->compile_search_params($params);
472
+
473
+ //Build the WHERE clause
474
+ if ( !empty($criteria['where_exprs']) ){
475
+ $where_expr = "\t( " . implode(" ) AND\n\t( ", $criteria['where_exprs']) . ' ) ';
476
+ } else {
477
+ $where_expr = '1';
478
+ }
479
+
480
+ //Join the blc_instances table if it's required to perform the search.
481
+ $joins = "";
482
+ if ( $criteria['join_instances'] ){
483
+ $joins = "JOIN {$wpdb->prefix}blc_instances AS instances ON links.link_id = instances.link_id";
484
+ }
485
+
486
+ if ( $params['count_only'] ){
487
+ //Only get the number of matching links.
488
+ $q = "
489
+ SELECT COUNT(*)
490
+ FROM (
491
+ SELECT 0
492
+
493
+ FROM
494
+ {$wpdb->prefix}blc_links AS links
495
+ $joins
496
+
497
+ WHERE
498
+ $where_expr
499
+
500
+ GROUP BY links.link_id) AS foo";
501
+
502
+ return $wpdb->get_var($q);
503
+ }
504
+
505
+ //Select the required links.
506
+ $q = "SELECT
507
+ links.*
508
+
509
+ FROM
510
+ {$wpdb->prefix}blc_links AS links
511
+ $joins
512
+
513
+ WHERE
514
+ $where_expr
515
+
516
+ GROUP BY links.link_id"; //Note: would be a lot faster without GROUP BY
517
+
518
+ //Add the LIMIT clause
519
+ if ( $params['max_results'] || $params['offset'] ){
520
+ $q .= sprintf("\nLIMIT %d, %d", $params['offset'], $params['max_results']);
521
+ }
522
+
523
+ $results = $wpdb->get_results($q, ARRAY_A);
524
+ if ( empty($results) ){
525
+ return array();
526
+ }
527
+
528
+ //Create the link objects
529
+ $links = array();
530
+
531
+ foreach($results as $result){
532
+ $link = new blcLink($result);
533
+ $links[$link->link_id] = $link;
534
+ }
535
+
536
+ $purpose = $params['purpose'];
537
+ /*
538
+ Preload instances if :
539
+ * It has been requested via the 'load_instances' argument.
540
+ * The links are going to be displayed or edited, which involves instances.
541
+ */
542
+ $load_instances = $params['load_instances'] || in_array($purpose, array(BLC_FOR_DISPLAY, BLC_FOR_EDITING));
543
+
544
+ if ( $load_instances ){
545
+ $link_ids = array_keys($links);
546
+ $all_instances = blc_get_instances($link_ids, $purpose, $params['load_containers'], $params['load_wrapped_objects']);
547
+ //Assign each batch of instances to the right link
548
+ foreach($all_instances as $link_id => $instances){
549
+ $links[$link_id]->_instances = $instances;
550
+ }
551
+ }
552
+
553
+ return $links;
554
+ }
555
+
556
+ /**
557
+ * Calculate the number of results for all known filters
558
+ *
559
+ * @return void
560
+ */
561
+ function count_filter_results(){
562
+ foreach($this->native_filters as $filter_id => $filter){
563
+ $this->native_filters[$filter_id]['count'] = $this->get_filter_links(
564
+ $filter, array('count_only' => true)
565
+ );
566
+ }
567
+
568
+ foreach($this->custom_filters as $filter_id => $filter){
569
+ $this->custom_filters[$filter_id]['count'] = $this->get_filter_links(
570
+ $filter, array('count_only' => true)
571
+ );
572
+ }
573
+
574
+ $this->search_filter['count'] = $this->get_filter_links($this->search_filter, array('count_only' => true));
575
+ }
576
+
577
+ /**
578
+ * Retrieve a list of links matching a filter.
579
+ *
580
+ * @uses blcLinkQuery::get_links()
581
+ *
582
+ * @param string|array $filter Either a filter ID or an array containing filter data.
583
+ * @param array $extra_params Optional extra criteria that will override those set by the filter. See blc_get_links() for details.
584
+ * @return array|int Either an array of blcLink objects, or an integer indicating the number of links that match the filter.
585
+ */
586
+ function get_filter_links($filter, $extra_params = null){
587
+ if ( is_string($filter) ){
588
+ $filter = $this->get_filter($filter);
589
+ }
590
+
591
+ $params = $this->get_search_params($filter);
592
+
593
+
594
+ if ( !empty($extra_params) ){
595
+ $params = array_merge($params, $extra_params);
596
+ }
597
+
598
+ return $this->get_links($params);
599
+ }
600
+
601
+ /**
602
+ * Print a menu of available filters, both native and user-created.
603
+ *
604
+ * @param string $current Current filter ID.
605
+ * @return void
606
+ */
607
+ function print_filter_menu($current = ''){
608
+ $filters = $this->get_filters();
609
+
610
+ echo '<ul class="subsubsub">';
611
+
612
+ //Construct a submenu of filter types
613
+ $items = array();
614
+ foreach ($filters as $filter => $data){
615
+ if ( !empty($data['hidden']) ) continue; //skip hidden filters
616
+
617
+ $class = $number_class = '';
618
+
619
+ if ( $current == $filter ) {
620
+ $class = 'class="current"';
621
+ $number_class = 'current-link-count';
622
+ }
623
+
624
+ $items[] = "<li><a href='tools.php?page=view-broken-links&filter_id=$filter' $class>
625
+ {$data['name']}</a> <span class='count'>(<span class='$number_class'>{$data['count']}</span>)</span>";
626
+ }
627
+ echo implode(' |</li>', $items);
628
+
629
+ echo '</ul>';
630
+ }
631
+
632
+ /**
633
+ * Print the appropriate heading for the given filter.
634
+ *
635
+ * @param array $current_filter
636
+ * @return void
637
+ */
638
+ function print_filter_heading($current_filter){
639
+ echo '<h2>';
640
+ //Output a header matching the current filter
641
+ if ( $current_filter['count'] > 0 ){
642
+ echo $current_filter['heading'] . " (<span class='current-link-count'>{$current_filter['count']}</span>)";
643
+ } else {
644
+ echo $current_filter['heading_zero'] . "<span class='current-link-count'></span>";
645
+ }
646
+ echo '</h2>';
647
+ }
648
+
649
+ /**
650
+ * Execute a filter.
651
+ *
652
+ * Gathers paging and search parameters from $_GET and executes the specified filter.
653
+ * The returned array contains standard filter data plus several additional fields :
654
+ * 'filter_id' - Which filter was used. May differ from the specified $filter_id due to fallback settings.
655
+ * 'per_page' - How many results per page the method tried to retrieve.
656
+ * 'page' - Which page of results was retrieved.
657
+ * 'max_pages' - The total number of results pages, calculated using the above 'per_page' value.
658
+ * 'links' - An array of retrieved links (blcLink objects).
659
+ * 'search_params' - An associative array of the current search parameters as extracted either from the current URL or the filter itself.
660
+ * 'is_broken_filter' - TRUE if the filter was set to retrieve only broken links, FALSE otherwise.
661
+ *
662
+ * @param string $filter_id Filter ID.
663
+ * @param int $page Optional. Which page of results to retrieve. Defaults to returning the first page of results.
664
+ * @param int $per_page Optional. The number of results per page. Defaults to 30.
665
+ * @param string $fallback Optional. Which filter to use if none match the specified $filter_id. Defaults to the native broken link filter.
666
+ * @return array Associative array of filter data and the results of its execution.
667
+ */
668
+ function exec_filter($filter_id, $page = 1, $per_page = 30, $fallback = 'broken'){
669
+
670
+ //Get the selected filter (defaults to displaying broken links)
671
+ $current_filter = $this->get_filter($filter_id);
672
+ if ( empty($current_filter) ){
673
+ $current_filter = $this->get_filter($fallback);
674
+ $filter_id = $fallback;
675
+ }
676
+
677
+ //Page number must be > 0
678
+ if ($page < 1) $page = 1;
679
+
680
+ //Links per page [1 - 500]
681
+ if ($per_page < 1){
682
+ $per_page = 30;
683
+ } else if ($per_page > 500){
684
+ $per_page = 500;
685
+ }
686
+
687
+ //Calculate the maximum number of pages.
688
+ $max_pages = ceil($current_filter['count'] / $per_page);
689
+
690
+ //Select the required links
691
+ $extra_params = array(
692
+ 'offset' => ( ($page-1) * $per_page ),
693
+ 'max_results' => $per_page,
694
+ 'purpose' => BLC_FOR_DISPLAY,
695
+ );
696
+ $links = $this->get_filter_links($current_filter, $extra_params);
697
+
698
+ //If the current request is a user-initiated search query (either directly or
699
+ //via a custom filter), save the search params. They can later be used to pre-fill
700
+ //the search form or build a new/modified custom filter.
701
+ $search_params = array();
702
+ if ( !empty($current_filter['custom']) || ($filter_id == 'search') ){
703
+ $search_params = $this->get_search_params($current_filter);
704
+ }
705
+
706
+ //TODO: Simplify this. Maybe overhaul the filter system to let us query the effective filter.
707
+ $is_broken_filter =
708
+ ($filter_id == 'broken')
709
+ || ( isset($current_filter['params']['s_filter']) && ($current_filter['params']['s_filter'] == 'broken') )
710
+ || ( isset($_GET['s_filter']) && ($_GET['s_filter'] == 'broken') );
711
+
712
+ //Save the effective filter data in the filter array.
713
+ //It can be used later to print the link table.
714
+ $current_filter = array_merge(array(
715
+ 'filter_id' => $filter_id,
716
+ 'page' => $page,
717
+ 'per_page' => $per_page,
718
+ 'max_pages' => $max_pages,
719
+ 'links' => $links,
720
+ 'search_params' => $search_params,
721
+ 'is_broken_filter' => $is_broken_filter,
722
+ ), $current_filter);
723
+
724
+ return $current_filter;
725
+ }
726
+ }
727
+
728
+ /**
729
+ * Retrieve a list of links matching some criteria.
730
+ *
731
+ * The function argument should be an associative array describing the criteria.
732
+ * The supported keys are :
733
+ * 'offset' - Skip the first X results. Default is 0.
734
+ * 'max_results' - The maximum number of links to return. Defaults to returning all results.
735
+ * 'link_ids' - Retrieve only links with these IDs. This should either be a comma-separated list or an array.
736
+ * 's_link_text' - Link text must match this keyphrase (performs a fulltext search).
737
+ * 's_link_url' - Link URL must contain this string. You can use "*" as a wildcard.
738
+ * 's_parser_type' - Filter links by the type of link parser that was used to find them.
739
+ * 's_container_type' - Filter links by where they were found, e.g. 'post'.
740
+ * 's_container_id' - Find links that belong to a container with this ID (should be used together with s_container_type).
741
+ * 's_link_type' - Either parser type or container type must match this.
742
+ * 's_http_code' - Filter by HTTP code. Example : 201,400-410,500
743
+ * 's_filter' - Use a built-in filter. Available filters : 'broken', 'redirects', 'all'
744
+ * 'where_expr' - Advanced. Lets you directly specify a part of the WHERE clause.
745
+ * 'load_instances' - Pre-load all link instance data for each link. Default is false.
746
+ * 'load_containers' - Pre-load container data for each instance. Default is false.
747
+ * 'load_wrapped_objects' - Pre-load wrapped object data (e.g. posts, comments, etc) for each container. Default is false.
748
+ * '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.
749
+ * 'purpose' - An optional code indicating how the links will be used.
750
+ * 'include_invalid' - Include links that have no instances and links that only have instances that reference not-loaded containers or parsers. Defaults to false.
751
+ *
752
+ * All keys are optional.
753
+ *
754
+ * @uses blcLinkQuery::get_links();
755
+ *
756
+ * @param array $params
757
+ * @return int|array Either an array of blcLink objects, or the number of results for the query.
758
+ */
759
+ function blc_get_links($params = null){
760
+ $instance = & blcLinkQuery::getInstance();
761
+ return $instance->get_links($params, $purpose);
762
+ }
763
+
764
+ ?>
includes/links.php CHANGED
@@ -6,6 +6,13 @@
6
  */
7
 
8
  if (!class_exists('blcLink')){
 
 
 
 
 
 
 
9
  class blcLink {
10
 
11
  //Object state
@@ -34,6 +41,9 @@ class blcLink {
34
  var $false_positive = false;
35
  var $result_hash = '';
36
 
 
 
 
37
  var $log = '';
38
 
39
  //A list of DB fields and their storage formats
@@ -42,6 +52,55 @@ class blcLink {
42
  //A cached list of the link's instances
43
  var $_instances = null;
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  function __construct($arg = null){
46
  global $wpdb;
47
 
@@ -63,6 +122,8 @@ class blcLink {
63
  'false_positive' => 'bool',
64
  'may_recheck' => 'bool',
65
  'being_checked' => 'bool',
 
 
66
  );
67
 
68
  if (is_int($arg)){
@@ -183,10 +244,12 @@ class blcLink {
183
  'may_recheck' => true,
184
  'log' => '',
185
  'result_hash' => '',
 
 
186
  );
187
 
188
 
189
- $checker = & blc_get_checker_for($this->url);
190
 
191
  if ( is_null($checker) ){
192
  //Oops, there are no checker implementations that can handle this link.
@@ -307,6 +370,26 @@ class blcLink {
307
 
308
  if ( $this->is_new ){
309
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  //Insert a new row
311
  $q = sprintf(
312
  "INSERT INTO {$wpdb->prefix}blc_links( %s ) VALUES( %s )",
@@ -743,645 +826,71 @@ class blcLink {
743
 
744
  return $this->_instances;
745
  }
746
- }
747
-
748
- } //class_exists
749
-
750
- /**
751
- * Class for querying, sorting and filtering links.
752
- * Used as a singleton.
753
- *
754
- * @package Broken Link Checker
755
- * @access public
756
- */
757
- class blcLinkQuery {
758
-
759
- var $native_filters;
760
- var $search_filter;
761
- var $custom_filters = array();
762
 
763
- var $valid_url_params = array();
764
-
765
- function __construct(){
766
- //Init. the available native filters.
767
- $this->native_filters = array(
768
- 'broken' => array(
769
- 'params' => array(
770
- 'where_expr' => '( broken = 1 )',
771
- ),
772
- 'name' => __('Broken', 'broken-link-checker'),
773
- 'heading' => __('Broken Links', 'broken-link-checker'),
774
- 'heading_zero' => __('No broken links found', 'broken-link-checker'),
775
- 'native' => true,
776
- ),
777
- 'redirects' => array(
778
- 'params' => array(
779
- 'where_expr' => '( redirect_count > 0 )',
780
- ),
781
- 'name' => __('Redirects', 'broken-link-checker'),
782
- 'heading' => __('Redirected Links', 'broken-link-checker'),
783
- 'heading_zero' => __('No redirects found', 'broken-link-checker'),
784
- 'native' => true,
785
- ),
786
 
787
- 'all' => array(
788
- 'params' => array(
789
- 'where_expr' => '1',
790
- ),
791
- 'name' => __('All', 'broken-link-checker'),
792
- 'heading' => __('Detected Links', 'broken-link-checker'),
793
- 'heading_zero' => __('No links found (yet)', 'broken-link-checker'),
794
- 'native' => true,
795
- ),
796
- );
797
-
798
- //Create the special "search" filter
799
- $this->search_filter = array(
800
- 'name' => __('Search', 'broken-link-checker'),
801
- 'heading' => __('Search Results', 'broken-link-checker'),
802
- 'heading_zero' => __('No links found for your query', 'broken-link-checker'),
803
- 'params' => array(),
804
- 'use_url_params' => true,
805
- 'hidden' => true,
806
- );
807
-
808
- //These search arguments may be passed via the URL if the filter's 'use_url_params' field is set to True.
809
- //They map to the fields of the search form on the Tools -> Broken Links page. Only these arguments
810
- //can be used in user-defined filters.
811
- $this->valid_url_params = array(
812
- 's_link_text',
813
- 's_link_url',
814
- 's_parser_type',
815
- 's_container_type',
816
- 's_link_type',
817
- 's_http_code',
818
- 's_filter',
819
- );
820
- }
821
-
822
- function blcLinkQuery(){
823
- $this->__construct();
824
- }
825
-
826
- function &getInstance(){
827
- static $instance = null;
828
- if ( is_null($instance) ){
829
- $instance = new blcLinkQuery;
830
- }
831
- return $instance;
832
- }
833
-
834
- /**
835
- * Load and return the list of user-defined link filters.
836
- *
837
- * @return array An array of custom filter definitions. If there are no custom filters defined returns an empty array.
838
- */
839
- function load_custom_filters(){
840
- global $wpdb;
841
-
842
- $filter_data = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}blc_filters ORDER BY name ASC", ARRAY_A);
843
- $filters = array();
844
-
845
- if ( !empty($filter_data) ) {
846
- foreach($filter_data as $data){
847
- wp_parse_str($data['params'], $params);
848
-
849
- $filters[ 'f'.$data['id'] ] = array(
850
- 'name' => $data['name'],
851
- 'params' => $params,
852
- 'heading' => ucwords($data['name']),
853
- 'heading_zero' => __('No links found for your query', 'broken-link-checker'),
854
- 'custom' => true,
855
- );
856
- }
857
- }
858
-
859
- $this->custom_filters = $filters;
860
-
861
- return $filters;
862
- }
863
-
864
- /**
865
- * Add a custom link filter.
866
- *
867
- * @param string $name Filter name.
868
- * @param string|array $params Filter params. Either as a query string, or an array.
869
- * @return string|bool The ID of the newly added filter, or False.
870
- */
871
- function create_custom_filter($name, $params){
872
- global $wpdb;
873
-
874
- if ( is_array($params) ){
875
- $params = http_build_query($params, null, '&');
876
- }
877
-
878
- //Save the new filter
879
- $q = $wpdb->prepare(
880
- "INSERT INTO {$wpdb->prefix}blc_filters(name, params) VALUES (%s, %s)",
881
- $name, $params
882
- );
883
-
884
- if ( $wpdb->query($q) !== false ){
885
- $filter_id = 'f'.$wpdb->insert_id;
886
- return $filter_id;
887
- } else {
888
- return false;
889
- }
890
- }
891
-
892
- /**
893
- * Delete a custom filter
894
- *
895
- * @param string $filter_id
896
- * @return bool True on success, False if a database error occured.
897
- */
898
- function delete_custom_filter($filter_id){
899
- global $wpdb;
900
-
901
- //Remove the "f" character from the filter ID to get its database key
902
- $filter_id = intval(ltrim($_POST['filter_id'], 'f'));
903
-
904
- //Try to delete the filter
905
- $q = $wpdb->prepare("DELETE FROM {$wpdb->prefix}blc_filters WHERE id = %d", $filter_id);
906
- if ( $wpdb->query($q) !== false ){
907
- return true;
908
- } else {
909
- return false;
910
- }
911
- }
912
-
913
- function get_filters(){
914
- $filters = array_merge($this->native_filters, $this->custom_filters);
915
- $filters['search'] = $this->search_filter;
916
- return $filters;
917
- }
918
-
919
- /**
920
- * Get a link search filter by filter ID.
921
- *
922
- * @param string $filter_id
923
- * @return array|null
924
- */
925
- function get_filter($filter_id){
926
- $filters = $this->get_filters();
927
- if ( isset($filters[$filter_id]) ){
928
- return $filters[$filter_id];
929
  } else {
930
- return null;
931
- }
932
- }
933
-
934
- /**
935
- * Get link search parameters from the specified filter.
936
- *
937
- * @param array $filter
938
- * @return array An array of parameters suitable for use with blcLinkQuery::get_links()
939
- */
940
- function get_search_params( $filter = null ){
941
- //If present, the filter's parameters may be saved either as an array or a string.
942
- $params = array();
943
- if ( !empty($filter) && !empty($filter['params']) ){
944
- $params = $filter['params'];
945
- if ( is_string( $params ) ){
946
- wp_parse_str($params, $params);
947
- }
948
- }
949
-
950
- //Merge in the parameters from the current request, if required
951
- if ( isset($filter['use_url_params']) && $filter['use_url_params'] ){
952
- $params = array_merge($params, $this->get_url_search_params());
953
- }
954
-
955
- return $params;
956
- }
957
-
958
- /**
959
- * Extract search query parameters from the current URL
960
- *
961
- * @return array
962
- */
963
- function get_url_search_params(){
964
- $url_params = array();
965
- foreach ($_GET as $param => $value){
966
- if ( in_array($param, $this->valid_url_params) ){
967
- $url_params[$param] = $value;
968
- }
969
- }
970
- return $url_params;
971
- }
972
-
973
-
974
-
975
- /**
976
- * A helper method for parsing a list of search criteria and generating the parts of the SQL query.
977
- *
978
- * @see blcLinkQuery::get_links()
979
- *
980
- * @param array $params An array of search criteria.
981
- * @return array 'where_exprs' - an array of search expressions, 'join_instances' - whether joining the instance table is required.
982
- */
983
- function compile_search_params($params){
984
- global $wpdb;
985
-
986
- //Track whether we'll need to left-join the instance table to run the query.
987
- $join_instances = false;
988
-
989
- //Generate the individual clauses of the WHERE expression and store them in an array.
990
- $pieces = array();
991
-
992
- //Convert parser and container type lists to arrays of valid values
993
- $s_parser_type = array();
994
- if ( !empty($params['s_parser_type']) ){
995
- $s_parser_type = $params['s_parser_type'];
996
- if ( is_string($s_parser_type) ){
997
- $s_parser_type = preg_split('/[,\s]+/', $s_parser_type);
998
- }
999
- }
1000
-
1001
- $s_container_type = array();
1002
- if ( !empty($params['s_container_type']) ){
1003
- $s_container_type = $params['s_container_type'];
1004
- if ( is_string($s_container_type) ){
1005
- $s_container_type = preg_split('/[,\s]+/', $s_container_type);
1006
- }
1007
- }
1008
-
1009
- //Don't include links with instances that reference invalid (not currently loaded)
1010
- //containers and parsers (unless specifically told to also include invalid links).
1011
- if ( empty($params['include_invalid']) ){
1012
- $join_instances = true;
1013
-
1014
- $containerRegistry = & blcContainerRegistry::getInstance();
1015
- $loaded_containers = array_keys($containerRegistry->get_registered_containers());
1016
- $parserRegistry = & blcParserRegistry::getInstance();
1017
- $loaded_parsers = array_keys($parserRegistry->get_registered_parsers());
1018
-
1019
- if ( empty($s_parser_type) ){
1020
- $s_parser_type = $loaded_parsers;
1021
- } else {
1022
- $s_parser_type = array_intersect($s_parser_type, $loaded_parsers);
1023
- }
1024
-
1025
- if ( empty($s_container_type) ){
1026
- $s_container_type = $loaded_containers;
1027
- } else {
1028
- $s_container_type = array_intersect($s_container_type, $loaded_containers);
1029
- }
1030
- }
1031
-
1032
- //Parser type should match the parser_type column in the instance table.
1033
- if ( !empty($s_parser_type) ){
1034
- $s_parser_type = array_map('trim', array_unique($s_parser_type));
1035
- $s_parser_type = array_map(array(&$wpdb, 'escape'), $s_parser_type);
1036
 
1037
- if ( count($s_parser_type) == 1 ){
1038
- $pieces[] = sprintf("instances.parser_type = '%s'", reset($s_parser_type));
1039
- } else {
1040
- $pieces[] = "instances.parser_type IN ('" . implode("', '", $s_parser_type) . "')";
1041
- }
1042
-
1043
- $join_instances = true;
1044
- }
1045
-
1046
- //Container type should match the container_type column in the instance table.
1047
- if ( !empty($s_container_type) ){
1048
- //Sanitize for use in SQL
1049
- $s_container_type = array_map('trim', array_unique($s_container_type));
1050
- $s_container_type = array_map(array(&$wpdb, 'escape'), $s_container_type);
1051
-
1052
- if ( count($s_container_type) == 1 ){
1053
- $pieces[] = sprintf("instances.container_type = '%s'", reset($s_container_type));
1054
- } else {
1055
- $pieces[] = "instances.container_type IN ('" . implode("', '", $s_container_type) . "')";
1056
- }
1057
-
1058
- $join_instances = true;
1059
- }
1060
-
1061
- //A part of the WHERE expression can be specified explicitly
1062
- if ( !empty($params['where_expr']) ){
1063
- $pieces[] = $params['where_expr'];
1064
- $join_instances = $join_instances || ( stripos($params['where_expr'], 'instances') !== false );
1065
- }
1066
-
1067
- //List of allowed link ids (either an array or comma-separated)
1068
- if ( !empty($params['link_ids']) ){
1069
- $link_ids = $params['link_ids'];
1070
-
1071
- if ( is_string($link_ids) ){
1072
- $link_ids = preg_split('/[,\s]+/', $link_ids);
1073
- }
1074
-
1075
- //Only accept non-zero integers
1076
- $sanitized_link_ids = array();
1077
- foreach($link_ids as $id){
1078
- $id = intval($id);
1079
- if ( $id != 0 ){
1080
- $sanitized_link_ids[] = $id;
1081
- }
1082
- }
1083
-
1084
- $pieces[] = 'links.link_id IN (' . implode(', ', $sanitized_link_ids) . ')';
1085
- }
1086
-
1087
- //Anchor text - use LIKE search
1088
- if ( !empty($params['s_link_text']) ){
1089
- $s_link_text = like_escape($wpdb->escape($params['s_link_text']));
1090
- $s_link_text = str_replace('*', '%', $s_link_text);
1091
-
1092
- $pieces[] = '(instances.link_text LIKE "%' . $s_link_text . '%")';
1093
- $join_instances = true;
1094
- }
1095
-
1096
- //URL - try to match both the initial URL and the final URL.
1097
- //There is limited wildcard support, e.g. "google.*/search" will match both
1098
- //"google.com/search" and "google.lv/search"
1099
- if ( !empty($params['s_link_url']) ){
1100
- $s_link_url = like_escape($wpdb->escape($params['s_link_url']));
1101
- $s_link_url = str_replace('*', '%', $s_link_url);
1102
-
1103
- $pieces[] = '(links.url LIKE "%'. $s_link_url .'%") OR '.
1104
- '(links.final_url LIKE "%'. $s_link_url .'%")';
1105
- }
1106
-
1107
- //Container ID should match... you guessed it - container_id
1108
- if ( !empty($params['s_container_id']) ){
1109
- $s_container_id = intval($params['s_container_id']);
1110
- if ( $s_container_id != 0 ){
1111
- $pieces[] = "instances.container_id = $s_container_id";
1112
- $join_instances = true;
1113
- }
1114
- }
1115
-
1116
- //Link type can match either the the parser_type or the container_type.
1117
- if ( !empty($params['s_link_type']) ){
1118
- $s_link_type = $wpdb->escape($params['s_link_type']);
1119
- $pieces[] = "instances.parser_type = '$s_link_type' OR instances.container_type='$s_link_type'";
1120
- $join_instances = true;
1121
- }
1122
-
1123
- //HTTP code - the user can provide a list of HTTP response codes and code ranges.
1124
- //Example : 201,400-410,500
1125
- if ( !empty($params['s_http_code']) ){
1126
- //Strip spaces.
1127
- $params['s_http_code'] = str_replace(' ', '', $params['s_http_code']);
1128
- //Split by comma
1129
- $codes = explode(',', $params['s_http_code']);
1130
-
1131
- $individual_codes = array();
1132
- $ranges = array();
1133
-
1134
- //Try to parse each response code or range. Invalid ones are simply ignored.
1135
- foreach($codes as $code){
1136
- if ( is_numeric($code) ){
1137
- //It's a single number
1138
- $individual_codes[] = abs(intval($code));
1139
- } elseif ( strpos($code, '-') !== false ) {
1140
- //Try to parse it as a range
1141
- $range = explode( '-', $code, 2 );
1142
- if ( (count($range) == 2) && is_numeric($range[0]) && is_numeric($range[0]) ){
1143
- //Make sure the smaller code comes first
1144
- $range = array( intval($range[0]), intval($range[1]) );
1145
- $ranges[] = array( min($range), max($range) );
1146
- }
1147
- }
1148
- }
1149
-
1150
- $piece = array();
1151
-
1152
- //All individual response codes get one "http_code IN (...)" clause
1153
- if ( !empty($individual_codes) ){
1154
- $piece[] = '(links.http_code IN ('. implode(', ', $individual_codes) .'))';
1155
- }
1156
-
1157
- //Ranges get a "http_code BETWEEN min AND max" clause each
1158
- if ( !empty($ranges) ){
1159
- $range_strings = array();
1160
- foreach($ranges as $range){
1161
- $range_strings[] = "(links.http_code BETWEEN $range[0] AND $range[1])";
1162
- }
1163
- $piece[] = '( ' . implode(' OR ', $range_strings) . ' )';
1164
- }
1165
-
1166
- //Finally, generate a composite WHERE clause for both types of response code queries
1167
- if ( !empty($piece) ){
1168
- $pieces[] = implode(' OR ', $piece);
1169
- }
1170
-
1171
- }
1172
-
1173
- //Custom filters can optionally call one of the native filters
1174
- //to narrow down the result set.
1175
- if ( !empty($params['s_filter']) && isset($this->native_filters[$params['s_filter']]) ){
1176
- $the_filter = $this->native_filters[$params['s_filter']];
1177
- $extra_criteria = $this->compile_search_params($the_filter['params']);
1178
-
1179
- $pieces = array_merge($pieces, $extra_criteria['where_exprs']);
1180
- $join_instances = $join_instances || $extra_criteria['join_instances'];
1181
- }
1182
-
1183
- return array(
1184
- 'where_exprs' => $pieces,
1185
- 'join_instances' => $join_instances,
1186
- );
1187
- }
1188
-
1189
- /**
1190
- * blcLinkQuery::get_links()
1191
- *
1192
- * @see blc_get_links()
1193
- *
1194
- * @param array $params
1195
- * @param string $purpose
1196
- * @return array|int
1197
- */
1198
- function get_links($params = null){
1199
- global $wpdb;
1200
-
1201
- if( !is_array($params) ){
1202
- $params = array();
1203
- }
1204
-
1205
- $defaults = array(
1206
- 'offset' => 0,
1207
- 'max_results' => 0,
1208
- 'load_instances' => false,
1209
- 'load_containers' => false,
1210
- 'load_wrapped_objects' => false,
1211
- 'count_only' => false,
1212
- 'purpose' => '',
1213
- 'include_invalid' => false,
1214
- );
1215
-
1216
- $params = array_merge($defaults, $params);
1217
-
1218
- //Compile the search-related params into search expressions usable in a WHERE clause
1219
- $criteria = $this->compile_search_params($params);
1220
-
1221
- //Build the WHERE clause
1222
- if ( !empty($criteria['where_exprs']) ){
1223
- $where_expr = "\t( " . implode(" ) AND\n\t( ", $criteria['where_exprs']) . ' ) ';
1224
- } else {
1225
- $where_expr = '1';
1226
- }
1227
-
1228
- //Join the blc_instances table if it's required to perform the search.
1229
- $joins = "";
1230
- if ( $criteria['join_instances'] ){
1231
- $joins = "JOIN {$wpdb->prefix}blc_instances AS instances ON links.link_id = instances.link_id";
1232
- }
1233
-
1234
- if ( $params['count_only'] ){
1235
- //Only get the number of matching links.
1236
- $q = "
1237
- SELECT COUNT(*)
1238
- FROM (
1239
- SELECT 0
1240
 
1241
- FROM
1242
- {$wpdb->prefix}blc_links AS links
1243
- $joins
1244
 
1245
- WHERE
1246
- $where_expr
1247
 
1248
- GROUP BY links.link_id) AS foo";
1249
-
1250
- return $wpdb->get_var($q);
1251
- }
1252
-
1253
- //Select the required links.
1254
- $q = "SELECT
1255
- links.*
 
 
 
1256
 
1257
- FROM
1258
- {$wpdb->prefix}blc_links AS links
1259
- $joins
1260
 
1261
- WHERE
1262
- $where_expr
 
 
 
 
 
 
 
 
1263
 
1264
- GROUP BY links.link_id"; //Note: would be a lot faster without GROUP BY
1265
-
1266
- //Add the LIMIT clause
1267
- if ( $params['max_results'] || $params['offset'] ){
1268
- $q .= sprintf("\nLIMIT %d, %d", $params['offset'], $params['max_results']);
1269
- }
1270
-
1271
- $results = $wpdb->get_results($q, ARRAY_A);
1272
- if ( empty($results) ){
1273
- return array();
1274
- }
1275
-
1276
- //Create the link objects
1277
- $links = array();
1278
-
1279
- foreach($results as $result){
1280
- $link = new blcLink($result);
1281
- $links[$link->link_id] = $link;
1282
- }
1283
-
1284
- $purpose = $params['purpose'];
1285
- /*
1286
- Preload instances if :
1287
- * It has been requested via the 'load_instances' argument.
1288
- * The links are going to be displayed or edited, which involves instances.
1289
- */
1290
- $load_instances = $params['load_instances'] || in_array($purpose, array(BLC_FOR_DISPLAY, BLC_FOR_EDITING));
1291
-
1292
- if ( $load_instances ){
1293
- $link_ids = array_keys($links);
1294
- $all_instances = blc_get_instances($link_ids, $purpose, $params['load_containers'], $params['load_wrapped_objects']);
1295
- //Assign each batch of instances to the right link
1296
- foreach($all_instances as $link_id => $instances){
1297
- $links[$link_id]->_instances = $instances;
1298
  }
1299
  }
1300
-
1301
- return $links;
1302
- }
1303
-
1304
- /**
1305
- * Calculate the number of results for all known filters
1306
- *
1307
- * @return void
1308
- */
1309
- function count_filter_results(){
1310
- foreach($this->native_filters as $filter_id => $filter){
1311
- $this->native_filters[$filter_id]['count'] = $this->get_filter_links(
1312
- $filter, array('count_only' => true)
1313
- );
1314
- }
1315
 
1316
- foreach($this->custom_filters as $filter_id => $filter){
1317
- $this->custom_filters[$filter_id]['count'] = $this->get_filter_links(
1318
- $filter, array('count_only' => true)
1319
- );
1320
- }
1321
-
1322
- $this->search_filter['count'] = $this->get_filter_links($this->search_filter, array('count_only' => true));
1323
  }
1324
 
1325
- /**
1326
- * Retrieve a list of links matching a filter.
1327
- *
1328
- * @uses blcLinkQuery::get_links()
1329
- *
1330
- * @param string|array $filter Either a filter ID or an array containing filter data.
1331
- * @param array $extra_params Optional extra criteria that will override those set by the filter. See blc_get_links() for details.
1332
- * @return array|int Either an array of blcLink objects, or an integer indicating the number of links that match the filter.
1333
- */
1334
- function get_filter_links($filter, $extra_params = null){
1335
- if ( is_string($filter) ){
1336
- $filter = $this->get_filter($filter);
1337
- }
1338
-
1339
- $params = $this->get_search_params($filter);
1340
-
1341
-
1342
- if ( !empty($extra_params) ){
1343
- $params = array_merge($params, $extra_params);
1344
- }
1345
-
1346
- return $this->get_links($params);
1347
- }
1348
  }
1349
 
1350
- /**
1351
- * Retrieve a list of links matching some criteria.
1352
- *
1353
- * The function argument should be an associative array describing the criteria.
1354
- * The supported keys are :
1355
- * 'offset' - Skip the first X results. Default is 0.
1356
- * 'max_results' - The maximum number of links to return. Defaults to returning all results.
1357
- * 'link_ids' - Retrieve only links with these IDs. This should either be a comma-separated list or an array.
1358
- * 's_link_text' - Link text must match this keyphrase (performs a fulltext search).
1359
- * 's_link_url' - Link URL must contain this string. You can use "*" as a wildcard.
1360
- * 's_parser_type' - Filter links by the type of link parser that was used to find them.
1361
- * 's_container_type' - Filter links by where they were found, e.g. 'post'.
1362
- * 's_container_id' - Find links that belong to a container with this ID (should be used together with s_container_type).
1363
- * 's_link_type' - Either parser type or container type must match this.
1364
- * 's_http_code' - Filter by HTTP code. Example : 201,400-410,500
1365
- * 's_filter' - Use a built-in filter. Available filters : 'broken', 'redirects', 'all'
1366
- * 'where_expr' - Advanced. Lets you directly specify a part of the WHERE clause.
1367
- * 'load_instances' - Pre-load all link instance data for each link. Default is false.
1368
- * 'load_containers' - Pre-load container data for each instance. Default is false.
1369
- * 'load_wrapped_objects' - Pre-load wrapped object data (e.g. posts, comments, etc) for each container. Default is false.
1370
- * '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.
1371
- * 'purpose' - An optional code indicating how the links will be used.
1372
- * 'include_invalid' - Include links that have no instances and links that only have instances that reference not-loaded containers or parsers. Defaults to false.
1373
- *
1374
- * All keys are optional.
1375
- *
1376
- * @uses blcLinkQuery::get_links();
1377
- *
1378
- * @param array $params
1379
- * @return int|array Either an array of blcLink objects, or the number of results for the query.
1380
- */
1381
- function blc_get_links($params = null){
1382
- $instance = & blcLinkQuery::getInstance();
1383
- return $instance->get_links($params, $purpose);
1384
- }
1385
 
1386
  /**
1387
  * Remove orphaned links that have no corresponding instances.
6
  */
7
 
8
  if (!class_exists('blcLink')){
9
+
10
+ define('BLC_LINK_STATUS_UNKNOWN', 'unknown');
11
+ define('BLC_LINK_STATUS_OK', 'ok');
12
+ define('BLC_LINK_STATUS_INFO', 'info');
13
+ define('BLC_LINK_STATUS_WARNING', 'warning');
14
+ define('BLC_LINK_STATUS_ERROR', 'error');
15
+
16
  class blcLink {
17
 
18
  //Object state
41
  var $false_positive = false;
42
  var $result_hash = '';
43
 
44
+ var $status_text = '';
45
+ var $status_code = '';
46
+
47
  var $log = '';
48
 
49
  //A list of DB fields and their storage formats
52
  //A cached list of the link's instances
53
  var $_instances = null;
54
 
55
+ var $http_status_codes = array(
56
+ // [Informational 1xx]
57
+ 100=>'Continue',
58
+ 101=>'Switching Protocols',
59
+ // [Successful 2xx]
60
+ 200=>'OK',
61
+ 201=>'Created',
62
+ 202=>'Accepted',
63
+ 203=>'Non-Authoritative Information',
64
+ 204=>'No Content',
65
+ 205=>'Reset Content',
66
+ 206=>'Partial Content',
67
+ // [Redirection 3xx]
68
+ 300=>'Multiple Choices',
69
+ 301=>'Moved Permanently',
70
+ 302=>'Found',
71
+ 303=>'See Other',
72
+ 304=>'Not Modified',
73
+ 305=>'Use Proxy',
74
+ //306=>'(Unused)',
75
+ 307=>'Temporary Redirect',
76
+ // [Client Error 4xx]
77
+ 400=>'Bad Request',
78
+ 401=>'Unauthorized',
79
+ 402=>'Payment Required',
80
+ 403=>'Forbidden',
81
+ 404=>'Not Found',
82
+ 405=>'Method Not Allowed',
83
+ 406=>'Not Acceptable',
84
+ 407=>'Proxy Authentication Required',
85
+ 408=>'Request Timeout',
86
+ 409=>'Conflict',
87
+ 410=>'Gone',
88
+ 411=>'Length Required',
89
+ 412=>'Precondition Failed',
90
+ 413=>'Request Entity Too Large',
91
+ 414=>'Request-URI Too Long',
92
+ 415=>'Unsupported Media Type',
93
+ 416=>'Requested Range Not Satisfiable',
94
+ 417=>'Expectation Failed',
95
+ // [Server Error 5xx]
96
+ 500=>'Internal Server Error',
97
+ 501=>'Not Implemented',
98
+ 502=>'Bad Gateway',
99
+ 503=>'Service Unavailable',
100
+ 504=>'Gateway Timeout',
101
+ 505=>'HTTP Version Not Supported',
102
+ );
103
+
104
  function __construct($arg = null){
105
  global $wpdb;
106
 
122
  'false_positive' => 'bool',
123
  'may_recheck' => 'bool',
124
  'being_checked' => 'bool',
125
+ 'status_text' => '%s',
126
+ 'status_code' => '%s',
127
  );
128
 
129
  if (is_int($arg)){
244
  'may_recheck' => true,
245
  'log' => '',
246
  'result_hash' => '',
247
+ 'status_text' => '',
248
+ 'status_code' => '',
249
  );
250
 
251
 
252
+ $checker = & blcCheckerHelper::get_checker_for($this->url);
253
 
254
  if ( is_null($checker) ){
255
  //Oops, there are no checker implementations that can handle this link.
370
 
371
  if ( $this->is_new ){
372
 
373
+ //BUG: Technically, there should be a 'LOCK TABLES wp_blc_links WRITE' here. In fact,
374
+ //the plugin should probably lock all involved tables whenever it parses something, lest
375
+ //the user (ot another plugin) modify the thing being parsed while we're working.
376
+ //The problem with table locking, though, is that parsing takes a long time and having
377
+ //all of WP freeze while the plugin is working would be a Bad Thing. Food for thought.
378
+
379
+ //Check if there's already a link with this URL present
380
+ $q = $wpdb->prepare(
381
+ "SELECT link_id FROM {$wpdb->prefix}blc_links WHERE url = %s",
382
+ $this->url
383
+ );
384
+ $existing_id = $wpdb->get_var($q);
385
+
386
+ if ( !empty($existing_id) ){
387
+ //Dammit.
388
+ $this->link_id = $existing_id;
389
+ $this->is_new = false;
390
+ return true;
391
+ }
392
+
393
  //Insert a new row
394
  $q = sprintf(
395
  "INSERT INTO {$wpdb->prefix}blc_links( %s ) VALUES( %s )",
826
 
827
  return $this->_instances;
828
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
829
 
830
+ /**
831
+ * Determine the status text and status code corresponding to the current state of this link.
832
+ *
833
+ * @return array Associative array with two keys, 'text' and 'code'.
834
+ */
835
+ function analyse_status(){
836
+ $code = BLC_LINK_STATUS_UNKNOWN;
837
+ $text = _x('Unknown', 'link status', 'broken-link-checker');
838
+
839
+ //Status text
840
+ if ( isset($this->status_text) && !empty($this->status_text) && !empty($this->status_code) ){
841
+
842
+ //Lucky, the checker module has already set it for us.
843
+ $text = $this->status_text;
844
+ $code = $this->status_code;
 
 
 
 
 
 
 
 
845
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
846
  } else {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
847
 
848
+ if ( $this->broken ){
849
+
850
+ $code = BLC_LINK_STATUS_WARNING;
851
+ $text = __('Unknown Error', 'link status', 'broken-link-checker');
852
+
853
+ if ( $this->timeout ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
854
 
855
+ $text = __('Timeout', 'broken-link-checker');
856
+ $code = BLC_LINK_STATUS_WARNING;
 
857
 
858
+ } elseif ( $this->http_code ) {
 
859
 
860
+ //Only 404 (Not Found) and 410 (Gone) are treated as broken-for-sure.
861
+ if ( in_array($this->http_code, array(404, 410)) ){
862
+ $code = BLC_LINK_STATUS_ERROR;
863
+ } else {
864
+ $code = BLC_LINK_STATUS_WARNING;
865
+ }
866
+
867
+ if ( array_key_exists(intval($this->http_code), $this->http_status_codes) ){
868
+ $text = $this->http_status_codes[intval($this->http_code)];
869
+ }
870
+ }
871
 
872
+ } else {
 
 
873
 
874
+ if ( !$this->last_check ) {
875
+ $text = __('Not checked', 'broken-link-checker');
876
+ $code = BLC_LINK_STATUS_UNKNOWN;
877
+ } elseif ( $this->false_positive ) {
878
+ $text = __('False positive', 'broken-link-checker');
879
+ $code = BLC_LINK_STATUS_UNKNOWN;
880
+ } else {
881
+ $text = _x('OK', 'link status', 'broken-link-checker');
882
+ $code = BLC_LINK_STATUS_OK;
883
+ }
884
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
885
  }
886
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
887
 
888
+ return compact('text', 'code');
 
 
 
 
 
 
889
  }
890
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
891
  }
892
 
893
+ } //class_exists
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
894
 
895
  /**
896
  * Remove orphaned links that have no corresponding instances.
logger.php → includes/logger.php RENAMED
File without changes
includes/module-base.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Janis Elsts
5
+ * @copyright 2010
6
+ */
7
+
8
+ /**
9
+ * Base class for BLC modules.
10
+ *
11
+ * @package Broken Link Checker
12
+ * @author Janis Elsts
13
+ * @access public
14
+ */
15
+ class blcModule {
16
+
17
+ var $module_id; //The ID of this module. Usually a lowercase string.
18
+ var $cached_header; //An associative array containing the header data of the module file.
19
+ var $plugin_conf; //A reference to the plugin's global configuration object.
20
+ var $module_manager; //A reference to the module manager.
21
+
22
+ /**
23
+ * Class constructor
24
+ *
25
+ * @param string $module_id
26
+ * @param array $cached_header
27
+ * @param blcPluginConfiguration $plugin_conf
28
+ * @param blcModuleManager $module_manager
29
+ * @return void
30
+ */
31
+ function blcModule($module_id, $cached_header, &$plugin_conf, &$module_manager){
32
+ $this->module_id = $module_id;
33
+ $this->cached_header = $cached_header;
34
+ $this->plugin_conf = &$plugin_conf;
35
+ $this->module_manager = &$module_manager;
36
+
37
+ $this->init();
38
+ }
39
+
40
+ /**
41
+ * Module initializer. Called when the module is first instantiated.
42
+ * The default implementation does nothing. Override it in a subclass to
43
+ * specify some sort of start-up behaviour.
44
+ *
45
+ * @return void
46
+ */
47
+ function init(){
48
+ //Should be overridden in a sub-class.
49
+ }
50
+
51
+ /**
52
+ * Called when the module is activated.
53
+ * Should be overridden in a sub-class.
54
+ *
55
+ * @return void
56
+ */
57
+ function activated(){
58
+ //Should be overridden in a sub-class.
59
+ }
60
+
61
+ /**
62
+ * Called when the module is deactivated.
63
+ * Should be overridden in a sub-class.
64
+ *
65
+ * @return void
66
+ */
67
+ function deactivated(){
68
+ //Should be overridden in a sub-class.
69
+ }
70
+ }
71
+
72
+ ?>
includes/module-manager.php ADDED
@@ -0,0 +1,860 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class blcModuleManager {
4
+
5
+ var $plugin_conf;
6
+ var $module_dir = '';
7
+
8
+ var $_module_cache;
9
+ var $_category_cache;
10
+ var $_category_cache_active;
11
+ var $_virtual_modules = array();
12
+
13
+ var $loaded;
14
+ var $instances;
15
+ var $default_active_modules;
16
+
17
+
18
+ /**
19
+ * Class "constructor".
20
+ *
21
+ * @param array $default_active_modules An array of module ids specifying which modules are active by default.
22
+ * @return void
23
+ */
24
+ function init($default_active_modules = null){
25
+ $this->module_dir = realpath(dirname(__FILE__) . '/../modules');
26
+
27
+ $this->plugin_conf = & blc_get_configuration();
28
+ $this->default_active_modules = $default_active_modules;
29
+
30
+ $this->loaded = array();
31
+ $this->instances = array();
32
+
33
+ add_filter('extra_plugin_headers', array(&$this, 'inject_module_headers'));
34
+ }
35
+
36
+ /**
37
+ * Get an instance of the module manager.
38
+ *
39
+ * @param array|null $default_active_modules
40
+ * @return object
41
+ */
42
+ function &getInstance($default_active_modules = null){
43
+ static $instance = null;
44
+ if ( is_null($instance) ){
45
+ $instance = new blcModuleManager();
46
+ $instance->init($default_active_modules);
47
+ }
48
+ return $instance;
49
+ }
50
+
51
+ /**
52
+ * Retrieve a list of all installed BLC modules.
53
+ *
54
+ * This is essentially a slightly modified copy of get_plugins().
55
+ *
56
+ * @return array An associative array of module headers indexed by module ID.
57
+ */
58
+ function get_modules(){
59
+ if ( !isset($this->_module_cache) ){
60
+ //Refresh the module cache.
61
+
62
+ $relative_path = '/' . plugin_basename($this->module_dir);
63
+ if ( !function_exists('get_plugins') ){
64
+ //BUG: Potentional security flaw/bug. plugin.php is not meant to be loaded outside admin panel.
65
+ require_once(ABSPATH . 'wp-admin/includes/plugin.php');
66
+ }
67
+ $modules = get_plugins( $relative_path );
68
+
69
+ $this->_module_cache = array();
70
+
71
+ foreach($modules as $module_filename => $module_header){
72
+ //Figure out the module ID. If not specified, it is equal to module's filename (sans the .php)
73
+ if ( !empty($module_header['ModuleID']) ){
74
+ $module_id = strtolower(trim($module_header['ModuleID']));
75
+ } else {
76
+ $module_id = strtolower(basename($module_filename, '.php'));
77
+ }
78
+
79
+ $module_header = $this->normalize_module_header($module_header, $module_id, $module_filename);
80
+ $this->_module_cache[$module_id] = $module_header;
81
+ }
82
+
83
+ $this->_category_cache = null;
84
+ }
85
+
86
+ return array_merge($this->_module_cache, $this->_virtual_modules);
87
+ }
88
+
89
+ /**
90
+ * Retrieve modules that match a specific category, or all modules sorted by categories.
91
+ *
92
+ * If a category ID is specified, this method returns the modules that have the "ModuleCategory:"
93
+ * file header set to that value, or an empty array if no modules match that category. The
94
+ * return array is indexed by module id :
95
+ * [module_id1 => module1_data, module_id1 => module2_data, ...]
96
+ *
97
+ * If category is omitted, this method returns a list of all categories plus the modules
98
+ * they contain. Only categories that have at least one module will be included. The return
99
+ * value is an array of arrays, indexed by category ID :
100
+ * [category1 => [module1_id => module1_data, module2_id => module2_data, ...], ...]
101
+ *
102
+ *
103
+ * @param string $category Category id, e.g. "parser" or "container". Optional.
104
+ * @param bool $markup Apply markup to module headers. Defaults to false.
105
+ * @param bool $translate Translate module headers. Defaults to false.
106
+ * @return array An array of categories or module data.
107
+ */
108
+ function get_modules_by_category($category = '', $markup = false, $translate = false){
109
+ if ( !isset($this->_category_cache) ){
110
+ $this->_category_cache = $this->sort_into_categories($this->get_modules());
111
+ }
112
+
113
+ if ( empty($category) ){
114
+ if ( $markup || $translate ){
115
+
116
+ //Translate/apply markup to module headers
117
+ $processed = array();
118
+ $blc_plugin_file = blc_get_plugin_file();
119
+
120
+ foreach($this->_category_cache as $category_id => $modules){
121
+ $processed[$category_id] = array();
122
+ foreach($modules as $module_id => $module_data){
123
+ $module_data = _get_plugin_data_markup_translate(
124
+ $blc_plugin_file, //Modules use the same .mo file as BLC itself
125
+ $module_data,
126
+ $markup,
127
+ $translate
128
+ );
129
+ $processed[$category_id][$module_id] = $module_data;
130
+ }
131
+ }
132
+
133
+ return $processed;
134
+ } else {
135
+ return $this->_category_cache;
136
+ }
137
+ } else {
138
+ if ( isset($this->_category_cache[$category]) ){
139
+ if ( $markup || $translate ){
140
+ //Translate/apply markup to module headers
141
+ $processed = array();
142
+ $blc_plugin_file = blc_get_plugin_file();
143
+ foreach($this->_category_cache[$category] as $module_id => $module_data){
144
+ $module_data = _get_plugin_data_markup_translate(
145
+ $blc_plugin_file, //Modules use the same .mo file as BLC itself
146
+ $module_data,
147
+ $markup,
148
+ $translate
149
+ );
150
+ $processed[$module_id] = $module_data;
151
+ }
152
+ return $processed;
153
+ } else {
154
+ return $this->_category_cache[$category];
155
+ }
156
+ } else {
157
+ return array();
158
+ }
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Retrieve active modules that match a specific category, or all active modules sorted by categories.
164
+ *
165
+ * @see blcModuleManager::get_modules_by_category()
166
+ *
167
+ * @param string $category Category id. Optional.
168
+ * @return array An associative array of categories or module data.
169
+ */
170
+ function get_active_by_category($category = ''){
171
+ if ( !isset($this->_category_cache_active) ){
172
+ $this->_category_cache_active = $this->sort_into_categories($this->get_active_modules());
173
+ }
174
+
175
+ if ( empty($category) ){
176
+ return $this->_category_cache_active;
177
+ } else {
178
+ if ( isset($this->_category_cache_active[$category]) ){
179
+ return $this->_category_cache_active[$category];
180
+ } else {
181
+ return array();
182
+ }
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Get the module ids of all active modules that belong to a specific category,
188
+ * quoted and ready for use in SQL.
189
+ *
190
+ * @param string $category Category ID. If not specified, a list of all active modules will be returned.
191
+ * @return string A comma separated list of single-quoted module ids, e.g. 'module-foo','module-bar','modbaz'
192
+ */
193
+ function get_escaped_ids($category = ''){
194
+ global $wpdb;
195
+
196
+ if ( empty($category) ){
197
+ $modules = $this->get_active_modules();
198
+ } else {
199
+ $modules = $this->get_active_by_category($category);
200
+ }
201
+
202
+ $modules = array_map(array(&$wpdb, 'escape'), array_keys($modules));
203
+ $modules = "'" . implode("', '", $modules) . "'";
204
+
205
+ return $modules;
206
+ }
207
+
208
+ /**
209
+ * Sort a list of modules into categories. Inside each category, modules are sorted by priority (descending).
210
+ *
211
+ * @access private
212
+ *
213
+ * @param array $modules
214
+ * @return array
215
+ */
216
+ function sort_into_categories($modules){
217
+ $categories = array();
218
+
219
+ foreach($modules as $module_id => $module_data){
220
+ $cat = $module_data['ModuleCategory'];
221
+ if ( isset($categories[$cat]) ){
222
+ $categories[$cat][$module_id] = $module_data;
223
+ } else {
224
+ $categories[$cat] = array($module_id => $module_data);
225
+ }
226
+ }
227
+
228
+ foreach($categories as $cat => $cat_modules){
229
+ uasort($categories[$cat], array(&$this, 'compare_priorities'));
230
+ }
231
+
232
+ return $categories;
233
+ }
234
+
235
+ /**
236
+ * Callback for sorting modules by priority.
237
+ *
238
+ * @access private
239
+ *
240
+ * @param array $a First module header.
241
+ * @param array $b Second module header.
242
+ * @return int
243
+ */
244
+ function compare_priorities($a, $b){
245
+ return $b['ModulePriority'] - $a['ModulePriority'];
246
+ }
247
+
248
+ /**
249
+ * Retrieve a reference to an active module.
250
+ *
251
+ * Each module is instantiated only once, so if the module was already loaded you'll get back
252
+ * a reference to the existing module object. If the module isn't loaded or instantiated yet,
253
+ * the function will do it automatically (but only for active modules).
254
+ *
255
+ * @param string $module_id Module ID.
256
+ * @param bool $autoload Optional. Whether to load the module file if it's not loaded yet. Defaults to TRUE.
257
+ * @param string $category Optional. Return the module only if it's in a specific category. Categories are ignored by default.
258
+ * @return blcModule A reference to a module object, or NULL on error.
259
+ */
260
+ function &get_module($module_id, $autoload = true, $category=''){
261
+ if ( !is_string($module_id) ){
262
+ //$backtrace = debug_backtrace();
263
+ //FB::error($backtrace, "get_module called with a non-string argument");
264
+ return null;
265
+ }
266
+
267
+ if ( empty($this->loaded[$module_id]) ){
268
+ if ( $autoload && $this->is_active($module_id) ){
269
+ if ( !$this->load_module($module_id) ){
270
+ return null;
271
+ }
272
+ } else {
273
+ return null;
274
+ }
275
+ }
276
+
277
+ if ( !empty($category) ){
278
+ $data = $this->get_module_data($module_id);
279
+ if ( $data['ModuleCategory'] != $category ){
280
+ return null;
281
+ }
282
+ }
283
+
284
+ $module = &$this->init_module($module_id);
285
+ return $module;
286
+ }
287
+
288
+ /**
289
+ * Retrieve the header data of a specific module.
290
+ * Uses cached module info if available.
291
+ *
292
+ * @param string $module_id
293
+ * @param bool $use_active_cache Check the active module cache before the general one. Defaults to true.
294
+ * @return array Associative array of module data, or FALSE if the specified module was not found.
295
+ */
296
+ function get_module_data($module_id, $use_active_cache = true){
297
+ //Check virtual modules
298
+ if ( isset($this->_virtual_modules[$module_id]) ){
299
+ return $this->_virtual_modules[$module_id];
300
+ }
301
+
302
+ //Check active modules
303
+ if ( $use_active_cache && isset($this->plugin_conf->options['active_modules'][$module_id]) ){
304
+ return $this->plugin_conf->options['active_modules'][$module_id];
305
+ }
306
+
307
+ //Otherwise, use the general module cache
308
+ if ( !isset($this->_module_cache) ){
309
+ $this->get_modules(); //Populates the cache
310
+ }
311
+
312
+ if ( isset($this->_module_cache[$module_id]) ){
313
+ return $this->_module_cache[$module_id];
314
+ } else {
315
+ return false;
316
+ }
317
+ }
318
+
319
+ /**
320
+ * Retrieve a list of active modules.
321
+ *
322
+ * The list of active modules is stored in the 'active_modules' key of the
323
+ * plugin configuration object. If this key is not set, this function will
324
+ * create it and populate it using the list of default active modules passed
325
+ * to the module manager's constructor.
326
+ *
327
+ * @return array Associative array of module data indexed by module ID.
328
+ */
329
+ function get_active_modules(){
330
+ if ( isset($this->plugin_conf->options['active_modules']) ){
331
+ return $this->plugin_conf->options['active_modules'];
332
+ }
333
+
334
+ $active = array();
335
+ $modules = $this->get_modules();
336
+
337
+ if ( is_array($this->default_active_modules) ){
338
+ foreach($this->default_active_modules as $module_id){
339
+ if ( array_key_exists($module_id, $modules) ){
340
+ $active[$module_id] = $modules[$module_id];
341
+ }
342
+ }
343
+ }
344
+
345
+ $this->plugin_conf->options['active_modules'] = $active;
346
+ $this->plugin_conf->save_options();
347
+
348
+ return $this->plugin_conf->options['active_modules'];
349
+ }
350
+
351
+ /**
352
+ * Determine if module is active.
353
+ *
354
+ * @param string $module_id
355
+ * @return bool
356
+ */
357
+ function is_active($module_id){
358
+ return array_key_exists($module_id, $this->get_active_modules());
359
+ }
360
+
361
+ /**
362
+ * Activate a module.
363
+ * Does nothing if the module is already active.
364
+ *
365
+ * @param string $module_id
366
+ * @return bool True if module was activated sucessfully, false otherwise.
367
+ */
368
+ function activate($module_id){
369
+ if ( $this->is_active($module_id) ){
370
+ return true;
371
+ }
372
+
373
+ //Retrieve the module header
374
+ $module_data = $this->get_module_data($module_id, false);
375
+ if ( !$module_data ){
376
+ return false;
377
+ }
378
+
379
+ //Attempt to load the module
380
+ if ( $this->load_module($module_id, $module_data) ){
381
+ //Okay, if it loads, we can assume it works.
382
+ $this->plugin_conf->options['active_modules'][$module_id] = $module_data;
383
+ $this->plugin_conf->save_options();
384
+ //Invalidate the per-category active module cache
385
+ $this->_category_cache_active = null;
386
+
387
+ //Notify the module that it's been activated
388
+ $module = & $this->get_module($module_id);
389
+ if ( $module ){
390
+ $module->activated();
391
+ }
392
+ } else {
393
+ return false;
394
+ }
395
+ }
396
+
397
+ /**
398
+ * Deactivate a module.
399
+ * Does nothing if the module is already inactive.
400
+ *
401
+ * @param string $module_id
402
+ * @return bool
403
+ */
404
+ function deactivate($module_id){
405
+ if ( !$this->is_active($module_id) ){
406
+ return true;
407
+ }
408
+
409
+ //Some modules are supposed to be always active and thus can't be deactivated
410
+ $module_data = $this->get_module_data($module_id, false);
411
+ if ( isset($module_data['ModuleAlwaysActive']) && $module_data['ModuleAlwaysActive'] ){
412
+ return false;
413
+ }
414
+
415
+ //Notify the module that it's being deactivated
416
+ $module = & $this->get_module($module_id);
417
+ if ( $module ){
418
+ $module->deactivated();
419
+ }
420
+
421
+ unset($this->plugin_conf->options['active_modules'][$module_id]);
422
+
423
+ //Keep track of when each module was last deactivated. Used for parser resynchronization.
424
+ if ( isset($this->plugin_conf->options['module_deactivated_when']) ){
425
+ $this->plugin_conf->options['module_deactivated_when'][$module_id] = current_time('timestamp');
426
+ } else {
427
+ $this->plugin_conf->options['module_deactivated_when'] = array(
428
+ $module_id => current_time('timestamp'),
429
+ );
430
+ }
431
+ $this->plugin_conf->save_options();
432
+
433
+ $this->_category_cache_active = null; //Invalidate the by-category cache since we just changed something
434
+ return true;
435
+ }
436
+
437
+ /**
438
+ * Determine when a module was last deactivated.
439
+ *
440
+ * @param string $module_id Module ID.
441
+ * @return int Timestamp of last deactivation, or 0 if the module has never been deactivated.
442
+ */
443
+ function get_last_deactivation_time($module_id){
444
+ if ( isset($this->plugin_conf->options['module_deactivated_when'][$module_id]) ){
445
+ return $this->plugin_conf->options['module_deactivated_when'][$module_id];
446
+ } else {
447
+ return 0;
448
+ }
449
+ }
450
+
451
+ /**
452
+ * Set the current list of active modules. If any of the modules are not currently active,
453
+ * they will be activated. Any currently active modules that are not on the new list will
454
+ * be deactivated.
455
+ *
456
+ * @param array $ids An array of module IDs.
457
+ * @return void
458
+ */
459
+ function set_active_modules($ids){
460
+ $current_active = array_keys($this->get_active_modules());
461
+
462
+ $activate = array_diff($ids, $current_active);
463
+ $deactivate = array_diff($current_active, $ids);
464
+
465
+ //Deactivate any modules not present in the new list
466
+ foreach($deactivate as $module_id){
467
+ $this->deactivate($module_id);
468
+ }
469
+
470
+ //Activate modules present in the new list but not in the old list
471
+ foreach($activate as $module_id){
472
+ $this->activate($module_id);
473
+ }
474
+
475
+ //Ensure all active modules have the latest headers
476
+ $this->refresh_active_module_cache();
477
+
478
+ //Invalidate the per-category active module cache
479
+ $this->_category_cache_active = null;
480
+ }
481
+
482
+ /**
483
+ * Send the activation message to all currently active plugins when the plugin is activated.
484
+ *
485
+ * @return void
486
+ */
487
+ function plugin_activated(){
488
+ //Ensure all active modules have the latest headers
489
+ $this->refresh_active_module_cache();
490
+
491
+ //Notify them that we've been activated
492
+ $active = $this->get_active_modules();
493
+ foreach($active as $module_id => $module_data){
494
+ $module = & $this->get_module($module_id);
495
+ if ( $module ){
496
+ $module->activated();
497
+ }
498
+ }
499
+ }
500
+
501
+ /**
502
+ * Refresh the cached data of all active modules.
503
+ *
504
+ * @return array An updated list of active modules.
505
+ */
506
+ function refresh_active_module_cache(){
507
+ $modules = $this->get_modules();
508
+ foreach($this->plugin_conf->options['active_modules'] as $module_id => $module_header){
509
+ if ( array_key_exists($module_id, $modules) ){
510
+ $this->plugin_conf->options['active_modules'][$module_id] = $modules[$module_id];
511
+ }
512
+ }
513
+ $this->plugin_conf->save_options();
514
+ $this->_category_cache_active = null; //Invalidate the by-category active module cache
515
+ return $this->plugin_conf->options['active_modules'];
516
+ }
517
+
518
+ /**
519
+ * Load active modules.
520
+ *
521
+ * @param string $context Optional. If specified, only the modules that match this context (or the "all" context) will be loaded.
522
+ * @return void
523
+ */
524
+ function load_modules($context = ''){
525
+ $active = $this->get_active_modules();
526
+ //Avoid trying to load a virtual module before the module that registered it has been loaded.
527
+ $active = $this->put_virtual_last($active);
528
+
529
+ foreach($active as $module_id => $module_data){
530
+ //Load the module
531
+ $should_load = ($module_data['ModuleContext'] == 'all') || (!empty($context) && $module_data['ModuleContext'] == $context);
532
+ if ( $should_load ){
533
+ $this->load_module($module_id, $module_data);
534
+ }
535
+ }
536
+ }
537
+
538
+ /**
539
+ * Load and possibly instantiate a specific module.
540
+ *
541
+ * @access private
542
+ *
543
+ * @param string $module_id
544
+ * @param array $module_data
545
+ * @return bool True if the module was successfully loaded, false otherwise.
546
+ */
547
+ function load_module($module_id, $module_data = null){
548
+
549
+ //Only load each module once.
550
+ if ( !empty($this->loaded[$module_id]) ){
551
+ return true;
552
+ }
553
+
554
+ if ( !isset($module_data) ){
555
+ $module_data = $this->get_module_data($module_id);
556
+ if ( empty($module_data) ){
557
+ return false;
558
+ }
559
+ }
560
+
561
+ //Only load Pro-version modules with BLC Pro
562
+ if ( $module_data['ModuleRequiresPro'] && !defined('BLC_PRO_VERSION') ){
563
+ return false;
564
+ }
565
+
566
+ //Load a normal module
567
+ if ( empty($module_data['virtual']) ){
568
+
569
+ //Skip invalid and missing modules
570
+ if ( empty($module_data['file']) ){
571
+ return false;
572
+ }
573
+
574
+ //Get the full path to the module file
575
+ $filename = $this->module_dir . '/' . $module_data['file'];
576
+ if ( !file_exists($filename) ){
577
+ return false;
578
+ }
579
+
580
+ //Load it
581
+ include $filename;
582
+ $this->loaded[$module_id] = true;
583
+
584
+ } else {
585
+
586
+ //Virtual modules don't need to be explicitly loaded, but they must
587
+ //be registered.
588
+ if ( !array_key_exists($module_id, $this->_virtual_modules) ) {
589
+ return false;
590
+ }
591
+ $this->loaded[$module_id] = true;
592
+
593
+ }
594
+
595
+ //Instantiate the main module class unless lazy init is on (default is off)
596
+ if ( !array_key_exists($module_id, $this->instances) ){ //Only try to instantiate once
597
+ if ( !$module_data['ModuleLazyInit'] ){
598
+ $this->init_module($module_id, $module_data);
599
+ }
600
+ }
601
+
602
+ return true;
603
+ }
604
+
605
+ /**
606
+ * Instantiate a certain module.
607
+ *
608
+ * @param string $module_id
609
+ * @param array $module_data Optional. The header data of the module that needs to be instantiated. If not specified, it will be retrieved automatically.
610
+ * @return object The newly instantiated module object (extends blcModule), or NULL on error.
611
+ */
612
+ function &init_module($module_id, $module_data = null){
613
+ //Each module is only instantiated once.
614
+ if ( isset($this->instances[$module_id]) ){
615
+ return $this->instances[$module_id];
616
+ }
617
+
618
+ if ( !isset($module_data) ){
619
+ $module_data = $this->get_module_data($module_id);
620
+ if ( empty($module_data) ){
621
+ return null;
622
+ }
623
+ }
624
+
625
+ if ( !empty($module_data['ModuleClassName']) && class_exists($module_data['ModuleClassName']) ){
626
+ $className = $module_data['ModuleClassName'];
627
+ $this->instances[$module_id] = new $className(
628
+ $module_id,
629
+ $module_data,
630
+ $this->plugin_conf,
631
+ $this
632
+ );
633
+ return $this->instances[$module_id];
634
+ };
635
+
636
+ return null;
637
+ }
638
+
639
+ function is_instantiated($module_id){
640
+ return !empty($this->instances[$module_id]);
641
+ }
642
+
643
+ /**
644
+ * Register a virtual module.
645
+ *
646
+ * Virtual modules are the same as normal modules, except that they can be added
647
+ * on the fly, e.g. by other modules.
648
+ *
649
+ * @param string $module_id Module Id.
650
+ * @param string $module_data Associative array of module data. All module header fields are allowed, except ModuleID.
651
+ * @return void
652
+ */
653
+ function register_virtual_module($module_id, $module_data){
654
+ $module_data = $this->normalize_module_header($module_data, $module_id);
655
+ $module_data['virtual'] = true;
656
+ $this->_virtual_modules[$module_id] = $module_data;
657
+ }
658
+
659
+ /**
660
+ * Sort an array of modules so that all virtual modules are placed at its end.
661
+ *
662
+ * @param array $modules Input array, [module_id => module_data, ...].
663
+ * @return array Sorted array.
664
+ */
665
+ function put_virtual_last($modules){
666
+ uasort($modules, array(&$this, 'compare_virtual_flags'));
667
+ return $modules;
668
+ }
669
+
670
+ /**
671
+ * Callback function for sorting modules by the state of their 'virtual' flag.
672
+ *
673
+ * @param array $a Associative array of module A data
674
+ * @param array $b Associative array of module B data
675
+ * @return int
676
+ */
677
+ function compare_virtual_flags($a, $b){
678
+ if ( empty($a['virtual']) ){
679
+ return empty($b['virtual'])?0:-1;
680
+ } else {
681
+ return empty($b['virtual'])?1:0;
682
+ }
683
+ }
684
+
685
+ /**
686
+ * Validate active modules.
687
+ *
688
+ * Validates all active modules, deactivates invalid ones and returns
689
+ * an array of deactivated modules.
690
+ *
691
+ * @return array
692
+ */
693
+ function validate_active_modules(){
694
+ $active = $this->get_active_modules();
695
+ if ( empty($active) ){
696
+ return array();
697
+ }
698
+
699
+ $invalid = array();
700
+ foreach($active as $module_id => $module_data){
701
+ $rez = $this->validate_module($module_data);
702
+ if ( is_wp_error($rez) ){
703
+ $invalid[$module_id] = $rez;
704
+ $this->deactivate($module_id);
705
+ }
706
+ }
707
+
708
+ return $invalid;
709
+ }
710
+
711
+ /**
712
+ * Validate module data.
713
+ *
714
+ * Checks that the module file exists or that the module
715
+ * is a currently registered virtual module.
716
+ *
717
+ * @param array $module_data Associative array of module data.
718
+ * @return bool|WP_Error True on success, an error object if the module fails validation
719
+ */
720
+ function validate_module($module_data){
721
+ if ( empty($module_data['ModuleID']) ){
722
+ return new WP_Error('invalid_cached_header', 'The cached module header is invalid');
723
+ }
724
+
725
+ if ( empty($module_data['virtual']) ){
726
+ //Normal modules must have a valid filename
727
+ if ( empty($module_data['file']) ){
728
+ return new WP_Error('module_not_found', 'Invalid module file');
729
+ }
730
+
731
+ $filename = $this->module_dir . '/' . $module_data['file'];
732
+ if ( !file_exists($filename) ){
733
+ return new WP_Error('module_not_found', 'Module file not found');
734
+ }
735
+
736
+ //The module file header must be in the proper format. While $module_data comes
737
+ //from cache and can be assumed to be correct, get_modules() will attempt to load
738
+ //the current headers and only return modules with semi-valid headers.
739
+ $installed = $this->get_modules();
740
+ if ( !array_key_exists($module_data['ModuleID'], $installed) ){
741
+ return new WP_Error('invalid_module_header', 'Invalid module header');
742
+ }
743
+ } else {
744
+ //Virtual modules need to be currently registered
745
+ if ( !array_key_exists($module_data['ModuleID'], $this->_virtual_modules) ){
746
+ return new WP_Error('module_not_registered', 'The virtual module is not registered');
747
+ }
748
+ }
749
+
750
+ return true;
751
+ }
752
+
753
+ /**
754
+ * Add BLC-module specific headers to the list of allowed plugin headers. This
755
+ * lets us use get_plugins() to retrieve the list of BLC modules.
756
+ *
757
+ * @param array $headers Currently known plugin headers.
758
+ * @return array New plugin headers.
759
+ */
760
+ function inject_module_headers($headers){
761
+ $module_headers = array(
762
+ 'ModuleID',
763
+ 'ModuleCategory',
764
+ 'ModuleContext',
765
+ 'ModuleLazyInit',
766
+ 'ModuleClassName',
767
+ 'ModulePriority',
768
+ 'ModuleCheckerUrlPattern',
769
+ 'ModuleHidden', //Don't show the module in the Settings page
770
+ 'ModuleAlwaysActive', //Module can't be deactivated.
771
+ 'ModuleRequiresPro', //Can only be activated in the Pro version
772
+ );
773
+
774
+ return array_merge($headers, $module_headers);
775
+ }
776
+
777
+ /**
778
+ * Normalize a module header, using defaults where necessary.
779
+ *
780
+ * @param array $module_header Module header, as read from the module's .php file.
781
+ * @param string $module_id Module ID.
782
+ * @param string $module_filename Module filename. Optional.
783
+ * @return array Normalized module header.
784
+ */
785
+ function normalize_module_header($module_header, $module_id, $module_filename = ''){
786
+ //Default values for optional module header fields
787
+ $defaults = array(
788
+ 'ModuleContext' => 'all',
789
+ 'ModuleCategory' => 'other',
790
+ 'ModuleLazyInit' => 'false',
791
+ 'ModulePriority' => '0',
792
+ 'ModuleHidden' => 'false',
793
+ 'ModuleAlwaysActive' => 'false',
794
+ 'ModuleRequiresPro' => 'false',
795
+ 'TextDomain' => 'broken-link-checker', //For translating module headers
796
+ );
797
+
798
+ $module_header['ModuleID'] = $module_id; //Just for consistency
799
+ $module_header['file'] = $module_filename; //Used later to load the module
800
+
801
+ //Apply defaults
802
+ foreach($defaults as $field => $default_value){
803
+ if ( empty($module_header[$field]) ){
804
+ $module_header[$field] = $default_value;
805
+ }
806
+ }
807
+
808
+ //Convert bool/int fields from strings to native datatypes
809
+ $module_header['ModuleLazyInit'] = $this->str_to_bool($module_header['ModuleLazyInit']);
810
+ $module_header['ModuleHidden'] = $this->str_to_bool($module_header['ModuleHidden']);
811
+ $module_header['ModuleAlwaysActive'] = $this->str_to_bool($module_header['ModuleAlwaysActive']);
812
+ $module_header['ModuleRequiresPro'] = $this->str_to_bool($module_header['ModuleRequiresPro']);
813
+ $module_header['ModulePriority'] = intval($module_header['ModulePriority']);
814
+
815
+ return $module_header;
816
+ }
817
+
818
+ /**
819
+ * Converts the strings "true" and "false" to boolean TRUE and FALSE, respectively.
820
+ * Any other string will yield FALSE.
821
+ *
822
+ * @param string $value "true" or "false", case-insensitive.
823
+ * @return bool
824
+ */
825
+ function str_to_bool($value){
826
+ $value = trim(strtolower($value));
827
+ return $value == 'true';
828
+ }
829
+
830
+ /**
831
+ * Generates a PHP script that calls the __() i18n function with
832
+ * the name and description of each available module. The generated
833
+ * script is used to make module headers show up in the .POT file.
834
+ *
835
+ * @access private
836
+ *
837
+ * @return string
838
+ */
839
+ function _build_header_translation_code(){
840
+ $this->_module_cache = null; //Clear the cache
841
+ $modules = $this->get_modules();
842
+
843
+ $strings = array();
844
+ foreach($modules as $module_id => $module_header){
845
+ if ( $module_header['ModuleHidden'] || ($module_id == 'write-module-placeholders')) {
846
+ continue;
847
+ }
848
+ if ( !empty($module_header['Name']) ){
849
+ $strings[] = sprintf(
850
+ '_x("%s", "module name", "broken-link-checker");',
851
+ str_replace('"', '\"', $module_header['Name'])
852
+ );
853
+ }
854
+ }
855
+
856
+ return "<?php\n" . implode("\n", $strings) . "\n?>";
857
+ }
858
+ }
859
+
860
+ ?>
includes/modules.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Load all files pertaining to BLC's module subsystem
5
+ */
6
+
7
+ require 'module-manager.php';
8
+ require 'module-base.php';
9
+
10
+ require 'containers.php';
11
+ require 'checkers.php';
12
+ require 'parsers.php';
13
+
14
+ $blc_module_manager = & blcModuleManager::getInstance(array(
15
+ //List of modules active by default
16
+ 'http', //Link checker for the HTTP(s) protocol
17
+ 'link', //HTML link parser
18
+ 'image', //HTML image parser
19
+ 'metadata', //Metadata (custom field) parser
20
+ 'url_field', //URL field parser
21
+ 'blogroll', //Blogroll container
22
+ 'comment', //Comment container
23
+ 'custom_field', //Post metadata container (aka custom fields)
24
+ 'post', //Post content container
25
+ 'page', //Page content container
26
+ 'dummy', //Dummy container used as a fallback
27
+ ));
28
+
29
+ require 'any-post.php';
30
+
31
+ ?>
includes/parsers.php CHANGED
@@ -1,100 +1,5 @@
1
  <?php
2
 
3
- /**
4
- * Parser Registry class for managing parsers. Used as a singleton.
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
- * Get an instance of the parser registry class.
20
- *
21
- * @return blcParserRegistry
22
- */
23
- function &getInstance(){
24
- static $instance = null;
25
- if ( is_null($instance) ){
26
- $instance = new blcParserRegistry;
27
- }
28
- return $instance;
29
- }
30
-
31
- /**
32
- * Register a new link parser.
33
- *
34
- * @param string $parser_type A unique string identifying the parser.
35
- * @param string $class_name Name of the class implementing the parser.
36
- * @return bool True on success, false if this parser type is already registered.
37
- */
38
- function register_parser( $parser_type, $class_name ){
39
- if ( isset($this->registered_parsers[$parser_type]) ){
40
- return false;
41
- }
42
-
43
- $parser = new $class_name($parser_type);
44
- $this->registered_parsers[$parser_type] = $parser;
45
-
46
- return true;
47
- }
48
-
49
- /**
50
- * Retrieve a list of all registered parsers.
51
- *
52
- * @return array An associative array of parser objects indexed by parser ID.
53
- */
54
- function get_registered_parsers(){
55
- return $this->registered_parsers;
56
- }
57
-
58
- /**
59
- * Get the parser matching a parser type ID.
60
- *
61
- * @param string $parser_type
62
- * @return blcParser|null
63
- */
64
- function &get_parser( $parser_type ){
65
- if ( isset($this->registered_parsers[$parser_type]) ){
66
- return $this->registered_parsers[$parser_type];
67
- } else {
68
- return null;
69
- }
70
- }
71
-
72
- /**
73
- * Get all parsers that support either the specified format or the container type.
74
- * If a parser supports both, it will still be included only once.
75
- *
76
- * @param string $format
77
- * @param string $container_type
78
- * @return array of blcParser
79
- */
80
- function get_parsers( $format, $container_type ){
81
- $found = array();
82
-
83
- foreach($this->registered_parsers as $parser){
84
- if ( in_array($format, $parser->supported_formats) || in_array($container_type, $parser->supported_containers) ){
85
- array_push($found, $parser);
86
- }
87
- }
88
-
89
- return $found;
90
- }
91
-
92
- }
93
-
94
- //Create the parser registry singleton.
95
- $GLOBALS['blc_parser_registry'] = & blcParserRegistry::getInstance();
96
-
97
-
98
  /**
99
  * A base class for parsers.
100
  *
@@ -117,30 +22,58 @@ $GLOBALS['blc_parser_registry'] = & blcParserRegistry::getInstance();
117
  * @package Broken Link Checker
118
  * @access public
119
  */
120
- class blcParser {
121
 
122
  var $parser_type;
123
  var $supported_formats = array();
124
  var $supported_containers = array();
125
 
126
- /**
127
- * Class construtor.
128
- *
129
- * @param string $parser_type
130
- * @return void
131
- */
132
- function __construct( $parser_type ){
133
- $this->parser_type = $parser_type;
134
  }
135
 
136
- /**
137
- * PHP4 constructor
138
- *
139
- * @param string $parser_type
140
- * @return void
141
- */
142
- function blcParser( $parser_type ){
143
- $this->__construct( $parser_type );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  }
145
 
146
  /**
@@ -196,13 +129,13 @@ class blcParser {
196
  * @param blcLinkInstance $instance
197
  * @return string HTML
198
  */
199
- function ui_get_link_text($instance, $context = 'display'){
200
  return $instance->link_text;
201
  }
202
 
203
  /**
204
  * Turn a relative URL into an absolute one.
205
- *
206
  * @param string $url Relative URL.
207
  * @param string $base_url Base URL. If omitted, the blog's root URL will be used.
208
  * @return string
@@ -332,47 +265,57 @@ class blcParser {
332
  }
333
 
334
  /**
335
- * Register a new link parser.
336
- *
337
  * @see blcParser
338
- *
339
- * @uses blcParserRegistry::register_parser()
340
- *
341
- * @param string $parser_type A unique string identifying the parser, e.g. "html_link"
342
- * @param string $class_name Name of the class that implements the parser.
343
- * @return bool
344
- */
345
- function blc_register_parser( $parser_type, $class_name ) {
346
- $instance = & blcParserRegistry::getInstance();
347
- return $instance->register_parser($parser_type, $class_name);
348
- }
349
-
350
- /**
351
- * Get the parser matching a parser type id.
352
- *
353
- * @uses blcParserRegistry::get_parser()
354
- *
355
- * @param string $parser_type
356
- * @return blcParser|null
357
- */
358
- function &blc_get_parser( $parser_type ){
359
- $instance = & blcParserRegistry::getInstance();
360
- return $instance->get_parser($parser_type);
361
- }
362
-
363
- /**
364
- * Get all parsers that support either the specified format or container type.
365
- *
366
- * @uses blcParserRegistry::get_parsers()
367
- *
368
- * @param string $format
369
- * @param string $container_type
370
- * @return array of blcParser
371
  */
372
- function blc_get_parsers( $format, $container_type ){
373
- $instance = & blcParserRegistry::getInstance();
374
- return $instance->get_parsers($format, $container_type);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375
  }
376
 
377
-
378
  ?>
1
  <?php
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  /**
4
  * A base class for parsers.
5
  *
22
  * @package Broken Link Checker
23
  * @access public
24
  */
25
+ class blcParser extends blcModule {
26
 
27
  var $parser_type;
28
  var $supported_formats = array();
29
  var $supported_containers = array();
30
 
31
+ /**
32
+ * Initialize the parser. Nothing much here.
33
+ *
34
+ * @return void
35
+ */
36
+ function init(){
37
+ parent::init();
38
+ $this->parser_type = $this->module_id;
39
  }
40
 
41
+ /**
42
+ * Called when the parser is activated.
43
+ *
44
+ * @return void
45
+ */
46
+ function activated(){
47
+ parent::activated();
48
+ $this->resynch_relevant_containers();
49
+ }
50
+
51
+ /**
52
+ * Mark containers that this parser might be interested in as unparsed.
53
+ *
54
+ * @uses blcContainerHelper::mark_as_unsynched_where()
55
+ *
56
+ * @param bool $only_return If true, just return the list of formats and container types without actually modifying any synch. records.
57
+ * @return void|array Either nothing or an array in the form [ [format1=>timestamp1, ...], [container_type1=>timestamp1, ...] ]
58
+ */
59
+ function resynch_relevant_containers($only_return = false){
60
+ $last_deactivated = $this->module_manager->get_last_deactivation_time($this->module_id);
61
+
62
+ $formats = array();
63
+ foreach($this->supported_formats as $format){
64
+ $formats[$format] = $last_deactivated;
65
+ }
66
+
67
+ $container_types = array();
68
+ foreach($this->supported_containers as $container_type){
69
+ $container_types[$container_type] = $last_deactivated;
70
+ }
71
+
72
+ if ( $only_return ){
73
+ return array($formats, $container_types);
74
+ } else {
75
+ blcContainerHelper::mark_as_unsynched_where($formats, $container_types);
76
+ }
77
  }
78
 
79
  /**
129
  * @param blcLinkInstance $instance
130
  * @return string HTML
131
  */
132
+ function ui_get_link_text(&$instance, $context = 'display'){
133
  return $instance->link_text;
134
  }
135
 
136
  /**
137
  * Turn a relative URL into an absolute one.
138
+ *
139
  * @param string $url Relative URL.
140
  * @param string $base_url Base URL. If omitted, the blog's root URL will be used.
141
  * @return string
265
  }
266
 
267
  /**
268
+ * A helper class for working with parsers. All its methods should be called statically.
269
+ *
270
  * @see blcParser
271
+ *
272
+ * @package Broken Link Checker
273
+ * @access public
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  */
275
+ class blcParserHelper {
276
+
277
+ /**
278
+ * Get the parser matching a parser type ID.
279
+ *
280
+ * @uses blcModuleManager::get_module()
281
+ *
282
+ * @param string $parser_type
283
+ * @return blcParser|null
284
+ */
285
+ function &get_parser( $parser_type ){
286
+ $manager = & blcModuleManager::getInstance();
287
+ return $manager->get_module($parser_type, true, 'parser');
288
+ }
289
+
290
+ /**
291
+ * Get all parsers that support either the specified format or the container type.
292
+ * If a parser supports both, it will still be included only once.
293
+ *
294
+ * @param string $format
295
+ * @param string $container_type
296
+ * @return array of blcParser
297
+ */
298
+ function get_parsers( $format, $container_type ){
299
+ $found = array();
300
+
301
+ //Retrieve a list of active parsers
302
+ $manager = & blcModuleManager::getInstance();
303
+ $active_parsers = $manager->get_modules_by_category('parser');
304
+
305
+ //Try each one
306
+ foreach($active_parsers as $module_id => $module_data){
307
+ $parser = & $manager->get_module($module_id); //Will autoload if necessary
308
+ if ( !$parser ){
309
+ continue;
310
+ }
311
+
312
+ if ( in_array($format, $parser->supported_formats) || in_array($container_type, $parser->supported_containers) ){
313
+ array_push($found, $parser);
314
+ }
315
+ }
316
+
317
+ return $found;
318
+ }
319
  }
320
 
 
321
  ?>
includes/screen-options/screen-options.js ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(function($){
2
+ function performAutosave(){
3
+ var panel = $(this).parents('div.custom-options-panel');
4
+ var params = panel.find('input, select, textarea').serialize();
5
+ params = params + '&action=save_settings-' + panel.attr('id');
6
+ $.post(
7
+ 'admin-ajax.php',
8
+ params
9
+ );
10
+ }
11
+
12
+ $('#screen-options-wrap div.requires-autosave').find('input, select, textarea').change(performAutosave);
13
+ });
includes/screen-options/screen-options.php ADDED
@@ -0,0 +1,282 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( !class_exists('wsScreenOptions12') ):
4
+
5
+ /**
6
+ * Class for adding new panels to the "Screen Options" box.
7
+ *
8
+ * Do not access this class directly. Instead, use the add_screen_options_panel() function.
9
+ *
10
+ * @author Janis Elsts
11
+ * @copyright 2010
12
+ * @version 1.2
13
+ * @access public
14
+ */
15
+ class wsScreenOptions12 {
16
+ var $registered_panels; //List of custom "Screen Options" panels
17
+ var $page_panels; //Index of panels registered for each page ($page => array of panel ids).
18
+
19
+ /**
20
+ * Class constructor
21
+ *
22
+ * @return void
23
+ */
24
+ function init(){
25
+ $this->registered_panels = array();
26
+ $this->page_panels = array();
27
+
28
+ add_filter('screen_settings', array(&$this, 'append_screen_settings'), 10, 2);
29
+ add_action('admin_print_scripts', array(&$this, 'add_autosave_script'));
30
+ }
31
+
32
+ /**
33
+ * Add a new settings panel to the "Screen Options" box.
34
+ *
35
+ * @param string $id String to use in the 'id' attribute of the settings panel. Should be unique.
36
+ * @param string $title Title of the settings panel. Set to an empty string to omit title.
37
+ * @param callback $callback Function that fills the panel with the desired content. Should return its output.
38
+ * @param string|array $page The page(s) on which to show the panel (similar to add_meta_box()).
39
+ * @param callback $save_callback Optional. Function that saves the settings.
40
+ * @param bool $autosave Optional. If se, settings will be automatically saved (via AJAX) when the value of any input element in the panel changes. Defaults to false.
41
+ * @return void
42
+ */
43
+ function add_screen_options_panel($id, $title, $callback, $page, $save_callback = null, $autosave = false){
44
+ if ( !is_array($page) ){
45
+ $page = array($page);
46
+ }
47
+ //Convert page hooks/slugs to screen IDs
48
+ $page = array_map(array(&$this, 'page_to_screen_id'), $page);
49
+ $page = array_unique($page);
50
+
51
+ $new_panel = array(
52
+ 'title' => $title,
53
+ 'callback' => $callback,
54
+ 'page' => $page,
55
+ 'save_callback' => $save_callback,
56
+ 'autosave' => $autosave,
57
+ );
58
+
59
+ if ( $save_callback ){
60
+ add_action('wp_ajax_save_settings-' . $id, array(&$this, 'ajax_save_callback'));
61
+ }
62
+
63
+ //Store the panel ID in each relevant page's list
64
+ foreach($page as $page_id){
65
+ if ( !isset($this->page_panels[$page_id]) ){
66
+ $this->page_panels[$page_id] = array();
67
+ }
68
+ $this->page_panels[$page_id][] = $id;
69
+ }
70
+
71
+ $this->registered_panels[$id] = $new_panel;
72
+ }
73
+
74
+ /**
75
+ * Convert a page hook name to a screen ID.
76
+ *
77
+ * @uses convert_to_screen()
78
+ * @access private
79
+ *
80
+ * @param string $page
81
+ * @return string
82
+ */
83
+ function page_to_screen_id($page){
84
+ if ( function_exists('convert_to_screen') ){
85
+ $screen = convert_to_screen($page);
86
+ if ( isset($screen->id) ){
87
+ return $screen->id;
88
+ } else {
89
+ return '';
90
+ }
91
+ } else {
92
+ return str_replace( array('.php', '-new', '-add' ), '', $page);
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Append custom panel HTML to the "Screen Options" box of the current page.
98
+ * Callback for the 'screen_settings' filter (available in WP 3.0 and up).
99
+ *
100
+ * @access private
101
+ *
102
+ * @param string $current
103
+ * @param string $screen Screen object (undocumented).
104
+ * @return string The HTML code to append to "Screen Options"
105
+ */
106
+ function append_screen_settings($current, $screen){
107
+ global $hook_suffix;
108
+
109
+ //Sanity check
110
+ if ( !isset($screen->id) ) {
111
+ return $current;
112
+ }
113
+
114
+ //Are there any panels that want to appear on this page?
115
+ $panels = $this->get_panels_for_screen($screen->id, $hook_suffix);
116
+ if ( empty($panels) ){
117
+ return $current;
118
+ }
119
+
120
+ //Append all panels registered for this screen
121
+ foreach($panels as $panel_id){
122
+ $panel = $this->registered_panels[$panel_id];
123
+
124
+ //Add panel title
125
+ if ( !empty($panel['title']) ){
126
+ $current .= "\n<h5>".$panel['title']."</h5>\n";
127
+ }
128
+ //Generate panel contents
129
+ if ( is_callable($panel['callback']) ){
130
+ $contents = call_user_func($panel['callback']);
131
+ $classes = array(
132
+ 'custom-options-panel',
133
+ );
134
+ if ( $panel['autosave'] ){
135
+ $classes[] = 'requires-autosave';
136
+ }
137
+
138
+ $contents = sprintf(
139
+ '<div id="%s" class="%s"><input type="hidden" name="_wpnonce-%s" value="%s" />%s</div>',
140
+ esc_attr($panel_id),
141
+ implode(' ',$classes),
142
+ esc_attr($panel_id),
143
+ wp_create_nonce('save_settings-'.$panel_id),
144
+ $contents
145
+ );
146
+
147
+ $current .= $contents;
148
+ }
149
+ }
150
+
151
+ return $current;
152
+ }
153
+
154
+ /**
155
+ * AJAX callback for the "Screen Options" autosave.
156
+ *
157
+ * @access private
158
+ * @return void
159
+ */
160
+ function ajax_save_callback(){
161
+ if ( empty($_POST['action']) ){
162
+ die('0');
163
+ }
164
+
165
+ //The 'action' argument is in the form "save_settings-panel_id"
166
+ $id = end(explode('-', $_POST['action'], 2));
167
+
168
+ //Basic security check.
169
+ check_ajax_referer('save_settings-' . $id, '_wpnonce-' . $id);
170
+
171
+ //Hand the request to the registered callback, if any
172
+ if ( !isset($this->registered_panels[$id]) ){
173
+ exit('0');
174
+ }
175
+ $panel = $this->registered_panels[$id];
176
+ if ( is_callable($panel['save_callback']) ){
177
+ call_user_func($panel['save_callback'], $_POST);
178
+ die('1');
179
+ } else {
180
+ die('0');
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Add/enqueue supporting JavaScript for the autosave function of custom "Screen Options" panels.
186
+ *
187
+ * Checks if the current page is supposed to contain any autosave-enabled
188
+ * panels and adds the script only if that's the case.
189
+ *
190
+ * @return void
191
+ */
192
+ function add_autosave_script(){
193
+ //Get the page id/hook/slug/whatever.
194
+ global $hook_suffix;
195
+
196
+ //Check if we have some panels with autosave registered for this page.
197
+ $panels = $this->get_panels_for_screen('', $hook_suffix);
198
+ if ( empty($panels) ){
199
+ return;
200
+ }
201
+
202
+ $got_autosave = false;
203
+ foreach($panels as $panel_id){
204
+ if ( $this->registered_panels[$panel_id]['autosave'] ){
205
+ $got_autosave = true;
206
+ break;
207
+ }
208
+ }
209
+
210
+ if ( $got_autosave ){
211
+ //Enqueue the script itself
212
+ $url = plugins_url('screen-options.js', __FILE__);
213
+ wp_enqueue_script('screen-options-custom-autosave', $url, array('jquery'));
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Get custom panels registered for a particular screen and/or page.
219
+ *
220
+ * @param string $screen_id Screen ID.
221
+ * @param string $page Optional. Page filename or hook name.
222
+ * @return array Array of custom panels.
223
+ */
224
+ function get_panels_for_screen($screen_id, $page = ''){
225
+ if ( isset($this->page_panels[$screen_id]) && !empty($this->page_panels[$screen_id]) ){
226
+ $panels = $this->page_panels[$screen_id];
227
+ } else {
228
+ $panels = array();
229
+ }
230
+ if ( !empty($page) ){
231
+ $page_as_screen = $this->page_to_screen_id($page);
232
+ if ( isset($this->page_panels[$page_as_screen]) && !empty($this->page_panels[$page_as_screen]) ){
233
+ $panels = array_merge($panels, $this->page_panels[$page_as_screen]);
234
+ }
235
+ }
236
+ return array_unique($panels);
237
+ }
238
+ }
239
+
240
+ //All versions of the class are stored in a global array
241
+ //and only the latest version is actually used.
242
+ global $ws_screen_options_versions;
243
+ if ( !isset($ws_screen_options_versions) ){
244
+ $ws_screen_options_versions = array();
245
+ }
246
+ $ws_screen_options_versions['1.2'] = 'wsScreenOptions12';
247
+
248
+ endif;
249
+
250
+ if ( !function_exists('add_screen_options_panel') ){
251
+
252
+ /**
253
+ * Add a new settings panel to the "Screen Options" box.
254
+ *
255
+ * @see wsScreenOptions10::add_screen_options_panel()
256
+ *
257
+ * @param string $id String to use in the 'id' attribute of the settings panel. Should be unique.
258
+ * @param string $title Title of the settings panel. Set to an empty string to omit title.
259
+ * @param callback $callback Function that fills the panel with the desired content. Should return its output.
260
+ * @param string|array $page The page(s) on which to show the panel (similar to add_meta_box()).
261
+ * @param callback $save_callback Optional. Function that saves the settings contained in the panel.
262
+ * @param bool $autosave Optional. If set, settings will be automatically saved (via AJAX) when the value of any input element in the panel changes. Defaults to false.
263
+ * @return void
264
+ */
265
+ function add_screen_options_panel($id, $title, $callback, $page, $save_callback = null, $autosave = false){
266
+ global $ws_screen_options_versions;
267
+
268
+ static $instance = null;
269
+ if ( is_null($instance) ){
270
+ //Instantiate the latest version of the wsScreenOptions class
271
+ uksort($ws_screen_options_versions, 'version_compare');
272
+ $className = end($ws_screen_options_versions);
273
+ $instance = new $className;
274
+ $instance->init();
275
+ }
276
+
277
+ return $instance->add_screen_options_panel($id, $title, $callback, $page, $save_callback, $autosave);
278
+ }
279
+
280
+ }
281
+
282
+ ?>
utility-class.php → includes/utility-class.php RENAMED
@@ -2,7 +2,7 @@
2
 
3
  /**
4
  * @author W-Shadow
5
- * @copyright 2009
6
  */
7
 
8
 
@@ -36,146 +36,6 @@ if ( !class_exists('blcUtility') ){
36
 
37
  class blcUtility {
38
 
39
- //A regxp for images
40
- function img_pattern(){
41
- // \1 \2 \3 URL \4
42
- return '/(<img[\s]+[^>]*src\s*=\s*)([\"\'])([^>]+?)\2([^<>]*>)/i';
43
- }
44
-
45
- //A regexp for links
46
- function link_pattern(){
47
- // \1 \2 \3 URL \4 \5 Text \6
48
- return '/(<a[\s]+[^>]*href\s*=\s*)([\"\'])([^>]+?)\2([^<>]*>)((?sU).*)(<\/a>)/i';
49
- }
50
-
51
- /**
52
- * blcUtility::normalize_url()
53
- *
54
- * @param string $url
55
- * @params string $base_url (Optional) The base URL is used to convert a relative URL to a fully-qualified one
56
- * @return string A normalized URL or FALSE if the URL is invalid
57
- */
58
- function normalize_url($url, $base_url = ''){
59
- //Sometimes links may contain shortcodes. Parse them.
60
- $url = do_shortcode($url);
61
-
62
- $parts = @parse_url($url);
63
- if(!$parts) return false; //Invalid URL
64
-
65
- if(isset($parts['scheme'])) {
66
- //Only HTTP(S) links are checked. Other protocols are not supported.
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
74
- '/(#[^\/]*)$/', //and anchors/fragments
75
- '/&amp;/', //convert improper HTML entities
76
- '/^(javascript:.*)/i', //treat links that contain JS as links with an empty URL
77
- '/([\?&]sid=\w+)$/i' //remove another flavour of session ID
78
- ),
79
- array('','','&','',''),
80
- $url);
81
- $url = trim($url);
82
-
83
- if ( $url=='' ) return false;
84
-
85
- // turn relative URLs into absolute URLs
86
- if ( empty($base_url) ) $base_url = get_option('siteurl');
87
- $url = blcUtility::relative2absolute( $base_url, $url);
88
- return $url;
89
- }
90
-
91
- /**
92
- * blcUtility::relative2absolute()
93
- * Turns a relative URL into an absolute one given a base URL.
94
- *
95
- * @param string $absolute Base URL
96
- * @param string $relative A relative URL
97
- * @return string
98
- */
99
- function relative2absolute($absolute, $relative) {
100
- $p = @parse_url($relative);
101
- if(!$p) {
102
- //WTF? $relative is a seriously malformed URL
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']);
121
- array_pop($aparts);
122
- $aparts=array_filter($aparts);
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']) {
146
- $url = "$parts[scheme]://";
147
- }
148
- if(isset($parts['user'])) {
149
- $url .= $parts['user'];
150
- if(isset($parts['pass'])) {
151
- $url .= ":".$parts['pass'];
152
- }
153
- $url .= "@";
154
- }
155
- if(isset($parts['host'])) {
156
- $url .= $parts['host']."/";
157
- }
158
- $url .= $path;
159
-
160
- return $url;
161
- }
162
-
163
-
164
- /**
165
- * blcUtility::urlencodefix()
166
- * Takes an URL and replaces spaces and some other non-alphanumeric characters with their urlencoded equivalents.
167
- *
168
- * @param string $str
169
- * @return string
170
- */
171
- function urlencodefix($url){
172
- return preg_replace_callback(
173
- '|[^a-z0-9\+\-\/\\#:.=?&%@]|i',
174
- create_function('$str','return rawurlencode($str[0]);'),
175
- $url
176
- );
177
- }
178
-
179
  /**
180
  * blcUtility::is_safe_mode()
181
  * Checks if PHP is running in safe mode
@@ -355,6 +215,131 @@ class blcUtility {
355
  return $tags;
356
  }
357
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
  }//class
359
 
360
  }//class_exists
2
 
3
  /**
4
  * @author W-Shadow
5
+ * @copyright 2010
6
  */
7
 
8
 
36
 
37
  class blcUtility {
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  /**
40
  * blcUtility::is_safe_mode()
41
  * Checks if PHP is running in safe mode
215
  return $tags;
216
  }
217
 
218
+ /**
219
+ * Extract <embed> elements from a HTML string.
220
+ *
221
+ * This function returns an array of <embed> elements found in the input
222
+ * string. Only <embed>'s that are inside <object>'s are considered. Embeds
223
+ * without a 'src' attribute are skipped.
224
+ *
225
+ * Each array item has the same basic structure as the array items
226
+ * returned by blcUtility::extract_tags(), plus an additional 'wrapper' key
227
+ * that contains similarly structured info about the wrapping <object> tag.
228
+ *
229
+ * @uses blcUtility::extract_tags() This function is a simple wrapper around extract_tags()
230
+ *
231
+ * @param string $html
232
+ * @return array
233
+ */
234
+ function extract_embeds($html){
235
+ $results = array();
236
+
237
+ //remove all <code></code> blocks first
238
+ $content = preg_replace('/<code[^>]*>.+?<\/code>/si', ' ', $content);
239
+
240
+ //Find likely-looking <object> elements
241
+ $objects = blcUtility::extract_tags($html, 'object', false, true);
242
+ foreach($objects as $candidate){
243
+ //Find the <embed> tag
244
+ $embed = blcUtility::extract_tags($candidate['full_tag'], 'embed', false);
245
+ if ( empty($embed)) continue;
246
+ $embed = reset($embed); //Take the first (and only) found <embed> element
247
+
248
+ if ( empty($embed['attributes']['src']) ){
249
+ continue;
250
+ }
251
+
252
+ $embed['wrapper'] = $candidate;
253
+
254
+ $results[] = $embed;
255
+ }
256
+
257
+ return $results;
258
+ }
259
+
260
+ /**
261
+ * Get the value of a cookie.
262
+ *
263
+ * @param string $cookie_name The name of the cookie to return.
264
+ * @param string $default_value Optional. If the cookie is not set, this value will be returned instead. Defaults to an empty string.
265
+ * @return mixed Either the value of the requested cookie, or $default_value.
266
+ */
267
+ function get_cookie($cookie_name, $default_value = ''){
268
+ if ( isset($_COOKIE[$cookie_name]) ){
269
+ return $_COOKIE[$cookie_name];
270
+ } else {
271
+ return $default_value;
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Format a time delta using a fuzzy format, e.g. '2 minutes ago', '2 days', etc.
277
+ *
278
+ * @param int $delta Time period in seconds.
279
+ * @param string $type Optional. The output template to use.
280
+ * @return string
281
+ */
282
+ function fuzzy_delta($delta, $template = 'default'){
283
+ $ONE_MINUTE = 60;
284
+ $ONE_HOUR = 60 * $ONE_MINUTE;
285
+ $ONE_DAY = 24 * $ONE_HOUR;
286
+ $ONE_MONTH = $ONE_DAY * 3652425 / 120000;
287
+ $ONE_YEAR = $ONE_DAY * 3652425 / 10000;
288
+
289
+ $templates = array(
290
+ 'seconds' => array(
291
+ 'default' => _n_noop('%d second', '%d seconds'),
292
+ 'ago' => _n_noop('%d second ago', '%d seconds ago'),
293
+ ),
294
+ 'minutes' => array(
295
+ 'default' => _n_noop('%d minute', '%d minutes'),
296
+ 'ago' => _n_noop('%d minute ago', '%d minutes ago'),
297
+ ),
298
+ 'hours' => array(
299
+ 'default' => _n_noop('%d hour', '%d hours'),
300
+ 'ago' => _n_noop('%d hour ago', '%d hours ago'),
301
+ ),
302
+ 'days' => array(
303
+ 'default' => _n_noop('%d day', '%d days'),
304
+ 'ago' => _n_noop('%d day ago', '%d days ago'),
305
+ ),
306
+ 'months' => array(
307
+ 'default' => _n_noop('%d month', '%d months'),
308
+ 'ago' => _n_noop('%d month ago', '%d months ago'),
309
+ ),
310
+ );
311
+
312
+ if ( $delta < 1 ) {
313
+ $delta = 1;
314
+ }
315
+
316
+ if ( $delta < $ONE_MINUTE ){
317
+ $units = 'seconds';
318
+ } elseif ( $delta < $ONE_HOUR ){
319
+ $delta = intval($delta / $ONE_MINUTE);
320
+ $units = 'minutes';
321
+ } elseif ( $delta < $ONE_DAY ){
322
+ $delta = intval($delta / $ONE_HOUR);
323
+ $units = 'hours';
324
+ } elseif ( $delta < $ONE_MONTH ){
325
+ $delta = intval($delta / $ONE_DAY);
326
+ $units = 'days';
327
+ } else {
328
+ $delta = intval( $delta / $ONE_MONTH );
329
+ $units = 'months';
330
+ }
331
+
332
+ return sprintf(
333
+ _n(
334
+ $templates[$units][$template][0],
335
+ $templates[$units][$template][1],
336
+ $delta,
337
+ 'broken-link-checker'
338
+ ),
339
+ $delta
340
+ );
341
+ }
342
+
343
  }//class
344
 
345
  }//class_exists
js/jquery.cookie.js ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Cookie plugin
3
+ *
4
+ * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
5
+ * Dual licensed under the MIT and GPL licenses:
6
+ * http://www.opensource.org/licenses/mit-license.php
7
+ * http://www.gnu.org/licenses/gpl.html
8
+ *
9
+ */
10
+
11
+ /**
12
+ * Create a cookie with the given name and value and other optional parameters.
13
+ *
14
+ * @example $.cookie('the_cookie', 'the_value');
15
+ * @desc Set the value of a cookie.
16
+ * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
17
+ * @desc Create a cookie with all available options.
18
+ * @example $.cookie('the_cookie', 'the_value');
19
+ * @desc Create a session cookie.
20
+ * @example $.cookie('the_cookie', null);
21
+ * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
22
+ * used when the cookie was set.
23
+ *
24
+ * @param String name The name of the cookie.
25
+ * @param String value The value of the cookie.
26
+ * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
27
+ * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
28
+ * If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
29
+ * If set to null or omitted, the cookie will be a session cookie and will not be retained
30
+ * when the the browser exits.
31
+ * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
32
+ * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
33
+ * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
34
+ * require a secure protocol (like HTTPS).
35
+ * @type undefined
36
+ *
37
+ * @name $.cookie
38
+ * @cat Plugins/Cookie
39
+ * @author Klaus Hartl/klaus.hartl@stilbuero.de
40
+ */
41
+
42
+ /**
43
+ * Get the value of a cookie with the given name.
44
+ *
45
+ * @example $.cookie('the_cookie');
46
+ * @desc Get the value of a cookie.
47
+ *
48
+ * @param String name The name of the cookie.
49
+ * @return The value of the cookie.
50
+ * @type String
51
+ *
52
+ * @name $.cookie
53
+ * @cat Plugins/Cookie
54
+ * @author Klaus Hartl/klaus.hartl@stilbuero.de
55
+ */
56
+ jQuery.cookie = function(name, value, options) {
57
+ if (typeof value != 'undefined') { // name and value given, set cookie
58
+ options = options || {};
59
+ if (value === null) {
60
+ value = '';
61
+ options.expires = -1;
62
+ }
63
+ var expires = '';
64
+ if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
65
+ var date;
66
+ if (typeof options.expires == 'number') {
67
+ date = new Date();
68
+ date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
69
+ } else {
70
+ date = options.expires;
71
+ }
72
+ expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
73
+ }
74
+ // CAUTION: Needed to parenthesize options.path and options.domain
75
+ // in the following expressions, otherwise they evaluate to undefined
76
+ // in the packed version for some reason...
77
+ var path = options.path ? '; path=' + (options.path) : '';
78
+ var domain = options.domain ? '; domain=' + (options.domain) : '';
79
+ var secure = options.secure ? '; secure' : '';
80
+ document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
81
+ } else { // only name given, get cookie
82
+ var cookieValue = null;
83
+ if (document.cookie && document.cookie != '') {
84
+ var cookies = document.cookie.split(';');
85
+ for (var i = 0; i < cookies.length; i++) {
86
+ var cookie = jQuery.trim(cookies[i]);
87
+ // Does this cookie string begin with the name we want?
88
+ if (cookie.substring(0, name.length + 1) == (name + '=')) {
89
+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
90
+ break;
91
+ }
92
+ }
93
+ }
94
+ return cookieValue;
95
+ }
96
+ };
languages/broken-link-checker-pt_PT.po CHANGED
@@ -1,18 +1,18 @@
1
- # Translation of the WordPress plugin Broken Link Checker 0.9.1 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
- # Tradução em português pt_PT do plugin Broken Link Checker - v.1.0 - 30/06/2010
5
- # Autor: PedroM - <pm[at]mowster[dot]net>
6
  # Website: http://jobs.mowster.net/ - <jobs@mowster.net>
7
  #
8
  msgid ""
9
  msgstr ""
10
  "Project-Id-Version: Broken Link Checker PT\n"
11
- "Report-Msgid-Bugs-To: http://wordpress.org/tag/broken-link-checker\n"
12
- "POT-Creation-Date: 2010-04-28 18:48+0000\n"
13
  "PO-Revision-Date: \n"
14
  "Last-Translator: \n"
15
- "Language-Team: MJobs | http://jobs.mowster.net <jobs@mowster.net>\n"
16
  "MIME-Version: 1.0\n"
17
  "Content-Type: text/plain; charset=UTF-8\n"
18
  "Content-Transfer-Encoding: 8bit\n"
@@ -24,765 +24,922 @@ msgstr ""
24
  "X-Poedit-Basepath: ..\n"
25
  "X-Poedit-SearchPath-0: .\n"
26
 
27
- #: broken-link-checker.php:273
28
  msgid "Once Weekly"
29
  msgstr "Uma vez por semana"
30
 
31
- #: core.php:137
32
- #: includes/admin/links-page-js.php:21
 
 
 
 
 
 
 
 
33
  msgid "Loading..."
34
  msgstr "Carregando..."
35
 
36
- #: core.php:160
37
- #: core.php:696
38
  msgid "[ Network error ]"
39
  msgstr "[ Problema na rede ]"
40
 
41
- #: core.php:185
42
  msgid "Automatically expand the widget if broken links have been detected"
43
  msgstr "Expandir automaticamente a caixa se existirem links offline"
44
 
45
- #: core.php:296
46
  #, php-format
47
  msgid "Failed to delete old DB tables. Database error : %s"
48
  msgstr "Não foi possível apagar as tabelas antigas da Base de dados. Erro de Base de dados : %s"
49
 
50
- #: core.php:313
51
  #, php-format
52
  msgid "Unexpected error: The plugin doesn't know how to upgrade its database to version '%d'."
53
  msgstr "Erro inesperado: O plugin não consegue actualizar a Base de dados para a versão '%d'."
54
 
55
- #: core.php:349
56
- #: core.php:378
57
- #: core.php:420
58
- #: core.php:445
59
  #, php-format
60
  msgid "Failed to create table '%s'. Database error: %s"
61
  msgstr "Não foi possível criar a tabela '%s'. Erro na Base de dados: %s"
62
 
63
- #: core.php:473
64
  msgid "Link Checker Settings"
65
  msgstr "Definições do Links offline"
66
 
67
- #: core.php:474
68
  msgid "Link Checker"
69
  msgstr "Links offline"
70
 
71
- #: core.php:480
72
- msgid "View Broken Links"
73
- msgstr "Ver Links offline"
74
-
75
- #: core.php:481
76
- #: includes/links.php:771
77
  msgid "Broken Links"
78
  msgstr "Links offline"
79
 
80
- #: core.php:502
 
 
 
 
81
  #, php-format
82
  msgid "Highlight links broken for at least %s days"
83
  msgstr "Sublinhar links offline pelo menos por %s dias"
84
 
85
- #: core.php:528
86
  msgid "Settings"
87
  msgstr "Definições"
88
 
89
- #: core.php:538
90
- #: core.php:1039
91
  #, php-format
92
  msgid "Error: The plugin's database tables are not up to date! (Current version : %d, expected : %d)"
93
  msgstr "Erro: As tabelas do plugin na Base de dados não estão actualizadas! (Versão actual : %d, obrigatória : %d)"
94
 
95
- #: core.php:653
96
  msgid "Settings saved."
97
  msgstr "Definições guardadas."
98
 
99
- #: core.php:661
100
  msgid "Broken Link Checker Options"
101
  msgstr "Opções : Links offline"
102
 
103
- #: core.php:674
104
  msgid "Status"
105
  msgstr "Estado"
106
 
107
- #: core.php:676
108
- #: core.php:1019
109
  msgid "Show debug info"
110
  msgstr "Mostrar sistema"
111
 
112
- #: core.php:709
113
  msgid "Re-check all pages"
114
  msgstr "Verificar de novo todas as páginas"
115
 
116
- #: core.php:733
117
  msgid "Check each link"
118
  msgstr "Verificar cada link"
119
 
120
- #: core.php:738
121
  #, php-format
122
  msgid "Every %s hours"
123
  msgstr "Cada %s horas"
124
 
125
- #: core.php:747
126
  msgid "Existing links will be checked this often. New links will usually be checked ASAP."
127
  msgstr "Os links existentes serão verificados com esta frequência. Os novos links comprovados logo que possível."
128
 
129
- #: core.php:754
130
  msgid "Broken link CSS"
131
  msgstr "Link CSS offline"
132
 
133
- #: core.php:759
134
  msgid "Apply <em>class=\"broken_link\"</em> to broken links"
135
  msgstr "Aplicar <em>class=\"broken_link\"</em> aos links offline"
136
 
137
- #: core.php:771
138
  msgid "Removed link CSS"
139
  msgstr "Link CSS removido"
140
 
141
- #: core.php:776
142
  msgid "Apply <em>class=\"removed_link\"</em> to unlinked links"
143
  msgstr "Aplicar <em>class=\"removed_link\"</em> aos links sem ligação"
144
 
145
- #: core.php:788
146
  msgid "Broken link SEO"
147
  msgstr "Link SEO offline"
148
 
149
- #: core.php:793
150
  msgid "Apply <em>rel=\"nofollow\"</em> to broken links"
151
  msgstr "Aplicar <em>rel=\"nofollow\"</em> aos links offline"
152
 
153
- #: core.php:799
154
  msgid "Exclusion list"
155
  msgstr "Lista de exclusão"
156
 
157
- #: core.php:800
158
  msgid "Don't check links where the URL contains any of these words (one per line) :"
159
  msgstr "Não verificar links que a URL tenha alguma destas palavras (uma por linha):"
160
 
161
- #: core.php:810
162
  msgid "Custom fields"
163
  msgstr "Campos personalizados"
164
 
165
- #: core.php:811
166
  msgid "Check URLs entered in these custom fields (one per line) :"
167
  msgstr "Verificar as seguintes URL personalizadas (uma por linha):"
168
 
169
- #: core.php:821
 
 
 
 
 
 
 
 
170
  msgid "E-mail notifications"
171
  msgstr "Notificações por e-mail"
172
 
173
- #: core.php:827
174
  msgid "Send me e-mail notifications about newly detected broken links"
175
  msgstr "Enviar um e-mail notificando sobre os novos links offline detectados"
176
 
177
- #: core.php:835
178
  msgid "Advanced"
179
  msgstr "Avançado"
180
 
181
- #: core.php:841
182
  msgid "Timeout"
183
  msgstr "Intervalo"
184
 
185
- #: core.php:847
186
- #: core.php:891
 
187
  #, php-format
188
  msgid "%s seconds"
189
  msgstr "%s segundos"
190
 
191
- #: core.php:856
192
  msgid "Links that take longer than this to load will be marked as broken."
193
  msgstr "Os links que demoram mais que este tempo a abrir serão marcados como offline."
194
 
195
- #: core.php:863
196
  msgid "Link monitor"
197
  msgstr "Monitor de links"
198
 
199
- #: core.php:869
200
  msgid "Run continuously while the Dashboard is open"
201
  msgstr "Executar continuamente enquanto o Painel do WordPress está aberto"
202
 
203
- #: core.php:877
204
  msgid "Run hourly in the background"
205
  msgstr "Executar a cada hora em segundo plano"
206
 
207
- #: core.php:885
208
  msgid "Max. execution time"
209
  msgstr "Tempo máximo de execução"
210
 
211
- #: core.php:902
212
  msgid "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."
213
  msgstr "O plugin funciona executando periodicamente uma tarefa em segundo plano que analiza os links, verifica os URL encontrados e realiza outras tarefas que consomem tempo. Aqui pode-se estabelecer a duração máxima cada vez que o monitor de links é executado antes de parar."
214
 
215
- #: core.php:912
216
  msgid "Custom temporary directory"
217
  msgstr "Pasta temporária personalizada"
218
 
219
- #: core.php:921
220
  msgid "OK"
221
  msgstr "Aceitar"
222
 
223
- #: core.php:924
224
  msgid "Error : This directory isn't writable by PHP."
225
  msgstr "Erro: PHP não pode escrever nesse directório."
226
 
227
- #: core.php:929
228
  msgid "Error : This directory doesn't exist."
229
  msgstr "Erro: Não existe esse directório."
230
 
231
- #: core.php:937
232
  msgid "Set this field if you want the plugin to use a custom directory for its lockfiles. Otherwise, leave it blank."
233
  msgstr "Preencha este campo se deseja que o plugin utilize um directório personalizado para seus ficheiros temporários. Caso contrário, deixa-lo em branco."
234
 
235
- #: core.php:944
236
  msgid "Server load limit"
237
  msgstr "Limite de carregamento do servidor"
238
 
239
- #: core.php:985
240
  #, php-format
241
  msgid "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."
242
  msgstr "A verificação dos links será suspensa se a média do <a href=\"%s\">carregamento do servidor</a> passa este valor. Deixar o campo em branco para não existir limite."
243
 
244
- #: core.php:995
245
  msgid "Load limiting only works on Linux-like systems where <code>/proc/loadavg</code> is present and accessible."
246
  msgstr "O limite de carregamento somente funciona em sistemas Linux onde <code>/proc/loadavg</code> está presente e acessível."
247
 
248
- #: core.php:1004
249
  msgid "Save Changes"
250
  msgstr "Guardar alterações"
251
 
252
- #: core.php:1017
253
  msgid "Hide debug info"
254
  msgstr "Ocultar informação"
255
 
256
- #: core.php:1125
257
- #: core.php:1458
258
- #: core.php:1490
259
  #, php-format
260
  msgid "Database error : %s"
261
  msgstr "Erro na Base de dados: %s"
262
 
263
- #: core.php:1200
264
  msgid "Bulk Actions"
265
  msgstr "Edição em Massa"
266
 
267
- #: core.php:1201
268
  msgid "Recheck"
269
  msgstr "Voltar a verificar"
270
 
271
- #: core.php:1202
272
  msgid "Fix redirects"
273
  msgstr "Reparar redirects"
274
 
275
- #: core.php:1203
276
- #: core.php:1357
277
- #: includes/admin/links-page-js.php:293
 
 
 
 
278
  msgid "Unlink"
279
  msgstr "Remover link"
280
 
281
- #: core.php:1204
282
  msgid "Delete sources"
283
  msgstr "Apagar fontes"
284
 
285
- #: core.php:1218
286
- #: core.php:1392
287
  msgid "Apply"
288
  msgstr "Aplicar"
289
 
290
- #: core.php:1225
291
  msgid "&laquo;"
292
  msgstr "&laquo;"
293
 
294
- #: core.php:1226
295
  msgid "&raquo;"
296
  msgstr "&raquo;"
297
 
298
- #: core.php:1233
299
- #: core.php:1398
300
  #, php-format
301
  msgid "Displaying %s&#8211;%s of <span class=\"current-link-count\">%s</span>"
302
  msgstr "Mostrando %s&#8211;%s de <span class=\"current-link-count\">%s</span>"
303
 
304
- #: core.php:1252
305
  msgid "Source"
306
  msgstr "Fonte"
307
 
308
- #: core.php:1253
309
  msgid "Link Text"
310
  msgstr "Texto do Link"
311
 
312
- #: core.php:1254
313
  #: includes/admin/search-form.php:42
314
  msgid "URL"
315
  msgstr "URL"
316
 
317
- #: core.php:1330
318
  msgid "[An orphaned link! This is a bug.]"
319
  msgstr "[Um link orfão! Bug.]"
320
 
321
- #: core.php:1354
322
  msgid "Show more info about this link"
323
  msgstr "Mostrar mais informação sobre este link"
324
 
325
- #: core.php:1354
326
- #: core.php:2726
327
  msgid "Details"
328
  msgstr "Detalhes"
329
 
330
- #: core.php:1356
331
  msgid "Remove this link from all posts"
332
  msgstr "Eliminar este link"
333
 
334
- #: core.php:1362
335
  msgid "Remove this link from the list of broken links and mark it as valid"
336
  msgstr "Eliminar este link da lista dos links offline e marca-lo como válido"
337
 
338
- #: core.php:1363
339
- #: includes/admin/links-page-js.php:78
340
  msgid "Not broken"
341
  msgstr "Funcional"
342
 
343
- #: core.php:1367
344
  msgid "Edit link URL"
345
  msgstr "Editar URL do link"
346
 
347
- #: core.php:1367
348
- #: includes/admin/links-page-js.php:199
349
- #: includes/admin/links-page-js.php:227
350
  msgid "Edit URL"
351
  msgstr "Editar URL"
352
 
353
- #: core.php:1373
354
  msgid "Cancel URL editing"
355
  msgstr "Cancelar a edição do URL"
356
 
357
- #: core.php:1373
358
- #: includes/admin/search-form.php:87
359
  msgid "Cancel"
360
  msgstr "Cancelar"
361
 
362
- #: core.php:1441
363
  msgid "You must enter a filter name!"
364
  msgstr "Deve introduzir um nome para o filtro!"
365
 
366
- #: core.php:1445
367
  msgid "Invalid search query."
368
  msgstr "Procura inválida."
369
 
370
- #: core.php:1453
371
  #, php-format
372
  msgid "Filter \"%s\" created"
373
  msgstr "Filtro \"%s\" criado"
374
 
375
- #: core.php:1481
376
  msgid "Filter ID not specified."
377
  msgstr "ID do Filtro não especificado."
378
 
379
- #: core.php:1487
380
  msgid "Filter deleted"
381
  msgstr "Filtro eliminado"
382
 
383
- #: core.php:1535
384
  #, php-format
385
  msgid "Replaced %d redirect with a direct link"
386
- msgid_plural "Replaced %d redirects with direct links"
387
- msgstr[0] "Substituídos %d redirect com um link directo"
388
- msgstr[1] "Substituídos %d redirects com links directos"
389
 
390
- #: core.php:1546
391
  #, php-format
392
  msgid "Failed to fix %d redirect"
393
  msgid_plural "Failed to fix %d redirects"
394
  msgstr[0] "Não foi possível reparar %d redirect"
395
  msgstr[1] "Não foi possível reparar %d redirects"
396
 
397
- #: core.php:1556
398
  msgid "None of the selected links are redirects!"
399
  msgstr "Nenhum dos links seleccionados são redirects!"
400
 
401
- #: core.php:1602
402
  #, php-format
403
  msgid "%d link removed"
404
  msgid_plural "%d links removed"
405
  msgstr[0] "%d link eliminado"
406
  msgstr[1] "%d links eliminados"
407
 
408
- #: core.php:1613
409
  #, php-format
410
  msgid "Failed to remove %d link"
411
  msgid_plural "Failed to remove %d links"
412
  msgstr[0] "Erro a remover %d link"
413
  msgstr[1] "Erro a remover %d links"
414
 
415
- #: core.php:1701
416
  msgid "Didn't find anything to delete!"
417
  msgstr "Não foi encontrado nada para apagar!"
418
 
419
- #: core.php:1729
420
  #, php-format
421
  msgid "%d link scheduled for rechecking"
422
  msgid_plural "%d links scheduled for rechecking"
423
  msgstr[0] "%d link agendado para verificação"
424
  msgstr[1] "%d links agendados para verificação"
425
 
426
- #: core.php:1752
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
427
  msgid "Post published on"
428
  msgstr "Post publicado em"
429
 
430
- #: core.php:1757
431
  msgid "Link last checked"
432
  msgstr "Última verificação"
433
 
434
- #: core.php:1761
435
  msgid "Never"
436
  msgstr "Nunca"
437
 
438
- #: core.php:1767
439
  #: includes/admin/search-form.php:45
440
  msgid "HTTP code"
441
  msgstr "Código HTTP"
442
 
443
- #: core.php:1772
444
  msgid "Response time"
445
  msgstr "Tempo de resposta"
446
 
447
- #: core.php:1774
448
  #, php-format
449
  msgid "%2.3f seconds"
450
  msgstr "%2.3f segundos"
451
 
452
- #: core.php:1777
453
  msgid "Final URL"
454
  msgstr "URL final"
455
 
456
- #: core.php:1782
457
  msgid "Redirect count"
458
  msgstr "Contagem de redirects"
459
 
460
- #: core.php:1787
461
  msgid "Instance count"
462
  msgstr "Contagem de casos"
463
 
464
- #: core.php:1796
465
  #, php-format
466
  msgid "This link has failed %d time."
467
  msgid_plural "This link has failed %d times."
468
  msgstr[0] "Este link falhou %d vez."
469
  msgstr[1] "Este link falhou %d vezes."
470
 
471
- #: core.php:1804
472
  #, php-format
473
  msgid "This link has been broken for %s."
474
  msgstr "Link offline durante %s."
475
 
476
- #: core.php:1815
477
  msgid "Log"
478
  msgstr "Registro"
479
 
480
- #: core.php:1841
481
  msgid "less than a minute"
482
  msgstr "menos de um minuto"
483
 
484
- #: core.php:1849
485
  #, php-format
486
  msgid "%d minute"
487
  msgid_plural "%d minutes"
488
  msgstr[0] "%d minuto"
489
  msgstr[1] "%d minutos"
490
 
491
- #: core.php:1863
492
- #: core.php:1890
493
  #, php-format
494
  msgid "%d hour"
495
  msgid_plural "%d hours"
496
  msgstr[0] "%d hora"
497
  msgstr[1] "%d horas"
498
 
499
- #: core.php:1878
500
- #: core.php:1919
501
  #, php-format
502
  msgid "%d day"
503
  msgid_plural "%d days"
504
  msgstr[0] "%d dia"
505
  msgstr[1] "%d dias"
506
 
507
- #: core.php:1908
508
  #, php-format
509
  msgid "%d month"
510
  msgid_plural "%d months"
511
  msgstr[0] "%d mês"
512
  msgstr[1] "%d meses"
513
 
514
- #: core.php:2231
515
  msgid "View broken links"
516
  msgstr "Ver links offline"
517
 
518
- #: core.php:2232
519
  #, php-format
520
  msgid "Found %d broken link"
521
  msgid_plural "Found %d broken links"
522
  msgstr[0] "Encontrado %d Link offline"
523
  msgstr[1] "Encontrados %d Links offline"
524
 
525
- #: core.php:2238
526
  msgid "No broken links found."
527
  msgstr "Não existem links offline."
528
 
529
- #: core.php:2245
530
  #, php-format
531
  msgid "%d URL in the work queue"
532
  msgid_plural "%d URLs in the work queue"
533
  msgstr[0] "%d URL em espera"
534
  msgstr[1] "%d URLs em espera"
535
 
536
- #: core.php:2248
537
  msgid "No URLs in the work queue."
538
  msgstr "Não existem URL em espera para verificação."
539
 
540
- #: core.php:2254
541
  #, php-format
542
  msgid "Detected %d unique URL"
543
  msgid_plural "Detected %d unique URLs"
544
  msgstr[0] "Detectada %d URL única"
545
  msgstr[1] "Detectadas %d URL únicas"
546
 
547
- #: core.php:2255
548
  #, php-format
549
  msgid "in %d link"
550
  msgid_plural "in %d links"
551
  msgstr[0] "em %d link"
552
  msgstr[1] "em %d links"
553
 
554
- #: core.php:2260
555
  msgid "and still searching..."
556
  msgstr "procurando..."
557
 
558
- #: core.php:2266
559
  msgid "Searching your blog for links..."
560
  msgstr "Procurando links..."
561
 
562
- #: core.php:2268
563
  msgid "No links detected."
564
  msgstr "Não se encontraram links."
565
 
566
- #: core.php:2353
567
- #: core.php:2389
568
- #: core.php:2452
569
- #: core.php:2534
570
  msgid "You're not allowed to do that!"
571
  msgstr "Não permitido!"
572
 
573
- #: core.php:2361
574
- #: core.php:2399
575
- #: core.php:2462
576
  #, php-format
577
  msgid "Oops, I can't find the link %d"
578
  msgstr "Oops, não é possível encontrar o link %d"
579
 
580
- #: core.php:2368
581
- msgid "This link was manually marked as working by the user."
582
- msgstr "Este link foi marcado manualmente como válido por outro utilizador."
583
-
584
- #: core.php:2374
585
  msgid "Oops, couldn't modify the link!"
586
  msgstr "Oops, não é possível modificar o link!"
587
 
588
- #: core.php:2377
589
- #: core.php:2488
590
  msgid "Error : link_id not specified"
591
  msgstr "Erro: link_id não especificado"
592
 
593
- #: core.php:2409
594
  msgid "Oops, the new URL is invalid!"
595
  msgstr "Oops, a nova URL não é válida"
596
 
597
- #: core.php:2420
598
- #: core.php:2471
599
  msgid "An unexpected error occured!"
600
  msgstr "Ocorreu um erro inesperado!"
601
 
602
- #: core.php:2438
603
  msgid "Error : link_id or new_url not specified"
604
  msgstr "Erro: link_id ou new_url não especificado"
605
 
606
- #: core.php:2497
607
  msgid "You don't have sufficient privileges to access this information!"
608
  msgstr "Não tem previlégios suficientes para aceder a esta informação!"
609
 
610
- #: core.php:2510
611
  msgid "Error : link ID not specified"
612
  msgstr "Erro: link ID não especificado"
613
 
614
- #: core.php:2521
615
  #, php-format
616
  msgid "Failed to load link details (%s)"
617
  msgstr "Erro a carregar os detalhes do link (%s)"
618
 
619
- #: core.php:2712
 
 
 
 
620
  #, php-format
621
  msgid "The current temporary directory is not accessible; please <a href=\"%s\">set a different one</a>."
622
  msgstr "O directório temporário não está acessível; por favor, <a href=\"%s\">especifique um diferente</a>."
623
 
624
- #: core.php:2717
625
  #, php-format
626
  msgid "Please make the directory <code>%1$s</code> writable by plugins or <a href=\"%2$s\">set a custom temporary directory</a>."
627
  msgstr "Por favor, deve permitir que os plugins possam gravar dados no directório <code>%1$s</code> ou <a href=\"%2$s\">especificar um directório temporário personalizado</a>."
628
 
629
- #: core.php:2724
630
  msgid "Broken Link Checker can't create a lockfile."
631
  msgstr "Links offline não pode criar um ficheiro temporário."
632
 
633
- #: core.php:2729
634
  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."
635
  msgstr "Este plugin utiliza um sistema de bloqueio de ficheiros para garantir que somente se executa uma instância do algoritmo de verificação de links num momento determinado, uma vez que consome bastantes recursos. Infelizmente, o plugin não pode encontrar um directório que possa armazenar um ficheiro temporário - erro ao detectar a localização do directório temporário no servidor, assim como o própio directório do plugin não permite a escrita pelo PHP. Para resolver, terá que dar permissões de escrita ao directório ou especificar um directório temporário na configuração do plugin."
636
 
637
- #: core.php:2748
638
  msgid "PHP version"
639
  msgstr "Versão PHP"
640
 
641
- #: core.php:2754
642
  msgid "MySQL version"
643
  msgstr "Versão MySQL"
644
 
645
- #: core.php:2767
646
  msgid "You have an old version of CURL. Redirect detection may not work properly."
647
  msgstr "Versão de CURL obsoleta. A detecção de redirects pode não funcionar correctamente."
648
 
649
- #: core.php:2779
650
- #: core.php:2795
651
- #: core.php:2800
652
  msgid "Not installed"
653
  msgstr "Não instalado"
654
 
655
- #: core.php:2782
656
  msgid "CURL version"
657
  msgstr "Versão CURL"
658
 
659
- #: core.php:2788
660
  msgid "Installed"
661
  msgstr "Instalado"
662
 
663
- #: core.php:2801
664
  msgid "You must have either CURL or Snoopy installed for the plugin to work!"
665
  msgstr "Instalação de CURL ou Snoopy necessário para que funcione o plugin!"
666
 
667
- #: core.php:2812
668
  msgid "On"
669
  msgstr "Activado"
670
 
671
- #: core.php:2813
672
  msgid "Redirects may be detected as broken links when safe_mode is on."
673
  msgstr "Os redirects podem ser detectados como links offline quando o safe_mode está habilitado."
674
 
675
- #: core.php:2818
676
- #: core.php:2832
677
  msgid "Off"
678
  msgstr "Desactivado"
679
 
680
- #: core.php:2826
681
  #, php-format
682
  msgid "On ( %s )"
683
  msgstr "Activado ( %s )"
684
 
685
- #: core.php:2827
686
  msgid "Redirects may be detected as broken links when open_basedir is on."
687
  msgstr "Os redirects podem ser considerados links offline quando o open_basedir está activo."
688
 
689
- #: core.php:2846
690
  msgid "Can't create a lockfile. Please specify a custom temporary directory."
691
  msgstr "Não foi possível criar um ficheiro. Por favor, especifique um directório temporário personalizado."
692
 
693
- #: core.php:2875
 
 
 
 
694
  #, php-format
695
  msgid "[%s] Broken links detected"
696
  msgstr "[%s] Links offline detectados"
697
 
698
- #: core.php:2881
699
  #, php-format
700
  msgid "Broken Link Checker has detected %d new broken link on your site."
701
  msgid_plural "Broken Link Checker has detected %d new broken links on your site."
702
  msgstr[0] "Links offline detectou %d novo link sem ligação."
703
  msgstr[1] "Links offline detectou %d novos links sem ligação."
704
 
705
- #: core.php:2896
706
  #, php-format
707
  msgid "Here's a list of the first %d broken links:"
708
  msgid_plural "Here's a list of the first %d broken links:"
709
  msgstr[0] "Lista do primeiro %d link sem ligação:"
710
  msgstr[1] "Lista dos primeiros %d links sem ligação:"
711
 
712
- #: core.php:2904
713
  msgid "Here's a list of the new broken links: "
714
  msgstr "Novos links offline:"
715
 
716
- #: core.php:2916
717
  #, php-format
718
  msgid "Link text : %s"
719
  msgstr "Texto do Link : %s"
720
 
721
- #: core.php:2917
722
  #, php-format
723
  msgid "Link URL : <a href=\"%s\">%s</a>"
724
  msgstr "Link URL : <a href=\"%s\">%s</a>"
725
 
726
- #: core.php:2918
727
  #, php-format
728
  msgid "Source : %s"
729
  msgstr "Fonte : %s"
730
 
731
- #: core.php:2932
732
  msgid "You can see all broken links here:"
733
  msgstr "Links offline:"
734
 
735
- #: includes/admin/links-page-js.php:40
736
- #: includes/admin/links-page-js.php:234
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
737
  msgid "Wait..."
738
  msgstr "Espere ..."
739
 
740
- #: includes/admin/links-page-js.php:109
741
  msgid "Save URL"
742
  msgstr "Guardar URL"
743
 
744
- #: includes/admin/links-page-js.php:120
745
  msgid "Saving changes..."
746
  msgstr "Guardando alterações ..."
747
 
748
- #: includes/admin/links-page-js.php:166
749
  #, php-format
750
  msgid "%d instances of the link were successfully modified."
751
  msgstr "%d casos de links que se modificaram com sucesso."
752
 
753
- #: includes/admin/links-page-js.php:172
754
  #, php-format
755
  msgid "However, %d instances couldn't be edited and still point to the old URL."
756
  msgstr "No entanto, %d casos não puderam ser editados e ainda apontam para a antiga URL."
757
 
758
- #: includes/admin/links-page-js.php:178
759
  msgid "The link could not be modified."
760
  msgstr "O link não pode ser modificado."
761
 
762
- #: includes/admin/links-page-js.php:181
763
- #: includes/admin/links-page-js.php:285
764
  msgid "The following error(s) occured :"
765
  msgstr "Erro(s) :"
766
 
767
- #: includes/admin/links-page-js.php:271
768
  #, php-format
769
  msgid "%d instances of the link were successfully unlinked."
770
  msgstr "%d casos de links foram removidos com sucesso."
771
 
772
- #: includes/admin/links-page-js.php:277
773
  #, php-format
774
  msgid "However, %d instances couldn't be removed."
775
  msgstr "No entanto, %d casos não foram removidos."
776
 
777
- #: includes/admin/links-page-js.php:282
778
  msgid "The plugin failed to remove the link."
779
  msgstr "O plugin não removeu o link."
780
 
781
- #: includes/admin/links-page-js.php:337
782
  msgid "Enter a name for the new custom filter"
783
  msgstr "Introduza o nome para o novo filtro personalizado"
784
 
785
- #: includes/admin/links-page-js.php:348
786
  msgid ""
787
  "You are about to delete the current filter.\n"
788
  "'Cancel' to stop, 'OK' to delete"
@@ -790,7 +947,7 @@ msgstr ""
790
  "Está a ponto de apagar o filtro actual.\n"
791
  " 'Cancelar' para sair, 'Aceitar' para apagar."
792
 
793
- #: includes/admin/links-page-js.php:371
794
  msgid ""
795
  "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"
796
  "'Cancel' to stop, 'OK' to delete"
@@ -799,19 +956,6 @@ msgstr ""
799
  "Esta acção não pode ser anulada.\n"
800
  "'Cancelar' para anular a operação, 'Aceitar' para apagar"
801
 
802
- #: includes/admin/search-form.php:13
803
- msgid "Save This Search As a Filter"
804
- msgstr "Criar Filtro desta Procura"
805
-
806
- #: includes/admin/search-form.php:23
807
- msgid "Delete This Filter"
808
- msgstr "Apagar este Filtro"
809
-
810
- #: includes/admin/search-form.php:29
811
- #: includes/links.php:798
812
- msgid "Search"
813
- msgstr "Procurar"
814
-
815
  #: includes/admin/search-form.php:39
816
  msgid "Link text"
817
  msgstr "Texto do link"
@@ -820,86 +964,64 @@ msgstr "Texto do link"
820
  msgid "Link status"
821
  msgstr "Estado do link"
822
 
823
- #: includes/admin/search-form.php:64
824
  msgid "Link type"
825
  msgstr "Tipo de link"
826
 
827
- #: includes/admin/search-form.php:68
828
  msgid "Any"
829
  msgstr "Qualquer"
830
 
831
- #: includes/admin/search-form.php:69
832
  msgid "Normal link"
833
  msgstr "Link normal"
834
 
835
- #: includes/admin/search-form.php:70
836
- #: includes/parsers/image.php:142
837
  msgid "Image"
838
  msgstr "Imagem"
839
 
840
- #: includes/admin/search-form.php:71
841
- #: includes/containers/custom_field.php:176
842
  msgid "Custom field"
843
  msgstr "Campo personalizado"
844
 
845
- #: includes/admin/search-form.php:72
846
  #: includes/containers/blogroll.php:13
847
  msgid "Bookmark"
848
  msgstr "Favorito"
849
 
850
- #: includes/admin/search-form.php:73
851
- #: includes/containers/comment.php:137
852
  msgid "Comment"
853
  msgstr "Comentário"
854
 
855
- #: includes/admin/search-form.php:86
856
- msgid "Search Links"
857
- msgstr "Procurar"
858
-
859
- #: includes/checkers/http.php:186
860
- #: includes/checkers/http.php:253
861
  #, php-format
862
  msgid "HTTP code : %d"
863
  msgstr "Código HTTP : %d"
864
 
865
- #: includes/checkers/http.php:188
866
- #: includes/checkers/http.php:255
867
  msgid "(No response)"
868
  msgstr "(Sem resposta)"
869
 
870
- #: includes/checkers/http.php:194
871
  msgid "Most likely the connection timed out or the domain doesn't exist."
872
  msgstr "Provável que o tempo da ligação se tenha esgotado ou que o domínio não exista."
873
 
874
- #: includes/checkers/http.php:262
875
  msgid "Request timed out."
876
  msgstr "Tempo de espera esgotado."
877
 
878
- #: includes/checkers/http.php:280
879
  msgid "Using Snoopy"
880
  msgstr "Utilizando Snoopy"
881
 
882
- #: includes/containers.php:262
883
- #, php-format
884
- msgid "Container type '%s' not recognized"
885
- msgstr "Recipiente tipo '%s' não foi reconhecido"
886
-
887
- #: includes/containers.php:792
888
- #, php-format
889
- msgid "%d '%s' has been deleted"
890
- msgid_plural "%d '%s' have been deleted"
891
- msgstr[0] "%d '%s' foi apagado"
892
- msgstr[1] "%d '%s' foram apagados"
893
-
894
  #: includes/containers/blogroll.php:19
895
  #: includes/containers/blogroll.php:38
896
  msgid "Edit this bookmark"
897
  msgstr "Editar este favorito"
898
 
899
  #: includes/containers/blogroll.php:38
900
- #: includes/containers/comment.php:107
901
- #: includes/containers/custom_field.php:201
902
- #: includes/containers/post.php:16
903
  msgid "Edit"
904
  msgstr "Editar"
905
 
@@ -913,14 +1035,10 @@ msgstr ""
913
  " 'Cancelar' para sair, 'Aceitar' para apagar."
914
 
915
  #: includes/containers/blogroll.php:39
916
- #: includes/containers/custom_field.php:206
917
- #: includes/containers/post.php:21
918
  msgid "Delete"
919
  msgstr "Apagar"
920
 
921
  #: includes/containers/blogroll.php:75
922
- #: includes/containers/comment.php:36
923
- #: includes/containers/post.php:86
924
  msgid "Nothing to update"
925
  msgstr "Sem actualização"
926
 
@@ -938,8 +1056,8 @@ msgstr "Não foi possível eliminar o link blogroll \"%s\" (%d)"
938
  #, php-format
939
  msgid "%d blogroll link deleted"
940
  msgid_plural "%d blogroll links deleted"
941
- msgstr[0] "%d link blogroll detectado"
942
- msgstr[1] "%d links blogroll detectados"
943
 
944
  #: includes/containers/comment.php:46
945
  #, php-format
@@ -951,24 +1069,10 @@ msgstr "Não foi possível actualizar o comentário %d"
951
  msgid "Failed to delete comment %d"
952
  msgstr "Erro ao apagar o comentário %d"
953
 
954
- #: includes/containers/comment.php:107
955
- #: includes/containers/comment.php:149
956
- msgid "Edit comment"
957
- msgstr "Editar comentário"
958
-
959
  #: includes/containers/comment.php:114
960
  msgid "Delete Permanently"
961
  msgstr "Apagado definitivamente"
962
 
963
- #: includes/containers/comment.php:116
964
- msgid "Move this comment to the trash"
965
- msgstr "Mover este comentário para o lixo"
966
-
967
- #: includes/containers/comment.php:116
968
- msgctxt "verb"
969
- msgid "Trash"
970
- msgstr "Lixo"
971
-
972
  #: includes/containers/comment.php:120
973
  msgid "View comment"
974
  msgstr "Ver comentário"
@@ -979,14 +1083,14 @@ msgstr "Ver comentário"
979
  msgid "View"
980
  msgstr "Ver"
981
 
982
- #: includes/containers/comment.php:273
983
  #, php-format
984
  msgid "%d comment moved to the trash"
985
  msgid_plural "%d comments moved to the trash"
986
  msgstr[0] "%d comentário movido para o lixo"
987
  msgstr[1] "%d comentários movidos para o lixo"
988
 
989
- #: includes/containers/comment.php:283
990
  #, php-format
991
  msgid "%d comment has been deleted"
992
  msgid_plural "%d comments have been deleted"
@@ -1004,15 +1108,17 @@ msgid "Failed to delete the meta field '%s' on %s [%d]"
1004
  msgstr "Erro ao apagar o campo meta '%s' em %s [%d]"
1005
 
1006
  #: includes/containers/custom_field.php:191
1007
- #: includes/containers/custom_field.php:201
1008
  #: includes/containers/post.php:16
1009
  #: includes/containers/post.php:41
1010
  msgid "Edit this post"
1011
  msgstr "Editar post"
1012
 
 
 
 
 
1013
  #: includes/containers/custom_field.php:204
1014
- #: includes/containers/post.php:19
1015
- msgid "Move this post to the Trash"
1016
  msgstr "Mover este post para o lixo"
1017
 
1018
  #: includes/containers/custom_field.php:204
@@ -1041,22 +1147,22 @@ msgstr ""
1041
  msgid "View \"%s\""
1042
  msgstr "Ver \"%s\""
1043
 
1044
- #: includes/containers/custom_field.php:248
1045
- #: includes/containers/post.php:127
1046
  #, php-format
1047
  msgid "Failed to delete post \"%s\" (%d)"
1048
  msgstr "Erro ao apagar o post \"%s\" (%d)"
1049
 
1050
- #: includes/containers/custom_field.php:479
1051
- #: includes/containers/post.php:300
1052
  #, php-format
1053
  msgid "%d post moved to the trash"
1054
  msgid_plural "%d posts moved to the trash"
1055
  msgstr[0] "%d post transferido para o lixo"
1056
  msgstr[1] "%d posts transferidos para o lixo"
1057
 
1058
- #: includes/containers/custom_field.php:481
1059
- #: includes/containers/post.php:302
1060
  #, php-format
1061
  msgid "%d post deleted"
1062
  msgid_plural "%d posts deleted"
@@ -1069,130 +1175,12 @@ msgstr[1] "%d posts apagados"
1069
  msgid "I don't know how to edit a '%s' [%d]."
1070
  msgstr "Não é possível editar '%s' [%d]."
1071
 
1072
- #: includes/containers/post.php:96
 
 
 
 
1073
  #, php-format
1074
  msgid "Updating post %d failed"
1075
  msgstr "Actualização do post %d falhou"
1076
 
1077
- #: includes/instances.php:102
1078
- #: includes/instances.php:148
1079
- #, php-format
1080
- msgid "Container %s[%d] not found"
1081
- msgstr "Recipiente %s[%d] não encontrado"
1082
-
1083
- #: includes/instances.php:111
1084
- #: includes/instances.php:157
1085
- #, php-format
1086
- msgid "Parser '%s' not found."
1087
- msgstr "Analizador sintáctico '%s' não encontrado."
1088
-
1089
- #: includes/links.php:157
1090
- msgid "The plugin script was terminated while trying to check the link."
1091
- msgstr "O script do plugin terminou enquanto tentava verificar o link."
1092
-
1093
- #: includes/links.php:201
1094
- msgid "The plugin doesn't know how to check this type of link."
1095
- msgstr "O plugin não consegue verificar este tipo de link."
1096
-
1097
- #: includes/links.php:289
1098
- msgid "Link is valid."
1099
- msgstr "Link operacional."
1100
-
1101
- #: includes/links.php:291
1102
- msgid "Link is broken."
1103
- msgstr "Link sem ligação."
1104
-
1105
- #: includes/links.php:484
1106
- #: includes/links.php:586
1107
- #: includes/links.php:621
1108
- msgid "Link is not valid"
1109
- msgstr "Link não válido"
1110
-
1111
- #: includes/links.php:501
1112
- msgid "This link can not be edited because it is not used anywhere on this site."
1113
- msgstr "Este link não pode ser editado porque não é utilizado em nenhuma parte da página."
1114
-
1115
- #: includes/links.php:527
1116
- msgid "Failed to create a DB entry for the new URL."
1117
- msgstr "Falhou a criação de um registro na Base de dados para um novo URL."
1118
-
1119
- #: includes/links.php:599
1120
- msgid "This link is not a redirect"
1121
- msgstr "O link não é um redirect"
1122
-
1123
- #: includes/links.php:648
1124
- #: includes/links.php:685
1125
- msgid "Couldn't delete the link's database record"
1126
- msgstr "Não é possível apagar o registro do link na Base de dados"
1127
-
1128
- #: includes/links.php:770
1129
- msgid "Broken"
1130
- msgstr "Offline"
1131
-
1132
- #: includes/links.php:772
1133
- msgid "No broken links found"
1134
- msgstr "Links offline (0)"
1135
-
1136
- #: includes/links.php:779
1137
- msgid "Redirects"
1138
- msgstr "Redirects"
1139
-
1140
- #: includes/links.php:780
1141
- msgid "Redirected Links"
1142
- msgstr "Links Redirects"
1143
-
1144
- #: includes/links.php:781
1145
- msgid "No redirects found"
1146
- msgstr "Redirects (0)"
1147
-
1148
- #: includes/links.php:789
1149
- msgid "All"
1150
- msgstr "Todos"
1151
-
1152
- #: includes/links.php:790
1153
- msgid "Detected Links"
1154
- msgstr "Links encontrados"
1155
-
1156
- #: includes/links.php:791
1157
- msgid "No links found (yet)"
1158
- msgstr "Links (0)"
1159
-
1160
- #: includes/links.php:799
1161
- msgid "Search Results"
1162
- msgstr "Resultados da procura"
1163
-
1164
- #: includes/links.php:800
1165
- #: includes/links.php:843
1166
- msgid "No links found for your query"
1167
- msgstr "Sem resultados"
1168
-
1169
- #: includes/parsers.php:151
1170
- #, php-format
1171
- msgid "Editing is not implemented in the '%s' parser"
1172
- msgstr "Edição não implementada no '%s' analizador sintáctico"
1173
-
1174
- #: includes/parsers.php:166
1175
- #, php-format
1176
- msgid "Unlinking is not implemented in the '%s' parser"
1177
- msgstr "Remover links não foi implementado no '%s' analizador sintáctico"
1178
-
1179
- #. Plugin Name of the plugin/theme
1180
- msgid "Broken Link Checker"
1181
- msgstr "Links offline"
1182
-
1183
- #. Plugin URI of the plugin/theme
1184
- msgid "http://w-shadow.com/blog/2007/08/05/broken-link-checker-for-wordpress/"
1185
- msgstr "http://w-shadow.com/blog/2007/08/05/broken-link-checker-for-wordpress/"
1186
-
1187
- #. Description of the plugin/theme
1188
- msgid "Checks your blog for broken links and missing images and notifies you on the dashboard if any are found."
1189
- msgstr "Verifica o blog procurando os links e imagens em falta, informa no Painel do WordPress os resultados da verificação."
1190
-
1191
- #. Author of the plugin/theme
1192
- msgid "Janis Elsts"
1193
- msgstr "Janis Elsts"
1194
-
1195
- #. Author URI of the plugin/theme
1196
- msgid "http://w-shadow.com/blog/"
1197
- msgstr "http://w-shadow.com/blog/"
1198
-
1
+ # Translation of the WordPress plugin Broken Link Checker 0.9.4.2 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
+ # Tradução em português pt_PT do plugin Broken Link Checker - v.1.1 - 30/06/2010
5
+ # Autor: PedroDM - <pm[at]mowster[dot]net>
6
  # Website: http://jobs.mowster.net/ - <jobs@mowster.net>
7
  #
8
  msgid ""
9
  msgstr ""
10
  "Project-Id-Version: Broken Link Checker PT\n"
11
+ "Report-Msgid-Bugs-To: \n"
12
+ "POT-Creation-Date: 2010-07-11 13:18-0000\n"
13
  "PO-Revision-Date: \n"
14
  "Last-Translator: \n"
15
+ "Language-Team: MwJobs | http://jobs.mowster.net <jobs@mowster.net>\n"
16
  "MIME-Version: 1.0\n"
17
  "Content-Type: text/plain; charset=UTF-8\n"
18
  "Content-Transfer-Encoding: 8bit\n"
24
  "X-Poedit-Basepath: ..\n"
25
  "X-Poedit-SearchPath-0: .\n"
26
 
27
+ #: broken-link-checker.php:316
28
  msgid "Once Weekly"
29
  msgstr "Uma vez por semana"
30
 
31
+ #: broken-link-checker.php:322
32
+ msgid "Twice a Month"
33
+ msgstr "Bi-Mensal"
34
+
35
+ #: broken-link-checker.php:345
36
+ msgid "Broken Link Checker installation failed"
37
+ msgstr "Opções : Links offline"
38
+
39
+ #: core.php:139
40
+ #: includes/admin/links-page-js.php:35
41
  msgid "Loading..."
42
  msgstr "Carregando..."
43
 
44
+ #: core.php:162
45
+ #: core.php:943
46
  msgid "[ Network error ]"
47
  msgstr "[ Problema na rede ]"
48
 
49
+ #: core.php:187
50
  msgid "Automatically expand the widget if broken links have been detected"
51
  msgstr "Expandir automaticamente a caixa se existirem links offline"
52
 
53
+ #: core.php:424
54
  #, php-format
55
  msgid "Failed to delete old DB tables. Database error : %s"
56
  msgstr "Não foi possível apagar as tabelas antigas da Base de dados. Erro de Base de dados : %s"
57
 
58
+ #: core.php:447
59
  #, php-format
60
  msgid "Unexpected error: The plugin doesn't know how to upgrade its database to version '%d'."
61
  msgstr "Erro inesperado: O plugin não consegue actualizar a Base de dados para a versão '%d'."
62
 
63
+ #: core.php:499
64
+ #: core.php:536
65
+ #: core.php:586
66
+ #: core.php:618
67
  #, php-format
68
  msgid "Failed to create table '%s'. Database error: %s"
69
  msgstr "Não foi possível criar a tabela '%s'. Erro na Base de dados: %s"
70
 
71
+ #: core.php:678
72
  msgid "Link Checker Settings"
73
  msgstr "Definições do Links offline"
74
 
75
+ #: core.php:679
76
  msgid "Link Checker"
77
  msgstr "Links offline"
78
 
79
+ #: core.php:684
80
+ #: includes/links.php:773
 
 
 
 
81
  msgid "Broken Links"
82
  msgstr "Links offline"
83
 
84
+ #: core.php:700
85
+ msgid "View Broken Links"
86
+ msgstr "Ver Links offline"
87
+
88
+ #: core.php:726
89
  #, php-format
90
  msgid "Highlight links broken for at least %s days"
91
  msgstr "Sublinhar links offline pelo menos por %s dias"
92
 
93
+ #: core.php:752
94
  msgid "Settings"
95
  msgstr "Definições"
96
 
97
+ #: core.php:762
98
+ #: core.php:1300
99
  #, php-format
100
  msgid "Error: The plugin's database tables are not up to date! (Current version : %d, expected : %d)"
101
  msgstr "Erro: As tabelas do plugin na Base de dados não estão actualizadas! (Versão actual : %d, obrigatória : %d)"
102
 
103
+ #: core.php:899
104
  msgid "Settings saved."
105
  msgstr "Definições guardadas."
106
 
107
+ #: core.php:908
108
  msgid "Broken Link Checker Options"
109
  msgstr "Opções : Links offline"
110
 
111
+ #: core.php:921
112
  msgid "Status"
113
  msgstr "Estado"
114
 
115
+ #: core.php:923
116
+ #: core.php:1278
117
  msgid "Show debug info"
118
  msgstr "Mostrar sistema"
119
 
120
+ #: core.php:956
121
  msgid "Re-check all pages"
122
  msgstr "Verificar de novo todas as páginas"
123
 
124
+ #: core.php:980
125
  msgid "Check each link"
126
  msgstr "Verificar cada link"
127
 
128
+ #: core.php:985
129
  #, php-format
130
  msgid "Every %s hours"
131
  msgstr "Cada %s horas"
132
 
133
+ #: core.php:994
134
  msgid "Existing links will be checked this often. New links will usually be checked ASAP."
135
  msgstr "Os links existentes serão verificados com esta frequência. Os novos links comprovados logo que possível."
136
 
137
+ #: core.php:1001
138
  msgid "Broken link CSS"
139
  msgstr "Link CSS offline"
140
 
141
+ #: core.php:1006
142
  msgid "Apply <em>class=\"broken_link\"</em> to broken links"
143
  msgstr "Aplicar <em>class=\"broken_link\"</em> aos links offline"
144
 
145
+ #: core.php:1018
146
  msgid "Removed link CSS"
147
  msgstr "Link CSS removido"
148
 
149
+ #: core.php:1023
150
  msgid "Apply <em>class=\"removed_link\"</em> to unlinked links"
151
  msgstr "Aplicar <em>class=\"removed_link\"</em> aos links sem ligação"
152
 
153
+ #: core.php:1035
154
  msgid "Broken link SEO"
155
  msgstr "Link SEO offline"
156
 
157
+ #: core.php:1040
158
  msgid "Apply <em>rel=\"nofollow\"</em> to broken links"
159
  msgstr "Aplicar <em>rel=\"nofollow\"</em> aos links offline"
160
 
161
+ #: core.php:1046
162
  msgid "Exclusion list"
163
  msgstr "Lista de exclusão"
164
 
165
+ #: core.php:1047
166
  msgid "Don't check links where the URL contains any of these words (one per line) :"
167
  msgstr "Não verificar links que a URL tenha alguma destas palavras (uma por linha):"
168
 
169
+ #: core.php:1057
170
  msgid "Custom fields"
171
  msgstr "Campos personalizados"
172
 
173
+ #: core.php:1058
174
  msgid "Check URLs entered in these custom fields (one per line) :"
175
  msgstr "Verificar as seguintes URL personalizadas (uma por linha):"
176
 
177
+ #: core.php:1068
178
+ msgid "Comment links"
179
+ msgstr "Comentário"
180
+
181
+ #: core.php:1074
182
+ msgid "Check comment links"
183
+ msgstr "Verificar link comentário"
184
+
185
+ #: core.php:1081
186
  msgid "E-mail notifications"
187
  msgstr "Notificações por e-mail"
188
 
189
+ #: core.php:1087
190
  msgid "Send me e-mail notifications about newly detected broken links"
191
  msgstr "Enviar um e-mail notificando sobre os novos links offline detectados"
192
 
193
+ #: core.php:1095
194
  msgid "Advanced"
195
  msgstr "Avançado"
196
 
197
+ #: core.php:1100
198
  msgid "Timeout"
199
  msgstr "Intervalo"
200
 
201
+ #: core.php:1106
202
+ #: core.php:1150
203
+ #: core.php:3216
204
  #, php-format
205
  msgid "%s seconds"
206
  msgstr "%s segundos"
207
 
208
+ #: core.php:1115
209
  msgid "Links that take longer than this to load will be marked as broken."
210
  msgstr "Os links que demoram mais que este tempo a abrir serão marcados como offline."
211
 
212
+ #: core.php:1122
213
  msgid "Link monitor"
214
  msgstr "Monitor de links"
215
 
216
+ #: core.php:1128
217
  msgid "Run continuously while the Dashboard is open"
218
  msgstr "Executar continuamente enquanto o Painel do WordPress está aberto"
219
 
220
+ #: core.php:1136
221
  msgid "Run hourly in the background"
222
  msgstr "Executar a cada hora em segundo plano"
223
 
224
+ #: core.php:1144
225
  msgid "Max. execution time"
226
  msgstr "Tempo máximo de execução"
227
 
228
+ #: core.php:1161
229
  msgid "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."
230
  msgstr "O plugin funciona executando periodicamente uma tarefa em segundo plano que analiza os links, verifica os URL encontrados e realiza outras tarefas que consomem tempo. Aqui pode-se estabelecer a duração máxima cada vez que o monitor de links é executado antes de parar."
231
 
232
+ #: core.php:1171
233
  msgid "Custom temporary directory"
234
  msgstr "Pasta temporária personalizada"
235
 
236
+ #: core.php:1180
237
  msgid "OK"
238
  msgstr "Aceitar"
239
 
240
+ #: core.php:1183
241
  msgid "Error : This directory isn't writable by PHP."
242
  msgstr "Erro: PHP não pode escrever nesse directório."
243
 
244
+ #: core.php:1188
245
  msgid "Error : This directory doesn't exist."
246
  msgstr "Erro: Não existe esse directório."
247
 
248
+ #: core.php:1196
249
  msgid "Set this field if you want the plugin to use a custom directory for its lockfiles. Otherwise, leave it blank."
250
  msgstr "Preencha este campo se deseja que o plugin utilize um directório personalizado para seus ficheiros temporários. Caso contrário, deixa-lo em branco."
251
 
252
+ #: core.php:1203
253
  msgid "Server load limit"
254
  msgstr "Limite de carregamento do servidor"
255
 
256
+ #: core.php:1244
257
  #, php-format
258
  msgid "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."
259
  msgstr "A verificação dos links será suspensa se a média do <a href=\"%s\">carregamento do servidor</a> passa este valor. Deixar o campo em branco para não existir limite."
260
 
261
+ #: core.php:1254
262
  msgid "Load limiting only works on Linux-like systems where <code>/proc/loadavg</code> is present and accessible."
263
  msgstr "O limite de carregamento somente funciona em sistemas Linux onde <code>/proc/loadavg</code> está presente e acessível."
264
 
265
+ #: core.php:1263
266
  msgid "Save Changes"
267
  msgstr "Guardar alterações"
268
 
269
+ #: core.php:1276
270
  msgid "Hide debug info"
271
  msgstr "Ocultar informação"
272
 
273
+ #: core.php:1393
274
+ #: core.php:1730
275
+ #: core.php:1762
276
  #, php-format
277
  msgid "Database error : %s"
278
  msgstr "Erro na Base de dados: %s"
279
 
280
+ #: core.php:1471
281
  msgid "Bulk Actions"
282
  msgstr "Edição em Massa"
283
 
284
+ #: core.php:1472
285
  msgid "Recheck"
286
  msgstr "Voltar a verificar"
287
 
288
+ #: core.php:1473
289
  msgid "Fix redirects"
290
  msgstr "Reparar redirects"
291
 
292
+ #: core.php:1474
293
+ msgid "Mark as not broken"
294
+ msgstr "Funcional"
295
+
296
+ #: core.php:1475
297
+ #: core.php:1629
298
+ #: includes/admin/links-page-js.php:307
299
  msgid "Unlink"
300
  msgstr "Remover link"
301
 
302
+ #: core.php:1476
303
  msgid "Delete sources"
304
  msgstr "Apagar fontes"
305
 
306
+ #: core.php:1490
307
+ #: core.php:1664
308
  msgid "Apply"
309
  msgstr "Aplicar"
310
 
311
+ #: core.php:1497
312
  msgid "&laquo;"
313
  msgstr "&laquo;"
314
 
315
+ #: core.php:1498
316
  msgid "&raquo;"
317
  msgstr "&raquo;"
318
 
319
+ #: core.php:1505
320
+ #: core.php:1670
321
  #, php-format
322
  msgid "Displaying %s&#8211;%s of <span class=\"current-link-count\">%s</span>"
323
  msgstr "Mostrando %s&#8211;%s de <span class=\"current-link-count\">%s</span>"
324
 
325
+ #: core.php:1524
326
  msgid "Source"
327
  msgstr "Fonte"
328
 
329
+ #: core.php:1525
330
  msgid "Link Text"
331
  msgstr "Texto do Link"
332
 
333
+ #: core.php:1526
334
  #: includes/admin/search-form.php:42
335
  msgid "URL"
336
  msgstr "URL"
337
 
338
+ #: core.php:1602
339
  msgid "[An orphaned link! This is a bug.]"
340
  msgstr "[Um link orfão! Bug.]"
341
 
342
+ #: core.php:1626
343
  msgid "Show more info about this link"
344
  msgstr "Mostrar mais informação sobre este link"
345
 
346
+ #: core.php:1626
347
+ #: core.php:3089
348
  msgid "Details"
349
  msgstr "Detalhes"
350
 
351
+ #: core.php:1628
352
  msgid "Remove this link from all posts"
353
  msgstr "Eliminar este link"
354
 
355
+ #: core.php:1634
356
  msgid "Remove this link from the list of broken links and mark it as valid"
357
  msgstr "Eliminar este link da lista dos links offline e marca-lo como válido"
358
 
359
+ #: core.php:1635
360
+ #: includes/admin/links-page-js.php:92
361
  msgid "Not broken"
362
  msgstr "Funcional"
363
 
364
+ #: core.php:1639
365
  msgid "Edit link URL"
366
  msgstr "Editar URL do link"
367
 
368
+ #: core.php:1639
369
+ #: includes/admin/links-page-js.php:213
370
+ #: includes/admin/links-page-js.php:241
371
  msgid "Edit URL"
372
  msgstr "Editar URL"
373
 
374
+ #: core.php:1645
375
  msgid "Cancel URL editing"
376
  msgstr "Cancelar a edição do URL"
377
 
378
+ #: core.php:1645
 
379
  msgid "Cancel"
380
  msgstr "Cancelar"
381
 
382
+ #: core.php:1712
383
  msgid "You must enter a filter name!"
384
  msgstr "Deve introduzir um nome para o filtro!"
385
 
386
+ #: core.php:1716
387
  msgid "Invalid search query."
388
  msgstr "Procura inválida."
389
 
390
+ #: core.php:1725
391
  #, php-format
392
  msgid "Filter \"%s\" created"
393
  msgstr "Filtro \"%s\" criado"
394
 
395
+ #: core.php:1752
396
  msgid "Filter ID not specified."
397
  msgstr "ID do Filtro não especificado."
398
 
399
+ #: core.php:1759
400
  msgid "Filter deleted"
401
  msgstr "Filtro eliminado"
402
 
403
+ #: core.php:1807
404
  #, php-format
405
  msgid "Replaced %d redirect with a direct link"
406
+ msgstr "Substituídos %d redirect com um link directo"
 
 
407
 
408
+ #: core.php:1818
409
  #, php-format
410
  msgid "Failed to fix %d redirect"
411
  msgid_plural "Failed to fix %d redirects"
412
  msgstr[0] "Não foi possível reparar %d redirect"
413
  msgstr[1] "Não foi possível reparar %d redirects"
414
 
415
+ #: core.php:1828
416
  msgid "None of the selected links are redirects!"
417
  msgstr "Nenhum dos links seleccionados são redirects!"
418
 
419
+ #: core.php:1874
420
  #, php-format
421
  msgid "%d link removed"
422
  msgid_plural "%d links removed"
423
  msgstr[0] "%d link eliminado"
424
  msgstr[1] "%d links eliminados"
425
 
426
+ #: core.php:1885
427
  #, php-format
428
  msgid "Failed to remove %d link"
429
  msgid_plural "Failed to remove %d links"
430
  msgstr[0] "Erro a remover %d link"
431
  msgstr[1] "Erro a remover %d links"
432
 
433
+ #: core.php:1973
434
  msgid "Didn't find anything to delete!"
435
  msgstr "Não foi encontrado nada para apagar!"
436
 
437
+ #: core.php:2001
438
  #, php-format
439
  msgid "%d link scheduled for rechecking"
440
  msgid_plural "%d links scheduled for rechecking"
441
  msgstr[0] "%d link agendado para verificação"
442
  msgstr[1] "%d links agendados para verificação"
443
 
444
+ #: core.php:2046
445
+ #: core.php:2723
446
+ msgid "This link was manually marked as working by the user."
447
+ msgstr "Este link foi marcado manualmente como válido por outro utilizador."
448
+
449
+ #: core.php:2053
450
+ #, php-format
451
+ msgid "Couldn't modify link %d"
452
+ msgstr "Oops, impossível modificar o link %d"
453
+
454
+ #: core.php:2064
455
+ #, php-format
456
+ msgid "%d link marked as not broken"
457
+ msgid_plural "%d links marked as not broken"
458
+ msgstr[0] "%d link marcado como funcional"
459
+ msgstr[1] "%d links marcados como funcionais"
460
+
461
+ #: core.php:2088
462
  msgid "Post published on"
463
  msgstr "Post publicado em"
464
 
465
+ #: core.php:2093
466
  msgid "Link last checked"
467
  msgstr "Última verificação"
468
 
469
+ #: core.php:2097
470
  msgid "Never"
471
  msgstr "Nunca"
472
 
473
+ #: core.php:2103
474
  #: includes/admin/search-form.php:45
475
  msgid "HTTP code"
476
  msgstr "Código HTTP"
477
 
478
+ #: core.php:2108
479
  msgid "Response time"
480
  msgstr "Tempo de resposta"
481
 
482
+ #: core.php:2110
483
  #, php-format
484
  msgid "%2.3f seconds"
485
  msgstr "%2.3f segundos"
486
 
487
+ #: core.php:2113
488
  msgid "Final URL"
489
  msgstr "URL final"
490
 
491
+ #: core.php:2118
492
  msgid "Redirect count"
493
  msgstr "Contagem de redirects"
494
 
495
+ #: core.php:2123
496
  msgid "Instance count"
497
  msgstr "Contagem de casos"
498
 
499
+ #: core.php:2132
500
  #, php-format
501
  msgid "This link has failed %d time."
502
  msgid_plural "This link has failed %d times."
503
  msgstr[0] "Este link falhou %d vez."
504
  msgstr[1] "Este link falhou %d vezes."
505
 
506
+ #: core.php:2140
507
  #, php-format
508
  msgid "This link has been broken for %s."
509
  msgstr "Link offline durante %s."
510
 
511
+ #: core.php:2151
512
  msgid "Log"
513
  msgstr "Registro"
514
 
515
+ #: core.php:2177
516
  msgid "less than a minute"
517
  msgstr "menos de um minuto"
518
 
519
+ #: core.php:2185
520
  #, php-format
521
  msgid "%d minute"
522
  msgid_plural "%d minutes"
523
  msgstr[0] "%d minuto"
524
  msgstr[1] "%d minutos"
525
 
526
+ #: core.php:2199
527
+ #: core.php:2226
528
  #, php-format
529
  msgid "%d hour"
530
  msgid_plural "%d hours"
531
  msgstr[0] "%d hora"
532
  msgstr[1] "%d horas"
533
 
534
+ #: core.php:2214
535
+ #: core.php:2255
536
  #, php-format
537
  msgid "%d day"
538
  msgid_plural "%d days"
539
  msgstr[0] "%d dia"
540
  msgstr[1] "%d dias"
541
 
542
+ #: core.php:2244
543
  #, php-format
544
  msgid "%d month"
545
  msgid_plural "%d months"
546
  msgstr[0] "%d mês"
547
  msgstr[1] "%d meses"
548
 
549
+ #: core.php:2589
550
  msgid "View broken links"
551
  msgstr "Ver links offline"
552
 
553
+ #: core.php:2590
554
  #, php-format
555
  msgid "Found %d broken link"
556
  msgid_plural "Found %d broken links"
557
  msgstr[0] "Encontrado %d Link offline"
558
  msgstr[1] "Encontrados %d Links offline"
559
 
560
+ #: core.php:2596
561
  msgid "No broken links found."
562
  msgstr "Não existem links offline."
563
 
564
+ #: core.php:2603
565
  #, php-format
566
  msgid "%d URL in the work queue"
567
  msgid_plural "%d URLs in the work queue"
568
  msgstr[0] "%d URL em espera"
569
  msgstr[1] "%d URLs em espera"
570
 
571
+ #: core.php:2606
572
  msgid "No URLs in the work queue."
573
  msgstr "Não existem URL em espera para verificação."
574
 
575
+ #: core.php:2612
576
  #, php-format
577
  msgid "Detected %d unique URL"
578
  msgid_plural "Detected %d unique URLs"
579
  msgstr[0] "Detectada %d URL única"
580
  msgstr[1] "Detectadas %d URL únicas"
581
 
582
+ #: core.php:2613
583
  #, php-format
584
  msgid "in %d link"
585
  msgid_plural "in %d links"
586
  msgstr[0] "em %d link"
587
  msgstr[1] "em %d links"
588
 
589
+ #: core.php:2618
590
  msgid "and still searching..."
591
  msgstr "procurando..."
592
 
593
+ #: core.php:2624
594
  msgid "Searching your blog for links..."
595
  msgstr "Procurando links..."
596
 
597
+ #: core.php:2626
598
  msgid "No links detected."
599
  msgstr "Não se encontraram links."
600
 
601
+ #: core.php:2708
602
+ #: core.php:2744
603
+ #: core.php:2807
604
+ #: core.php:2889
605
  msgid "You're not allowed to do that!"
606
  msgstr "Não permitido!"
607
 
608
+ #: core.php:2716
609
+ #: core.php:2754
610
+ #: core.php:2817
611
  #, php-format
612
  msgid "Oops, I can't find the link %d"
613
  msgstr "Oops, não é possível encontrar o link %d"
614
 
615
+ #: core.php:2729
 
 
 
 
616
  msgid "Oops, couldn't modify the link!"
617
  msgstr "Oops, não é possível modificar o link!"
618
 
619
+ #: core.php:2732
620
+ #: core.php:2843
621
  msgid "Error : link_id not specified"
622
  msgstr "Erro: link_id não especificado"
623
 
624
+ #: core.php:2764
625
  msgid "Oops, the new URL is invalid!"
626
  msgstr "Oops, a nova URL não é válida"
627
 
628
+ #: core.php:2775
629
+ #: core.php:2826
630
  msgid "An unexpected error occured!"
631
  msgstr "Ocorreu um erro inesperado!"
632
 
633
+ #: core.php:2793
634
  msgid "Error : link_id or new_url not specified"
635
  msgstr "Erro: link_id ou new_url não especificado"
636
 
637
+ #: core.php:2852
638
  msgid "You don't have sufficient privileges to access this information!"
639
  msgstr "Não tem previlégios suficientes para aceder a esta informação!"
640
 
641
+ #: core.php:2865
642
  msgid "Error : link ID not specified"
643
  msgstr "Erro: link ID não especificado"
644
 
645
+ #: core.php:2876
646
  #, php-format
647
  msgid "Failed to load link details (%s)"
648
  msgstr "Erro a carregar os detalhes do link (%s)"
649
 
650
+ #: core.php:3061
651
+ msgid "Broken Link Checker"
652
+ msgstr "Links offline"
653
+
654
+ #: core.php:3075
655
  #, php-format
656
  msgid "The current temporary directory is not accessible; please <a href=\"%s\">set a different one</a>."
657
  msgstr "O directório temporário não está acessível; por favor, <a href=\"%s\">especifique um diferente</a>."
658
 
659
+ #: core.php:3080
660
  #, php-format
661
  msgid "Please make the directory <code>%1$s</code> writable by plugins or <a href=\"%2$s\">set a custom temporary directory</a>."
662
  msgstr "Por favor, deve permitir que os plugins possam gravar dados no directório <code>%1$s</code> ou <a href=\"%2$s\">especificar um directório temporário personalizado</a>."
663
 
664
+ #: core.php:3087
665
  msgid "Broken Link Checker can't create a lockfile."
666
  msgstr "Links offline não pode criar um ficheiro temporário."
667
 
668
+ #: core.php:3092
669
  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."
670
  msgstr "Este plugin utiliza um sistema de bloqueio de ficheiros para garantir que somente se executa uma instância do algoritmo de verificação de links num momento determinado, uma vez que consome bastantes recursos. Infelizmente, o plugin não pode encontrar um directório que possa armazenar um ficheiro temporário - erro ao detectar a localização do directório temporário no servidor, assim como o própio directório do plugin não permite a escrita pelo PHP. Para resolver, terá que dar permissões de escrita ao directório ou especificar um directório temporário na configuração do plugin."
671
 
672
+ #: core.php:3111
673
  msgid "PHP version"
674
  msgstr "Versão PHP"
675
 
676
+ #: core.php:3117
677
  msgid "MySQL version"
678
  msgstr "Versão MySQL"
679
 
680
+ #: core.php:3130
681
  msgid "You have an old version of CURL. Redirect detection may not work properly."
682
  msgstr "Versão de CURL obsoleta. A detecção de redirects pode não funcionar correctamente."
683
 
684
+ #: core.php:3142
685
+ #: core.php:3158
686
+ #: core.php:3163
687
  msgid "Not installed"
688
  msgstr "Não instalado"
689
 
690
+ #: core.php:3145
691
  msgid "CURL version"
692
  msgstr "Versão CURL"
693
 
694
+ #: core.php:3151
695
  msgid "Installed"
696
  msgstr "Instalado"
697
 
698
+ #: core.php:3164
699
  msgid "You must have either CURL or Snoopy installed for the plugin to work!"
700
  msgstr "Instalação de CURL ou Snoopy necessário para que funcione o plugin!"
701
 
702
+ #: core.php:3175
703
  msgid "On"
704
  msgstr "Activado"
705
 
706
+ #: core.php:3176
707
  msgid "Redirects may be detected as broken links when safe_mode is on."
708
  msgstr "Os redirects podem ser detectados como links offline quando o safe_mode está habilitado."
709
 
710
+ #: core.php:3181
711
+ #: core.php:3195
712
  msgid "Off"
713
  msgstr "Desactivado"
714
 
715
+ #: core.php:3189
716
  #, php-format
717
  msgid "On ( %s )"
718
  msgstr "Activado ( %s )"
719
 
720
+ #: core.php:3190
721
  msgid "Redirects may be detected as broken links when open_basedir is on."
722
  msgstr "Os redirects podem ser considerados links offline quando o open_basedir está activo."
723
 
724
+ #: core.php:3209
725
  msgid "Can't create a lockfile. Please specify a custom temporary directory."
726
  msgstr "Não foi possível criar um ficheiro. Por favor, especifique um directório temporário personalizado."
727
 
728
+ #: core.php:3233
729
+ msgid "If this value is zero even after several page reloads you have probably encountered a bug."
730
+ msgstr "Se este valor é zero depois de recarregar várias provavelmente encontrou um bug."
731
+
732
+ #: core.php:3289
733
  #, php-format
734
  msgid "[%s] Broken links detected"
735
  msgstr "[%s] Links offline detectados"
736
 
737
+ #: core.php:3295
738
  #, php-format
739
  msgid "Broken Link Checker has detected %d new broken link on your site."
740
  msgid_plural "Broken Link Checker has detected %d new broken links on your site."
741
  msgstr[0] "Links offline detectou %d novo link sem ligação."
742
  msgstr[1] "Links offline detectou %d novos links sem ligação."
743
 
744
+ #: core.php:3310
745
  #, php-format
746
  msgid "Here's a list of the first %d broken links:"
747
  msgid_plural "Here's a list of the first %d broken links:"
748
  msgstr[0] "Lista do primeiro %d link sem ligação:"
749
  msgstr[1] "Lista dos primeiros %d links sem ligação:"
750
 
751
+ #: core.php:3318
752
  msgid "Here's a list of the new broken links: "
753
  msgstr "Novos links offline:"
754
 
755
+ #: core.php:3330
756
  #, php-format
757
  msgid "Link text : %s"
758
  msgstr "Texto do Link : %s"
759
 
760
+ #: core.php:3331
761
  #, php-format
762
  msgid "Link URL : <a href=\"%s\">%s</a>"
763
  msgstr "Link URL : <a href=\"%s\">%s</a>"
764
 
765
+ #: core.php:3332
766
  #, php-format
767
  msgid "Source : %s"
768
  msgstr "Fonte : %s"
769
 
770
+ #: core.php:3346
771
  msgid "You can see all broken links here:"
772
  msgstr "Links offline:"
773
 
774
+ #: includes/containers.php:284
775
+ #, php-format
776
+ msgid "Container type '%s' not recognized"
777
+ msgstr "Recipiente tipo '%s' não foi reconhecido"
778
+
779
+ #: includes/containers.php:814
780
+ #, php-format
781
+ msgid "%d '%s' has been deleted"
782
+ msgid_plural "%d '%s' have been deleted"
783
+ msgstr[0] "%d '%s' foi apagado"
784
+ msgstr[1] "%d '%s' foram apagados"
785
+
786
+ #: includes/instances.php:102
787
+ #: includes/instances.php:148
788
+ #, php-format
789
+ msgid "Container %s[%d] not found"
790
+ msgstr "Recipiente %s[%d] não encontrado"
791
+
792
+ #: includes/instances.php:111
793
+ #: includes/instances.php:157
794
+ #, php-format
795
+ msgid "Parser '%s' not found."
796
+ msgstr "Analizador sintáctico '%s' não encontrado."
797
+
798
+ #: includes/links.php:152
799
+ msgid "The plugin script was terminated while trying to check the link."
800
+ msgstr "O script do plugin terminou enquanto tentava verificar o link."
801
+
802
+ #: includes/links.php:196
803
+ msgid "The plugin doesn't know how to check this type of link."
804
+ msgstr "O plugin não consegue verificar este tipo de link."
805
+
806
+ #: includes/links.php:284
807
+ msgid "Link is valid."
808
+ msgstr "Link operacional."
809
+
810
+ #: includes/links.php:286
811
+ msgid "Link is broken."
812
+ msgstr "Link sem ligação."
813
+
814
+ #: includes/links.php:479
815
+ #: includes/links.php:581
816
+ #: includes/links.php:616
817
+ msgid "Link is not valid"
818
+ msgstr "Link não válido"
819
+
820
+ #: includes/links.php:496
821
+ msgid "This link can not be edited because it is not used anywhere on this site."
822
+ msgstr "Este link não pode ser editado porque não é utilizado em nenhuma parte da página."
823
+
824
+ #: includes/links.php:522
825
+ msgid "Failed to create a DB entry for the new URL."
826
+ msgstr "Falhou a criação de um registro na Base de dados para um novo URL."
827
+
828
+ #: includes/links.php:594
829
+ msgid "This link is not a redirect"
830
+ msgstr "O link não é um redirect"
831
+
832
+ #: includes/links.php:643
833
+ #: includes/links.php:680
834
+ msgid "Couldn't delete the link's database record"
835
+ msgstr "Não é possível apagar o registro do link na Base de dados"
836
+
837
+ #: includes/links.php:772
838
+ msgid "Broken"
839
+ msgstr "Offline"
840
+
841
+ #: includes/links.php:774
842
+ msgid "No broken links found"
843
+ msgstr "Links offline (0)"
844
+
845
+ #: includes/links.php:781
846
+ msgid "Redirects"
847
+ msgstr "Redirects"
848
+
849
+ #: includes/links.php:782
850
+ msgid "Redirected Links"
851
+ msgstr "Links Redirects"
852
+
853
+ #: includes/links.php:783
854
+ msgid "No redirects found"
855
+ msgstr "Redirects (0)"
856
+
857
+ #: includes/links.php:791
858
+ msgid "All"
859
+ msgstr "Todos"
860
+
861
+ #: includes/links.php:792
862
+ msgid "Detected Links"
863
+ msgstr "Links encontrados"
864
+
865
+ #: includes/links.php:793
866
+ msgid "No links found (yet)"
867
+ msgstr "Links (0)"
868
+
869
+ #: includes/links.php:800
870
+ msgid "Search"
871
+ msgstr "Procurar"
872
+
873
+ #: includes/links.php:801
874
+ msgid "Search Results"
875
+ msgstr "Resultados da procura"
876
+
877
+ #: includes/links.php:802
878
+ #: includes/links.php:853
879
+ msgid "No links found for your query"
880
+ msgstr "Sem resultados"
881
+
882
+ #: includes/parsers.php:173
883
+ #, php-format
884
+ msgid "Editing is not implemented in the '%s' parser"
885
+ msgstr "Edição não implementada no '%s' analizador sintáctico"
886
+
887
+ #: includes/parsers.php:188
888
+ #, php-format
889
+ msgid "Unlinking is not implemented in the '%s' parser"
890
+ msgstr "Remover links não foi implementado no '%s' analizador sintáctico"
891
+
892
+ #: includes/admin/links-page-js.php:54
893
+ #: includes/admin/links-page-js.php:248
894
  msgid "Wait..."
895
  msgstr "Espere ..."
896
 
897
+ #: includes/admin/links-page-js.php:123
898
  msgid "Save URL"
899
  msgstr "Guardar URL"
900
 
901
+ #: includes/admin/links-page-js.php:134
902
  msgid "Saving changes..."
903
  msgstr "Guardando alterações ..."
904
 
905
+ #: includes/admin/links-page-js.php:180
906
  #, php-format
907
  msgid "%d instances of the link were successfully modified."
908
  msgstr "%d casos de links que se modificaram com sucesso."
909
 
910
+ #: includes/admin/links-page-js.php:186
911
  #, php-format
912
  msgid "However, %d instances couldn't be edited and still point to the old URL."
913
  msgstr "No entanto, %d casos não puderam ser editados e ainda apontam para a antiga URL."
914
 
915
+ #: includes/admin/links-page-js.php:192
916
  msgid "The link could not be modified."
917
  msgstr "O link não pode ser modificado."
918
 
919
+ #: includes/admin/links-page-js.php:195
920
+ #: includes/admin/links-page-js.php:299
921
  msgid "The following error(s) occured :"
922
  msgstr "Erro(s) :"
923
 
924
+ #: includes/admin/links-page-js.php:285
925
  #, php-format
926
  msgid "%d instances of the link were successfully unlinked."
927
  msgstr "%d casos de links foram removidos com sucesso."
928
 
929
+ #: includes/admin/links-page-js.php:291
930
  #, php-format
931
  msgid "However, %d instances couldn't be removed."
932
  msgstr "No entanto, %d casos não foram removidos."
933
 
934
+ #: includes/admin/links-page-js.php:296
935
  msgid "The plugin failed to remove the link."
936
  msgstr "O plugin não removeu o link."
937
 
938
+ #: includes/admin/links-page-js.php:351
939
  msgid "Enter a name for the new custom filter"
940
  msgstr "Introduza o nome para o novo filtro personalizado"
941
 
942
+ #: includes/admin/links-page-js.php:362
943
  msgid ""
944
  "You are about to delete the current filter.\n"
945
  "'Cancel' to stop, 'OK' to delete"
947
  "Está a ponto de apagar o filtro actual.\n"
948
  " 'Cancelar' para sair, 'Aceitar' para apagar."
949
 
950
+ #: includes/admin/links-page-js.php:385
951
  msgid ""
952
  "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"
953
  "'Cancel' to stop, 'OK' to delete"
956
  "Esta acção não pode ser anulada.\n"
957
  "'Cancelar' para anular a operação, 'Aceitar' para apagar"
958
 
 
 
 
 
 
 
 
 
 
 
 
 
 
959
  #: includes/admin/search-form.php:39
960
  msgid "Link text"
961
  msgstr "Texto do link"
964
  msgid "Link status"
965
  msgstr "Estado do link"
966
 
967
+ #: includes/admin/search-form.php:65
968
  msgid "Link type"
969
  msgstr "Tipo de link"
970
 
971
+ #: includes/admin/search-form.php:69
972
  msgid "Any"
973
  msgstr "Qualquer"
974
 
975
+ #: includes/admin/search-form.php:70
976
  msgid "Normal link"
977
  msgstr "Link normal"
978
 
979
+ #: includes/admin/search-form.php:71
 
980
  msgid "Image"
981
  msgstr "Imagem"
982
 
983
+ #: includes/admin/search-form.php:72
 
984
  msgid "Custom field"
985
  msgstr "Campo personalizado"
986
 
987
+ #: includes/admin/search-form.php:73
988
  #: includes/containers/blogroll.php:13
989
  msgid "Bookmark"
990
  msgstr "Favorito"
991
 
992
+ #: includes/admin/search-form.php:74
 
993
  msgid "Comment"
994
  msgstr "Comentário"
995
 
996
+ #: includes/checkers/http.php:195
997
+ #: includes/checkers/http.php:262
 
 
 
 
998
  #, php-format
999
  msgid "HTTP code : %d"
1000
  msgstr "Código HTTP : %d"
1001
 
1002
+ #: includes/checkers/http.php:197
1003
+ #: includes/checkers/http.php:264
1004
  msgid "(No response)"
1005
  msgstr "(Sem resposta)"
1006
 
1007
+ #: includes/checkers/http.php:203
1008
  msgid "Most likely the connection timed out or the domain doesn't exist."
1009
  msgstr "Provável que o tempo da ligação se tenha esgotado ou que o domínio não exista."
1010
 
1011
+ #: includes/checkers/http.php:271
1012
  msgid "Request timed out."
1013
  msgstr "Tempo de espera esgotado."
1014
 
1015
+ #: includes/checkers/http.php:289
1016
  msgid "Using Snoopy"
1017
  msgstr "Utilizando Snoopy"
1018
 
 
 
 
 
 
 
 
 
 
 
 
 
1019
  #: includes/containers/blogroll.php:19
1020
  #: includes/containers/blogroll.php:38
1021
  msgid "Edit this bookmark"
1022
  msgstr "Editar este favorito"
1023
 
1024
  #: includes/containers/blogroll.php:38
 
 
 
1025
  msgid "Edit"
1026
  msgstr "Editar"
1027
 
1035
  " 'Cancelar' para sair, 'Aceitar' para apagar."
1036
 
1037
  #: includes/containers/blogroll.php:39
 
 
1038
  msgid "Delete"
1039
  msgstr "Apagar"
1040
 
1041
  #: includes/containers/blogroll.php:75
 
 
1042
  msgid "Nothing to update"
1043
  msgstr "Sem actualização"
1044
 
1056
  #, php-format
1057
  msgid "%d blogroll link deleted"
1058
  msgid_plural "%d blogroll links deleted"
1059
+ msgstr[0] "%d link blogroll apagado"
1060
+ msgstr[1] "%d links blogroll apagados"
1061
 
1062
  #: includes/containers/comment.php:46
1063
  #, php-format
1069
  msgid "Failed to delete comment %d"
1070
  msgstr "Erro ao apagar o comentário %d"
1071
 
 
 
 
 
 
1072
  #: includes/containers/comment.php:114
1073
  msgid "Delete Permanently"
1074
  msgstr "Apagado definitivamente"
1075
 
 
 
 
 
 
 
 
 
 
1076
  #: includes/containers/comment.php:120
1077
  msgid "View comment"
1078
  msgstr "Ver comentário"
1083
  msgid "View"
1084
  msgstr "Ver"
1085
 
1086
+ #: includes/containers/comment.php:279
1087
  #, php-format
1088
  msgid "%d comment moved to the trash"
1089
  msgid_plural "%d comments moved to the trash"
1090
  msgstr[0] "%d comentário movido para o lixo"
1091
  msgstr[1] "%d comentários movidos para o lixo"
1092
 
1093
+ #: includes/containers/comment.php:289
1094
  #, php-format
1095
  msgid "%d comment has been deleted"
1096
  msgid_plural "%d comments have been deleted"
1108
  msgstr "Erro ao apagar o campo meta '%s' em %s [%d]"
1109
 
1110
  #: includes/containers/custom_field.php:191
 
1111
  #: includes/containers/post.php:16
1112
  #: includes/containers/post.php:41
1113
  msgid "Edit this post"
1114
  msgstr "Editar post"
1115
 
1116
+ #: includes/containers/custom_field.php:201
1117
+ msgid "Edit this item"
1118
+ msgstr "Editar post"
1119
+
1120
  #: includes/containers/custom_field.php:204
1121
+ msgid "Move this item to the Trash"
 
1122
  msgstr "Mover este post para o lixo"
1123
 
1124
  #: includes/containers/custom_field.php:204
1147
  msgid "View \"%s\""
1148
  msgstr "Ver \"%s\""
1149
 
1150
+ #: includes/containers/custom_field.php:304
1151
+ #: includes/containers/post.php:183
1152
  #, php-format
1153
  msgid "Failed to delete post \"%s\" (%d)"
1154
  msgstr "Erro ao apagar o post \"%s\" (%d)"
1155
 
1156
+ #: includes/containers/custom_field.php:535
1157
+ #: includes/containers/post.php:356
1158
  #, php-format
1159
  msgid "%d post moved to the trash"
1160
  msgid_plural "%d posts moved to the trash"
1161
  msgstr[0] "%d post transferido para o lixo"
1162
  msgstr[1] "%d posts transferidos para o lixo"
1163
 
1164
+ #: includes/containers/custom_field.php:537
1165
+ #: includes/containers/post.php:358
1166
  #, php-format
1167
  msgid "%d post deleted"
1168
  msgid_plural "%d posts deleted"
1175
  msgid "I don't know how to edit a '%s' [%d]."
1176
  msgstr "Não é possível editar '%s' [%d]."
1177
 
1178
+ #: includes/containers/post.php:19
1179
+ msgid "Move this post to the Trash"
1180
+ msgstr "Mover este post para o lixo"
1181
+
1182
+ #: includes/containers/post.php:152
1183
  #, php-format
1184
  msgid "Updating post %d failed"
1185
  msgstr "Actualização do post %d falhou"
1186
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
languages/broken-link-checker.pot CHANGED
@@ -1,4 +1,4 @@
1
- # Translation of the WordPress plugin Broken Link Checker 0.9.3 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.
@@ -6,216 +6,202 @@
6
  #, fuzzy
7
  msgid ""
8
  msgstr ""
9
- "Project-Id-Version: Broken Link Checker 0.9.3\n"
10
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/broken-link-checker\n"
11
- "POT-Creation-Date: 2010-07-02 13:13+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"
16
  "Content-Type: text/plain; charset=utf-8\n"
17
  "Content-Transfer-Encoding: 8bit\n"
18
- "Plural-Forms: nplurals=2; plural=n != 1;\n"
19
 
20
- #: broken-link-checker.php:314
21
- msgid "Once Weekly"
22
  msgstr ""
23
 
24
- #: broken-link-checker.php:320
25
- msgid "Twice a Month"
26
  msgstr ""
27
 
28
- #: broken-link-checker.php:343
29
- msgid "Broken Link Checker installation failed"
30
  msgstr ""
31
 
32
- #: core.php:139 includes/admin/links-page-js.php:21
33
- msgid "Loading..."
34
  msgstr ""
35
 
36
- #: core.php:162 core.php:919
37
- msgid "[ Network error ]"
38
  msgstr ""
39
 
40
- #: core.php:187
41
- msgid "Automatically expand the widget if broken links have been detected"
42
  msgstr ""
43
 
44
- #: core.php:424
45
- #, php-format
46
- msgid "Failed to delete old DB tables. Database error : %s"
47
  msgstr ""
48
 
49
- #: core.php:447
50
- #, php-format
51
- msgid ""
52
- "Unexpected error: The plugin doesn't know how to upgrade its database to "
53
- "version '%d'."
54
  msgstr ""
55
 
56
- #: core.php:499 core.php:535 core.php:585 core.php:617
57
  #, php-format
58
- msgid "Failed to create table '%s'. Database error: %s"
 
 
59
  msgstr ""
60
 
61
- #: core.php:671
62
- msgid "Link Checker Settings"
63
  msgstr ""
64
 
65
- #: core.php:672
66
- msgid "Link Checker"
67
  msgstr ""
68
 
69
- #: core.php:678
70
- msgid "View Broken Links"
71
  msgstr ""
72
 
73
- #: core.php:679 includes/links.php:773
74
- msgid "Broken Links"
75
  msgstr ""
76
 
77
- #: core.php:704
78
- #, php-format
79
- msgid "Highlight links broken for at least %s days"
80
  msgstr ""
81
 
82
- #: core.php:730
83
- msgid "Settings"
84
  msgstr ""
85
 
86
- #: core.php:740 core.php:1276
87
- #, php-format
88
- msgid ""
89
- "Error: The plugin's database tables are not up to date! (Current version : %"
90
- "d, expected : %d)"
91
  msgstr ""
92
 
93
- #: core.php:875
94
- msgid "Settings saved."
95
  msgstr ""
96
 
97
- #: core.php:884
98
  msgid "Broken Link Checker Options"
99
  msgstr ""
100
 
101
- #: core.php:897
102
  msgid "Status"
103
  msgstr ""
104
 
105
- #: core.php:899 core.php:1254
106
  msgid "Show debug info"
107
  msgstr ""
108
 
109
- #: core.php:932
110
- msgid "Re-check all pages"
111
- msgstr ""
112
-
113
- #: core.php:956
114
  msgid "Check each link"
115
  msgstr ""
116
 
117
- #: core.php:961
118
  #, php-format
119
  msgid "Every %s hours"
120
  msgstr ""
121
 
122
- #: core.php:970
123
  msgid ""
124
  "Existing links will be checked this often. New links will usually be checked "
125
  "ASAP."
126
  msgstr ""
127
 
128
- #: core.php:977
129
- msgid "Broken link CSS"
130
- msgstr ""
131
-
132
- #: core.php:982
133
- msgid "Apply <em>class=\"broken_link\"</em> to broken links"
134
  msgstr ""
135
 
136
- #: core.php:994
137
- msgid "Removed link CSS"
138
  msgstr ""
139
 
140
- #: core.php:999
141
- msgid "Apply <em>class=\"removed_link\"</em> to unlinked links"
142
  msgstr ""
143
 
144
- #: core.php:1011
145
- msgid "Broken link SEO"
146
  msgstr ""
147
 
148
- #: core.php:1016
149
- msgid "Apply <em>rel=\"nofollow\"</em> to broken links"
150
  msgstr ""
151
 
152
- #: core.php:1022
153
- msgid "Exclusion list"
154
  msgstr ""
155
 
156
- #: core.php:1023
157
- msgid ""
158
- "Don't check links where the URL contains any of these words (one per line) :"
159
  msgstr ""
160
 
161
- #: core.php:1033
162
- msgid "Custom fields"
163
  msgstr ""
164
 
165
- #: core.php:1034
166
- msgid "Check URLs entered in these custom fields (one per line) :"
167
  msgstr ""
168
 
169
- #: core.php:1044
170
- msgid "Comment links"
171
  msgstr ""
172
 
173
- #: core.php:1050
174
- msgid "Check comment links"
175
  msgstr ""
176
 
177
- #: core.php:1057
178
- msgid "E-mail notifications"
179
  msgstr ""
180
 
181
- #: core.php:1063
182
- msgid "Send me e-mail notifications about newly detected broken links"
 
183
  msgstr ""
184
 
185
- #: core.php:1071
186
- msgid "Advanced"
187
  msgstr ""
188
 
189
- #: core.php:1076
190
  msgid "Timeout"
191
  msgstr ""
192
 
193
- #: core.php:1082 core.php:1126 core.php:3189
194
  #, php-format
195
  msgid "%s seconds"
196
  msgstr ""
197
 
198
- #: core.php:1091
199
  msgid "Links that take longer than this to load will be marked as broken."
200
  msgstr ""
201
 
202
- #: core.php:1098
203
  msgid "Link monitor"
204
  msgstr ""
205
 
206
- #: core.php:1104
207
  msgid "Run continuously while the Dashboard is open"
208
  msgstr ""
209
 
210
- #: core.php:1112
211
  msgid "Run hourly in the background"
212
  msgstr ""
213
 
214
- #: core.php:1120
215
  msgid "Max. execution time"
216
  msgstr ""
217
 
218
- #: core.php:1137
219
  msgid ""
220
  "The plugin works by periodically launching a background job that parses your "
221
  "posts for links, checks the discovered URLs, and performs other time-"
@@ -223,436 +209,324 @@ msgid ""
223
  "may run each time before stopping."
224
  msgstr ""
225
 
226
- #: core.php:1147
227
  msgid "Custom temporary directory"
228
  msgstr ""
229
 
230
- #: core.php:1156
231
  msgid "OK"
232
  msgstr ""
233
 
234
- #: core.php:1159
235
  msgid "Error : This directory isn't writable by PHP."
236
  msgstr ""
237
 
238
- #: core.php:1164
239
  msgid "Error : This directory doesn't exist."
240
  msgstr ""
241
 
242
- #: core.php:1172
243
  msgid ""
244
  "Set this field if you want the plugin to use a custom directory for its "
245
  "lockfiles. Otherwise, leave it blank."
246
  msgstr ""
247
 
248
- #: core.php:1179
249
  msgid "Server load limit"
250
  msgstr ""
251
 
252
- #: core.php:1220
253
  #, php-format
254
  msgid ""
255
  "Link checking will be suspended if the average <a href=\"%s\">server load</"
256
  "a> rises above this number. Leave this field blank to disable load limiting."
257
  msgstr ""
258
 
259
- #: core.php:1230
260
  msgid ""
261
  "Load limiting only works on Linux-like systems where <code>/proc/loadavg</"
262
  "code> is present and accessible."
263
  msgstr ""
264
 
265
- #: core.php:1239
266
- msgid "Save Changes"
267
- msgstr ""
268
-
269
- #: core.php:1252
270
- msgid "Hide debug info"
271
- msgstr ""
272
-
273
- #: core.php:1369 core.php:1705 core.php:1737
274
- #, php-format
275
- msgid "Database error : %s"
276
- msgstr ""
277
-
278
- #: core.php:1446
279
- msgid "Bulk Actions"
280
- msgstr ""
281
-
282
- #: core.php:1447
283
- msgid "Recheck"
284
  msgstr ""
285
 
286
- #: core.php:1448
287
- msgid "Fix redirects"
288
- msgstr ""
289
-
290
- #: core.php:1449
291
- msgid "Mark as not broken"
292
  msgstr ""
293
 
294
- #: core.php:1450 core.php:1604 includes/admin/links-page-js.php:293
295
- msgid "Unlink"
 
 
296
  msgstr ""
297
 
298
- #: core.php:1451
299
- msgid "Delete sources"
300
  msgstr ""
301
 
302
- #: core.php:1465 core.php:1639
303
- msgid "Apply"
304
  msgstr ""
305
 
306
- #: core.php:1472
307
- msgid "&laquo;"
308
  msgstr ""
309
 
310
- #: core.php:1473
311
- msgid "&raquo;"
312
  msgstr ""
313
 
314
- #: core.php:1480 core.php:1645
315
  #, php-format
316
- msgid "Displaying %s&#8211;%s of <span class=\"current-link-count\">%s</span>"
317
- msgstr ""
318
-
319
- #: core.php:1499
320
- msgid "Source"
321
- msgstr ""
322
-
323
- #: core.php:1500
324
- msgid "Link Text"
325
- msgstr ""
326
-
327
- #: core.php:1501 includes/admin/search-form.php:42
328
- msgid "URL"
329
- msgstr ""
330
-
331
- #: core.php:1577
332
- msgid "[An orphaned link! This is a bug.]"
333
- msgstr ""
334
-
335
- #: core.php:1601
336
- msgid "Show more info about this link"
337
- msgstr ""
338
-
339
- #: core.php:1601 core.php:3062
340
- msgid "Details"
341
- msgstr ""
342
-
343
- #: core.php:1603
344
- msgid "Remove this link from all posts"
345
- msgstr ""
346
-
347
- #: core.php:1609
348
- msgid "Remove this link from the list of broken links and mark it as valid"
349
- msgstr ""
350
-
351
- #: core.php:1610 includes/admin/links-page-js.php:78
352
- msgid "Not broken"
353
- msgstr ""
354
-
355
- #: core.php:1614
356
- msgid "Edit link URL"
357
- msgstr ""
358
-
359
- #: core.php:1614 includes/admin/links-page-js.php:199
360
- #: includes/admin/links-page-js.php:227
361
- msgid "Edit URL"
362
- msgstr ""
363
-
364
- #: core.php:1620
365
- msgid "Cancel URL editing"
366
- msgstr ""
367
-
368
- #: core.php:1620 includes/admin/search-form.php:87
369
- msgid "Cancel"
370
  msgstr ""
371
 
372
- #: core.php:1687
373
  msgid "You must enter a filter name!"
374
  msgstr ""
375
 
376
- #: core.php:1691
377
  msgid "Invalid search query."
378
  msgstr ""
379
 
380
- #: core.php:1700
381
  #, php-format
382
  msgid "Filter \"%s\" created"
383
  msgstr ""
384
 
385
- #: core.php:1727
386
  msgid "Filter ID not specified."
387
  msgstr ""
388
 
389
- #: core.php:1734
390
  msgid "Filter deleted"
391
  msgstr ""
392
 
393
- #: core.php:1782
394
  #, php-format
395
  msgid "Replaced %d redirect with a direct link"
396
  msgid_plural "Replaced %d redirects with direct links"
397
  msgstr[0] ""
398
  msgstr[1] ""
399
 
400
- #: core.php:1793
401
  #, php-format
402
  msgid "Failed to fix %d redirect"
403
  msgid_plural "Failed to fix %d redirects"
404
  msgstr[0] ""
405
  msgstr[1] ""
406
 
407
- #: core.php:1803
408
  msgid "None of the selected links are redirects!"
409
  msgstr ""
410
 
411
- #: core.php:1849
412
  #, php-format
413
  msgid "%d link removed"
414
  msgid_plural "%d links removed"
415
  msgstr[0] ""
416
  msgstr[1] ""
417
 
418
- #: core.php:1860
419
  #, php-format
420
  msgid "Failed to remove %d link"
421
  msgid_plural "Failed to remove %d links"
422
  msgstr[0] ""
423
  msgstr[1] ""
424
 
425
- #: core.php:1948
 
 
 
 
 
 
 
 
 
 
 
426
  msgid "Didn't find anything to delete!"
427
  msgstr ""
428
 
429
- #: core.php:1976
430
  #, php-format
431
  msgid "%d link scheduled for rechecking"
432
  msgid_plural "%d links scheduled for rechecking"
433
  msgstr[0] ""
434
  msgstr[1] ""
435
 
436
- #: core.php:2021 core.php:2696
437
  msgid "This link was manually marked as working by the user."
438
  msgstr ""
439
 
440
- #: core.php:2028
441
  #, php-format
442
  msgid "Couldn't modify link %d"
443
  msgstr ""
444
 
445
- #: core.php:2039
446
  #, php-format
447
  msgid "%d link marked as not broken"
448
  msgid_plural "%d links marked as not broken"
449
  msgstr[0] ""
450
  msgstr[1] ""
451
 
452
- #: core.php:2063
453
- msgid "Post published on"
454
- msgstr ""
455
-
456
- #: core.php:2068
457
- msgid "Link last checked"
458
- msgstr ""
459
-
460
- #: core.php:2072
461
- msgid "Never"
462
- msgstr ""
463
-
464
- #: core.php:2078 includes/admin/search-form.php:45
465
- msgid "HTTP code"
466
- msgstr ""
467
-
468
- #: core.php:2083
469
- msgid "Response time"
470
  msgstr ""
471
 
472
- #: core.php:2085
473
- #, php-format
474
- msgid "%2.3f seconds"
475
  msgstr ""
476
 
477
- #: core.php:2088
478
- msgid "Final URL"
479
  msgstr ""
480
 
481
- #: core.php:2093
482
- msgid "Redirect count"
483
  msgstr ""
484
 
485
- #: core.php:2098
486
- msgid "Instance count"
487
  msgstr ""
488
 
489
- #: core.php:2107
490
- #, php-format
491
- msgid "This link has failed %d time."
492
- msgid_plural "This link has failed %d times."
493
- msgstr[0] ""
494
- msgstr[1] ""
495
-
496
- #: core.php:2115
497
  #, php-format
498
- msgid "This link has been broken for %s."
499
  msgstr ""
500
 
501
- #: core.php:2126
502
- msgid "Log"
503
  msgstr ""
504
 
505
- #: core.php:2152
506
- msgid "less than a minute"
507
  msgstr ""
508
 
509
- #: core.php:2160
510
- #, php-format
511
- msgid "%d minute"
512
- msgid_plural "%d minutes"
513
- msgstr[0] ""
514
- msgstr[1] ""
515
-
516
- #: core.php:2174 core.php:2201
517
- #, php-format
518
- msgid "%d hour"
519
- msgid_plural "%d hours"
520
- msgstr[0] ""
521
- msgstr[1] ""
522
-
523
- #: core.php:2189 core.php:2230
524
- #, php-format
525
- msgid "%d day"
526
- msgid_plural "%d days"
527
- msgstr[0] ""
528
- msgstr[1] ""
529
-
530
- #: core.php:2219
531
- #, php-format
532
- msgid "%d month"
533
- msgid_plural "%d months"
534
- msgstr[0] ""
535
- msgstr[1] ""
536
-
537
- #: core.php:2562
538
  msgid "View broken links"
539
  msgstr ""
540
 
541
- #: core.php:2563
542
  #, php-format
543
  msgid "Found %d broken link"
544
  msgid_plural "Found %d broken links"
545
  msgstr[0] ""
546
  msgstr[1] ""
547
 
548
- #: core.php:2569
549
  msgid "No broken links found."
550
  msgstr ""
551
 
552
- #: core.php:2576
553
  #, php-format
554
  msgid "%d URL in the work queue"
555
  msgid_plural "%d URLs in the work queue"
556
  msgstr[0] ""
557
  msgstr[1] ""
558
 
559
- #: core.php:2579
560
  msgid "No URLs in the work queue."
561
  msgstr ""
562
 
563
- #: core.php:2585
564
  #, php-format
565
  msgid "Detected %d unique URL"
566
  msgid_plural "Detected %d unique URLs"
567
  msgstr[0] ""
568
  msgstr[1] ""
569
 
570
- #: core.php:2586
571
  #, php-format
572
  msgid "in %d link"
573
  msgid_plural "in %d links"
574
  msgstr[0] ""
575
  msgstr[1] ""
576
 
577
- #: core.php:2591
578
  msgid "and still searching..."
579
  msgstr ""
580
 
581
- #: core.php:2597
582
  msgid "Searching your blog for links..."
583
  msgstr ""
584
 
585
- #: core.php:2599
586
  msgid "No links detected."
587
  msgstr ""
588
 
589
- #: core.php:2681 core.php:2717 core.php:2780 core.php:2862
590
- msgid "You're not allowed to do that!"
 
591
  msgstr ""
592
 
593
- #: core.php:2689 core.php:2727 core.php:2790
594
  #, php-format
595
  msgid "Oops, I can't find the link %d"
596
  msgstr ""
597
 
598
- #: core.php:2702
599
  msgid "Oops, couldn't modify the link!"
600
  msgstr ""
601
 
602
- #: core.php:2705 core.php:2816
603
  msgid "Error : link_id not specified"
604
  msgstr ""
605
 
606
- #: core.php:2737
607
  msgid "Oops, the new URL is invalid!"
608
  msgstr ""
609
 
610
- #: core.php:2748 core.php:2799
611
  msgid "An unexpected error occured!"
612
  msgstr ""
613
 
614
- #: core.php:2766
615
  msgid "Error : link_id or new_url not specified"
616
  msgstr ""
617
 
618
- #: core.php:2825
619
  msgid "You don't have sufficient privileges to access this information!"
620
  msgstr ""
621
 
622
- #: core.php:2838
623
  msgid "Error : link ID not specified"
624
  msgstr ""
625
 
626
- #: core.php:2849
627
  #, php-format
628
  msgid "Failed to load link details (%s)"
629
  msgstr ""
630
 
631
- #. #-#-#-#-# plugin.pot (Broken Link Checker 0.9.3) #-#-#-#-#
632
  #. Plugin Name of the plugin/theme
633
- #: core.php:3034
634
  msgid "Broken Link Checker"
635
  msgstr ""
636
 
637
- #: core.php:3048
638
  #, php-format
639
  msgid ""
640
  "The current temporary directory is not accessible; please <a href=\"%s\">set "
641
  "a different one</a>."
642
  msgstr ""
643
 
644
- #: core.php:3053
645
  #, php-format
646
  msgid ""
647
  "Please make the directory <code>%1$s</code> writable by plugins or <a href="
648
  "\"%2$s\">set a custom temporary directory</a>."
649
  msgstr ""
650
 
651
- #: core.php:3060
652
  msgid "Broken Link Checker can't create a lockfile."
653
  msgstr ""
654
 
655
- #: core.php:3065
656
  msgid ""
657
  "The plugin uses a file-based locking mechanism to ensure that only one "
658
  "instance of the resource-heavy link checking algorithm is running at any "
@@ -663,66 +537,72 @@ msgid ""
663
  "specify a custom temporary directory in the plugin's settings."
664
  msgstr ""
665
 
666
- #: core.php:3084
667
  msgid "PHP version"
668
  msgstr ""
669
 
670
- #: core.php:3090
671
  msgid "MySQL version"
672
  msgstr ""
673
 
674
- #: core.php:3103
675
  msgid ""
676
  "You have an old version of CURL. Redirect detection may not work properly."
677
  msgstr ""
678
 
679
- #: core.php:3115 core.php:3131 core.php:3136
680
  msgid "Not installed"
681
  msgstr ""
682
 
683
- #: core.php:3118
684
  msgid "CURL version"
685
  msgstr ""
686
 
687
- #: core.php:3124
688
  msgid "Installed"
689
  msgstr ""
690
 
691
- #: core.php:3137
692
  msgid "You must have either CURL or Snoopy installed for the plugin to work!"
693
  msgstr ""
694
 
695
- #: core.php:3148
696
  msgid "On"
697
  msgstr ""
698
 
699
- #: core.php:3149
700
  msgid "Redirects may be detected as broken links when safe_mode is on."
701
  msgstr ""
702
 
703
- #: core.php:3154 core.php:3168
704
  msgid "Off"
705
  msgstr ""
706
 
707
- #: core.php:3162
708
  #, php-format
709
  msgid "On ( %s )"
710
  msgstr ""
711
 
712
- #: core.php:3163
713
  msgid "Redirects may be detected as broken links when open_basedir is on."
714
  msgstr ""
715
 
716
- #: core.php:3182
717
  msgid "Can't create a lockfile. Please specify a custom temporary directory."
718
  msgstr ""
719
 
720
- #: core.php:3217
 
 
 
 
 
 
721
  #, php-format
722
  msgid "[%s] Broken links detected"
723
  msgstr ""
724
 
725
- #: core.php:3223
726
  #, php-format
727
  msgid "Broken Link Checker has detected %d new broken link on your site."
728
  msgid_plural ""
@@ -730,447 +610,858 @@ msgid_plural ""
730
  msgstr[0] ""
731
  msgstr[1] ""
732
 
733
- #: core.php:3238
734
  #, php-format
735
  msgid "Here's a list of the first %d broken links:"
736
  msgid_plural "Here's a list of the first %d broken links:"
737
  msgstr[0] ""
738
  msgstr[1] ""
739
 
740
- #: core.php:3246
741
  msgid "Here's a list of the new broken links: "
742
  msgstr ""
743
 
744
- #: core.php:3258
745
  #, php-format
746
  msgid "Link text : %s"
747
  msgstr ""
748
 
749
- #: core.php:3259
750
  #, php-format
751
  msgid "Link URL : <a href=\"%s\">%s</a>"
752
  msgstr ""
753
 
754
- #: core.php:3260
755
  #, php-format
756
  msgid "Source : %s"
757
  msgstr ""
758
 
759
- #: core.php:3274
760
  msgid "You can see all broken links here:"
761
  msgstr ""
762
 
763
- #: includes/admin/links-page-js.php:40 includes/admin/links-page-js.php:234
764
- msgid "Wait..."
 
 
 
 
 
 
 
 
 
 
 
 
 
765
  msgstr ""
766
 
767
- #: includes/admin/links-page-js.php:109
768
- msgid "Save URL"
769
  msgstr ""
770
 
771
- #: includes/admin/links-page-js.php:120
772
- msgid "Saving changes..."
 
773
  msgstr ""
774
 
775
- #: includes/admin/links-page-js.php:166
776
  #, php-format
777
  msgid "%d instances of the link were successfully modified."
778
  msgstr ""
779
 
780
- #: includes/admin/links-page-js.php:172
781
  #, php-format
782
  msgid ""
783
  "However, %d instances couldn't be edited and still point to the old URL."
784
  msgstr ""
785
 
786
- #: includes/admin/links-page-js.php:178
787
  msgid "The link could not be modified."
788
  msgstr ""
789
 
790
- #: includes/admin/links-page-js.php:181 includes/admin/links-page-js.php:285
791
  msgid "The following error(s) occured :"
792
  msgstr ""
793
 
794
- #: includes/admin/links-page-js.php:271
795
  #, php-format
796
  msgid "%d instances of the link were successfully unlinked."
797
  msgstr ""
798
 
799
- #: includes/admin/links-page-js.php:277
800
  #, php-format
801
  msgid "However, %d instances couldn't be removed."
802
  msgstr ""
803
 
804
- #: includes/admin/links-page-js.php:282
805
  msgid "The plugin failed to remove the link."
806
  msgstr ""
807
 
808
- #: includes/admin/links-page-js.php:337
 
 
 
 
 
809
  msgid "Enter a name for the new custom filter"
810
  msgstr ""
811
 
812
- #: includes/admin/links-page-js.php:348
813
  msgid ""
814
  "You are about to delete the current filter.\n"
815
  "'Cancel' to stop, 'OK' to delete"
816
  msgstr ""
817
 
818
- #: includes/admin/links-page-js.php:371
819
  msgid ""
820
  "Are you sure you want to delete all posts, bookmarks or other items that "
821
  "contain any of the selected links? This action can't be undone.\n"
822
  "'Cancel' to stop, 'OK' to delete"
823
  msgstr ""
824
 
825
- #: includes/admin/search-form.php:13
 
 
 
 
826
  msgid "Save This Search As a Filter"
827
  msgstr ""
828
 
829
- #: includes/admin/search-form.php:23
830
  msgid "Delete This Filter"
831
  msgstr ""
832
 
833
- #: includes/admin/search-form.php:29 includes/links.php:800
834
  msgid "Search"
835
  msgstr ""
836
 
837
- #: includes/admin/search-form.php:39
838
  msgid "Link text"
839
  msgstr ""
840
 
841
- #: includes/admin/search-form.php:48
 
 
 
 
 
 
 
 
 
842
  msgid "Link status"
843
  msgstr ""
844
 
845
- #: includes/admin/search-form.php:64
846
  msgid "Link type"
847
  msgstr ""
848
 
849
- #: includes/admin/search-form.php:68
850
  msgid "Any"
851
  msgstr ""
852
 
853
- #: includes/admin/search-form.php:69
854
- msgid "Normal link"
855
  msgstr ""
856
 
857
- #: includes/admin/search-form.php:70 includes/parsers/image.php:142
858
- msgid "Image"
859
  msgstr ""
860
 
861
- #: includes/admin/search-form.php:71 includes/containers/custom_field.php:176
862
- msgid "Custom field"
 
863
  msgstr ""
864
 
865
- #: includes/admin/search-form.php:72 includes/containers/blogroll.php:13
866
- msgid "Bookmark"
867
  msgstr ""
868
 
869
- #: includes/admin/search-form.php:73 includes/containers/comment.php:137
870
- msgid "Comment"
871
  msgstr ""
872
 
873
- #: includes/admin/search-form.php:86
874
- msgid "Search Links"
875
  msgstr ""
876
 
877
- #: includes/checkers/http.php:195 includes/checkers/http.php:262
878
- #, php-format
879
- msgid "HTTP code : %d"
880
  msgstr ""
881
 
882
- #: includes/checkers/http.php:197 includes/checkers/http.php:264
883
- msgid "(No response)"
884
  msgstr ""
885
 
886
- #: includes/checkers/http.php:203
887
- msgid "Most likely the connection timed out or the domain doesn't exist."
888
  msgstr ""
889
 
890
- #: includes/checkers/http.php:271
891
- msgid "Request timed out."
892
  msgstr ""
893
 
894
- #: includes/checkers/http.php:289
895
- msgid "Using Snoopy"
896
  msgstr ""
897
 
898
- #: includes/containers.php:279
899
- #, php-format
900
- msgid "Container type '%s' not recognized"
901
  msgstr ""
902
 
903
- #: includes/containers.php:809
904
- #, php-format
905
- msgid "%d '%s' has been deleted"
906
- msgid_plural "%d '%s' have been deleted"
907
- msgstr[0] ""
908
- msgstr[1] ""
909
 
910
- #: includes/containers/blogroll.php:19 includes/containers/blogroll.php:38
911
- msgid "Edit this bookmark"
912
  msgstr ""
913
 
914
- #: includes/containers/blogroll.php:38 includes/containers/comment.php:107
915
- #: includes/containers/custom_field.php:201 includes/containers/post.php:16
916
- msgid "Edit"
 
 
 
917
  msgstr ""
918
 
919
- #: includes/containers/blogroll.php:39
920
  #, php-format
921
- msgid ""
922
- "You are about to delete this link '%s'\n"
923
- " 'Cancel' to stop, 'OK' to delete."
924
  msgstr ""
925
 
926
- #: includes/containers/blogroll.php:39
927
- #: includes/containers/custom_field.php:206 includes/containers/post.php:21
928
- msgid "Delete"
929
  msgstr ""
930
 
931
- #: includes/containers/blogroll.php:75 includes/containers/comment.php:36
932
- #: includes/containers/post.php:142
933
- msgid "Nothing to update"
934
  msgstr ""
935
 
936
- #: includes/containers/blogroll.php:89
937
- #, php-format
938
- msgid "Updating bookmark %d failed"
939
  msgstr ""
940
 
941
- #: includes/containers/blogroll.php:120
 
 
 
 
942
  #, php-format
943
- msgid "Failed to delete blogroll link \"%s\" (%d)"
 
 
 
 
 
 
 
 
944
  msgstr ""
945
 
946
- #: includes/containers/blogroll.php:280
 
 
 
 
947
  #, php-format
948
- msgid "%d blogroll link deleted"
949
- msgid_plural "%d blogroll links deleted"
950
  msgstr[0] ""
951
  msgstr[1] ""
952
 
953
- #: includes/containers/comment.php:46
954
  #, php-format
955
- msgid "Updating comment %d failed"
956
  msgstr ""
957
 
958
- #: includes/containers/comment.php:64
959
- #, php-format
960
- msgid "Failed to delete comment %d"
961
  msgstr ""
962
 
963
- #: includes/containers/comment.php:107 includes/containers/comment.php:149
964
- msgid "Edit comment"
965
  msgstr ""
966
 
967
- #: includes/containers/comment.php:114
968
- msgid "Delete Permanently"
969
  msgstr ""
970
 
971
- #: includes/containers/comment.php:116
972
- msgid "Move this comment to the trash"
973
  msgstr ""
974
 
975
- #: includes/containers/comment.php:116
976
- msgctxt "verb"
977
- msgid "Trash"
978
  msgstr ""
979
 
980
- #: includes/containers/comment.php:120
981
- msgid "View comment"
982
  msgstr ""
983
 
984
- #: includes/containers/comment.php:120
985
- #: includes/containers/custom_field.php:209 includes/containers/post.php:24
986
- msgid "View"
987
  msgstr ""
988
 
989
- #: includes/containers/comment.php:279
990
- #, php-format
991
- msgid "%d comment moved to the trash"
992
- msgid_plural "%d comments moved to the trash"
993
- msgstr[0] ""
994
- msgstr[1] ""
995
 
996
- #: includes/containers/comment.php:289
997
- #, php-format
998
- msgid "%d comment has been deleted"
999
- msgid_plural "%d comments have been deleted"
1000
- msgstr[0] ""
1001
- msgstr[1] ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1002
 
1003
- #: includes/containers/custom_field.php:73
1004
  #, php-format
1005
- msgid "Failed to update the meta field '%s' on %s [%d]"
1006
  msgstr ""
1007
 
1008
- #: includes/containers/custom_field.php:99
 
 
 
 
1009
  #, php-format
1010
- msgid "Failed to delete the meta field '%s' on %s [%d]"
1011
  msgstr ""
1012
 
1013
- #: includes/containers/custom_field.php:191 includes/containers/post.php:16
1014
- #: includes/containers/post.php:41
1015
- msgid "Edit this post"
1016
  msgstr ""
1017
 
1018
- #: includes/containers/custom_field.php:201
1019
  msgid "Edit this item"
1020
  msgstr ""
1021
 
1022
- #: includes/containers/custom_field.php:204
1023
- msgid "Move this item to the Trash"
 
1024
  msgstr ""
1025
 
1026
- #: includes/containers/custom_field.php:204 includes/containers/post.php:19
1027
- msgid "Trash"
 
1028
  msgstr ""
1029
 
1030
- #: includes/containers/custom_field.php:206 includes/containers/post.php:21
1031
- msgid "Delete this post permanently"
 
1032
  msgstr ""
1033
 
1034
- #: includes/containers/custom_field.php:206 includes/containers/post.php:21
1035
  #, php-format
1036
  msgid ""
1037
- "You are about to delete this post '%s'\n"
1038
- " 'Cancel' to stop, 'OK' to delete."
1039
  msgstr ""
1040
 
1041
- #: includes/containers/custom_field.php:209 includes/containers/post.php:24
1042
  #, php-format
1043
- msgid "View \"%s\""
1044
  msgstr ""
1045
 
1046
- #: includes/containers/custom_field.php:304 includes/containers/post.php:183
1047
  #, php-format
1048
- msgid "Failed to delete post \"%s\" (%d)"
1049
- msgstr ""
 
 
1050
 
1051
- #: includes/containers/custom_field.php:535 includes/containers/post.php:356
1052
  #, php-format
1053
- msgid "%d post moved to the trash"
1054
- msgid_plural "%d posts moved to the trash"
1055
  msgstr[0] ""
1056
  msgstr[1] ""
1057
 
1058
- #: includes/containers/custom_field.php:537 includes/containers/post.php:358
1059
  #, php-format
1060
- msgid "%d post deleted"
1061
- msgid_plural "%d posts deleted"
1062
  msgstr[0] ""
1063
  msgstr[1] ""
1064
 
1065
- #: includes/containers/dummy.php:21 includes/containers/dummy.php:32
1066
  #, php-format
1067
- msgid "I don't know how to edit a '%s' [%d]."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1068
  msgstr ""
1069
 
1070
- #: includes/containers/post.php:19
1071
- msgid "Move this post to the Trash"
 
1072
  msgstr ""
1073
 
1074
- #: includes/containers/post.php:152
1075
- #, php-format
1076
- msgid "Updating post %d failed"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1077
  msgstr ""
1078
 
1079
- #: includes/instances.php:102 includes/instances.php:148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1080
  #, php-format
1081
  msgid "Container %s[%d] not found"
1082
  msgstr ""
1083
 
1084
- #: includes/instances.php:111 includes/instances.php:157
1085
  #, php-format
1086
  msgid "Parser '%s' not found."
1087
  msgstr ""
1088
 
1089
- #: includes/links.php:152
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1090
  msgid "The plugin script was terminated while trying to check the link."
1091
  msgstr ""
1092
 
1093
- #: includes/links.php:196
1094
  msgid "The plugin doesn't know how to check this type of link."
1095
  msgstr ""
1096
 
1097
- #: includes/links.php:284
1098
  msgid "Link is valid."
1099
  msgstr ""
1100
 
1101
- #: includes/links.php:286
1102
  msgid "Link is broken."
1103
  msgstr ""
1104
 
1105
- #: includes/links.php:479 includes/links.php:581 includes/links.php:616
1106
  msgid "Link is not valid"
1107
  msgstr ""
1108
 
1109
- #: includes/links.php:496
1110
  msgid ""
1111
  "This link can not be edited because it is not used anywhere on this site."
1112
  msgstr ""
1113
 
1114
- #: includes/links.php:522
1115
  msgid "Failed to create a DB entry for the new URL."
1116
  msgstr ""
1117
 
1118
- #: includes/links.php:594
1119
  msgid "This link is not a redirect"
1120
  msgstr ""
1121
 
1122
- #: includes/links.php:643 includes/links.php:680
1123
  msgid "Couldn't delete the link's database record"
1124
  msgstr ""
1125
 
1126
- #: includes/links.php:772
1127
- msgid "Broken"
 
1128
  msgstr ""
1129
 
1130
- #: includes/links.php:774
1131
- msgid "No broken links found"
1132
  msgstr ""
1133
 
1134
- #: includes/links.php:781
1135
- msgid "Redirects"
1136
  msgstr ""
1137
 
1138
- #: includes/links.php:782
1139
- msgid "Redirected Links"
1140
  msgstr ""
1141
 
1142
- #: includes/links.php:783
1143
- msgid "No redirects found"
 
1144
  msgstr ""
1145
 
1146
- #: includes/links.php:791
1147
- msgid "All"
 
1148
  msgstr ""
1149
 
1150
- #: includes/links.php:792
1151
- msgid "Detected Links"
 
1152
  msgstr ""
1153
 
1154
- #: includes/links.php:793
1155
- msgid "No links found (yet)"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1156
  msgstr ""
1157
 
1158
- #: includes/links.php:801
1159
- msgid "Search Results"
1160
  msgstr ""
1161
 
1162
- #: includes/links.php:802 includes/links.php:853
1163
- msgid "No links found for your query"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1164
  msgstr ""
1165
 
1166
- #: includes/parsers.php:173
 
 
 
 
1167
  #, php-format
1168
- msgid "Editing is not implemented in the '%s' parser"
 
 
1169
  msgstr ""
1170
 
1171
- #: includes/parsers.php:188
1172
  #, php-format
1173
- msgid "Unlinking is not implemented in the '%s' parser"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1174
  msgstr ""
1175
 
1176
  #. Plugin URI of the plugin/theme
1
+ # Translation of the WordPress plugin Broken Link Checker 0.9.5-alpha 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.
6
  #, fuzzy
7
  msgid ""
8
  msgstr ""
9
+ "Project-Id-Version: Broken Link Checker 0.9.5-alpha\n"
10
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/broken-link-checker\n"
11
+ "POT-Creation-Date: 2010-08-04 07:17+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"
16
  "Content-Type: text/plain; charset=utf-8\n"
17
  "Content-Transfer-Encoding: 8bit\n"
18
+ "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
19
 
20
+ #: core/core.php:152 includes/admin/links-page-js.php:37
21
+ msgid "Loading..."
22
  msgstr ""
23
 
24
+ #: core/core.php:176 includes/admin/options-page-js.php:18
25
+ msgid "[ Network error ]"
26
  msgstr ""
27
 
28
+ #: core/core.php:201
29
+ msgid "Automatically expand the widget if broken links have been detected"
30
  msgstr ""
31
 
32
+ #: core/core.php:459
33
+ msgid "Link Checker Settings"
34
  msgstr ""
35
 
36
+ #: core/core.php:460
37
+ msgid "Link Checker"
38
  msgstr ""
39
 
40
+ #: core/core.php:465 includes/link-query.php:26
41
+ msgid "Broken Links"
42
  msgstr ""
43
 
44
+ #: core/core.php:481
45
+ msgid "View Broken Links"
 
46
  msgstr ""
47
 
48
+ #: core/core.php:518
49
+ msgid "Settings"
 
 
 
50
  msgstr ""
51
 
52
+ #: core/core.php:530 core/core.php:1312
53
  #, php-format
54
+ msgid ""
55
+ "Error: The plugin's database tables are not up to date! (Current version : %"
56
+ "d, expected : %d)"
57
  msgstr ""
58
 
59
+ #: core/core.php:674
60
+ msgid "Settings saved."
61
  msgstr ""
62
 
63
+ #: core/core.php:681
64
+ msgid "Complete site recheck started."
65
  msgstr ""
66
 
67
+ #: core/core.php:693 core/core.php:2806 includes/admin/table-printer.php:521
68
+ msgid "Details"
69
  msgstr ""
70
 
71
+ #: core/core.php:707
72
+ msgid "General"
73
  msgstr ""
74
 
75
+ #: core/core.php:708
76
+ msgid "Look For Links In"
 
77
  msgstr ""
78
 
79
+ #: core/core.php:709
80
+ msgid "Which Links To Check"
81
  msgstr ""
82
 
83
+ #: core/core.php:710
84
+ msgid "Protocols & APIs"
 
 
 
85
  msgstr ""
86
 
87
+ #: core/core.php:711
88
+ msgid "Advanced"
89
  msgstr ""
90
 
91
+ #: core/core.php:715
92
  msgid "Broken Link Checker Options"
93
  msgstr ""
94
 
95
+ #: core/core.php:741 includes/admin/table-printer.php:181
96
  msgid "Status"
97
  msgstr ""
98
 
99
+ #: core/core.php:743 includes/admin/options-page-js.php:56
100
  msgid "Show debug info"
101
  msgstr ""
102
 
103
+ #: core/core.php:771
 
 
 
 
104
  msgid "Check each link"
105
  msgstr ""
106
 
107
+ #: core/core.php:776
108
  #, php-format
109
  msgid "Every %s hours"
110
  msgstr ""
111
 
112
+ #: core/core.php:785
113
  msgid ""
114
  "Existing links will be checked this often. New links will usually be checked "
115
  "ASAP."
116
  msgstr ""
117
 
118
+ #: core/core.php:792
119
+ msgid "E-mail notifications"
 
 
 
 
120
  msgstr ""
121
 
122
+ #: core/core.php:798
123
+ msgid "Send me e-mail notifications about newly detected broken links"
124
  msgstr ""
125
 
126
+ #: core/core.php:805
127
+ msgid "Link tweaks"
128
  msgstr ""
129
 
130
+ #: core/core.php:811
131
+ msgid "Apply custom formatting to broken links"
132
  msgstr ""
133
 
134
+ #: core/core.php:815 core/core.php:843
135
+ msgid "Edit CSS"
136
  msgstr ""
137
 
138
+ #: core/core.php:839
139
+ msgid "Apply custom formatting to removed links"
140
  msgstr ""
141
 
142
+ #: core/core.php:867
143
+ msgid "Stop search engines from following broken links"
 
144
  msgstr ""
145
 
146
+ #: core/core.php:884
147
+ msgid "Look for links in"
148
  msgstr ""
149
 
150
+ #: core/core.php:895
151
+ msgid "Post statuses"
152
  msgstr ""
153
 
154
+ #: core/core.php:928
155
+ msgid "Link types"
156
  msgstr ""
157
 
158
+ #: core/core.php:934
159
+ msgid "Error : All link parsers missing!"
160
  msgstr ""
161
 
162
+ #: core/core.php:941
163
+ msgid "Exclusion list"
164
  msgstr ""
165
 
166
+ #: core/core.php:942
167
+ msgid ""
168
+ "Don't check links where the URL contains any of these words (one per line) :"
169
  msgstr ""
170
 
171
+ #: core/core.php:960
172
+ msgid "Check links using"
173
  msgstr ""
174
 
175
+ #: core/core.php:979 includes/links.php:855
176
  msgid "Timeout"
177
  msgstr ""
178
 
179
+ #: core/core.php:985 core/core.php:1031 core/core.php:2933
180
  #, php-format
181
  msgid "%s seconds"
182
  msgstr ""
183
 
184
+ #: core/core.php:994
185
  msgid "Links that take longer than this to load will be marked as broken."
186
  msgstr ""
187
 
188
+ #: core/core.php:1001
189
  msgid "Link monitor"
190
  msgstr ""
191
 
192
+ #: core/core.php:1009
193
  msgid "Run continuously while the Dashboard is open"
194
  msgstr ""
195
 
196
+ #: core/core.php:1017
197
  msgid "Run hourly in the background"
198
  msgstr ""
199
 
200
+ #: core/core.php:1025
201
  msgid "Max. execution time"
202
  msgstr ""
203
 
204
+ #: core/core.php:1042
205
  msgid ""
206
  "The plugin works by periodically launching a background job that parses your "
207
  "posts for links, checks the discovered URLs, and performs other time-"
209
  "may run each time before stopping."
210
  msgstr ""
211
 
212
+ #: core/core.php:1052
213
  msgid "Custom temporary directory"
214
  msgstr ""
215
 
216
+ #: core/core.php:1061
217
  msgid "OK"
218
  msgstr ""
219
 
220
+ #: core/core.php:1064
221
  msgid "Error : This directory isn't writable by PHP."
222
  msgstr ""
223
 
224
+ #: core/core.php:1069
225
  msgid "Error : This directory doesn't exist."
226
  msgstr ""
227
 
228
+ #: core/core.php:1077
229
  msgid ""
230
  "Set this field if you want the plugin to use a custom directory for its "
231
  "lockfiles. Otherwise, leave it blank."
232
  msgstr ""
233
 
234
+ #: core/core.php:1084
235
  msgid "Server load limit"
236
  msgstr ""
237
 
238
+ #: core/core.php:1102
239
  #, php-format
240
  msgid ""
241
  "Link checking will be suspended if the average <a href=\"%s\">server load</"
242
  "a> rises above this number. Leave this field blank to disable load limiting."
243
  msgstr ""
244
 
245
+ #: core/core.php:1112
246
  msgid ""
247
  "Load limiting only works on Linux-like systems where <code>/proc/loadavg</"
248
  "code> is present and accessible."
249
  msgstr ""
250
 
251
+ #: core/core.php:1120
252
+ msgid "Forced recheck"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
  msgstr ""
254
 
255
+ #: core/core.php:1123
256
+ msgid "Re-check all pages"
 
 
 
 
257
  msgstr ""
258
 
259
+ #: core/core.php:1127
260
+ msgid ""
261
+ "The \"Nuclear Option\". Click this button to make the plugin empty its link "
262
+ "database and recheck the entire site from scratch."
263
  msgstr ""
264
 
265
+ #: core/core.php:1138
266
+ msgid "Save Changes"
267
  msgstr ""
268
 
269
+ #: core/core.php:1183
270
+ msgid "Configure"
271
  msgstr ""
272
 
273
+ #: core/core.php:1243
274
+ msgid "Upgrade to Pro to enable this feature"
275
  msgstr ""
276
 
277
+ #: core/core.php:1278
278
+ msgid "Check URLs entered in these custom fields (one per line) :"
279
  msgstr ""
280
 
281
+ #: core/core.php:1414 core/core.php:1497 core/core.php:1529
282
  #, php-format
283
+ msgid "Database error : %s"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  msgstr ""
285
 
286
+ #: core/core.php:1479
287
  msgid "You must enter a filter name!"
288
  msgstr ""
289
 
290
+ #: core/core.php:1483
291
  msgid "Invalid search query."
292
  msgstr ""
293
 
294
+ #: core/core.php:1492
295
  #, php-format
296
  msgid "Filter \"%s\" created"
297
  msgstr ""
298
 
299
+ #: core/core.php:1519
300
  msgid "Filter ID not specified."
301
  msgstr ""
302
 
303
+ #: core/core.php:1526
304
  msgid "Filter deleted"
305
  msgstr ""
306
 
307
+ #: core/core.php:1574
308
  #, php-format
309
  msgid "Replaced %d redirect with a direct link"
310
  msgid_plural "Replaced %d redirects with direct links"
311
  msgstr[0] ""
312
  msgstr[1] ""
313
 
314
+ #: core/core.php:1585
315
  #, php-format
316
  msgid "Failed to fix %d redirect"
317
  msgid_plural "Failed to fix %d redirects"
318
  msgstr[0] ""
319
  msgstr[1] ""
320
 
321
+ #: core/core.php:1595
322
  msgid "None of the selected links are redirects!"
323
  msgstr ""
324
 
325
+ #: core/core.php:1641
326
  #, php-format
327
  msgid "%d link removed"
328
  msgid_plural "%d links removed"
329
  msgstr[0] ""
330
  msgstr[1] ""
331
 
332
+ #: core/core.php:1652
333
  #, php-format
334
  msgid "Failed to remove %d link"
335
  msgid_plural "Failed to remove %d links"
336
  msgstr[0] ""
337
  msgstr[1] ""
338
 
339
+ #: core/core.php:1761
340
+ #, php-format
341
+ msgid ""
342
+ "%d item was skipped because it can't be moved to the Trash. You need to "
343
+ "delete it manually."
344
+ msgid_plural ""
345
+ "%d items were skipped because they can't be moved to the Trash. You need to "
346
+ "delete them manually."
347
+ msgstr[0] ""
348
+ msgstr[1] ""
349
+
350
+ #: core/core.php:1782
351
  msgid "Didn't find anything to delete!"
352
  msgstr ""
353
 
354
+ #: core/core.php:1810
355
  #, php-format
356
  msgid "%d link scheduled for rechecking"
357
  msgid_plural "%d links scheduled for rechecking"
358
  msgstr[0] ""
359
  msgstr[1] ""
360
 
361
+ #: core/core.php:1855 core/core.php:2460
362
  msgid "This link was manually marked as working by the user."
363
  msgstr ""
364
 
365
+ #: core/core.php:1862
366
  #, php-format
367
  msgid "Couldn't modify link %d"
368
  msgstr ""
369
 
370
+ #: core/core.php:1873
371
  #, php-format
372
  msgid "%d link marked as not broken"
373
  msgid_plural "%d links marked as not broken"
374
  msgstr[0] ""
375
  msgstr[1] ""
376
 
377
+ #: core/core.php:1913
378
+ msgid "Table columns"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
  msgstr ""
380
 
381
+ #: core/core.php:1932
382
+ msgid "Show on screen"
 
383
  msgstr ""
384
 
385
+ #: core/core.php:1939
386
+ msgid "links"
387
  msgstr ""
388
 
389
+ #: core/core.php:1940 includes/admin/table-printer.php:134
390
+ msgid "Apply"
391
  msgstr ""
392
 
393
+ #: core/core.php:1944
394
+ msgid "Misc"
395
  msgstr ""
396
 
397
+ #: core/core.php:1959
 
 
 
 
 
 
 
398
  #, php-format
399
+ msgid "Highlight links broken for at least %s days"
400
  msgstr ""
401
 
402
+ #: core/core.php:1968
403
+ msgid "Color-code status codes"
404
  msgstr ""
405
 
406
+ #: core/core.php:1985 core/core.php:2445 core/core.php:2481 core/core.php:2544
407
+ msgid "You're not allowed to do that!"
408
  msgstr ""
409
 
410
+ #: core/core.php:2326
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
411
  msgid "View broken links"
412
  msgstr ""
413
 
414
+ #: core/core.php:2327
415
  #, php-format
416
  msgid "Found %d broken link"
417
  msgid_plural "Found %d broken links"
418
  msgstr[0] ""
419
  msgstr[1] ""
420
 
421
+ #: core/core.php:2333
422
  msgid "No broken links found."
423
  msgstr ""
424
 
425
+ #: core/core.php:2340
426
  #, php-format
427
  msgid "%d URL in the work queue"
428
  msgid_plural "%d URLs in the work queue"
429
  msgstr[0] ""
430
  msgstr[1] ""
431
 
432
+ #: core/core.php:2343
433
  msgid "No URLs in the work queue."
434
  msgstr ""
435
 
436
+ #: core/core.php:2349
437
  #, php-format
438
  msgid "Detected %d unique URL"
439
  msgid_plural "Detected %d unique URLs"
440
  msgstr[0] ""
441
  msgstr[1] ""
442
 
443
+ #: core/core.php:2350
444
  #, php-format
445
  msgid "in %d link"
446
  msgid_plural "in %d links"
447
  msgstr[0] ""
448
  msgstr[1] ""
449
 
450
+ #: core/core.php:2355
451
  msgid "and still searching..."
452
  msgstr ""
453
 
454
+ #: core/core.php:2361
455
  msgid "Searching your blog for links..."
456
  msgstr ""
457
 
458
+ #: core/core.php:2363
459
  msgid "No links detected."
460
  msgstr ""
461
 
462
+ #: core/core.php:2389
463
+ msgctxt "current load"
464
+ msgid "Unknown"
465
  msgstr ""
466
 
467
+ #: core/core.php:2453 core/core.php:2491 core/core.php:2554
468
  #, php-format
469
  msgid "Oops, I can't find the link %d"
470
  msgstr ""
471
 
472
+ #: core/core.php:2466
473
  msgid "Oops, couldn't modify the link!"
474
  msgstr ""
475
 
476
+ #: core/core.php:2469 core/core.php:2580
477
  msgid "Error : link_id not specified"
478
  msgstr ""
479
 
480
+ #: core/core.php:2501
481
  msgid "Oops, the new URL is invalid!"
482
  msgstr ""
483
 
484
+ #: core/core.php:2512 core/core.php:2563
485
  msgid "An unexpected error occured!"
486
  msgstr ""
487
 
488
+ #: core/core.php:2530
489
  msgid "Error : link_id or new_url not specified"
490
  msgstr ""
491
 
492
+ #: core/core.php:2589
493
  msgid "You don't have sufficient privileges to access this information!"
494
  msgstr ""
495
 
496
+ #: core/core.php:2602
497
  msgid "Error : link ID not specified"
498
  msgstr ""
499
 
500
+ #: core/core.php:2616
501
  #, php-format
502
  msgid "Failed to load link details (%s)"
503
  msgstr ""
504
 
505
+ #. #-#-#-#-# plugin.pot (Broken Link Checker 0.9.5-alpha) #-#-#-#-#
506
  #. Plugin Name of the plugin/theme
507
+ #: core/core.php:2778
508
  msgid "Broken Link Checker"
509
  msgstr ""
510
 
511
+ #: core/core.php:2792
512
  #, php-format
513
  msgid ""
514
  "The current temporary directory is not accessible; please <a href=\"%s\">set "
515
  "a different one</a>."
516
  msgstr ""
517
 
518
+ #: core/core.php:2797
519
  #, php-format
520
  msgid ""
521
  "Please make the directory <code>%1$s</code> writable by plugins or <a href="
522
  "\"%2$s\">set a custom temporary directory</a>."
523
  msgstr ""
524
 
525
+ #: core/core.php:2804
526
  msgid "Broken Link Checker can't create a lockfile."
527
  msgstr ""
528
 
529
+ #: core/core.php:2809
530
  msgid ""
531
  "The plugin uses a file-based locking mechanism to ensure that only one "
532
  "instance of the resource-heavy link checking algorithm is running at any "
537
  "specify a custom temporary directory in the plugin's settings."
538
  msgstr ""
539
 
540
+ #: core/core.php:2828
541
  msgid "PHP version"
542
  msgstr ""
543
 
544
+ #: core/core.php:2834
545
  msgid "MySQL version"
546
  msgstr ""
547
 
548
+ #: core/core.php:2847
549
  msgid ""
550
  "You have an old version of CURL. Redirect detection may not work properly."
551
  msgstr ""
552
 
553
+ #: core/core.php:2859 core/core.php:2875 core/core.php:2880
554
  msgid "Not installed"
555
  msgstr ""
556
 
557
+ #: core/core.php:2862
558
  msgid "CURL version"
559
  msgstr ""
560
 
561
+ #: core/core.php:2868
562
  msgid "Installed"
563
  msgstr ""
564
 
565
+ #: core/core.php:2881
566
  msgid "You must have either CURL or Snoopy installed for the plugin to work!"
567
  msgstr ""
568
 
569
+ #: core/core.php:2892
570
  msgid "On"
571
  msgstr ""
572
 
573
+ #: core/core.php:2893
574
  msgid "Redirects may be detected as broken links when safe_mode is on."
575
  msgstr ""
576
 
577
+ #: core/core.php:2898 core/core.php:2912
578
  msgid "Off"
579
  msgstr ""
580
 
581
+ #: core/core.php:2906
582
  #, php-format
583
  msgid "On ( %s )"
584
  msgstr ""
585
 
586
+ #: core/core.php:2907
587
  msgid "Redirects may be detected as broken links when open_basedir is on."
588
  msgstr ""
589
 
590
+ #: core/core.php:2926
591
  msgid "Can't create a lockfile. Please specify a custom temporary directory."
592
  msgstr ""
593
 
594
+ #: core/core.php:2950
595
+ msgid ""
596
+ "If this value is zero even after several page reloads you have probably "
597
+ "encountered a bug."
598
+ msgstr ""
599
+
600
+ #: core/core.php:3006
601
  #, php-format
602
  msgid "[%s] Broken links detected"
603
  msgstr ""
604
 
605
+ #: core/core.php:3012
606
  #, php-format
607
  msgid "Broken Link Checker has detected %d new broken link on your site."
608
  msgid_plural ""
610
  msgstr[0] ""
611
  msgstr[1] ""
612
 
613
+ #: core/core.php:3027
614
  #, php-format
615
  msgid "Here's a list of the first %d broken links:"
616
  msgid_plural "Here's a list of the first %d broken links:"
617
  msgstr[0] ""
618
  msgstr[1] ""
619
 
620
+ #: core/core.php:3035
621
  msgid "Here's a list of the new broken links: "
622
  msgstr ""
623
 
624
+ #: core/core.php:3047
625
  #, php-format
626
  msgid "Link text : %s"
627
  msgstr ""
628
 
629
+ #: core/core.php:3048
630
  #, php-format
631
  msgid "Link URL : <a href=\"%s\">%s</a>"
632
  msgstr ""
633
 
634
+ #: core/core.php:3049
635
  #, php-format
636
  msgid "Source : %s"
637
  msgstr ""
638
 
639
+ #: core/core.php:3063
640
  msgid "You can see all broken links here:"
641
  msgstr ""
642
 
643
+ #: core/init.php:230
644
+ msgid "Once Weekly"
645
+ msgstr ""
646
+
647
+ #: core/init.php:236
648
+ msgid "Twice a Month"
649
+ msgstr ""
650
+
651
+ #: core/init.php:259
652
+ msgid "Broken Link Checker installation failed"
653
+ msgstr ""
654
+
655
+ #: includes/admin/db-upgrade.php:95
656
+ #, php-format
657
+ msgid "Failed to delete old DB tables. Database error : %s"
658
  msgstr ""
659
 
660
+ #: includes/admin/links-page-js.php:58 includes/admin/links-page-js.php:301
661
+ msgid "Wait..."
662
  msgstr ""
663
 
664
+ #: includes/admin/links-page-js.php:99 includes/admin/table-printer.php:530
665
+ #: includes/admin/table-printer.php:620
666
+ msgid "Not broken"
667
  msgstr ""
668
 
669
+ #: includes/admin/links-page-js.php:213
670
  #, php-format
671
  msgid "%d instances of the link were successfully modified."
672
  msgstr ""
673
 
674
+ #: includes/admin/links-page-js.php:219
675
  #, php-format
676
  msgid ""
677
  "However, %d instances couldn't be edited and still point to the old URL."
678
  msgstr ""
679
 
680
+ #: includes/admin/links-page-js.php:225
681
  msgid "The link could not be modified."
682
  msgstr ""
683
 
684
+ #: includes/admin/links-page-js.php:228 includes/admin/links-page-js.php:353
685
  msgid "The following error(s) occured :"
686
  msgstr ""
687
 
688
+ #: includes/admin/links-page-js.php:339
689
  #, php-format
690
  msgid "%d instances of the link were successfully unlinked."
691
  msgstr ""
692
 
693
+ #: includes/admin/links-page-js.php:345
694
  #, php-format
695
  msgid "However, %d instances couldn't be removed."
696
  msgstr ""
697
 
698
+ #: includes/admin/links-page-js.php:350
699
  msgid "The plugin failed to remove the link."
700
  msgstr ""
701
 
702
+ #: includes/admin/links-page-js.php:361 includes/admin/table-printer.php:249
703
+ #: includes/admin/table-printer.php:524 includes/admin/table-printer.php:614
704
+ msgid "Unlink"
705
+ msgstr ""
706
+
707
+ #: includes/admin/links-page-js.php:405
708
  msgid "Enter a name for the new custom filter"
709
  msgstr ""
710
 
711
+ #: includes/admin/links-page-js.php:416
712
  msgid ""
713
  "You are about to delete the current filter.\n"
714
  "'Cancel' to stop, 'OK' to delete"
715
  msgstr ""
716
 
717
+ #: includes/admin/links-page-js.php:439
718
  msgid ""
719
  "Are you sure you want to delete all posts, bookmarks or other items that "
720
  "contain any of the selected links? This action can't be undone.\n"
721
  "'Cancel' to stop, 'OK' to delete"
722
  msgstr ""
723
 
724
+ #: includes/admin/options-page-js.php:54
725
+ msgid "Hide debug info"
726
+ msgstr ""
727
+
728
+ #: includes/admin/search-form.php:16
729
  msgid "Save This Search As a Filter"
730
  msgstr ""
731
 
732
+ #: includes/admin/search-form.php:26
733
  msgid "Delete This Filter"
734
  msgstr ""
735
 
736
+ #: includes/admin/search-form.php:32 includes/link-query.php:53
737
  msgid "Search"
738
  msgstr ""
739
 
740
+ #: includes/admin/search-form.php:42
741
  msgid "Link text"
742
  msgstr ""
743
 
744
+ #: includes/admin/search-form.php:45 includes/admin/table-printer.php:176
745
+ #: includes/admin/table-printer.php:186
746
+ msgid "URL"
747
+ msgstr ""
748
+
749
+ #: includes/admin/search-form.php:48 includes/admin/table-printer.php:422
750
+ msgid "HTTP code"
751
+ msgstr ""
752
+
753
+ #: includes/admin/search-form.php:51
754
  msgid "Link status"
755
  msgstr ""
756
 
757
+ #: includes/admin/search-form.php:68 includes/admin/search-form.php:85
758
  msgid "Link type"
759
  msgstr ""
760
 
761
+ #: includes/admin/search-form.php:70
762
  msgid "Any"
763
  msgstr ""
764
 
765
+ #: includes/admin/search-form.php:74
766
+ msgid "Links used in"
767
  msgstr ""
768
 
769
+ #: includes/admin/search-form.php:112
770
+ msgid "Search Links"
771
  msgstr ""
772
 
773
+ #: includes/admin/search-form.php:113 includes/admin/table-printer.php:540
774
+ #: includes/admin/table-printer.php:628 includes/admin/table-printer.php:634
775
+ msgid "Cancel"
776
  msgstr ""
777
 
778
+ #: includes/admin/table-printer.php:147
779
+ msgid "Compact View"
780
  msgstr ""
781
 
782
+ #: includes/admin/table-printer.php:148
783
+ msgid "Detailed View"
784
  msgstr ""
785
 
786
+ #: includes/admin/table-printer.php:165
787
+ msgid "Source"
788
  msgstr ""
789
 
790
+ #: includes/admin/table-printer.php:171 includes/admin/table-printer.php:197
791
+ msgid "Link Text"
 
792
  msgstr ""
793
 
794
+ #: includes/admin/table-printer.php:191
795
+ msgid "Used in"
796
  msgstr ""
797
 
798
+ #: includes/admin/table-printer.php:245
799
+ msgid "Bulk Actions"
800
  msgstr ""
801
 
802
+ #: includes/admin/table-printer.php:246
803
+ msgid "Recheck"
804
  msgstr ""
805
 
806
+ #: includes/admin/table-printer.php:247
807
+ msgid "Fix redirects"
808
  msgstr ""
809
 
810
+ #: includes/admin/table-printer.php:248
811
+ msgid "Mark as not broken"
 
812
  msgstr ""
813
 
814
+ #: includes/admin/table-printer.php:252
815
+ msgid "Move sources to Trash"
816
+ msgstr ""
 
 
 
817
 
818
+ #: includes/admin/table-printer.php:254
819
+ msgid "Delete sources"
820
  msgstr ""
821
 
822
+ #: includes/admin/table-printer.php:269
823
+ msgid "&laquo;"
824
+ msgstr ""
825
+
826
+ #: includes/admin/table-printer.php:270
827
+ msgid "&raquo;"
828
  msgstr ""
829
 
830
+ #: includes/admin/table-printer.php:278
831
  #, php-format
832
+ msgid "Displaying %s&#8211;%s of <span class=\"current-link-count\">%s</span>"
 
 
833
  msgstr ""
834
 
835
+ #: includes/admin/table-printer.php:407
836
+ msgid "Post published on"
 
837
  msgstr ""
838
 
839
+ #: includes/admin/table-printer.php:412
840
+ msgid "Link last checked"
 
841
  msgstr ""
842
 
843
+ #: includes/admin/table-printer.php:416
844
+ msgid "Never"
 
845
  msgstr ""
846
 
847
+ #: includes/admin/table-printer.php:427
848
+ msgid "Response time"
849
+ msgstr ""
850
+
851
+ #: includes/admin/table-printer.php:429
852
  #, php-format
853
+ msgid "%2.3f seconds"
854
+ msgstr ""
855
+
856
+ #: includes/admin/table-printer.php:432
857
+ msgid "Final URL"
858
+ msgstr ""
859
+
860
+ #: includes/admin/table-printer.php:437
861
+ msgid "Redirect count"
862
  msgstr ""
863
 
864
+ #: includes/admin/table-printer.php:442
865
+ msgid "Instance count"
866
+ msgstr ""
867
+
868
+ #: includes/admin/table-printer.php:451
869
  #, php-format
870
+ msgid "This link has failed %d time."
871
+ msgid_plural "This link has failed %d times."
872
  msgstr[0] ""
873
  msgstr[1] ""
874
 
875
+ #: includes/admin/table-printer.php:459
876
  #, php-format
877
+ msgid "This link has been broken for %s."
878
  msgstr ""
879
 
880
+ #: includes/admin/table-printer.php:470
881
+ msgid "Log"
 
882
  msgstr ""
883
 
884
+ #: includes/admin/table-printer.php:506 includes/admin/table-printer.php:657
885
+ msgid "[An orphaned link! This is a bug.]"
886
  msgstr ""
887
 
888
+ #: includes/admin/table-printer.php:521 includes/admin/table-printer.php:557
889
+ msgid "Show more info about this link"
890
  msgstr ""
891
 
892
+ #: includes/admin/table-printer.php:523 includes/admin/table-printer.php:613
893
+ msgid "Remove this link from all posts"
894
  msgstr ""
895
 
896
+ #: includes/admin/table-printer.php:529 includes/admin/table-printer.php:619
897
+ msgid "Remove this link from the list of broken links and mark it as valid"
 
898
  msgstr ""
899
 
900
+ #: includes/admin/table-printer.php:534 includes/admin/table-printer.php:611
901
+ msgid "Edit link URL"
902
  msgstr ""
903
 
904
+ #: includes/admin/table-printer.php:534 includes/admin/table-printer.php:611
905
+ msgid "Edit URL"
 
906
  msgstr ""
907
 
908
+ #: includes/admin/table-printer.php:540 includes/admin/table-printer.php:628
909
+ msgid "Cancel URL editing"
910
+ msgstr ""
 
 
 
911
 
912
+ #: includes/admin/table-printer.php:575
913
+ msgctxt "checked how long ago"
914
+ msgid "Checked"
915
+ msgstr ""
916
+
917
+ #: includes/admin/table-printer.php:591
918
+ msgid "Broken for"
919
+ msgstr ""
920
+
921
+ #: includes/admin/table-printer.php:635
922
+ msgid "Update URL"
923
+ msgstr ""
924
+
925
+ #: includes/any-post.php:384 modules/containers/blogroll.php:46
926
+ #: modules/containers/comment.php:153 modules/containers/custom_field.php:197
927
+ msgid "Edit"
928
+ msgstr ""
929
+
930
+ #: includes/any-post.php:392 modules/containers/custom_field.php:203
931
+ msgid "Move this item to the Trash"
932
+ msgstr ""
933
+
934
+ #: includes/any-post.php:394 modules/containers/custom_field.php:205
935
+ msgid "Trash"
936
+ msgstr ""
937
+
938
+ #: includes/any-post.php:399 modules/containers/custom_field.php:210
939
+ msgid "Delete this item permanently"
940
+ msgstr ""
941
+
942
+ #: includes/any-post.php:401 modules/containers/blogroll.php:47
943
+ #: modules/containers/custom_field.php:212
944
+ msgid "Delete"
945
+ msgstr ""
946
 
947
+ #: includes/any-post.php:414
948
  #, php-format
949
+ msgid "Preview &#8220;%s&#8221;"
950
  msgstr ""
951
 
952
+ #: includes/any-post.php:415
953
+ msgid "Preview"
954
+ msgstr ""
955
+
956
+ #: includes/any-post.php:422
957
  #, php-format
958
+ msgid "View &#8220;%s&#8221;"
959
  msgstr ""
960
 
961
+ #: includes/any-post.php:423 modules/containers/comment.php:166
962
+ #: modules/containers/custom_field.php:217
963
+ msgid "View"
964
  msgstr ""
965
 
966
+ #: includes/any-post.php:442 modules/containers/custom_field.php:197
967
  msgid "Edit this item"
968
  msgstr ""
969
 
970
+ #: includes/any-post.php:506 modules/containers/blogroll.php:83
971
+ #: modules/containers/comment.php:43
972
+ msgid "Nothing to update"
973
  msgstr ""
974
 
975
+ #: includes/any-post.php:516
976
+ #, php-format
977
+ msgid "Updating post %d failed"
978
  msgstr ""
979
 
980
+ #: includes/any-post.php:551 modules/containers/custom_field.php:284
981
+ #, php-format
982
+ msgid "Failed to delete post \"%s\" (%d)"
983
  msgstr ""
984
 
985
+ #: includes/any-post.php:570 modules/containers/custom_field.php:303
986
  #, php-format
987
  msgid ""
988
+ "Can't move post \"%s\" (%d) to the trash because the trash feature is "
989
+ "disabled"
990
  msgstr ""
991
 
992
+ #: includes/any-post.php:590 modules/containers/custom_field.php:322
993
  #, php-format
994
+ msgid "Failed to move post \"%s\" (%d) to the trash"
995
  msgstr ""
996
 
997
+ #: includes/any-post.php:698
998
  #, php-format
999
+ msgid "%d post deleted."
1000
+ msgid_plural "%d posts deleted."
1001
+ msgstr[0] ""
1002
+ msgstr[1] ""
1003
 
1004
+ #: includes/any-post.php:700
1005
  #, php-format
1006
+ msgid "%d page deleted."
1007
+ msgid_plural "%d pages deleted."
1008
  msgstr[0] ""
1009
  msgstr[1] ""
1010
 
1011
+ #: includes/any-post.php:702
1012
  #, php-format
1013
+ msgid "%d \"%s\" deleted."
1014
+ msgid_plural "%d \"%s\" deleted."
1015
  msgstr[0] ""
1016
  msgstr[1] ""
1017
 
1018
+ #: includes/any-post.php:721
1019
  #, php-format
1020
+ msgid "%d post moved to the Trash."
1021
+ msgid_plural "%d posts moved to the Trash."
1022
+ msgstr[0] ""
1023
+ msgstr[1] ""
1024
+
1025
+ #: includes/any-post.php:723
1026
+ #, php-format
1027
+ msgid "%d page moved to the Trash."
1028
+ msgid_plural "%d pages moved to the Trash."
1029
+ msgstr[0] ""
1030
+ msgstr[1] ""
1031
+
1032
+ #: includes/any-post.php:725
1033
+ #, php-format
1034
+ msgid "%d \"%s\" moved to the Trash."
1035
+ msgid_plural "%d \"%s\" moved to the Trash."
1036
+ msgstr[0] ""
1037
+ msgstr[1] ""
1038
+
1039
+ #: includes/containers.php:122
1040
+ #, php-format
1041
+ msgid "%d '%s' has been deleted"
1042
+ msgid_plural "%d '%s' have been deleted"
1043
+ msgstr[0] ""
1044
+ msgstr[1] ""
1045
+
1046
+ #: includes/containers.php:876 includes/containers.php:894
1047
+ #, php-format
1048
+ msgid "Container type '%s' not recognized"
1049
  msgstr ""
1050
 
1051
+ #: includes/extra-strings.php:2
1052
+ msgctxt "module name"
1053
+ msgid "Basic HTTP"
1054
  msgstr ""
1055
 
1056
+ #: includes/extra-strings.php:3
1057
+ msgctxt "module name"
1058
+ msgid "Blogroll items"
1059
+ msgstr ""
1060
+
1061
+ #: includes/extra-strings.php:4
1062
+ msgctxt "module name"
1063
+ msgid "Comments"
1064
+ msgstr ""
1065
+
1066
+ #: includes/extra-strings.php:5
1067
+ msgctxt "module name"
1068
+ msgid "Custom fields"
1069
+ msgstr ""
1070
+
1071
+ #: includes/extra-strings.php:6
1072
+ msgctxt "module name"
1073
+ msgid "Embedded DailyMotion videos"
1074
+ msgstr ""
1075
+
1076
+ #: includes/extra-strings.php:7
1077
+ msgctxt "module name"
1078
+ msgid "Embedded Vimeo videos"
1079
+ msgstr ""
1080
+
1081
+ #: includes/extra-strings.php:8
1082
+ msgctxt "module name"
1083
+ msgid "Embedded YouTube videos"
1084
+ msgstr ""
1085
+
1086
+ #: includes/extra-strings.php:9
1087
+ msgctxt "module name"
1088
+ msgid "HTML images"
1089
+ msgstr ""
1090
+
1091
+ #: includes/extra-strings.php:10
1092
+ msgctxt "module name"
1093
+ msgid "HTML links"
1094
+ msgstr ""
1095
+
1096
+ #: includes/extra-strings.php:11
1097
+ msgctxt "module name"
1098
+ msgid "MediaFire API"
1099
+ msgstr ""
1100
+
1101
+ #: includes/extra-strings.php:12
1102
+ msgctxt "module name"
1103
+ msgid "MegaUpload API"
1104
  msgstr ""
1105
 
1106
+ #: includes/extra-strings.php:13
1107
+ msgctxt "module name"
1108
+ msgid "Plaintext URLs"
1109
+ msgstr ""
1110
+
1111
+ #: includes/extra-strings.php:14
1112
+ msgctxt "module name"
1113
+ msgid "RapidShare API"
1114
+ msgstr ""
1115
+
1116
+ #: includes/extra-strings.php:15
1117
+ msgctxt "module name"
1118
+ msgid "YouTube API"
1119
+ msgstr ""
1120
+
1121
+ #: includes/extra-strings.php:16
1122
+ msgctxt "module name"
1123
+ msgid "Posts"
1124
+ msgstr ""
1125
+
1126
+ #: includes/extra-strings.php:17
1127
+ msgctxt "module name"
1128
+ msgid "Pages"
1129
+ msgstr ""
1130
+
1131
+ #: includes/instances.php:102 includes/instances.php:158
1132
  #, php-format
1133
  msgid "Container %s[%d] not found"
1134
  msgstr ""
1135
 
1136
+ #: includes/instances.php:111 includes/instances.php:167
1137
  #, php-format
1138
  msgid "Parser '%s' not found."
1139
  msgstr ""
1140
 
1141
+ #: includes/link-query.php:25
1142
+ msgid "Broken"
1143
+ msgstr ""
1144
+
1145
+ #: includes/link-query.php:27
1146
+ msgid "No broken links found"
1147
+ msgstr ""
1148
+
1149
+ #: includes/link-query.php:34
1150
+ msgid "Redirects"
1151
+ msgstr ""
1152
+
1153
+ #: includes/link-query.php:35
1154
+ msgid "Redirected Links"
1155
+ msgstr ""
1156
+
1157
+ #: includes/link-query.php:36
1158
+ msgid "No redirects found"
1159
+ msgstr ""
1160
+
1161
+ #: includes/link-query.php:44
1162
+ msgid "All"
1163
+ msgstr ""
1164
+
1165
+ #: includes/link-query.php:45
1166
+ msgid "Detected Links"
1167
+ msgstr ""
1168
+
1169
+ #: includes/link-query.php:46
1170
+ msgid "No links found (yet)"
1171
+ msgstr ""
1172
+
1173
+ #: includes/link-query.php:54
1174
+ msgid "Search Results"
1175
+ msgstr ""
1176
+
1177
+ #: includes/link-query.php:55 includes/link-query.php:106
1178
+ msgid "No links found for your query"
1179
+ msgstr ""
1180
+
1181
+ #: includes/links.php:213
1182
  msgid "The plugin script was terminated while trying to check the link."
1183
  msgstr ""
1184
 
1185
+ #: includes/links.php:259
1186
  msgid "The plugin doesn't know how to check this type of link."
1187
  msgstr ""
1188
 
1189
+ #: includes/links.php:347
1190
  msgid "Link is valid."
1191
  msgstr ""
1192
 
1193
+ #: includes/links.php:349
1194
  msgid "Link is broken."
1195
  msgstr ""
1196
 
1197
+ #: includes/links.php:562 includes/links.php:664 includes/links.php:699
1198
  msgid "Link is not valid"
1199
  msgstr ""
1200
 
1201
+ #: includes/links.php:579
1202
  msgid ""
1203
  "This link can not be edited because it is not used anywhere on this site."
1204
  msgstr ""
1205
 
1206
+ #: includes/links.php:605
1207
  msgid "Failed to create a DB entry for the new URL."
1208
  msgstr ""
1209
 
1210
+ #: includes/links.php:677
1211
  msgid "This link is not a redirect"
1212
  msgstr ""
1213
 
1214
+ #: includes/links.php:726 includes/links.php:763
1215
  msgid "Couldn't delete the link's database record"
1216
  msgstr ""
1217
 
1218
+ #: includes/links.php:837
1219
+ msgctxt "link status"
1220
+ msgid "Unknown"
1221
  msgstr ""
1222
 
1223
+ #: includes/links.php:851 modules/checkers/http.php:255
1224
+ msgid "Unknown Error"
1225
  msgstr ""
1226
 
1227
+ #: includes/links.php:875
1228
+ msgid "Not checked"
1229
  msgstr ""
1230
 
1231
+ #: includes/links.php:878
1232
+ msgid "False positive"
1233
  msgstr ""
1234
 
1235
+ #: includes/links.php:881
1236
+ msgctxt "link status"
1237
+ msgid "OK"
1238
  msgstr ""
1239
 
1240
+ #: includes/parsers.php:106
1241
+ #, php-format
1242
+ msgid "Editing is not implemented in the '%s' parser"
1243
  msgstr ""
1244
 
1245
+ #: includes/parsers.php:121
1246
+ #, php-format
1247
+ msgid "Unlinking is not implemented in the '%s' parser"
1248
  msgstr ""
1249
 
1250
+ #: includes/utility-class.php:291
1251
+ #, php-format
1252
+ msgid "%d second"
1253
+ msgid_plural "%d seconds"
1254
+ msgstr[0] ""
1255
+ msgstr[1] ""
1256
+
1257
+ #: includes/utility-class.php:292
1258
+ #, php-format
1259
+ msgid "%d second ago"
1260
+ msgid_plural "%d seconds ago"
1261
+ msgstr[0] ""
1262
+ msgstr[1] ""
1263
+
1264
+ #: includes/utility-class.php:295
1265
+ #, php-format
1266
+ msgid "%d minute"
1267
+ msgid_plural "%d minutes"
1268
+ msgstr[0] ""
1269
+ msgstr[1] ""
1270
+
1271
+ #: includes/utility-class.php:296
1272
+ #, php-format
1273
+ msgid "%d minute ago"
1274
+ msgid_plural "%d minutes ago"
1275
+ msgstr[0] ""
1276
+ msgstr[1] ""
1277
+
1278
+ #: includes/utility-class.php:299
1279
+ #, php-format
1280
+ msgid "%d hour"
1281
+ msgid_plural "%d hours"
1282
+ msgstr[0] ""
1283
+ msgstr[1] ""
1284
+
1285
+ #: includes/utility-class.php:300
1286
+ #, php-format
1287
+ msgid "%d hour ago"
1288
+ msgid_plural "%d hours ago"
1289
+ msgstr[0] ""
1290
+ msgstr[1] ""
1291
+
1292
+ #: includes/utility-class.php:303
1293
+ #, php-format
1294
+ msgid "%d day"
1295
+ msgid_plural "%d days"
1296
+ msgstr[0] ""
1297
+ msgstr[1] ""
1298
+
1299
+ #: includes/utility-class.php:304
1300
+ #, php-format
1301
+ msgid "%d day ago"
1302
+ msgid_plural "%d days ago"
1303
+ msgstr[0] ""
1304
+ msgstr[1] ""
1305
+
1306
+ #: includes/utility-class.php:307
1307
+ #, php-format
1308
+ msgid "%d month"
1309
+ msgid_plural "%d months"
1310
+ msgstr[0] ""
1311
+ msgstr[1] ""
1312
+
1313
+ #: includes/utility-class.php:308
1314
+ #, php-format
1315
+ msgid "%d month ago"
1316
+ msgid_plural "%d months ago"
1317
+ msgstr[0] ""
1318
+ msgstr[1] ""
1319
+
1320
+ #: modules/checkers/http.php:241
1321
+ msgid "Server Not Found"
1322
  msgstr ""
1323
 
1324
+ #: modules/checkers/http.php:250
1325
+ msgid "Connection Failed"
1326
  msgstr ""
1327
 
1328
+ #: modules/checkers/http.php:284 modules/checkers/http.php:354
1329
+ #, php-format
1330
+ msgid "HTTP code : %d"
1331
+ msgstr ""
1332
+
1333
+ #: modules/checkers/http.php:286 modules/checkers/http.php:356
1334
+ msgid "(No response)"
1335
+ msgstr ""
1336
+
1337
+ #: modules/checkers/http.php:292
1338
+ msgid "Most likely the connection timed out or the domain doesn't exist."
1339
+ msgstr ""
1340
+
1341
+ #: modules/checkers/http.php:363
1342
+ msgid "Request timed out."
1343
+ msgstr ""
1344
+
1345
+ #: modules/checkers/http.php:381
1346
+ msgid "Using Snoopy"
1347
+ msgstr ""
1348
+
1349
+ #: modules/containers/blogroll.php:21
1350
+ msgid "Bookmark"
1351
  msgstr ""
1352
 
1353
+ #: modules/containers/blogroll.php:27 modules/containers/blogroll.php:46
1354
+ msgid "Edit this bookmark"
1355
+ msgstr ""
1356
+
1357
+ #: modules/containers/blogroll.php:47
1358
  #, php-format
1359
+ msgid ""
1360
+ "You are about to delete this link '%s'\n"
1361
+ " 'Cancel' to stop, 'OK' to delete."
1362
  msgstr ""
1363
 
1364
+ #: modules/containers/blogroll.php:97
1365
  #, php-format
1366
+ msgid "Updating bookmark %d failed"
1367
+ msgstr ""
1368
+
1369
+ #: modules/containers/blogroll.php:128
1370
+ #, php-format
1371
+ msgid "Failed to delete blogroll link \"%s\" (%d)"
1372
+ msgstr ""
1373
+
1374
+ #: modules/containers/blogroll.php:299
1375
+ #, php-format
1376
+ msgid "%d blogroll link deleted."
1377
+ msgid_plural "%d blogroll links deleted."
1378
+ msgstr[0] ""
1379
+ msgstr[1] ""
1380
+
1381
+ #: modules/containers/comment.php:53
1382
+ #, php-format
1383
+ msgid "Updating comment %d failed"
1384
+ msgstr ""
1385
+
1386
+ #: modules/containers/comment.php:74
1387
+ #, php-format
1388
+ msgid "Failed to delete comment %d"
1389
+ msgstr ""
1390
+
1391
+ #: modules/containers/comment.php:95
1392
+ #, php-format
1393
+ msgid "Can't move comment %d to the trash"
1394
+ msgstr ""
1395
+
1396
+ #: modules/containers/comment.php:153 modules/containers/comment.php:195
1397
+ msgid "Edit comment"
1398
+ msgstr ""
1399
+
1400
+ #: modules/containers/comment.php:160
1401
+ msgid "Delete Permanently"
1402
+ msgstr ""
1403
+
1404
+ #: modules/containers/comment.php:162
1405
+ msgid "Move this comment to the trash"
1406
+ msgstr ""
1407
+
1408
+ #: modules/containers/comment.php:162
1409
+ msgctxt "verb"
1410
+ msgid "Trash"
1411
+ msgstr ""
1412
+
1413
+ #: modules/containers/comment.php:166
1414
+ msgid "View comment"
1415
+ msgstr ""
1416
+
1417
+ #: modules/containers/comment.php:183
1418
+ msgid "Comment"
1419
+ msgstr ""
1420
+
1421
+ #: modules/containers/comment.php:360
1422
+ #, php-format
1423
+ msgid "%d comment has been deleted."
1424
+ msgid_plural "%d comments have been deleted."
1425
+ msgstr[0] ""
1426
+ msgstr[1] ""
1427
+
1428
+ #: modules/containers/comment.php:379
1429
+ #, php-format
1430
+ msgid "%d comment moved to the Trash."
1431
+ msgid_plural "%d comments moved to the Trash."
1432
+ msgstr[0] ""
1433
+ msgstr[1] ""
1434
+
1435
+ #: modules/containers/custom_field.php:84
1436
+ #, php-format
1437
+ msgid "Failed to update the meta field '%s' on %s [%d]"
1438
+ msgstr ""
1439
+
1440
+ #: modules/containers/custom_field.php:110
1441
+ #, php-format
1442
+ msgid "Failed to delete the meta field '%s' on %s [%d]"
1443
+ msgstr ""
1444
+
1445
+ #: modules/containers/custom_field.php:187
1446
+ msgid "Edit this post"
1447
+ msgstr ""
1448
+
1449
+ #: modules/containers/custom_field.php:217
1450
+ #, php-format
1451
+ msgid "View \"%s\""
1452
+ msgstr ""
1453
+
1454
+ #: modules/containers/dummy.php:34 modules/containers/dummy.php:45
1455
+ #, php-format
1456
+ msgid "I don't know how to edit a '%s' [%d]."
1457
+ msgstr ""
1458
+
1459
+ #: modules/parsers/image.php:156
1460
+ msgid "Image"
1461
+ msgstr ""
1462
+
1463
+ #: modules/parsers/metadata.php:117
1464
+ msgid "Custom field"
1465
  msgstr ""
1466
 
1467
  #. Plugin URI of the plugin/theme
{includes → modules}/checkers/http.php RENAMED
@@ -1,14 +1,75 @@
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);
@@ -19,7 +80,7 @@ class blcHttpChecker extends blcChecker{
19
  '/&amp;/', //convert improper HTML entities
20
  '/([\?&]sid=\w+)$/i' //remove another flavour of session ID
21
  ),
22
- array('','','&','',''),
23
  $url
24
  );
25
  $url = trim($url);
@@ -57,7 +118,7 @@ class blcHttpChecker extends blcChecker{
57
  function urlencodefix($url){
58
  //TODO: Remove/fix this. Probably not a good idea to "fix" invalid URLs like that.
59
  return preg_replace_callback(
60
- '|[^a-z0-9\+\-\/\\#:.,;=?!&%@()$\|*~]|i',
61
  create_function('$str','return rawurlencode($str[0]);'),
62
  $url
63
  );
@@ -65,8 +126,7 @@ class blcHttpChecker extends blcChecker{
65
 
66
  }
67
 
68
- //TODO: Rewrite sub-classes as transports, not stand-alone checkers
69
- class blcCurlHttp extends blcHttpChecker {
70
 
71
  var $last_headers = '';
72
 
@@ -105,6 +165,7 @@ class blcCurlHttp extends blcHttpChecker {
105
 
106
  //Set the timeout
107
  curl_setopt($ch, CURLOPT_TIMEOUT, $conf->options['timeout']);
 
108
 
109
  //Set the proxy configuration. The user can provide this in wp-config.php
110
  if (defined('WP_PROXY_HOST')) {
@@ -129,8 +190,8 @@ class blcCurlHttp extends blcHttpChecker {
129
 
130
  $parts = @parse_url($url);
131
  if( $parts['scheme'] == 'https' ){
132
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); //Required to make HTTPS URLs work.
133
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); //Likewise.
134
  $nobody = false; //Can't use HEAD with HTTPS.
135
  }
136
 
@@ -152,11 +213,9 @@ class blcCurlHttp extends blcHttpChecker {
152
  $measured_request_duration = microtime_float() - $start_time;
153
 
154
  $info = curl_getinfo($ch);
155
- curl_close($ch);
156
 
157
  //Store the results
158
  $result['http_code'] = intval( $info['http_code'] );
159
- $result['timeout'] = ($result['http_code'] == 0); //If the code is 0 then it's probably a timeout
160
  $result['final_url'] = $info['url'];
161
  $result['request_duration'] = $info['total_time'];
162
  $result['redirect_count'] = $info['redirect_count'];
@@ -168,7 +227,46 @@ class blcCurlHttp extends blcHttpChecker {
168
  }
169
 
170
  //Determine if the link counts as "broken"
171
- $result['broken'] = $this->is_error_code($result['http_code']) || $result['timeout'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
 
173
  if ( $nobody && $result['broken'] ){
174
  //The site in question might be expecting GET instead of HEAD, so lets retry the request
@@ -189,7 +287,6 @@ class blcCurlHttp extends blcHttpChecker {
189
  }
190
 
191
  //Build the log from HTTP code and headers.
192
- //TODO: Put some kind of a color-coded error explanation at the top of the log, not a cryptic HTTP code.
193
  $log .= '=== ';
194
  if ( $result['http_code'] ){
195
  $log .= sprintf( __('HTTP code : %d', 'broken-link-checker'), $result['http_code']);
@@ -224,13 +321,15 @@ class blcCurlHttp extends blcHttpChecker {
224
 
225
  }
226
 
227
- class blcSnoopyHttp extends blcHttpChecker {
228
 
229
  function check($url){
230
- $url = $this->clean_url($url); //Note : Snoopy doesn't work too well with HTTPS URLs.
 
231
 
232
  $result = array(
233
  'broken' => false,
 
234
  );
235
  $log = '';
236
 
@@ -244,8 +343,9 @@ class blcSnoopyHttp extends blcHttpChecker {
244
  $snoopy = new Snoopy;
245
  $snoopy->read_timeout = $timeout; //read timeout in seconds
246
  $snoopy->agent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"; //masquerade as IE 7
 
247
  $snoopy->maxlength = 1024*5; //load up to 5 kilobytes
248
- $snoopy->fetch($url);
249
 
250
  $result['request_duration'] = microtime_float() - $start_time;
251
 
@@ -303,23 +403,4 @@ class blcSnoopyHttp extends blcHttpChecker {
303
 
304
  }
305
 
306
- if ( function_exists('curl_init') ) {
307
- blc_register_checker('blcCurlHttp');
308
- } else {
309
- //Try to load Snoopy.
310
- if ( !class_exists('Snoopy') ){
311
- $snoopy_file = ABSPATH. WPINC . '/class-snoopy.php';
312
- if (file_exists($snoopy_file) ){
313
- include $snoopy_file;
314
- }
315
- }
316
-
317
- //If Snoopy is available, it will be used in place of CURL.
318
- if ( class_exists('Snoopy') ){
319
- blc_register_checker('blcSnoopyHttp');
320
- }
321
- }
322
-
323
-
324
-
325
  ?>
1
  <?php
2
 
3
+ /*
4
+ Plugin Name: Basic HTTP
5
+ Description: Check all links that have the HTTP/HTTPS protocol.
6
+ Version: 1.0
7
+ Author: Janis Elsts
8
+
9
+ ModuleID: http
10
+ ModuleCategory: checker
11
+ ModuleContext: on-demand
12
+ ModuleLazyInit: true
13
+ ModuleClassName: blcHttpChecker
14
+ ModulePriority: -1
15
+ */
16
+
17
+ //TODO: Rewrite sub-classes as transports, not stand-alone checkers
18
+ class blcHttpChecker extends blcChecker {
19
+ var $implementation;
20
+
21
+ function init(){
22
+ parent::init();
23
+
24
+ if ( function_exists('curl_init') ) {
25
+ $this->implementation = new blcCurlHttp(
26
+ $this->module_id,
27
+ $this->cached_header,
28
+ $this->plugin_conf,
29
+ $this->module_manager
30
+ );
31
+ } else {
32
+ //Try to load Snoopy.
33
+ if ( !class_exists('Snoopy') ){
34
+ $snoopy_file = ABSPATH. WPINC . '/class-snoopy.php';
35
+ if (file_exists($snoopy_file) ){
36
+ include $snoopy_file;
37
+ }
38
+ }
39
+
40
+ //If Snoopy is available, it will be used in place of CURL.
41
+ if ( class_exists('Snoopy') ){
42
+ $this->implementation = new blcSnoopyHttp(
43
+ $this->module_id,
44
+ $this->cached_header,
45
+ $this->plugin_conf,
46
+ $this->module_manager
47
+ );
48
+ }
49
+ }
50
+ }
51
+
52
+ function can_check($url, $parsed){
53
+ if ( isset($this->implementation) ){
54
+ return $this->implementation->can_check($url, $parsed);
55
+ } else {
56
+ return false;
57
+ }
58
+ }
59
+
60
+ function check($url, $use_get = false){
61
+ return $this->implementation->check($url, $use_get);
62
+ }
63
+ }
64
+
65
+
66
  /**
67
  * Base class for checkers that deal with HTTP(S) URLs.
68
  *
69
  * @package Broken Link Checker
70
  * @access public
71
  */
72
+ class blcHttpCheckerBase extends blcChecker {
 
 
73
 
74
  function clean_url($url){
75
  $url = html_entity_decode($url);
80
  '/&amp;/', //convert improper HTML entities
81
  '/([\?&]sid=\w+)$/i' //remove another flavour of session ID
82
  ),
83
+ array('','','&',''),
84
  $url
85
  );
86
  $url = trim($url);
118
  function urlencodefix($url){
119
  //TODO: Remove/fix this. Probably not a good idea to "fix" invalid URLs like that.
120
  return preg_replace_callback(
121
+ '|[^a-z0-9\+\-\/\\#:.,;=?!&%@()$\|*~_]|i',
122
  create_function('$str','return rawurlencode($str[0]);'),
123
  $url
124
  );
126
 
127
  }
128
 
129
+ class blcCurlHttp extends blcHttpCheckerBase {
 
130
 
131
  var $last_headers = '';
132
 
165
 
166
  //Set the timeout
167
  curl_setopt($ch, CURLOPT_TIMEOUT, $conf->options['timeout']);
168
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $conf->options['timeout']);
169
 
170
  //Set the proxy configuration. The user can provide this in wp-config.php
171
  if (defined('WP_PROXY_HOST')) {
190
 
191
  $parts = @parse_url($url);
192
  if( $parts['scheme'] == 'https' ){
193
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //Required to make HTTPS URLs work.
194
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
195
  $nobody = false; //Can't use HEAD with HTTPS.
196
  }
197
 
213
  $measured_request_duration = microtime_float() - $start_time;
214
 
215
  $info = curl_getinfo($ch);
 
216
 
217
  //Store the results
218
  $result['http_code'] = intval( $info['http_code'] );
 
219
  $result['final_url'] = $info['url'];
220
  $result['request_duration'] = $info['total_time'];
221
  $result['redirect_count'] = $info['redirect_count'];
227
  }
228
 
229
  //Determine if the link counts as "broken"
230
+ if ( $result['http_code'] == 0 ){
231
+ $result['broken'] = true;
232
+
233
+ $error_code = curl_errno($ch);
234
+ $log .= sprintf( "%s [Error #%d]\n", curl_error($ch), $error_code );
235
+
236
+ //We only handle a couple of CURL error codes; most are highly esoteric.
237
+ //libcurl "CURLE_" constants can't be used here because some of them have
238
+ //different names or values in PHP.
239
+ switch( $error_code ) {
240
+ case 6: //CURLE_COULDNT_RESOLVE_HOST
241
+ $result['status_code'] = BLC_LINK_STATUS_WARNING;
242
+ $result['status_text'] = __('Server Not Found', 'broken-link-checker');
243
+ break;
244
+
245
+ case 28: //CURLE_OPERATION_TIMEDOUT
246
+ $result['timeout'] = true;
247
+ break;
248
+
249
+ case 7: //CURLE_COULDNT_CONNECT
250
+ //More often than not, this error code indicates that the connection attempt
251
+ //timed out. This heuristic tries to distinguish between connections that fail
252
+ //due to timeouts and those that fail due to other causes.
253
+ if ( $result['request_duration'] >= 0.9*$conf->options['timeout'] ){
254
+ $result['timeout'] = true;
255
+ } else {
256
+ $result['status_code'] = BLC_LINK_STATUS_WARNING;
257
+ $result['status_text'] = __('Connection Failed', 'broken-link-checker');
258
+ }
259
+ break;
260
+
261
+ default:
262
+ $result['status_code'] = BLC_LINK_STATUS_WARNING;
263
+ $result['status_text'] = __('Unknown Error', 'broken-link-checker');
264
+ }
265
+
266
+ } else {
267
+ $result['broken'] = $this->is_error_code($result['http_code']);
268
+ }
269
+ curl_close($ch);
270
 
271
  if ( $nobody && $result['broken'] ){
272
  //The site in question might be expecting GET instead of HEAD, so lets retry the request
287
  }
288
 
289
  //Build the log from HTTP code and headers.
 
290
  $log .= '=== ';
291
  if ( $result['http_code'] ){
292
  $log .= sprintf( __('HTTP code : %d', 'broken-link-checker'), $result['http_code']);
321
 
322
  }
323
 
324
+ class blcSnoopyHttp extends blcHttpCheckerBase {
325
 
326
  function check($url){
327
+ $url = $this->clean_url($url);
328
+ //Note : Snoopy doesn't work too well with HTTPS URLs.
329
 
330
  $result = array(
331
  'broken' => false,
332
+ 'timeout' => false,
333
  );
334
  $log = '';
335
 
343
  $snoopy = new Snoopy;
344
  $snoopy->read_timeout = $timeout; //read timeout in seconds
345
  $snoopy->agent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"; //masquerade as IE 7
346
+ $snoopy->referer = get_option('home'); //valid referer helps circumvent some hotlink protection schemes
347
  $snoopy->maxlength = 1024*5; //load up to 5 kilobytes
348
+ $snoopy->fetch( $this->urlencodefix($url) );
349
 
350
  $result['request_duration'] = microtime_float() - $start_time;
351
 
403
 
404
  }
405
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406
  ?>
{includes → modules}/containers/blogroll.php RENAMED
@@ -1,10 +1,18 @@
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(
@@ -29,7 +37,7 @@ class blcBookmark extends blcContainer{
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
 
@@ -124,7 +132,15 @@ class blcBookmark extends blcContainer{
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.
@@ -150,6 +166,7 @@ class blcBookmark extends blcContainer{
150
 
151
  class blcBookmarkManager extends blcContainerManager{
152
  var $container_class_name = 'blcBookmark';
 
153
 
154
  /**
155
  * Set up hooks that monitor added/modified/deleted bookmarks.
@@ -157,6 +174,8 @@ class blcBookmarkManager extends blcContainerManager{
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'));
@@ -231,7 +250,7 @@ class blcBookmarkManager extends blcContainerManager{
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
 
@@ -253,7 +272,7 @@ class blcBookmarkManager extends blcContainerManager{
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
 
@@ -277,8 +296,8 @@ class blcBookmarkManager extends blcContainerManager{
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
  ),
@@ -287,6 +306,4 @@ class blcBookmarkManager extends blcContainerManager{
287
  }
288
  }
289
 
290
- blc_register_container('blogroll', 'blcBookmarkManager');
291
-
292
  ?>
1
  <?php
2
+ /*
3
+ Plugin Name: Blogroll items
4
+ Description:
5
+ Version: 1.0
6
+ Author: Janis Elsts
7
+
8
+ ModuleID: blogroll
9
+ ModuleCategory: container
10
+ ModuleClassName: blcBookmarkManager
11
+ */
12
 
13
  class blcBookmark extends blcContainer{
14
 
15
+ function ui_get_source($container_field = '', $context = 'display'){
 
 
16
  $bookmark = $this->get_wrapped_object();
17
 
18
  $image = sprintf(
37
 
38
  function ui_get_action_links($container_field){
39
  //Inline action links for bookmarks
40
+ $bookmark = &$this->get_wrapped_object();
41
 
42
  $delete_url = admin_url( wp_nonce_url("link.php?action=delete&link_id={$this->container_id}", 'delete-bookmark_' . $this->container_id) );
43
 
132
 
133
  return new WP_Error( 'delete_failed', $msg );
134
  };
135
+ }
136
+
137
+ function current_user_can_delete(){
138
+ return current_user_can('manage_links');
139
+ }
140
+
141
+ function can_be_trashed(){
142
+ return false;
143
+ }
144
 
145
  /**
146
  * Get the default link text. For bookmarks, this is the bookmark name.
166
 
167
  class blcBookmarkManager extends blcContainerManager{
168
  var $container_class_name = 'blcBookmark';
169
+ var $fields = array('link_url' => 'url_field');
170
 
171
  /**
172
  * Set up hooks that monitor added/modified/deleted bookmarks.
174
  * @return void
175
  */
176
  function init(){
177
+ parent::init();
178
+
179
  add_action('add_link', array(&$this,'hook_add_link'));
180
  add_action('edit_link', array(&$this,'hook_edit_link'));
181
  add_action('delete_link', array(&$this,'hook_delete_link'));
250
  * @return void
251
  */
252
  function hook_add_link( $link_id ){
253
+ $container = & blcContainerHelper::get_container( array($this->container_type, $link_id) );
254
  $container->mark_as_unsynched();
255
  }
256
 
272
  */
273
  function hook_delete_link( $link_id ){
274
  //Get the container object.
275
+ $container = & blcContainerHelper::get_container( array($this->container_type, $link_id) );
276
  //Get the link(s) associated with it.
277
  $links = $container->get_links();
278
 
296
  function ui_bulk_delete_message($n){
297
  return sprintf(
298
  _n(
299
+ "%d blogroll link deleted.",
300
+ "%d blogroll links deleted.",
301
  $n,
302
  'broken-link-checker'
303
  ),
306
  }
307
  }
308
 
 
 
309
  ?>
{includes → modules}/containers/comment.php RENAMED
@@ -1,10 +1,17 @@
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.
@@ -38,7 +45,6 @@ class blcComment extends blcContainer{
38
  }
39
 
40
  $data = (array)$this->wrapped_object;
41
- //FB::info($data, sprintf("Attempting to update comment %d with data", $this->container_id));
42
  if ( wp_update_comment($data) ){
43
  return true;
44
  } else {
@@ -56,17 +62,56 @@ class blcComment extends blcContainer{
56
  * @return bool|WP_error
57
  */
58
  function delete_wrapped_object(){
59
- if ( wp_delete_comment($this->container_id) ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  return true;
61
  } else {
62
  return new WP_Error(
63
- 'delete_failed',
64
  sprintf(
65
- __('Failed to delete comment %d', 'broken-link-checker'),
66
  $this->container_id
67
  )
68
  );
69
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  }
71
 
72
  /**
@@ -112,9 +157,9 @@ class blcComment extends blcContainer{
112
  $delete_url = esc_url( admin_url("comment.php?action=deletecomment&p=$post->ID&c=$comment->comment_ID&$del_nonce") );
113
 
114
  if ( !constant('EMPTY_TRASH_DAYS') ) {
115
- $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>';
116
  } else {
117
- $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>';
118
  }
119
  }
120
 
@@ -123,7 +168,7 @@ class blcComment extends blcContainer{
123
  return $actions;
124
  }
125
 
126
- function ui_get_source($container_field, $context = 'display'){
127
  //Display a comment icon.
128
  if ( $container_field == 'comment_author_url' ){
129
  $image = 'user_comment.png';
@@ -168,7 +213,14 @@ class blcComment extends blcContainer{
168
  class blcCommentManager extends blcContainerManager {
169
  var $container_class_name = 'blcComment';
170
 
 
 
 
 
 
171
  function init(){
 
 
172
  add_action('edit_comment', array(&$this, 'hook_modified_comment'));
173
  add_action('unspammed_comment', array(&$this, 'hook_modified_comment'));
174
  add_action('untrashed_comment', array(&$this, 'hook_modified_comment'));
@@ -180,20 +232,23 @@ class blcCommentManager extends blcContainerManager {
180
  add_action('trashed_comment', array(&$this, 'hook_deleted_comment'));
181
 
182
  add_action('transition_comment_status', array(&$this, 'hook_comment_status'), 10, 3);
 
 
 
183
  }
184
 
185
  function hook_modified_comment($comment_id){
186
  $comment = get_comment($comment_id);
187
 
188
  if ( $comment->comment_approved == '1'){
189
- $container = blc_get_container(array($this->container_type, $comment_id));
190
  $container->mark_as_unsynched();
191
  }
192
  }
193
 
194
  function hook_wp_insert_comment($comment_id, $comment){
195
  if ( $comment->comment_approved == '1'){
196
- $container = blc_get_container(array($this->container_type, $comment_id));
197
  $container->mark_as_unsynched();
198
  }
199
  }
@@ -204,7 +259,7 @@ class blcCommentManager extends blcContainerManager {
204
  }
205
 
206
  foreach($comment_ids as $comment_id){
207
- $container = blc_get_container(array($this->container_type, $comment_id));
208
  $container->delete();
209
  }
210
  //Clean up any dangling links
@@ -212,7 +267,7 @@ class blcCommentManager extends blcContainerManager {
212
  }
213
 
214
  function hook_comment_status($new_status, $old_status, $comment){
215
- $container = blc_get_container(array($this->container_type, $comment->comment_ID));
216
  if ( $new_status == 'approved' ){
217
  $container->mark_as_unsynched();
218
  } else {
@@ -221,6 +276,27 @@ class blcCommentManager extends blcContainerManager {
221
  }
222
  }
223
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  /**
225
  * Create or update synchronization records for all comments.
226
  *
@@ -239,13 +315,15 @@ class blcCommentManager extends blcContainerManager {
239
  {$wpdb->comments}.comment_approved = '1'";
240
  $wpdb->query( $q );
241
  } else {
242
- //Delete synch records corresponding to comments that no longer exist.
 
243
  $q = "DELETE synch.*
244
  FROM
245
  {$wpdb->prefix}blc_synch AS synch LEFT JOIN {$wpdb->comments} AS comments
246
  ON comments.comment_ID = synch.container_id
247
  WHERE
248
- synch.container_type = '{$this->container_type}' AND comments.comment_ID IS NULL";
 
249
  $wpdb->query( $q );
250
 
251
  //Create synch. records for comments that don't have them.
@@ -271,24 +349,16 @@ class blcCommentManager extends blcContainerManager {
271
  * Get the message to display after $n comments have been deleted.
272
  *
273
  * @param int $n Number of deleted comments.
274
- * @return string A delete confirmation message, e.g. "5 comments were moved to trash"
275
  */
276
  function ui_bulk_delete_message($n){
277
  if ( EMPTY_TRASH_DAYS ){
278
- return sprintf(
279
- _n(
280
- "%d comment moved to the trash",
281
- "%d comments moved to the trash",
282
- $n,
283
- 'broken-link-checker'
284
- ),
285
- $n
286
- );
287
  } else {
288
  return sprintf(
289
  _n(
290
- "%d comment has been deleted",
291
- "%d comments have been deleted",
292
  $n,
293
  'broken-link-checker'
294
  ),
@@ -297,6 +367,24 @@ class blcCommentManager extends blcContainerManager {
297
  }
298
  }
299
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  /**
301
  * Instantiate multiple containers of the container type managed by this class.
302
  *
@@ -340,5 +428,4 @@ class blcCommentManager extends blcContainerManager {
340
  }
341
  }
342
 
343
- blc_register_container('comment', 'blcCommentManager');
344
  ?>
1
  <?php
2
 
3
+ /*
4
+ Plugin Name: Comments
5
+ Description:
6
+ Version: 1.0
7
+ Author: Janis Elsts
8
+
9
+ ModuleID: comment
10
+ ModuleCategory: container
11
+ ModuleClassName: blcCommentManager
12
+ */
13
+
14
  class blcComment extends blcContainer{
 
 
 
 
15
 
16
  /**
17
  * Retrieve the comment wrapped by this container.
45
  }
46
 
47
  $data = (array)$this->wrapped_object;
 
48
  if ( wp_update_comment($data) ){
49
  return true;
50
  } else {
62
  * @return bool|WP_error
63
  */
64
  function delete_wrapped_object(){
65
+ if ( EMPTY_TRASH_DAYS ){
66
+ return $this->trash_wrapped_object();
67
+ } else {
68
+ if ( wp_delete_comment($this->container_id, true) ){
69
+ return true;
70
+ } else {
71
+ return new WP_Error(
72
+ 'delete_failed',
73
+ sprintf(
74
+ __('Failed to delete comment %d', 'broken-link-checker'),
75
+ $this->container_id
76
+ )
77
+ );
78
+ };
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Delete the comment corresponding to this container.
84
+ * This will actually move the comment to the trash in newer versions of WP.
85
+ *
86
+ * @return bool|WP_error
87
+ */
88
+ function trash_wrapped_object(){
89
+ if ( wp_trash_comment($this->container_id) ){
90
  return true;
91
  } else {
92
  return new WP_Error(
93
+ 'trash_failed',
94
  sprintf(
95
+ __('Can\'t move comment %d to the trash', 'broken-link-checker'),
96
  $this->container_id
97
  )
98
  );
99
  };
100
+ }
101
+
102
+ /**
103
+ * Check if the current user can delete/trash this comment.
104
+ *
105
+ * @return bool
106
+ */
107
+ function current_user_can_delete(){
108
+ //TODO: Fix for custom post types? WP itself doesn't care, at least in 3.0.
109
+ $comment = &$this->get_wrapped_object();
110
+ return current_user_can('edit_post', $comment->comment_post_ID);
111
+ }
112
+
113
+ function can_be_trashed(){
114
+ return defined('EMPTY_TRASH_DAYS') && EMPTY_TRASH_DAYS;
115
  }
116
 
117
  /**
157
  $delete_url = esc_url( admin_url("comment.php?action=deletecomment&p=$post->ID&c=$comment->comment_ID&$del_nonce") );
158
 
159
  if ( !constant('EMPTY_TRASH_DAYS') ) {
160
+ $actions['delete'] = "<a href='$delete_url' class='delete:the-comment-list:comment-$comment->comment_ID::delete=1 delete vim-d vim-destructive submitdelete'>" . __('Delete Permanently') . '</a>';
161
  } else {
162
+ $actions['trash'] = "<a href='$trash_url' class='delete:the-comment-list:comment-$comment->comment_ID::trash=1 delete vim-d vim-destructive submitdelete' title='" . esc_attr__( 'Move this comment to the trash' ) . "'>" . _x('Trash', 'verb') . '</a>';
163
  }
164
  }
165
 
168
  return $actions;
169
  }
170
 
171
+ function ui_get_source($container_field = '', $context = 'display'){
172
  //Display a comment icon.
173
  if ( $container_field == 'comment_author_url' ){
174
  $image = 'user_comment.png';
213
  class blcCommentManager extends blcContainerManager {
214
  var $container_class_name = 'blcComment';
215
 
216
+ var $fields = array(
217
+ 'comment_author_url' => 'url_field',
218
+ 'comment_content' => 'html',
219
+ );
220
+
221
  function init(){
222
+ parent::init();
223
+
224
  add_action('edit_comment', array(&$this, 'hook_modified_comment'));
225
  add_action('unspammed_comment', array(&$this, 'hook_modified_comment'));
226
  add_action('untrashed_comment', array(&$this, 'hook_modified_comment'));
232
  add_action('trashed_comment', array(&$this, 'hook_deleted_comment'));
233
 
234
  add_action('transition_comment_status', array(&$this, 'hook_comment_status'), 10, 3);
235
+
236
+ add_action('trashed_post_comments', array(&$this, 'hook_trashed_post_comments'), 10, 2);
237
+ add_action('untrash_post_comments', array(&$this, 'hook_untrash_post_comments'));
238
  }
239
 
240
  function hook_modified_comment($comment_id){
241
  $comment = get_comment($comment_id);
242
 
243
  if ( $comment->comment_approved == '1'){
244
+ $container = & blcContainerHelper::get_container(array($this->container_type, $comment_id));
245
  $container->mark_as_unsynched();
246
  }
247
  }
248
 
249
  function hook_wp_insert_comment($comment_id, $comment){
250
  if ( $comment->comment_approved == '1'){
251
+ $container = & blcContainerHelper::get_container(array($this->container_type, $comment_id));
252
  $container->mark_as_unsynched();
253
  }
254
  }
259
  }
260
 
261
  foreach($comment_ids as $comment_id){
262
+ $container = & blcContainerHelper::get_container(array($this->container_type, $comment_id));
263
  $container->delete();
264
  }
265
  //Clean up any dangling links
267
  }
268
 
269
  function hook_comment_status($new_status, $old_status, $comment){
270
+ $container = & blcContainerHelper::get_container(array($this->container_type, $comment->comment_ID));
271
  if ( $new_status == 'approved' ){
272
  $container->mark_as_unsynched();
273
  } else {
276
  }
277
  }
278
 
279
+ function hook_trashed_post_comments($post_id, $statuses){
280
+ $comment_ids = array_keys($statuses);
281
+ $this->hook_deleted_comment($comment_ids);
282
+ }
283
+
284
+ function hook_untrash_post_comments($post_id){
285
+ //Unlike with the 'trashed_post_comments' hook, WP doesn't pass the list of (un)trashed
286
+ //comments to callbacks assigned to the 'untrash_post_comments' and 'untrashed_post_comments'
287
+ //actions. Therefore, we must read it from the appropriate metadata entry.
288
+ $statuses = get_post_meta($post_id, '_wp_trash_meta_comments_status', true);
289
+ if ( empty($statuses) || !is_array($statuses) ) return;
290
+
291
+ $comment_ids = array();
292
+ foreach ( $statuses as $comment_id => $comment_status ){
293
+ if ( $comment_status == '1' ){ //if approved
294
+ $container = & blcContainerHelper::get_container(array($this->container_type, $comment_id));
295
+ $container->mark_as_unsynched();
296
+ }
297
+ }
298
+ }
299
+
300
  /**
301
  * Create or update synchronization records for all comments.
302
  *
315
  {$wpdb->comments}.comment_approved = '1'";
316
  $wpdb->query( $q );
317
  } else {
318
+ //Delete synch records corresponding to comments that no longer exist
319
+ //or have been trashed/spammed/unapproved.
320
  $q = "DELETE synch.*
321
  FROM
322
  {$wpdb->prefix}blc_synch AS synch LEFT JOIN {$wpdb->comments} AS comments
323
  ON comments.comment_ID = synch.container_id
324
  WHERE
325
+ synch.container_type = '{$this->container_type}'
326
+ AND (comments.comment_ID IS NULL OR comments.comment_approved <> '1')";
327
  $wpdb->query( $q );
328
 
329
  //Create synch. records for comments that don't have them.
349
  * Get the message to display after $n comments have been deleted.
350
  *
351
  * @param int $n Number of deleted comments.
352
+ * @return string A delete confirmation message, e.g. "5 comments were deleted"
353
  */
354
  function ui_bulk_delete_message($n){
355
  if ( EMPTY_TRASH_DAYS ){
356
+ return $this->ui_bulk_trash_message($n);
 
 
 
 
 
 
 
 
357
  } else {
358
  return sprintf(
359
  _n(
360
+ "%d comment has been deleted.",
361
+ "%d comments have been deleted.",
362
  $n,
363
  'broken-link-checker'
364
  ),
367
  }
368
  }
369
 
370
+ /**
371
+ * Get the message to display after $n comments have been moved to the trash.
372
+ *
373
+ * @param int $n Number of trashed comments.
374
+ * @return string A delete confirmation message, e.g. "5 comments were moved to trash"
375
+ */
376
+ function ui_bulk_trash_message($n){
377
+ return sprintf(
378
+ _n(
379
+ "%d comment moved to the Trash.",
380
+ "%d comments moved to the Trash.",
381
+ $n,
382
+ 'broken-link-checker'
383
+ ),
384
+ $n
385
+ );
386
+ }
387
+
388
  /**
389
  * Instantiate multiple containers of the container type managed by this class.
390
  *
428
  }
429
  }
430
 
 
431
  ?>
{includes → modules}/containers/custom_field.php RENAMED
@@ -1,5 +1,16 @@
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
 
@@ -31,7 +42,7 @@ class blcPostMeta extends blcContainer {
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
  }
@@ -169,22 +180,7 @@ class blcPostMeta extends blcContainer {
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()),
@@ -192,7 +188,7 @@ class blcPostMeta extends blcContainer {
192
  get_the_title($this->container_id)
193
  );
194
 
195
- return "$post_html &mdash; $field_html";
196
  }
197
 
198
  function ui_get_action_links($container_field){
@@ -200,13 +196,25 @@ class blcPostMeta extends blcContainer {
200
  if ( current_user_can('edit_post', $this->container_id) ) {
201
  $actions['edit'] = '<span class="edit"><a href="' . $this->get_edit_url() . '" title="' . esc_attr(__('Edit this item')) . '">' . __('Edit') . '</a>';
202
 
203
- if ( EMPTY_TRASH_DAYS ) {
204
- $actions['trash'] = "<a class='submitdelete' title='" . esc_attr(__('Move this item 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&amp;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="' . esc_attr(sprintf(__('View "%s"', 'broken-link-checker'), get_the_title($this->container_id))) . '" rel="permalink">' . __('View') . '</a>';
210
 
211
  return $actions;
212
  }
@@ -227,56 +235,24 @@ class blcPostMeta extends blcContainer {
227
  executed by Cron.
228
  */
229
 
230
- if ( !$post = &get_post( $this->container_id ) ){
231
  return '';
232
  }
233
 
234
  $context = 'display';
235
 
236
- if ( function_exists('get_post_type_object') ){
237
- //WP 3.0
238
- if ( 'display' == $context )
239
- $action = '&amp;action=edit';
240
- else
241
- $action = '&action=edit';
242
-
243
- $post_type_object = get_post_type_object( $post->post_type );
244
- if ( !$post_type_object ){
245
- return '';
246
- }
247
-
248
- return apply_filters( 'get_edit_post_link', admin_url( sprintf($post_type_object->_edit_link . $action, $post->ID) ), $post->ID, $context );
249
-
250
- } else {
251
- //WP 2.9.x
252
- if ( 'display' == $context )
253
- $action = 'action=edit&amp;';
254
- else
255
- $action = 'action=edit&';
256
-
257
- switch ( $post->post_type ) :
258
- case 'page' :
259
- $file = 'page';
260
- $var = 'post';
261
- break;
262
- case 'attachment' :
263
- $file = 'media';
264
- $var = 'attachment_id';
265
- break;
266
- case 'revision' :
267
- $file = 'revision';
268
- $var = 'revision';
269
- $action = '';
270
- break;
271
- default :
272
- $file = 'post';
273
- $var = 'post';
274
- break;
275
- endswitch;
276
-
277
- return apply_filters( 'get_edit_post_link', admin_url("$file.php?{$action}$var=$post->ID"), $post->ID, $context );
278
-
279
  }
 
 
280
  }
281
 
282
  /**
@@ -290,18 +266,60 @@ class blcPostMeta extends blcContainer {
290
  }
291
 
292
  /**
293
- * Delete the post corresponding to this container.
 
294
  *
295
  * @return bool|WP_error
296
  */
297
  function delete_wrapped_object(){
298
- if ( wp_delete_post($this->container_id) ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
  return true;
300
  } else {
301
  return new WP_Error(
302
- 'delete_failed',
303
  sprintf(
304
- __('Failed to delete post "%s" (%d)', 'broken-link-checker'),
305
  get_the_title($this->container_id),
306
  $this->container_id
307
  )
@@ -309,6 +327,15 @@ class blcPostMeta extends blcContainer {
309
  };
310
  }
311
 
 
 
 
 
 
 
 
 
 
312
  }
313
 
314
  class blcPostMetaManager extends blcContainerManager {
@@ -316,6 +343,8 @@ class blcPostMetaManager extends blcContainerManager {
316
  var $meta_type = 'post';
317
 
318
  function init(){
 
 
319
  //Intercept 2.9+ style metadata modification actions
320
  add_action( "added_{$this->meta_type}_meta", array(&$this, 'meta_modified'), 10, 4 );
321
  add_action( "updated_{$this->meta_type}_meta", array(&$this, 'meta_modified'), 10, 4 );
@@ -335,27 +364,22 @@ class blcPostMetaManager extends blcContainerManager {
335
  }
336
 
337
 
338
- /**
339
- * Instantiate a link container.
340
- *
341
- * @param array $container An associative array of container data.
342
- * @return blcPostMeta
343
- */
344
- function get_container($container){
345
- $container = parent::get_container($container);
346
-
347
- //Set up the parseable fields
348
  $fields = array();
349
 
350
- $conf = & blc_get_configuration();
351
- if ( is_array($conf->options['custom_fields']) ){
352
- foreach($conf->options['custom_fields'] as $meta_name){
353
  $fields[$meta_name] = 'metadata';
354
  }
355
  }
356
 
357
- $container->fields = $fields;
358
- return $container;
359
  }
360
 
361
  /**
@@ -489,7 +513,7 @@ class blcPostMetaManager extends blcContainerManager {
489
  return;
490
  }
491
 
492
- $container = blc_get_container( array($this->container_type, intval($object_id)) );
493
  $container->mark_as_unsynched();
494
  }
495
 
@@ -501,7 +525,7 @@ class blcPostMetaManager extends blcContainerManager {
501
  */
502
  function post_deleted($post_id){
503
  //Get the associated container object
504
- $container = blc_get_container( array($this->container_type, intval($post_id)) );
505
  //Delete it
506
  $container->delete();
507
  //Clean up any dangling links
@@ -517,29 +541,31 @@ class blcPostMetaManager extends blcContainerManager {
517
  */
518
  function post_untrashed($post_id){
519
  //Get the associated container object
520
- $container = blc_get_container( array($this->container_type, intval($post_id)) );
521
  $container->mark_as_unsynched();
522
  }
523
 
524
  /**
525
  * Get the message to display after $n posts have been deleted.
526
  *
527
- * @see blcPostContainer::ui_bulk_delete_message()
528
  *
529
  * @param int $n Number of deleted posts.
530
  * @return string A delete confirmation message, e.g. "5 posts were moved to the trash"
531
  */
532
  function ui_bulk_delete_message($n){
533
- //This is identical
534
- if ( function_exists('wp_trash_post') && EMPTY_TRASH_DAYS ){
535
- $delete_msg = _n("%d post moved to the trash", "%d posts moved to the trash", $n, 'broken-link-checker');
536
- } else {
537
- $delete_msg = _n("%d post deleted", "%d posts deleted", $n, 'broken-link-checker');
538
- }
539
- return sprintf($delete_msg, $n);
 
 
 
 
540
  }
541
  }
542
 
543
- blc_register_container('custom_field', 'blcPostMetaManager');
544
-
545
  ?>
1
  <?php
2
 
3
+ /*
4
+ Plugin Name: Custom fields
5
+ Description: Container module for post metadata.
6
+ Version: 1.0
7
+ Author: Janis Elsts
8
+
9
+ ModuleID: custom_field
10
+ ModuleCategory: container
11
+ ModuleClassName: blcPostMetaManager
12
+ */
13
+
14
  //Note : If it ever becomes necessary to check metadata on objects other than posts, it will
15
  //be fairly easy to extract a more general metadata container class from blcPostMeta.
16
 
42
  */
43
  function get_wrapped_object($ensure_consistency = false){
44
  if ( is_null($this->wrapped_object) || $ensure_consistency ) {
45
+ $this->wrapped_object = get_metadata($this->meta_type, $this->container_id);
46
  }
47
  return $this->wrapped_object;
48
  }
180
  return $field;
181
  }
182
 
183
+ function ui_get_source($container_field = '', $context = 'display'){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  $post_html = sprintf(
185
  '<a class="row-title" href="%s" title="%s">%s</a>',
186
  esc_url($this->get_edit_url()),
188
  get_the_title($this->container_id)
189
  );
190
 
191
+ return $post_html;
192
  }
193
 
194
  function ui_get_action_links($container_field){
196
  if ( current_user_can('edit_post', $this->container_id) ) {
197
  $actions['edit'] = '<span class="edit"><a href="' . $this->get_edit_url() . '" title="' . esc_attr(__('Edit this item')) . '">' . __('Edit') . '</a>';
198
 
199
+ if ( $this->current_user_can_delete() ){
200
+ if ( $this->can_be_trashed() ) {
201
+ $actions['trash'] = sprintf(
202
+ "<span><a class='submitdelete' title='%s' href='%s'>%s</a>",
203
+ esc_attr(__('Move this item to the Trash')),
204
+ get_delete_post_link($this->container_id, '', false),
205
+ __('Trash')
206
+ );
207
+ } else {
208
+ $actions['delete'] = sprintf(
209
+ "<span><a class='submitdelete' title='%s' href='%s'>%s</a>",
210
+ esc_attr(__('Delete this item permanently')),
211
+ get_delete_post_link($this->container_id, '', true),
212
+ __('Delete')
213
+ );
214
+ }
215
  }
216
  }
217
+ $actions['view'] = '<span class="view"><a href="' . esc_url(get_permalink($this->container_id)) . '" title="' . esc_attr(sprintf(__('View "%s"', 'broken-link-checker'), get_the_title($this->container_id))) . '" rel="permalink">' . __('View') . '</a>';
218
 
219
  return $actions;
220
  }
235
  executed by Cron.
236
  */
237
 
238
+ if ( !($post = &get_post( $this->container_id )) ){
239
  return '';
240
  }
241
 
242
  $context = 'display';
243
 
244
+ //WP 3.0
245
+ if ( 'display' == $context )
246
+ $action = '&amp;action=edit';
247
+ else
248
+ $action = '&action=edit';
249
+
250
+ $post_type_object = get_post_type_object( $post->post_type );
251
+ if ( !$post_type_object ){
252
+ return '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
  }
254
+
255
+ return apply_filters( 'get_edit_post_link', admin_url( sprintf($post_type_object->_edit_link . $action, $post->ID) ), $post->ID, $context );
256
  }
257
 
258
  /**
266
  }
267
 
268
  /**
269
+ * Delete or trash the post corresponding to this container. If trash is enabled,
270
+ * will always move the post to the trash instead of deleting.
271
  *
272
  * @return bool|WP_error
273
  */
274
  function delete_wrapped_object(){
275
+ if ( EMPTY_TRASH_DAYS ){
276
+ return $this->trash_wrapped_object();
277
+ } else {
278
+ if ( wp_delete_post($this->container_id) ){
279
+ return true;
280
+ } else {
281
+ return new WP_Error(
282
+ 'delete_failed',
283
+ sprintf(
284
+ __('Failed to delete post "%s" (%d)', 'broken-link-checker'),
285
+ get_the_title($this->container_id),
286
+ $this->container_id
287
+ )
288
+ );
289
+ };
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Move the post corresponding to this custom field to the Trash.
295
+ *
296
+ * @return bool|WP_Error
297
+ */
298
+ function trash_wrapped_object(){
299
+ if ( !EMPTY_TRASH_DAYS ){
300
+ return new WP_Error(
301
+ 'trash_disabled',
302
+ sprintf(
303
+ __('Can\'t move post "%s" (%d) to the trash because the trash feature is disabled', 'broken-link-checker'),
304
+ get_the_title($this->container_id),
305
+ $this->container_id
306
+ )
307
+ );
308
+ }
309
+
310
+ $post = &get_post($this->container_id);
311
+ if ( $post->post_status == 'trash' ){
312
+ //Prevent conflicts between post and custom field containers trying to trash the same post.
313
+ return true;
314
+ }
315
+
316
+ if ( wp_trash_post($this->container_id) ){
317
  return true;
318
  } else {
319
  return new WP_Error(
320
+ 'trash_failed',
321
  sprintf(
322
+ __('Failed to move post "%s" (%d) to the trash', 'broken-link-checker'),
323
  get_the_title($this->container_id),
324
  $this->container_id
325
  )
327
  };
328
  }
329
 
330
+ function current_user_can_delete(){
331
+ $post = &get_post($this->container_id);
332
+ $post_type_object = get_post_type_object($post->post_type);
333
+ return current_user_can( $post_type_object->cap->delete_post, $this->container_id );
334
+ }
335
+
336
+ function can_be_trashed(){
337
+ return defined('EMPTY_TRASH_DAYS') && EMPTY_TRASH_DAYS;
338
+ }
339
  }
340
 
341
  class blcPostMetaManager extends blcContainerManager {
343
  var $meta_type = 'post';
344
 
345
  function init(){
346
+ parent::init();
347
+
348
  //Intercept 2.9+ style metadata modification actions
349
  add_action( "added_{$this->meta_type}_meta", array(&$this, 'meta_modified'), 10, 4 );
350
  add_action( "updated_{$this->meta_type}_meta", array(&$this, 'meta_modified'), 10, 4 );
364
  }
365
 
366
 
367
+ /**
368
+ * Get a list of parseable fields.
369
+ *
370
+ * @return array
371
+ */
372
+ function get_parseable_fields(){
373
+ //Fields = custom field names as entered by the user.
 
 
 
374
  $fields = array();
375
 
376
+ if ( is_array($this->plugin_conf->options['custom_fields']) ){
377
+ foreach($this->plugin_conf->options['custom_fields'] as $meta_name){
 
378
  $fields[$meta_name] = 'metadata';
379
  }
380
  }
381
 
382
+ return $fields;
 
383
  }
384
 
385
  /**
513
  return;
514
  }
515
 
516
+ $container = & blcContainerHelper::get_container( array($this->container_type, intval($object_id)) );
517
  $container->mark_as_unsynched();
518
  }
519
 
525
  */
526
  function post_deleted($post_id){
527
  //Get the associated container object
528
+ $container = & blcContainerHelper::get_container( array($this->container_type, intval($post_id)) );
529
  //Delete it
530
  $container->delete();
531
  //Clean up any dangling links
541
  */
542
  function post_untrashed($post_id){
543
  //Get the associated container object
544
+ $container = & blcContainerHelper::get_container( array($this->container_type, intval($post_id)) );
545
  $container->mark_as_unsynched();
546
  }
547
 
548
  /**
549
  * Get the message to display after $n posts have been deleted.
550
  *
551
+ * @uses blcAnyPostContainerManager::ui_bulk_delete_message()
552
  *
553
  * @param int $n Number of deleted posts.
554
  * @return string A delete confirmation message, e.g. "5 posts were moved to the trash"
555
  */
556
  function ui_bulk_delete_message($n){
557
+ return blcAnyPostContainerManager::ui_bulk_delete_message($n);
558
+ }
559
+
560
+ /**
561
+ * Get the message to display after $n posts have been trashed.
562
+ *
563
+ * @param int $n Number of deleted posts.
564
+ * @return string A confirmation message, e.g. "5 posts were moved to trash"
565
+ */
566
+ function ui_bulk_trash_message($n){
567
+ return blcAnyPostContainerManager::ui_bulk_trash_message($n);
568
  }
569
  }
570
 
 
 
571
  ?>
{includes → modules}/containers/dummy.php RENAMED
@@ -1,5 +1,18 @@
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
  *
@@ -61,6 +74,4 @@ class blcDummyManager extends blcContainerManager {
61
  }
62
  }
63
 
64
- blc_register_container('dummy', 'blcDummyManager');
65
-
66
  ?>
1
  <?php
2
 
3
+ /*
4
+ Plugin Name: Dummy
5
+ Description:
6
+ Version: 1.0
7
+ Author: Janis Elsts
8
+
9
+ ModuleID: dummy
10
+ ModuleCategory: container
11
+ ModuleClassName: blcDummyManager
12
+ ModuleAlwaysActive: true
13
+ ModuleHidden: true
14
+ */
15
+
16
  /**
17
  * A "dummy" container class that can be used as a fallback when the real container class can't be found.
18
  *
74
  }
75
  }
76
 
 
 
77
  ?>
modules/extras/dailymotion-embed.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ ModuleID: dailymotion-embed
4
+ ModuleCategory: parser
5
+ ModuleContext: on-demand
6
+ ModuleLazyInit: true
7
+ ModuleClassName: blcDailyMotionEmbed
8
+ ModulePriority: 0
9
+ ModuleCheckerUrlPattern:
10
+ ModuleHidden: false
11
+ ModuleAlwaysActive: false
12
+ ModuleRequiresPro: true
13
+ Version: 1.0
14
+ Description: Parse embedded videos from DailyMotion
15
+ Plugin Name: Embedded DailyMotion videos
16
+ */
17
+ ?>
modules/extras/mediafire.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ ModuleID: mediafire-checker
4
+ ModuleCategory: checker
5
+ ModuleContext: on-demand
6
+ ModuleLazyInit: true
7
+ ModuleClassName: blcMediaFireChecker
8
+ ModulePriority: 100
9
+ ModuleCheckerUrlPattern: @^http://(?:www\.)?mediafire\.com/(?:download\.php)?\?([0-9a-zA-Z]{11})(?:$|[^0-9a-zA-Z])@
10
+ ModuleHidden: false
11
+ ModuleAlwaysActive: false
12
+ ModuleRequiresPro: true
13
+ Version: 1.0
14
+ Description: Check links to files hosted on MediaFire.
15
+ Plugin Name: MediaFire API
16
+ */
17
+ ?>
modules/extras/megaupload.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ ModuleID: megaupload-checker
4
+ ModuleCategory: checker
5
+ ModuleContext: on-demand
6
+ ModuleLazyInit: true
7
+ ModuleClassName: blcMegaUploadChecker
8
+ ModulePriority: 100
9
+ ModuleCheckerUrlPattern: @^http://[\w\.]*?megaupload\.com/.*?(?:\?|&)d=([0-9A-Za-z]+)@
10
+ ModuleHidden: false
11
+ ModuleAlwaysActive: false
12
+ ModuleRequiresPro: true
13
+ Version: 1.0
14
+ Description: Check links to MegaUpload files.
15
+ Plugin Name: MegaUpload API
16
+ */
17
+ ?>
modules/extras/plaintext-url.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ ModuleID: plaintext-url
4
+ ModuleCategory: parser
5
+ ModuleContext: on-demand
6
+ ModuleLazyInit: true
7
+ ModuleClassName: blcPlaintextURL
8
+ ModulePriority: 800
9
+ ModuleCheckerUrlPattern:
10
+ ModuleHidden: false
11
+ ModuleAlwaysActive: false
12
+ ModuleRequiresPro: true
13
+ Version: 1.0
14
+ Description: Parse plaintext URLs as links
15
+ Plugin Name: Plaintext URLs
16
+ */
17
+ ?>
modules/extras/rapidshare.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ ModuleID: rapidshare-checker
4
+ ModuleCategory: checker
5
+ ModuleContext: on-demand
6
+ ModuleLazyInit: true
7
+ ModuleClassName: blcRapidShareChecker
8
+ ModulePriority: 100
9
+ ModuleCheckerUrlPattern: @^https?://(?:[\w\d]+\.)*rapidshare\.\w+/files/(\d+)/([^&?#/]+?)(?:$|[&?#/])@i
10
+ ModuleHidden: false
11
+ ModuleAlwaysActive: false
12
+ ModuleRequiresPro: true
13
+ Version: 1.0
14
+ Description: Check links to RapidShare files using the RapidShare API.
15
+ Plugin Name: RapidShare API
16
+ */
17
+ ?>
modules/extras/vimeo-embed.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ ModuleID: vimeo-embed
4
+ ModuleCategory: parser
5
+ ModuleContext: on-demand
6
+ ModuleLazyInit: true
7
+ ModuleClassName: blcVimeoEmbed
8
+ ModulePriority: 0
9
+ ModuleCheckerUrlPattern:
10
+ ModuleHidden: false
11
+ ModuleAlwaysActive: false
12
+ ModuleRequiresPro: true
13
+ Version: 1.0
14
+ Description: Parse embedded videos from Vimeo
15
+ Plugin Name: Embedded Vimeo videos
16
+ */
17
+ ?>
modules/extras/youtube-embed.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ ModuleID: youtube-embed
4
+ ModuleCategory: parser
5
+ ModuleContext: on-demand
6
+ ModuleLazyInit: true
7
+ ModuleClassName: blcYouTubeEmbed
8
+ ModulePriority: 0
9
+ ModuleCheckerUrlPattern:
10
+ ModuleHidden: false
11
+ ModuleAlwaysActive: false
12
+ ModuleRequiresPro: true
13
+ Version: 1.0
14
+ Description: Parse embedded videos from YouTube
15
+ Plugin Name: Embedded YouTube videos
16
+ */
17
+ ?>
modules/extras/youtube.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ ModuleID: youtube-checker
4
+ ModuleCategory: checker
5
+ ModuleContext: on-demand
6
+ ModuleLazyInit: true
7
+ ModuleClassName: blcYouTubeChecker
8
+ ModulePriority: 100
9
+ ModuleCheckerUrlPattern: @^http://([\w\d]+\.)*youtube\.[^/]+/watch\?.*v=[^/#]@i
10
+ ModuleHidden: false
11
+ ModuleAlwaysActive: false
12
+ ModuleRequiresPro: true
13
+ Version: 1.0
14
+ Description: Check links to YouTube videos using the YouTube API.
15
+ Plugin Name: YouTube API
16
+ */
17
+ ?>
{includes → modules}/parsers/html_link.php RENAMED
@@ -1,5 +1,20 @@
1
  <?php
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  class blcHTMLLink extends blcParser {
4
  var $supported_formats = array('html');
5
 
@@ -323,6 +338,4 @@ class blcHTMLLink extends blcParser {
323
  }
324
  }
325
 
326
- blc_register_parser('link', 'blcHTMLLink');
327
-
328
  ?>
1
  <?php
2
 
3
+ /*
4
+ Plugin Name: HTML links
5
+ Description: Example : <code>&lt;a href="http://example.com/"&gt;link text&lt;/a&gt;</code>
6
+ Version: 1.0
7
+ Author: Janis Elsts
8
+
9
+ ModuleID: link
10
+ ModuleCategory: parser
11
+ ModuleClassName: blcHTMLLink
12
+ ModuleContext: on-demand
13
+ ModuleLazyInit: true
14
+
15
+ ModulePriority: 1000
16
+ */
17
+
18
  class blcHTMLLink extends blcParser {
19
  var $supported_formats = array('html');
20
 
338
  }
339
  }
340
 
 
 
341
  ?>
{includes → modules}/parsers/image.php RENAMED
@@ -1,4 +1,18 @@
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 {
@@ -142,8 +156,8 @@ class blcHTMLImage extends blcParser {
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
 
@@ -155,7 +169,4 @@ class blcHTMLImage extends blcParser {
155
  }
156
  }
157
 
158
- blc_register_parser('image', 'blcHTMLImage');
159
-
160
-
161
  ?>
1
  <?php
2
+ /*
3
+ Plugin Name: HTML images
4
+ Description: e.g. <code>&lt;img src="http://example.com/fluffy.jpg"&gt;</code>
5
+ Version: 1.0
6
+ Author: Janis Elsts
7
+
8
+ ModuleID: image
9
+ ModuleCategory: parser
10
+ ModuleClassName: blcHTMLImage
11
+ ModuleContext: on-demand
12
+ ModuleLazyInit: true
13
+
14
+ ModulePriority: 900
15
+ */
16
 
17
  //TODO: Update image parser to use the same HTML tag parsing routine as the HTML link parser.
18
  class blcHTMLImage extends blcParser {
156
  $text = __('Image', 'broken-link-checker');
157
 
158
  $image = sprintf(
159
+ '<img src="%s" class="blc-small-image" alt="%2$s" title="%2$s"> ',
160
+ esc_attr(plugins_url('/images/image.png', blc_get_plugin_file())),
161
  esc_attr($text)
162
  );
163
 
169
  }
170
  }
171
 
 
 
 
172
  ?>
{includes → modules}/parsers/metadata.php RENAMED
@@ -1,4 +1,18 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  class blcMetadataParser extends blcParser {
4
  var $supported_formats = array('metadata');
@@ -89,9 +103,31 @@ class blcMetadataParser extends blcParser {
89
  'raw_url' => $new_url,
90
  );
91
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  }
93
 
94
- blc_register_parser('metadata', 'blcMetadataParser');
95
-
96
-
97
  ?>
1
  <?php
2
+ /*
3
+ Plugin Name: Metadata
4
+ Description: Parses metadata (AKA custom fields)
5
+ Version: 1.0
6
+ Author: Janis Elsts
7
+
8
+ ModuleID: metadata
9
+ ModuleCategory: parser
10
+ ModuleClassName: blcMetadataParser
11
+ ModuleContext: on-demand
12
+ ModuleLazyInit: true
13
+ ModuleAlwaysActive: true
14
+ ModuleHidden: true
15
+ */
16
 
17
  class blcMetadataParser extends blcParser {
18
  var $supported_formats = array('metadata');
103
  'raw_url' => $new_url,
104
  );
105
  }
106
+
107
+ /**
108
+ * Get the link text for printing in the "Broken Links" table.
109
+ *
110
+ * @param blcLinkInstance $instance
111
+ * @return string HTML
112
+ */
113
+ function ui_get_link_text(&$instance, $context = 'display'){
114
+ $image_html = sprintf(
115
+ '<img src="%s" class="blc-small-image" title="%2$s" alt="%2$s"> ',
116
+ esc_attr( plugins_url('/images/script_code.png', blc_get_plugin_file()) ),
117
+ __('Custom field', 'broken-link-checker')
118
+ );
119
+
120
+ $field_html = sprintf(
121
+ '<code>%s</code>',
122
+ $instance->container_field
123
+ );
124
+
125
+ if ( $context != 'email' ){
126
+ $field_html = $image_html . $field_html;
127
+ }
128
+
129
+ return $field_html;
130
+ }
131
  }
132
 
 
 
 
133
  ?>
{includes → modules}/parsers/url_field.php RENAMED
@@ -1,4 +1,18 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  /**
4
  * A "parser" for data fields that contain a single, plaintext URL.
@@ -81,7 +95,4 @@ class blcUrlField extends blcParser {
81
  }
82
  }
83
 
84
- blc_register_parser('url_field', 'blcUrlField');
85
-
86
-
87
  ?>
1
  <?php
2
+ /*
3
+ Plugin Name: URL fields
4
+ Description: Parses data fields that contain a single, plaintext URL.
5
+ Version: 1.0
6
+ Author: Janis Elsts
7
+
8
+ ModuleID: url_field
9
+ ModuleCategory: parser
10
+ ModuleClassName: blcUrlField
11
+ ModuleContext: on-demand
12
+ ModuleLazyInit: true
13
+ ModuleAlwaysActive: true
14
+ ModuleHidden: true
15
+ */
16
 
17
  /**
18
  * A "parser" for data fields that contain a single, plaintext URL.
95
  }
96
  }
97
 
 
 
 
98
  ?>
readme.txt CHANGED
@@ -2,11 +2,11 @@
2
  Contributors: whiteshadow
3
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A6P9S6CE3SRSW
4
  Tags: links, broken, maintenance, blogroll, custom fields, admin, comments, posts
5
- Requires at least: 2.9.0
6
- Tested up to: 3.0
7
- Stable tag: 0.9.4.4
8
 
9
- This plugin will check your posts, comments and other places for broken links and missing images and notify you if any are found.
10
 
11
  == Description ==
12
  This plugin will monitor your blog looking for broken links and let you know if any are found.
@@ -14,33 +14,32 @@ This plugin will monitor your blog looking for broken links and let you know if
14
  **Features**
15
 
16
  * Monitors links in your posts, pages, comments, the blogroll, and custom fields (optional).
17
- * Detects links that don't work and missing images.
18
- * Notifies you on the Dashboard if any are found.
19
- * Also detects redirected links.
20
  * Makes broken links display differently in posts (optional).
21
- * Link checking intervals can be configured.
22
- * New/modified posts are checked ASAP.
23
- * You view broken links, redirects, and a complete list of links used on your site, in the *Tools -> Broken Links* tab.
24
- * Searching and filtering links by URL, anchor text and so on is also possible.
25
- * Each link can be edited or unlinked directly via the plugin's page, without manually editing each post.
26
 
27
  [Suggest new features and improvements here](http://feedback.w-shadow.com/forums/58400-broken-link-checker)
28
 
29
  **Basic Usage**
30
 
31
- 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*.
32
 
33
- 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.
34
 
35
  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.
36
 
37
  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 -
38
 
39
- * "Details" shows more info about the link. You can also toggle link details by clicking on the "link text" cell.
40
- * "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 occurrences of that URL will be changed.
41
  * "Unlink" removes the link but leaves the link text intact.
42
  * "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.
43
 
 
 
44
  **Translations**
45
 
46
  * Belorussian - [M. Comfi](http://www.comfi.com/)
@@ -58,16 +57,22 @@ There are several actions associated with each link. They show up when you move
58
  * Spanish - [Neoshinji](http://blog.tuayudainformatica.com/traducciones-de-plugins-wordpress/)
59
  * Ukrainian - [Stas Mykhajlyuk](http://www.kosivart.com/)
60
 
 
 
 
 
 
 
61
  == Installation ==
62
 
63
  To do a new installation of the plugin, please follow these steps
64
 
65
- 1. Download the broken-link-checker.zip file to your local machine.
66
  1. Unzip the file
67
  1. Upload `broken-link-checker` folder to the `/wp-content/plugins/` directory
68
  1. Activate the plugin through the 'Plugins' menu in WordPress
69
 
70
- That's it.
71
 
72
  To upgrade your installation
73
 
@@ -79,6 +84,20 @@ To upgrade your installation
79
 
80
  *This is an automatically generated changelog*
81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  = 0.9.4.4 =
83
  * Fixed "Edit URL" and "Unlink" not working on PHP4 servers.
84
 
2
  Contributors: whiteshadow
3
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A6P9S6CE3SRSW
4
  Tags: links, broken, maintenance, blogroll, custom fields, admin, comments, posts
5
+ Requires at least: 3.0
6
+ Tested up to: 3.1-alpha
7
+ Stable tag: 0.9.5
8
 
9
+ This plugin will check your posts, comments and other content for broken links and missing images, and notify you if any are found.
10
 
11
  == Description ==
12
  This plugin will monitor your blog looking for broken links and let you know if any are found.
14
  **Features**
15
 
16
  * Monitors links in your posts, pages, comments, the blogroll, and custom fields (optional).
17
+ * Detects links that don't work, missing images and redirects.
18
+ * Notifies you either via the Dashboard or by email.
 
19
  * Makes broken links display differently in posts (optional).
20
+ * Prevents search engines from following broken links (optional).
21
+ * You can search and filter links by URL, anchor text and so on.
22
+ * Links can be edited directly from the plugin's page, without manually updating each post.
23
+ * Highly configurable.
 
24
 
25
  [Suggest new features and improvements here](http://feedback.w-shadow.com/forums/58400-broken-link-checker)
26
 
27
  **Basic Usage**
28
 
29
+ Once installed, the plugin will begin parsing your posts, bookmarks (AKA blogroll) and other content and looking for links. Depending on the size of your site this can take from a few minutes up to an hour or more. 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*.
30
 
31
+ 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. E-mail notifications need to be enabled separately (in *Settings -> Link Checker*).
32
 
33
  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.
34
 
35
  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 -
36
 
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), all occurrences 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
+ You can also click on the contents of the "Status" or "Link Text" columns to get more info about the status of each link.
42
+
43
  **Translations**
44
 
45
  * Belorussian - [M. Comfi](http://www.comfi.com/)
57
  * Spanish - [Neoshinji](http://blog.tuayudainformatica.com/traducciones-de-plugins-wordpress/)
58
  * Ukrainian - [Stas Mykhajlyuk](http://www.kosivart.com/)
59
 
60
+ *Note: Some translations are not entirely up to date with the latest release, so parts of the interface may appear untranslated.*
61
+
62
+ **Other Credits**
63
+
64
+ This plugin uses one or more icons from the beautiful ["Silk" icon set](http://www.famfamfam.com/lab/icons/silk/).
65
+
66
  == Installation ==
67
 
68
  To do a new installation of the plugin, please follow these steps
69
 
70
+ 1. Download the broken-link-checker.zip file to your computer.
71
  1. Unzip the file
72
  1. Upload `broken-link-checker` folder to the `/wp-content/plugins/` directory
73
  1. Activate the plugin through the 'Plugins' menu in WordPress
74
 
75
+ To enable/disable various features and tweak the plugin's configuration go to *Settings -> Link Checker*.
76
 
77
  To upgrade your installation
78
 
84
 
85
  *This is an automatically generated changelog*
86
 
87
+ = 0.9.5 =
88
+ * Added the ability to check scheduled, draft and private posts.
89
+ * Added a way to individually enable/disable the monitoring of posts, pages, comments, the blogroll, and so on.
90
+ * New "Status" column in the "Broken Links" table.
91
+ * Visible table columns and the number of links per page can now be selected in the "Screen Options" panel.
92
+ * Replaced the "Delete sources" action with "Move sources to Trash" (except on blogs where Trash is disabled).
93
+ * New URL editor interface, now more consistent with the look-n-feel of the inline editor for posts.
94
+ * New status icon to help distinguish "maybe broken" and "definitely broken" links.
95
+ * Tweaked table layout - links first, posts/etc last.
96
+ * Added "Compact" and "Detailed" table views (for now, the differences are quite minor).
97
+ * Split the settings page into several tabs.
98
+ * Removed the "Details" links as redundant. To display link details, click the contents of the "Status" or "Link text" columns instead.
99
+ * Added a way to individually enable/disable the monitoring of various link types, e.g. HTML links, images, etc.
100
+
101
  = 0.9.4.4 =
102
  * Fixed "Edit URL" and "Unlink" not working on PHP4 servers.
103
 
uninstall.php CHANGED
@@ -1,16 +1,17 @@
1
  <?php
2
 
3
  /**
4
- * @author W-Shadow
5
- * @copyright 2009
6
  *
7
  * The terrifying uninstallation script.
8
  */
9
 
10
  if( defined( 'ABSPATH') && defined('WP_UNINSTALL_PLUGIN') ) {
11
 
12
- //Remove the plugin's settings
13
  delete_option('wsblc_options');
 
14
 
15
  //Remove the database tables
16
  $mywpdb = $GLOBALS['wpdb'];
1
  <?php
2
 
3
  /**
4
+ * @author Janis Elsts
5
+ * @copyright 2010
6
  *
7
  * The terrifying uninstallation script.
8
  */
9
 
10
  if( defined( 'ABSPATH') && defined('WP_UNINSTALL_PLUGIN') ) {
11
 
12
+ //Remove the plugin's settings & installation log
13
  delete_option('wsblc_options');
14
+ delete_option('blc_installation_log');
15
 
16
  //Remove the database tables
17
  $mywpdb = $GLOBALS['wpdb'];