SEO Ultimate - Version 1.5

Version Description

Download this release

Release Info

Developer SEO Design Solutions
Plugin Icon 128x128 SEO Ultimate
Version 1.5
Comparing to
See all releases

Code changes from version 1.4.1 to 1.5

Files changed (51) hide show
  1. functions.php +0 -278
  2. includes/jlfunctions/arr.php +61 -0
  3. includes/jlfunctions/io.php +30 -0
  4. includes/jlfunctions/jlfunctions.php +15 -0
  5. includes/jlfunctions/md.php +87 -0
  6. includes/jlfunctions/str.php +126 -0
  7. includes/jlfunctions/url.php +33 -0
  8. includes/jlwp/functions.php +118 -0
  9. includes/jlwp/jlwp.php +6 -0
  10. includes/jlwp/screen-meta.php +118 -0
  11. includes/markdown/markdown.php +1732 -0
  12. tabs.js → includes/tabs.js +0 -0
  13. modules/404s.php +0 -180
  14. modules/404s/404s.php +117 -0
  15. modules/{canonical.php → canonical/canonical.php} +4 -29
  16. modules/class.su-importmodule.php +84 -0
  17. class.su-module.php → modules/class.su-module.php +529 -139
  18. modules/{competition-queries.php → competition-queries/competition-queries.php} +2 -2
  19. modules/{files.php → files/files.php} +4 -4
  20. modules/{linkbox.php → linkbox/linkbox.php} +4 -47
  21. modules/meta.php +0 -201
  22. modules/meta/meta-settings.php +50 -0
  23. modules/meta/meta.php +122 -0
  24. modules.css → modules/modules.css +19 -0
  25. modules.js → modules/modules.js +0 -0
  26. modules/{modules.php → modules/modules.php} +45 -26
  27. modules/{more-links.php → more-links/more-links.php} +2 -12
  28. modules/{noindex.php → noindex/noindex.php} +2 -41
  29. modules/{sds-blog.php → sds-blog/sds-blog.php} +5 -4
  30. modules/{settings.php → settings/settings.php} +42 -31
  31. modules/{site-keyword-queries.php → site-keyword-queries/site-keyword-queries.php} +3 -3
  32. modules/{slugs.php → slugs/slugs.php} +2 -47
  33. modules/titles/titles-formats.php +17 -0
  34. modules/titles/titles-posts.php +40 -0
  35. modules/{titles.php → titles/titles.php} +124 -90
  36. class.seo-ultimate.php → plugin/class.seo-ultimate.php +199 -126
  37. class.su-hitset.php → plugin/class.su-hitset.php +3 -3
  38. global.css → plugin/global.css +12 -2
  39. {images → plugin/images}/error.png +0 -0
  40. {images → plugin/images}/icon.png +0 -0
  41. {images → plugin/images}/index.php +0 -0
  42. {images → plugin/images}/info.png +0 -0
  43. {images → plugin/images}/sds-logo.png +0 -0
  44. {images → plugin/images}/seo.png +0 -0
  45. {images → plugin/images}/success.png +0 -0
  46. {images → plugin/images}/warning.png +0 -0
  47. plugin/su-constants.php +14 -0
  48. plugin/su-functions.php +133 -0
  49. readme.txt +45 -18
  50. seo-ultimate.php +20 -18
  51. seo-ultimate.pot +402 -843
functions.php DELETED
@@ -1,278 +0,0 @@
1
- <?php
2
- /**
3
- * Non-class functions.
4
- */
5
-
6
- /********** INDEPENDENTLY-OPERABLE FUNCTIONS **********/
7
-
8
- /**
9
- * Returns the plugin's User-Agent value.
10
- * Can be used as a WordPress filter.
11
- *
12
- * @since 0.1
13
- * @uses SU_USER_AGENT
14
- *
15
- * @return string The user agent.
16
- */
17
- function su_get_user_agent() {
18
- return SU_USER_AGENT;
19
- }
20
-
21
- /**
22
- * Records an event in the debug log file.
23
- * Usage: su_debug_log(__FILE__, __CLASS__, __FUNCTION__, __LINE__, "Message");
24
- *
25
- * @since 0.1
26
- * @uses SU_VERSION
27
- *
28
- * @param string $file The value of __FILE__
29
- * @param string $class The value of __CLASS__
30
- * @param string $function The value of __FUNCTION__
31
- * @param string $line The value of __LINE__
32
- * @param string $message The message to log.
33
- */
34
- function su_debug_log($file, $class, $function, $line, $message) {
35
- global $seo_ultimate;
36
- if (isset($seo_ultimate->modules['settings']) && $seo_ultimate->modules['settings']->get_setting('debug_mode') === true) {
37
-
38
- $date = date("Y-m-d H:i:s");
39
- $version = SU_VERSION;
40
- $message = str_replace("\r\n", "\n", $message);
41
- $message = str_replace("\n", "\r\n", $message);
42
-
43
- $log = "Date: $date\r\nVersion: $version\r\nFile: $file\r\nClass: $class\r\nFunction: $function\r\nLine: $line\r\nMessage: $message\r\n\r\n";
44
- $logfile = trailingslashit(dirname(__FILE__))."seo-ultimate.log";
45
-
46
- @error_log($log, 3, $logfile);
47
- }
48
- }
49
-
50
- /**
51
- * Returns whether or not a given string starts with a given substring.
52
- *
53
- * @since 0.4
54
- *
55
- * @param string $str The "haystack" string.
56
- * @param string $sub The "needle" string.
57
- * @return bool Whether or not $str starts with $sub.
58
- */
59
- function su_str_startswith( $str, $sub ) {
60
- return ( substr( $str, 0, strlen( $sub ) ) === $sub );
61
- }
62
-
63
- /**
64
- * Returns whether or not a given string ends with a given substring.
65
- *
66
- * @since 1.0
67
- *
68
- * @param string $str The "haystack" string.
69
- * @param string $sub The "needle" string.
70
- * @return bool Whether or not $str ends with $sub.
71
- */
72
- function su_str_endswith( $str, $sub ) {
73
- return ( substr( $str, strlen( $str ) - strlen( $sub ) ) === $sub );
74
- }
75
-
76
- /**
77
- * Truncates a string if it is longer than a given length.
78
- *
79
- * @since 0.8
80
- *
81
- * @param string $str The string to possibly truncate.
82
- * @param int $maxlen The desired maximum length of the string.
83
- * @param str $truncate The string that should be added to the end of a truncated string.
84
- */
85
- function su_str_truncate( $str, $maxlen, $truncate = '...' ) {
86
- if ( strlen($str) > $maxlen )
87
- return substr( $str, 0, $maxlen - strlen($truncate) ) . $truncate;
88
-
89
- return $str;
90
- }
91
-
92
- /**
93
- * Escapes an attribute value and removes unwanted characters.
94
- *
95
- * @since 0.8
96
- *
97
- * @param string $str The attribute value.
98
- * @return string The filtered attribute value.
99
- */
100
- function su_esc_attr($str) {
101
- $str = str_replace(array("\t", "\r\n", "\n"), ' ', $str);
102
- $str = attribute_escape($str);
103
- return $str;
104
- }
105
-
106
- /**
107
- * Joins strings into a natural-language list.
108
- * Can be internationalized with gettext or the su_lang_implode filter.
109
- *
110
- * @since 1.1
111
- *
112
- * @param array $items The strings (or objects with $var child strings) to join.
113
- * @param string|false $var The name of the items' object variables whose values should be imploded into a list.
114
- If false, the items themselves will be used.
115
- * @param bool $ucwords Whether or not to capitalize the first letter of every word in the list.
116
- * @return string|array The items in a natural-language list.
117
- */
118
- function su_lang_implode($items, $var=false, $ucwords=false) {
119
-
120
- if (is_array($items) ) {
121
-
122
- if (strlen($var)) {
123
- $_items = array();
124
- foreach ($items as $item) $_items[] = $item->$var;
125
- $items = $_items;
126
- }
127
-
128
- if ($ucwords) $items = array_map('ucwords', $items);
129
-
130
- switch (count($items)) {
131
- case 0: $list = ''; break;
132
- case 1: $list = $items[0]; break;
133
- case 2: $list = sprintf(__('%s and %s', 'seo-ultimate'), $items[0], $items[1]); break;
134
- default:
135
- $last = array_pop($items);
136
- $list = implode(__(', ', 'seo-ultimate'), $items);
137
- $list = sprintf(__('%s, and %s', 'seo-ultimate'), $list, $last);
138
- break;
139
- }
140
-
141
- return apply_filters('su_lang_implode', $list, $items);
142
- }
143
-
144
- return $items;
145
- }
146
-
147
- /********** CLASS FUNCTION ALIASES **********/
148
-
149
- /**
150
- * Launches the uninstallation process.
151
- * WordPress will call this when the plugin is uninstalled, as instructed by the register_uninstall_hook() call in {@link SEO_Ultimate::__construct()}.
152
- *
153
- * @since 0.1
154
- * @uses $seo_ultimate
155
- * @uses SEO_Ultimate::uninstall()
156
- */
157
- function su_uninstall() {
158
- global $seo_ultimate;
159
- $seo_ultimate->uninstall();
160
- }
161
-
162
- /********** DROPDOWN CODE **********/
163
-
164
- //Special thanks to the Drafts Dropdown plugin for the abstracted code
165
- //http://alexking.org/projects/wordpress
166
-
167
- if (!function_exists('screen_meta_html')) {
168
-
169
- function screen_meta_html($meta) {
170
- extract($meta);
171
- if (function_exists($content)) {
172
- $content = $content();
173
- }
174
- echo '
175
- <div id="screen-meta-'.$key.'-wrap" class="screen-meta-wrap hidden">
176
- <div class="screen-meta-content">'.$content.'</div>
177
- </div>
178
- <div id="screen-meta-'.$key.'-link-wrap" class="hide-if-no-js screen-meta-toggle cf">
179
- <a href="#screen-meta-'.$key.'-wrap" id="screen-meta-'.$key.'-link" class="show-settings">'.$label.'</a>
180
- </div>
181
- ';
182
- }
183
-
184
- }
185
-
186
- if (!function_exists('screen_meta_output')) {
187
-
188
- function screen_meta_output() {
189
- global $screen_meta;
190
- /*
191
- expected format:
192
- $screen_meta = array(
193
- array(
194
- 'key' => 'drafts',
195
- 'label' => 'Drafts',
196
- 'content' => 'screen_meta_drafts_content' // can be content or function name
197
- )
198
- );
199
- */
200
- if (!$screen_meta) $screen_meta = array();
201
- $screen_meta = apply_filters('screen_meta', $screen_meta);
202
- echo '<div id="screen-meta-extra-content">';
203
- foreach ($screen_meta as $meta) {
204
- screen_meta_html($meta);
205
- }
206
- echo '</div>';
207
- ?>
208
- <style type="text/css">
209
- .screen-meta-toggle {
210
- float: right;
211
- background: transparent url( <?php bloginfo('wpurl'); ?>/wp-admin/images/screen-options-left.gif ) no-repeat 0 0;
212
- font-family: "Lucida Grande", Verdana, Arial, "Bitstream Vera Sans", sans-serif;
213
- height: 22px;
214
- padding: 0;
215
- margin: 0 6px 0 0;
216
- }
217
- .screen-meta-wrap h5 {
218
- margin: 8px 0;
219
- font-size: 13px;
220
- }
221
- .screen-meta-wrap {
222
- border-style: none solid solid;
223
- border-top: 0 none;
224
- border-width: 0 1px 1px;
225
- margin: 0 15px;
226
- padding: 8px 12px 12px;
227
- -moz-border-radius: 0 0 0 4px;
228
- -webkit-border-bottom-left-radius: 4px;
229
- -khtml-border-bottom-left-radius: 4px;
230
- border-bottom-left-radius: 4px;
231
- }
232
- </style>
233
- <script type="text/javascript">
234
- jQuery(function($) {
235
-
236
- // These hacks not needed if adopted into core
237
- // move tabs into place
238
- $('#screen-meta-extra-content .screen-meta-toggle.cf').each(function() {
239
- $('#screen-meta-links').append($(this));
240
- });
241
- // Move content into place
242
- $('#screen-meta-extra-content .screen-meta-wrap').each(function() {
243
- $('#screen-meta-links').before($(this));
244
- });
245
- // end hacks
246
-
247
- // simplified generic code to handle all screen meta tabs
248
- $('#screen-meta-links a.show-settings').unbind().click(function() {
249
- var link = $(this);
250
- $(link.attr('href')).slideToggle('fast', function() {
251
- if (link.hasClass('screen-meta-shown')) {
252
- link.css({'backgroundImage':'url("images/screen-options-right.gif")'}).removeClass('screen-meta-shown');
253
- $('.screen-meta-toggle').css('visibility', 'visible');
254
- }
255
- else {
256
- $('.screen-meta-toggle').css('visibility', 'hidden');
257
- link.css({'backgroundImage':'url("images/screen-options-right-up.gif")'}).addClass('screen-meta-shown').parent().css('visibility', 'visible');
258
- }
259
- });
260
- return false;
261
- });
262
-
263
- var copy = $('#contextual-help-wrap');
264
- $('.screen-meta-wrap').css({
265
- 'background-color': copy.css('background-color'),
266
- 'border-color': copy.css('border-bottom-color')
267
- });
268
-
269
- });
270
- </script>
271
-
272
- <?php
273
- }
274
- add_action('admin_footer', 'screen_meta_output');
275
-
276
- }
277
-
278
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/jlfunctions/arr.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ JLFunctions Array Class
4
+ Copyright (c)2009 John Lamansky
5
+ All rights reserved
6
+ May not be redistributed or used without express written permission.
7
+ */
8
+
9
+ class suarr {
10
+
11
+ /**
12
+ * Plugs an array's keys and/or values into sprintf-style format string(s).
13
+ *
14
+ * @param string|false $keyformat The sprintf-style format for the key, e.g. "prefix_%s" or "%s_suffix"
15
+ * @param string|false $valueformat The sprintf-style format for the value.
16
+ * @param array $array The array whose keys/values should be formatted.
17
+ * @return array The array with the key/value formats applied.
18
+ */
19
+ function aprintf($keyformat, $valueformat, $array) {
20
+ $newarray = array();
21
+ foreach ($array as $key => $value) {
22
+ if ($keyformat) {
23
+ if (is_int($key)) $key = $value;
24
+ $key = str_replace('%s', $key, $keyformat);
25
+ }
26
+ if ($valueformat) $value = str_replace('%s', $value, $valueformat);
27
+ $newarray[$key] = $value;
28
+ }
29
+ return $newarray;
30
+ }
31
+
32
+ /**
33
+ * Removes elements that are blank (after trimming) from the beginning of the given array.
34
+ */
35
+ function ltrim($array) {
36
+ while (count($array) && !strlen(trim($array[0])))
37
+ array_shift($array);
38
+ return $array;
39
+ }
40
+
41
+ /**
42
+ * Removes a value from the array if found.
43
+ */
44
+ function remove_value(&$array, $value) {
45
+ $index = array_search($value, $array);
46
+ if ($index !== false)
47
+ unset($array[$index]);
48
+ }
49
+
50
+ //Based on recursive array search function from:
51
+ //http://www.php.net/manual/en/function.array-search.php#91365
52
+ function search_recursive($needle, $haystack) {
53
+ foreach ($haystack as $key => $value) {
54
+ if ($needle === $value || (is_array($value) && suarr::search_recursive($needle, $value) !== false))
55
+ return $key;
56
+ }
57
+ return false;
58
+ }
59
+ }
60
+
61
+ ?>
includes/jlfunctions/io.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ JLFunctions IO Class
4
+ Copyright (c)2009 John Lamansky
5
+ All rights reserved
6
+ May not be redistributed or used without express written permission.
7
+ */
8
+
9
+ class suio {
10
+
11
+ function is_file($filename, $path, $ext=false) {
12
+ $is_ext = strlen($ext) ? sustr::endswith($filename, '.'.ltrim($ext, '*.')) : true;
13
+ return is_file(suio::tslash($path).$filename) && $is_ext;
14
+ }
15
+
16
+ function is_dir($name, $path) {
17
+ return $name != '.' && $name != '..' && is_dir(suio::tslash($path).$name);
18
+ }
19
+
20
+ function tslash($path) {
21
+ return suio::untslash($path).'/';
22
+ }
23
+
24
+ function untslash($path) {
25
+ return rtrim($path, '/');
26
+ }
27
+
28
+ }
29
+
30
+ ?>
includes/jlfunctions/jlfunctions.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ JLFunctions Library
4
+ Copyright (c)2009 John Lamansky
5
+ All rights reserved
6
+ May not be redistributed or used without express written permission.
7
+ */
8
+
9
+ include 'arr.php';
10
+ include 'io.php';
11
+ include 'md.php';
12
+ include 'str.php';
13
+ include 'url.php';
14
+
15
+ ?>
includes/jlfunctions/md.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ JLFunctions MD Class
4
+ Copyright (c)2009 John Lamansky
5
+ All rights reserved
6
+ May not be redistributed or used without express written permission.
7
+ */
8
+
9
+ class sumd {
10
+
11
+ /**
12
+ * Retrieves the content of a specific section of an MD document.
13
+ *
14
+ * @param string $md The MD document, with Windows-style newlines.
15
+ * @param string $path The header of the section to retrieve. Nested headers are separated by slashes. If headers contain actual slashes, escape those slashes with backslashes. For example: "Header/Subheader/Sub-sub-header/Regarding A and\\/or B". If the number of headers is greater than $nms, the extra headers will be ignored.
16
+ * @param int $nms The number of minus signs that top-level headers will have. If $nms=2, then top header will look like <code>== Header ==</code>.
17
+ * @return string The section specified by the $path.
18
+ */
19
+ function get_section($md, $path, $nms=2) {
20
+
21
+ //Permit escaped slashes.
22
+ $path = str_replace("\\/", "<SLASH>", $path);
23
+
24
+ //Break up the path into header levels
25
+ $levels = explode("/", $path);
26
+
27
+ //Cycle through the header levels
28
+ foreach ($levels as $level) {
29
+
30
+ //Add in escaped slashes again
31
+ $level = str_replace("<SLASH>", "/", $level);
32
+
33
+ //Create the string that will prefix and suffix the header text
34
+ $m = str_repeat("=", $nms);
35
+
36
+ //If the document contains the header specified...
37
+ if ($levelstart = strpos($md, $levelheader = "\r\n\r\n$m $level $m\r\n\r\n")) {
38
+
39
+ //Lop off everything in the document that comes before the header
40
+ $md = substr($md, $levelstart + strlen($levelheader));
41
+
42
+ //If another sibling (i.e. non-child) header comes afterwards, remove it and everything proceding so that we just have the section we want.
43
+ //If no other sibling headers follow, then the section we want must continue to the end of the document.
44
+ if ($levelend = strpos($md, "\r\n\r\n$m "))
45
+ $md = substr($md, 0, $levelend);
46
+ } else
47
+ //One of the headers wasn't found, so this specific path must not exist. Return empty string.
48
+ return '';
49
+
50
+ //Now we'll go one header level down.
51
+ $nms--;
52
+
53
+ //If we've reached the end, break the loop.
54
+ if ($nms == 0) break;
55
+ }
56
+
57
+ return $md;
58
+ }
59
+
60
+ /**
61
+ * Gets all sections of an MD document and returns them in an array.
62
+ *
63
+ * @param string $md The MD document.
64
+ * @return array An array of header text => section content.
65
+ */
66
+ function get_sections($md) {
67
+
68
+ $md = "\r\n$md";
69
+
70
+ $sections = array();
71
+
72
+ //Get MD sections
73
+ $preg_sections = preg_split("|\r\n=+ ([^=]+) =+\r\n|", $md, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
74
+ $preg_sections = array_chunk($preg_sections, 2);
75
+
76
+ foreach ($preg_sections as $preg_section) {
77
+ $header = trim($preg_section[0]);
78
+ $content = trim($preg_section[1]);
79
+ if (strlen($header))
80
+ $sections[$header] = $content;
81
+ }
82
+
83
+ return $sections;
84
+ }
85
+ }
86
+
87
+ ?>
includes/jlfunctions/str.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ JLFunctions String Class
4
+ Copyright (c)2009 John Lamansky
5
+ All rights reserved
6
+ May not be redistributed or used without express written permission.
7
+ */
8
+
9
+ class sustr {
10
+
11
+ /**
12
+ * Returns whether or not a given string starts with a given substring.
13
+ *
14
+ * @param string $str The "haystack" string.
15
+ * @param string $sub The "needle" string.
16
+ * @return bool Whether or not $str starts with $sub.
17
+ */
18
+ function startswith( $str, $sub ) {
19
+ return ( substr( $str, 0, strlen( $sub ) ) === $sub );
20
+ }
21
+
22
+ /**
23
+ * Returns whether or not a given string ends with a given substring.
24
+ *
25
+ * @param string $str The "haystack" string.
26
+ * @param string $sub The "needle" string.
27
+ * @return bool Whether or not $str ends with $sub.
28
+ */
29
+ function endswith( $str, $sub ) {
30
+ return ( substr( $str, strlen( $str ) - strlen( $sub ) ) === $sub );
31
+ }
32
+
33
+ function has($str, $sub) {
34
+ return (strpos($str, $sub) !== false);
35
+ }
36
+
37
+ /**
38
+ * Truncates a string if it is longer than a given length.
39
+ *
40
+ * @param string $str The string to possibly truncate.
41
+ * @param int $maxlen The desired maximum length of the string.
42
+ * @param str $truncate The string that should be added to the end of a truncated string.
43
+ */
44
+ function truncate( $str, $maxlen, $truncate = '...' ) {
45
+ if ( strlen($str) > $maxlen )
46
+ return substr( $str, 0, $maxlen - strlen($truncate) ) . $truncate;
47
+
48
+ return $str;
49
+ }
50
+
51
+ /**
52
+ * Joins strings into a natural-language list.
53
+ * Can be internationalized with gettext or the su_lang_implode filter.
54
+ *
55
+ * @param array $items The strings (or objects with $var child strings) to join.
56
+ * @param string|false $var The name of the items' object variables whose values should be imploded into a list.
57
+ If false, the items themselves will be used.
58
+ * @param bool $ucwords Whether or not to capitalize the first letter of every word in the list.
59
+ * @return string|array The items in a natural-language list.
60
+ */
61
+ function nl_implode($items, $var=false, $ucwords=false) {
62
+
63
+ if (is_array($items) ) {
64
+
65
+ if (strlen($var)) {
66
+ $_items = array();
67
+ foreach ($items as $item) $_items[] = $item->$var;
68
+ $items = $_items;
69
+ }
70
+
71
+ if ($ucwords) $items = array_map('ucwords', $items);
72
+
73
+ switch (count($items)) {
74
+ case 0: $list = ''; break;
75
+ case 1: $list = $items[0]; break;
76
+ case 2: $list = sprintf(__('%s and %s', 'seo-ultimate'), $items[0], $items[1]); break;
77
+ default:
78
+ $last = array_pop($items);
79
+ $list = implode(__(', ', 'seo-ultimate'), $items);
80
+ $list = sprintf(__('%s, and %s', 'seo-ultimate'), $list, $last);
81
+ break;
82
+ }
83
+
84
+ return apply_filters('su_lang_implode', $list, $items);
85
+ }
86
+
87
+ return $items;
88
+ }
89
+
90
+ /**
91
+ * If the given string ends with the given suffix, the suffix is removed.
92
+ *
93
+ * @param string $str The string of which the provided suffix should be trimmed if located.
94
+ * @param string $totrim The suffix that should be trimmed if found.
95
+ * @return string The possibly-trimmed string.
96
+ */
97
+ function rtrim_str($str, $totrim) {
98
+ if (strlen($str) > strlen($totrim) && sustr::endswith($str, $totrim))
99
+ return substr($str, -strlen($totrim));
100
+
101
+ return $str;
102
+ }
103
+
104
+ function batch_replace($search, $replace, $subjects) {
105
+ $subjects = array_unique((array)$subjects);
106
+ $results = array();
107
+ foreach ($subjects as $subject) {
108
+ $results[$subject] = str_replace($search, $replace, $subject);
109
+ }
110
+ return $results;
111
+ }
112
+
113
+ function unique_words($str) {
114
+ $str = explode(' ', $str);
115
+ $str = array_unique($str);
116
+ $str = implode(' ', $str);
117
+ return $str;
118
+ }
119
+
120
+ function preg_filter($filter, $str) {
121
+ return preg_replace("/[^{$filter}]/", '', $str);
122
+ }
123
+
124
+ }
125
+
126
+ ?>
includes/jlfunctions/url.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ JLFunctions URL Class
4
+ Copyright (c)2009 John Lamansky
5
+ All rights reserved
6
+ May not be redistributed or used without express written permission.
7
+ */
8
+
9
+ class suurl {
10
+
11
+ /**
12
+ * Approximately determines the URL in the visitor's address bar. (Includes query strings, but not #anchors.)
13
+ *
14
+ * @return string The current URL.
15
+ */
16
+ function current() {
17
+ $url = 'http';
18
+ if ($_SERVER["HTTPS"] == "on") $url .= "s";
19
+ $url .= "://";
20
+
21
+ if ($_SERVER["SERVER_PORT"] != "80")
22
+ return $url.$_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
23
+ else
24
+ return $url.$_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
25
+ }
26
+
27
+ function build_query($array) {
28
+ return html_entity_decode(http_build_query($array));
29
+ }
30
+
31
+ }
32
+
33
+ ?>
includes/jlwp/functions.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class suwp {
4
+
5
+ /**
6
+ * Determines the ID of the current post.
7
+ * Works in the admin as well as the front-end.
8
+ *
9
+ * @return int|false The ID of the current post, or false on failure.
10
+ */
11
+ function get_post_id() {
12
+ if (is_admin())
13
+ return intval($_REQUEST['post']);
14
+ elseif (in_the_loop())
15
+ return intval(get_the_ID());
16
+ elseif (is_singular()) {
17
+ global $wp_query;
18
+ return $wp_query->get_queried_object_id();
19
+ }
20
+
21
+ return false;
22
+ }
23
+
24
+ function get_any_posts($args = null) {
25
+ $args['post_type'] = implode(',', suwp::get_post_type_names());
26
+ return get_posts($args);
27
+ }
28
+
29
+ function get_post_type_names() {
30
+ $types = get_post_types();
31
+ suarr::remove_value($types, 'revision');
32
+ return $types;
33
+ }
34
+
35
+ /**
36
+ * Loads a webpage and returns its HTML as a string.
37
+ *
38
+ * @param string $url The URL of the webpage to load.
39
+ * @param string $ua The user agent to use.
40
+ * @return string The HTML of the URL.
41
+ */
42
+ function load_webpage($url, $ua) {
43
+
44
+ $options = array();
45
+ $options['headers'] = array(
46
+ 'User-Agent' => $ua
47
+ );
48
+
49
+ $response = wp_remote_request($url, $options);
50
+
51
+ if ( is_wp_error( $response ) ) return false;
52
+ if ( 200 != $response['response']['code'] ) return false;
53
+
54
+ return trim( $response['body'] );
55
+ }
56
+
57
+ /**
58
+ * Loads an RSS feed and returns it as an object.
59
+ *
60
+ * @param string $url The URL of the RSS feed to load.
61
+ * @param callback $ua The user agent to use.
62
+ * @return object $rss The RSS object.
63
+ */
64
+ function load_rss($url, $ua) {
65
+ $uafunc = create_function('', "return '$ua';");
66
+ add_filter('http_headers_useragent', $uafunc);
67
+ require_once (ABSPATH . WPINC . '/rss.php');
68
+ $rss = fetch_rss($url);
69
+ remove_filter('http_headers_useragent', $uafunc);
70
+ return $rss;
71
+ }
72
+
73
+ /**
74
+ * @return string
75
+ */
76
+ function get_backup_url() {
77
+ if (is_plugin_active('wp-db-backup/wp-db-backup.php'))
78
+ return admin_url('tools.php?page=wp-db-backup');
79
+ else
80
+ return 'http://codex.wordpress.org/Backing_Up_Your_Database';
81
+ }
82
+
83
+ function get_taxonomy_link($id, $taxonomy) {
84
+ switch ($taxonomy) {
85
+ case 'category': return get_category_link($id); break;
86
+ case 'post_tag': return get_tag_link($id); break;
87
+ default: return suwp::get_edit_taxonomy_link($id, $taxonomy); break;
88
+ }
89
+ }
90
+
91
+ function get_edit_taxonomy_link($id, $taxonomy) {
92
+ if ($taxonomy == 'category')
93
+ return admin_url("categories.php?action=edit&amp;cat_ID=$id");
94
+ else
95
+ return get_edit_tag_link($id, $taxonomy);
96
+ }
97
+
98
+ function remove_instance_action($tag, $class, $function, $priority=10) {
99
+ return suwp::remove_instance_filter($tag, $class, $function, $priority);
100
+ }
101
+
102
+ function remove_instance_filter($tag, $class, $function, $priority=10) {
103
+ if (isset($GLOBALS['wp_filter'][$tag][$priority]) && count($GLOBALS['wp_filter'][$tag][$priority])) {
104
+ foreach ($GLOBALS['wp_filter'][$tag][$priority] as $key => $x) {
105
+ if (sustr::startswith($key, $class.$function)) {
106
+ unset($GLOBALS['wp_filter'][$tag][$priority][$key]);
107
+ if ( empty($GLOBALS['wp_filter'][$tag][$priority]) )
108
+ unset($GLOBALS['wp_filter'][$tag][$priority]);
109
+ unset($GLOBALS['merged_filters'][$tag]);
110
+ return true;
111
+ }
112
+ }
113
+ }
114
+
115
+ return false;
116
+ }
117
+ }
118
+ ?>
includes/jlwp/jlwp.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ include 'functions.php';
4
+ include 'screen-meta.php';
5
+
6
+ ?>
includes/jlwp/screen-meta.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /********** DROPDOWN CODE **********/
3
+
4
+ //Special thanks to the Drafts Dropdown plugin for the abstracted code
5
+ //http://alexking.org/projects/wordpress
6
+
7
+ if (!function_exists('screen_meta_html')) {
8
+
9
+ function screen_meta_html($meta) {
10
+ extract($meta);
11
+ if (function_exists($content)) {
12
+ $content = $content();
13
+ }
14
+ echo '
15
+ <div id="screen-meta-'.$key.'-wrap" class="screen-meta-wrap hidden">
16
+ <div class="screen-meta-content">'.$content.'</div>
17
+ </div>
18
+ <div id="screen-meta-'.$key.'-link-wrap" class="hide-if-no-js screen-meta-toggle cf">
19
+ <a href="#screen-meta-'.$key.'-wrap" id="screen-meta-'.$key.'-link" class="show-settings">'.$label.'</a>
20
+ </div>
21
+ ';
22
+ }
23
+
24
+ }
25
+
26
+ if (!function_exists('screen_meta_output')) {
27
+
28
+ function screen_meta_output() {
29
+ global $screen_meta;
30
+ /*
31
+ expected format:
32
+ $screen_meta = array(
33
+ array(
34
+ 'key' => 'drafts',
35
+ 'label' => 'Drafts',
36
+ 'content' => 'screen_meta_drafts_content' // can be content or function name
37
+ )
38
+ );
39
+ */
40
+ if (!$screen_meta) $screen_meta = array();
41
+ $screen_meta = apply_filters('screen_meta', $screen_meta);
42
+ if (!$screen_meta) return;
43
+ echo '<div id="screen-meta-extra-content">';
44
+ foreach ($screen_meta as $meta) {
45
+ screen_meta_html($meta);
46
+ }
47
+ echo '</div>';
48
+ ?>
49
+ <style type="text/css">
50
+ .screen-meta-toggle {
51
+ float: right;
52
+ background: transparent url( <?php bloginfo('wpurl'); ?>/wp-admin/images/screen-options-left.gif ) no-repeat 0 0;
53
+ font-family: "Lucida Grande", Verdana, Arial, "Bitstream Vera Sans", sans-serif;
54
+ height: 22px;
55
+ padding: 0;
56
+ margin: 0 6px 0 0;
57
+ }
58
+ .screen-meta-wrap h5 {
59
+ margin: 8px 0;
60
+ font-size: 13px;
61
+ }
62
+ .screen-meta-wrap {
63
+ border-style: none solid solid;
64
+ border-top: 0 none;
65
+ border-width: 0 1px 1px;
66
+ margin: 0 15px;
67
+ padding: 8px 12px 12px;
68
+ -moz-border-radius: 0 0 0 4px;
69
+ -webkit-border-bottom-left-radius: 4px;
70
+ -khtml-border-bottom-left-radius: 4px;
71
+ border-bottom-left-radius: 4px;
72
+ }
73
+ </style>
74
+ <script type="text/javascript">
75
+ jQuery(function($) {
76
+
77
+ // These hacks not needed if adopted into core
78
+ // move tabs into place
79
+ $('#screen-meta-extra-content .screen-meta-toggle.cf').each(function() {
80
+ $('#screen-meta-links').append($(this));
81
+ });
82
+ // Move content into place
83
+ $('#screen-meta-extra-content .screen-meta-wrap').each(function() {
84
+ $('#screen-meta-links').before($(this));
85
+ });
86
+ // end hacks
87
+
88
+ // simplified generic code to handle all screen meta tabs
89
+ $('#screen-meta-links a.show-settings').unbind().click(function() {
90
+ var link = $(this);
91
+ $(link.attr('href')).slideToggle('fast', function() {
92
+ if (link.hasClass('screen-meta-shown')) {
93
+ link.css({'backgroundImage':'url("images/screen-options-right.gif")'}).removeClass('screen-meta-shown');
94
+ $('.screen-meta-toggle').css('visibility', 'visible');
95
+ }
96
+ else {
97
+ $('.screen-meta-toggle').css('visibility', 'hidden');
98
+ link.css({'backgroundImage':'url("images/screen-options-right-up.gif")'}).addClass('screen-meta-shown').parent().css('visibility', 'visible');
99
+ }
100
+ });
101
+ return false;
102
+ });
103
+
104
+ var copy = $('#contextual-help-wrap');
105
+ $('.screen-meta-wrap').css({
106
+ 'background-color': copy.css('background-color'),
107
+ 'border-color': copy.css('border-bottom-color')
108
+ });
109
+
110
+ });
111
+ </script>
112
+
113
+ <?php
114
+ }
115
+ add_action('admin_footer', 'screen_meta_output');
116
+
117
+ }
118
+ ?>
includes/markdown/markdown.php ADDED
@@ -0,0 +1,1732 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ #
3
+ # Markdown - A text-to-HTML conversion tool for web writers
4
+ #
5
+ # PHP Markdown
6
+ # Copyright (c) 2004-2009 Michel Fortin
7
+ # <http://michelf.com/projects/php-markdown/>
8
+ #
9
+ # Original Markdown
10
+ # Copyright (c) 2004-2006 John Gruber
11
+ # <http://daringfireball.net/projects/markdown/>
12
+ #
13
+
14
+
15
+ define( 'MARKDOWN_VERSION', "1.0.1n" ); # Sat 10 Oct 2009
16
+
17
+
18
+ #
19
+ # Global default settings:
20
+ #
21
+
22
+ # Change to ">" for HTML output
23
+ @define( 'MARKDOWN_EMPTY_ELEMENT_SUFFIX', " />");
24
+
25
+ # Define the width of a tab for code blocks.
26
+ @define( 'MARKDOWN_TAB_WIDTH', 4 );
27
+
28
+
29
+ #
30
+ # WordPress settings:
31
+ #
32
+
33
+ # Change to false to remove Markdown from posts and/or comments.
34
+ @define( 'MARKDOWN_WP_POSTS', true );
35
+ @define( 'MARKDOWN_WP_COMMENTS', true );
36
+
37
+
38
+
39
+ ### Standard Function Interface ###
40
+
41
+ @define( 'MARKDOWN_PARSER_CLASS', 'Markdown_Parser' );
42
+
43
+ function Markdown($text) {
44
+ #
45
+ # Initialize the parser and return the result of its transform method.
46
+ #
47
+ # Setup static parser variable.
48
+ static $parser;
49
+ if (!isset($parser)) {
50
+ $parser_class = MARKDOWN_PARSER_CLASS;
51
+ $parser = new $parser_class;
52
+ }
53
+
54
+ # Transform text using parser.
55
+ return $parser->transform($text);
56
+ }
57
+
58
+
59
+ ### WordPress Plugin Interface ###
60
+
61
+ /*
62
+ Plugin Name: Markdown
63
+ Plugin URI: http://michelf.com/projects/php-markdown/
64
+ Description: <a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://michelf.com/projects/php-markdown/">More...</a>
65
+ Version: 1.0.1n
66
+ Author: Michel Fortin
67
+ Author URI: http://michelf.com/
68
+ */
69
+
70
+ if (isset($wp_version)) {
71
+ # More details about how it works here:
72
+ # <http://michelf.com/weblog/2005/wordpress-text-flow-vs-markdown/>
73
+
74
+ # Post content and excerpts
75
+ # - Remove WordPress paragraph generator.
76
+ # - Run Markdown on excerpt, then remove all tags.
77
+ # - Add paragraph tag around the excerpt, but remove it for the excerpt rss.
78
+ if (MARKDOWN_WP_POSTS) {
79
+ remove_filter('the_content', 'wpautop');
80
+ remove_filter('the_content_rss', 'wpautop');
81
+ remove_filter('the_excerpt', 'wpautop');
82
+ add_filter('the_content', 'Markdown', 6);
83
+ add_filter('the_content_rss', 'Markdown', 6);
84
+ add_filter('get_the_excerpt', 'Markdown', 6);
85
+ add_filter('get_the_excerpt', 'trim', 7);
86
+ add_filter('the_excerpt', 'mdwp_add_p');
87
+ add_filter('the_excerpt_rss', 'mdwp_strip_p');
88
+
89
+ remove_filter('content_save_pre', 'balanceTags', 50);
90
+ remove_filter('excerpt_save_pre', 'balanceTags', 50);
91
+ add_filter('the_content', 'balanceTags', 50);
92
+ add_filter('get_the_excerpt', 'balanceTags', 9);
93
+ }
94
+
95
+ # Comments
96
+ # - Remove WordPress paragraph generator.
97
+ # - Remove WordPress auto-link generator.
98
+ # - Scramble important tags before passing them to the kses filter.
99
+ # - Run Markdown on excerpt then remove paragraph tags.
100
+ if (MARKDOWN_WP_COMMENTS) {
101
+ remove_filter('comment_text', 'wpautop', 30);
102
+ remove_filter('comment_text', 'make_clickable');
103
+ add_filter('pre_comment_content', 'Markdown', 6);
104
+ add_filter('pre_comment_content', 'mdwp_hide_tags', 8);
105
+ add_filter('pre_comment_content', 'mdwp_show_tags', 12);
106
+ add_filter('get_comment_text', 'Markdown', 6);
107
+ add_filter('get_comment_excerpt', 'Markdown', 6);
108
+ add_filter('get_comment_excerpt', 'mdwp_strip_p', 7);
109
+
110
+ global $mdwp_hidden_tags, $mdwp_placeholders;
111
+ $mdwp_hidden_tags = explode(' ',
112
+ '<p> </p> <pre> </pre> <ol> </ol> <ul> </ul> <li> </li>');
113
+ $mdwp_placeholders = explode(' ', str_rot13(
114
+ 'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR '.
115
+ 'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli'));
116
+ }
117
+
118
+ function mdwp_add_p($text) {
119
+ if (!preg_match('{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text)) {
120
+ $text = '<p>'.$text.'</p>';
121
+ $text = preg_replace('{\n{2,}}', "</p>\n\n<p>", $text);
122
+ }
123
+ return $text;
124
+ }
125
+
126
+ function mdwp_strip_p($t) { return preg_replace('{</?p>}i', '', $t); }
127
+
128
+ function mdwp_hide_tags($text) {
129
+ global $mdwp_hidden_tags, $mdwp_placeholders;
130
+ return str_replace($mdwp_hidden_tags, $mdwp_placeholders, $text);
131
+ }
132
+ function mdwp_show_tags($text) {
133
+ global $mdwp_hidden_tags, $mdwp_placeholders;
134
+ return str_replace($mdwp_placeholders, $mdwp_hidden_tags, $text);
135
+ }
136
+ }
137
+
138
+
139
+ ### bBlog Plugin Info ###
140
+
141
+ function identify_modifier_markdown() {
142
+ return array(
143
+ 'name' => 'markdown',
144
+ 'type' => 'modifier',
145
+ 'nicename' => 'Markdown',
146
+ 'description' => 'A text-to-HTML conversion tool for web writers',
147
+ 'authors' => 'Michel Fortin and John Gruber',
148
+ 'licence' => 'BSD-like',
149
+ 'version' => MARKDOWN_VERSION,
150
+ 'help' => '<a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://michelf.com/projects/php-markdown/">More...</a>'
151
+ );
152
+ }
153
+
154
+
155
+ ### Smarty Modifier Interface ###
156
+
157
+ function smarty_modifier_markdown($text) {
158
+ return Markdown($text);
159
+ }
160
+
161
+
162
+ ### Textile Compatibility Mode ###
163
+
164
+ # Rename this file to "classTextile.php" and it can replace Textile everywhere.
165
+
166
+ if (strcasecmp(substr(__FILE__, -16), "classTextile.php") == 0) {
167
+ # Try to include PHP SmartyPants. Should be in the same directory.
168
+ @include_once 'smartypants.php';
169
+ # Fake Textile class. It calls Markdown instead.
170
+ class Textile {
171
+ function TextileThis($text, $lite='', $encode='') {
172
+ if ($lite == '' && $encode == '') $text = Markdown($text);
173
+ if (function_exists('SmartyPants')) $text = SmartyPants($text);
174
+ return $text;
175
+ }
176
+ # Fake restricted version: restrictions are not supported for now.
177
+ function TextileRestricted($text, $lite='', $noimage='') {
178
+ return $this->TextileThis($text, $lite);
179
+ }
180
+ # Workaround to ensure compatibility with TextPattern 4.0.3.
181
+ function blockLite($text) { return $text; }
182
+ }
183
+ }
184
+
185
+
186
+
187
+ #
188
+ # Markdown Parser Class
189
+ #
190
+
191
+ class Markdown_Parser {
192
+
193
+ # Regex to match balanced [brackets].
194
+ # Needed to insert a maximum bracked depth while converting to PHP.
195
+ var $nested_brackets_depth = 6;
196
+ var $nested_brackets_re;
197
+
198
+ var $nested_url_parenthesis_depth = 4;
199
+ var $nested_url_parenthesis_re;
200
+
201
+ # Table of hash values for escaped characters:
202
+ var $escape_chars = '\`*_{}[]()>#+-.!';
203
+ var $escape_chars_re;
204
+
205
+ # Change to ">" for HTML output.
206
+ var $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX;
207
+ var $tab_width = MARKDOWN_TAB_WIDTH;
208
+
209
+ # Change to `true` to disallow markup or entities.
210
+ var $no_markup = false;
211
+ var $no_entities = false;
212
+
213
+ # Predefined urls and titles for reference links and images.
214
+ var $predef_urls = array();
215
+ var $predef_titles = array();
216
+
217
+
218
+ function Markdown_Parser() {
219
+ #
220
+ # Constructor function. Initialize appropriate member variables.
221
+ #
222
+ $this->_initDetab();
223
+ $this->prepareItalicsAndBold();
224
+
225
+ $this->nested_brackets_re =
226
+ str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth).
227
+ str_repeat('\])*', $this->nested_brackets_depth);
228
+
229
+ $this->nested_url_parenthesis_re =
230
+ str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth).
231
+ str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth);
232
+
233
+ $this->escape_chars_re = '['.preg_quote($this->escape_chars).']';
234
+
235
+ # Sort document, block, and span gamut in ascendent priority order.
236
+ asort($this->document_gamut);
237
+ asort($this->block_gamut);
238
+ asort($this->span_gamut);
239
+ }
240
+
241
+
242
+ # Internal hashes used during transformation.
243
+ var $urls = array();
244
+ var $titles = array();
245
+ var $html_hashes = array();
246
+
247
+ # Status flag to avoid invalid nesting.
248
+ var $in_anchor = false;
249
+
250
+
251
+ function setup() {
252
+ #
253
+ # Called before the transformation process starts to setup parser
254
+ # states.
255
+ #
256
+ # Clear global hashes.
257
+ $this->urls = $this->predef_urls;
258
+ $this->titles = $this->predef_titles;
259
+ $this->html_hashes = array();
260
+
261
+ $in_anchor = false;
262
+ }
263
+
264
+ function teardown() {
265
+ #
266
+ # Called after the transformation process to clear any variable
267
+ # which may be taking up memory unnecessarly.
268
+ #
269
+ $this->urls = array();
270
+ $this->titles = array();
271
+ $this->html_hashes = array();
272
+ }
273
+
274
+
275
+ function transform($text) {
276
+ #
277
+ # Main function. Performs some preprocessing on the input text
278
+ # and pass it through the document gamut.
279
+ #
280
+ $this->setup();
281
+
282
+ # Remove UTF-8 BOM and marker character in input, if present.
283
+ $text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text);
284
+
285
+ # Standardize line endings:
286
+ # DOS to Unix and Mac to Unix
287
+ $text = preg_replace('{\r\n?}', "\n", $text);
288
+
289
+ # Make sure $text ends with a couple of newlines:
290
+ $text .= "\n\n";
291
+
292
+ # Convert all tabs to spaces.
293
+ $text = $this->detab($text);
294
+
295
+ # Turn block-level HTML blocks into hash entries
296
+ $text = $this->hashHTMLBlocks($text);
297
+
298
+ # Strip any lines consisting only of spaces and tabs.
299
+ # This makes subsequent regexen easier to write, because we can
300
+ # match consecutive blank lines with /\n+/ instead of something
301
+ # contorted like /[ ]*\n+/ .
302
+ $text = preg_replace('/^[ ]+$/m', '', $text);
303
+
304
+ # Run document gamut methods.
305
+ foreach ($this->document_gamut as $method => $priority) {
306
+ $text = $this->$method($text);
307
+ }
308
+
309
+ $this->teardown();
310
+
311
+ return $text . "\n";
312
+ }
313
+
314
+ var $document_gamut = array(
315
+ # Strip link definitions, store in hashes.
316
+ "stripLinkDefinitions" => 20,
317
+
318
+ "runBasicBlockGamut" => 30,
319
+ );
320
+
321
+
322
+ function stripLinkDefinitions($text) {
323
+ #
324
+ # Strips link definitions from text, stores the URLs and titles in
325
+ # hash references.
326
+ #
327
+ $less_than_tab = $this->tab_width - 1;
328
+
329
+ # Link defs are in the form: ^[id]: url "optional title"
330
+ $text = preg_replace_callback('{
331
+ ^[ ]{0,'.$less_than_tab.'}\[(.+)\][ ]?: # id = $1
332
+ [ ]*
333
+ \n? # maybe *one* newline
334
+ [ ]*
335
+ (?:
336
+ <(.+?)> # url = $2
337
+ |
338
+ (\S+?) # url = $3
339
+ )
340
+ [ ]*
341
+ \n? # maybe one newline
342
+ [ ]*
343
+ (?:
344
+ (?<=\s) # lookbehind for whitespace
345
+ ["(]
346
+ (.*?) # title = $4
347
+ [")]
348
+ [ ]*
349
+ )? # title is optional
350
+ (?:\n+|\Z)
351
+ }xm',
352
+ array(&$this, '_stripLinkDefinitions_callback'),
353
+ $text);
354
+ return $text;
355
+ }
356
+ function _stripLinkDefinitions_callback($matches) {
357
+ $link_id = strtolower($matches[1]);
358
+ $url = $matches[2] == '' ? $matches[3] : $matches[2];
359
+ $this->urls[$link_id] = $url;
360
+ $this->titles[$link_id] =& $matches[4];
361
+ return ''; # String that will replace the block
362
+ }
363
+
364
+
365
+ function hashHTMLBlocks($text) {
366
+ if ($this->no_markup) return $text;
367
+
368
+ $less_than_tab = $this->tab_width - 1;
369
+
370
+ # Hashify HTML blocks:
371
+ # We only want to do this for block-level HTML tags, such as headers,
372
+ # lists, and tables. That's because we still want to wrap <p>s around
373
+ # "paragraphs" that are wrapped in non-block-level tags, such as anchors,
374
+ # phrase emphasis, and spans. The list of tags we're looking for is
375
+ # hard-coded:
376
+ #
377
+ # * List "a" is made of tags which can be both inline or block-level.
378
+ # These will be treated block-level when the start tag is alone on
379
+ # its line, otherwise they're not matched here and will be taken as
380
+ # inline later.
381
+ # * List "b" is made of tags which are always block-level;
382
+ #
383
+ $block_tags_a_re = 'ins|del';
384
+ $block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'.
385
+ 'script|noscript|form|fieldset|iframe|math';
386
+
387
+ # Regular expression for the content of a block tag.
388
+ $nested_tags_level = 4;
389
+ $attr = '
390
+ (?> # optional tag attributes
391
+ \s # starts with whitespace
392
+ (?>
393
+ [^>"/]+ # text outside quotes
394
+ |
395
+ /+(?!>) # slash not followed by ">"
396
+ |
397
+ "[^"]*" # text inside double quotes (tolerate ">")
398
+ |
399
+ \'[^\']*\' # text inside single quotes (tolerate ">")
400
+ )*
401
+ )?
402
+ ';
403
+ $content =
404
+ str_repeat('
405
+ (?>
406
+ [^<]+ # content without tag
407
+ |
408
+ <\2 # nested opening tag
409
+ '.$attr.' # attributes
410
+ (?>
411
+ />
412
+ |
413
+ >', $nested_tags_level). # end of opening tag
414
+ '.*?'. # last level nested tag content
415
+ str_repeat('
416
+ </\2\s*> # closing nested tag
417
+ )
418
+ |
419
+ <(?!/\2\s*> # other tags with a different name
420
+ )
421
+ )*',
422
+ $nested_tags_level);
423
+ $content2 = str_replace('\2', '\3', $content);
424
+
425
+ # First, look for nested blocks, e.g.:
426
+ # <div>
427
+ # <div>
428
+ # tags for inner block must be indented.
429
+ # </div>
430
+ # </div>
431
+ #
432
+ # The outermost tags must start at the left margin for this to match, and
433
+ # the inner nested divs must be indented.
434
+ # We need to do this before the next, more liberal match, because the next
435
+ # match will start at the first `<div>` and stop at the first `</div>`.
436
+ $text = preg_replace_callback('{(?>
437
+ (?>
438
+ (?<=\n\n) # Starting after a blank line
439
+ | # or
440
+ \A\n? # the beginning of the doc
441
+ )
442
+ ( # save in $1
443
+
444
+ # Match from `\n<tag>` to `</tag>\n`, handling nested tags
445
+ # in between.
446
+
447
+ [ ]{0,'.$less_than_tab.'}
448
+ <('.$block_tags_b_re.')# start tag = $2
449
+ '.$attr.'> # attributes followed by > and \n
450
+ '.$content.' # content, support nesting
451
+ </\2> # the matching end tag
452
+ [ ]* # trailing spaces/tabs
453
+ (?=\n+|\Z) # followed by a newline or end of document
454
+
455
+ | # Special version for tags of group a.
456
+
457
+ [ ]{0,'.$less_than_tab.'}
458
+ <('.$block_tags_a_re.')# start tag = $3
459
+ '.$attr.'>[ ]*\n # attributes followed by >
460
+ '.$content2.' # content, support nesting
461
+ </\3> # the matching end tag
462
+ [ ]* # trailing spaces/tabs
463
+ (?=\n+|\Z) # followed by a newline or end of document
464
+
465
+ | # Special case just for <hr />. It was easier to make a special
466
+ # case than to make the other regex more complicated.
467
+
468
+ [ ]{0,'.$less_than_tab.'}
469
+ <(hr) # start tag = $2
470
+ '.$attr.' # attributes
471
+ /?> # the matching end tag
472
+ [ ]*
473
+ (?=\n{2,}|\Z) # followed by a blank line or end of document
474
+
475
+ | # Special case for standalone HTML comments:
476
+
477
+ [ ]{0,'.$less_than_tab.'}
478
+ (?s:
479
+ <!-- .*? -->
480
+ )
481
+ [ ]*
482
+ (?=\n{2,}|\Z) # followed by a blank line or end of document
483
+
484
+ | # PHP and ASP-style processor instructions (<? and <%)
485
+
486
+ [ ]{0,'.$less_than_tab.'}
487
+ (?s:
488
+ <([?%]) # $2
489
+ .*?
490
+ \2>
491
+ )
492
+ [ ]*
493
+ (?=\n{2,}|\Z) # followed by a blank line or end of document
494
+
495
+ )
496
+ )}Sxmi',
497
+ array(&$this, '_hashHTMLBlocks_callback'),
498
+ $text);
499
+
500
+ return $text;
501
+ }
502
+ function _hashHTMLBlocks_callback($matches) {
503
+ $text = $matches[1];
504
+ $key = $this->hashBlock($text);
505
+ return "\n\n$key\n\n";
506
+ }
507
+
508
+
509
+ function hashPart($text, $boundary = 'X') {
510
+ #
511
+ # Called whenever a tag must be hashed when a function insert an atomic
512
+ # element in the text stream. Passing $text to through this function gives
513
+ # a unique text-token which will be reverted back when calling unhash.
514
+ #
515
+ # The $boundary argument specify what character should be used to surround
516
+ # the token. By convension, "B" is used for block elements that needs not
517
+ # to be wrapped into paragraph tags at the end, ":" is used for elements
518
+ # that are word separators and "X" is used in the general case.
519
+ #
520
+ # Swap back any tag hash found in $text so we do not have to `unhash`
521
+ # multiple times at the end.
522
+ $text = $this->unhash($text);
523
+
524
+ # Then hash the block.
525
+ static $i = 0;
526
+ $key = "$boundary\x1A" . ++$i . $boundary;
527
+ $this->html_hashes[$key] = $text;
528
+ return $key; # String that will replace the tag.
529
+ }
530
+
531
+
532
+ function hashBlock($text) {
533
+ #
534
+ # Shortcut function for hashPart with block-level boundaries.
535
+ #
536
+ return $this->hashPart($text, 'B');
537
+ }
538
+
539
+
540
+ var $block_gamut = array(
541
+ #
542
+ # These are all the transformations that form block-level
543
+ # tags like paragraphs, headers, and list items.
544
+ #
545
+ "doHeaders" => 10,
546
+ "doHorizontalRules" => 20,
547
+
548
+ "doLists" => 40,
549
+ "doCodeBlocks" => 50,
550
+ "doBlockQuotes" => 60,
551
+ );
552
+
553
+ function runBlockGamut($text) {
554
+ #
555
+ # Run block gamut tranformations.
556
+ #
557
+ # We need to escape raw HTML in Markdown source before doing anything
558
+ # else. This need to be done for each block, and not only at the
559
+ # begining in the Markdown function since hashed blocks can be part of
560
+ # list items and could have been indented. Indented blocks would have
561
+ # been seen as a code block in a previous pass of hashHTMLBlocks.
562
+ $text = $this->hashHTMLBlocks($text);
563
+
564
+ return $this->runBasicBlockGamut($text);
565
+ }
566
+
567
+ function runBasicBlockGamut($text) {
568
+ #
569
+ # Run block gamut tranformations, without hashing HTML blocks. This is
570
+ # useful when HTML blocks are known to be already hashed, like in the first
571
+ # whole-document pass.
572
+ #
573
+ foreach ($this->block_gamut as $method => $priority) {
574
+ $text = $this->$method($text);
575
+ }
576
+
577
+ # Finally form paragraph and restore hashed blocks.
578
+ $text = $this->formParagraphs($text);
579
+
580
+ return $text;
581
+ }
582
+
583
+
584
+ function doHorizontalRules($text) {
585
+ # Do Horizontal Rules:
586
+ return preg_replace(
587
+ '{
588
+ ^[ ]{0,3} # Leading space
589
+ ([-*_]) # $1: First marker
590
+ (?> # Repeated marker group
591
+ [ ]{0,2} # Zero, one, or two spaces.
592
+ \1 # Marker character
593
+ ){2,} # Group repeated at least twice
594
+ [ ]* # Tailing spaces
595
+ $ # End of line.
596
+ }mx',
597
+ "\n".$this->hashBlock("<hr$this->empty_element_suffix")."\n",
598
+ $text);
599
+ }
600
+
601
+
602
+ var $span_gamut = array(
603
+ #
604
+ # These are all the transformations that occur *within* block-level
605
+ # tags like paragraphs, headers, and list items.
606
+ #
607
+ # Process character escapes, code spans, and inline HTML
608
+ # in one shot.
609
+ "parseSpan" => -30,
610
+
611
+ # Process anchor and image tags. Images must come first,
612
+ # because ![foo][f] looks like an anchor.
613
+ "doImages" => 10,
614
+ "doAnchors" => 20,
615
+
616
+ # Make links out of things like `<http://example.com/>`
617
+ # Must come after doAnchors, because you can use < and >
618
+ # delimiters in inline links like [this](<url>).
619
+ "doAutoLinks" => 30,
620
+ "encodeAmpsAndAngles" => 40,
621
+
622
+ "doItalicsAndBold" => 50,
623
+ "doHardBreaks" => 60,
624
+ );
625
+
626
+ function runSpanGamut($text) {
627
+ #
628
+ # Run span gamut tranformations.
629
+ #
630
+ foreach ($this->span_gamut as $method => $priority) {
631
+ $text = $this->$method($text);
632
+ }
633
+
634
+ return $text;
635
+ }
636
+
637
+
638
+ function doHardBreaks($text) {
639
+ # Do hard breaks:
640
+ return preg_replace_callback('/ {2,}\n/',
641
+ array(&$this, '_doHardBreaks_callback'), $text);
642
+ }
643
+ function _doHardBreaks_callback($matches) {
644
+ return $this->hashPart("<br$this->empty_element_suffix\n");
645
+ }
646
+
647
+
648
+ function doAnchors($text) {
649
+ #
650
+ # Turn Markdown link shortcuts into XHTML <a> tags.
651
+ #
652
+ if ($this->in_anchor) return $text;
653
+ $this->in_anchor = true;
654
+
655
+ #
656
+ # First, handle reference-style links: [link text] [id]
657
+ #
658
+ $text = preg_replace_callback('{
659
+ ( # wrap whole match in $1
660
+ \[
661
+ ('.$this->nested_brackets_re.') # link text = $2
662
+ \]
663
+
664
+ [ ]? # one optional space
665
+ (?:\n[ ]*)? # one optional newline followed by spaces
666
+
667
+ \[
668
+ (.*?) # id = $3
669
+ \]
670
+ )
671
+ }xs',
672
+ array(&$this, '_doAnchors_reference_callback'), $text);
673
+
674
+ #
675
+ # Next, inline-style links: [link text](url "optional title")
676
+ #
677
+ $text = preg_replace_callback('{
678
+ ( # wrap whole match in $1
679
+ \[
680
+ ('.$this->nested_brackets_re.') # link text = $2
681
+ \]
682
+ \( # literal paren
683
+ [ \n]*
684
+ (?:
685
+ <(.+?)> # href = $3
686
+ |
687
+ ('.$this->nested_url_parenthesis_re.') # href = $4
688
+ )
689
+ [ \n]*
690
+ ( # $5
691
+ ([\'"]) # quote char = $6
692
+ (.*?) # Title = $7
693
+ \6 # matching quote
694
+ [ \n]* # ignore any spaces/tabs between closing quote and )
695
+ )? # title is optional
696
+ \)
697
+ )
698
+ }xs',
699
+ array(&$this, '_doAnchors_inline_callback'), $text);
700
+
701
+ #
702
+ # Last, handle reference-style shortcuts: [link text]
703
+ # These must come last in case you've also got [link text][1]
704
+ # or [link text](/foo)
705
+ #
706
+ $text = preg_replace_callback('{
707
+ ( # wrap whole match in $1
708
+ \[
709
+ ([^\[\]]+) # link text = $2; can\'t contain [ or ]
710
+ \]
711
+ )
712
+ }xs',
713
+ array(&$this, '_doAnchors_reference_callback'), $text);
714
+
715
+ $this->in_anchor = false;
716
+ return $text;
717
+ }
718
+ function _doAnchors_reference_callback($matches) {
719
+ $whole_match = $matches[1];
720
+ $link_text = $matches[2];
721
+ $link_id =& $matches[3];
722
+
723
+ if ($link_id == "") {
724
+ # for shortcut links like [this][] or [this].
725
+ $link_id = $link_text;
726
+ }
727
+
728
+ # lower-case and turn embedded newlines into spaces
729
+ $link_id = strtolower($link_id);
730
+ $link_id = preg_replace('{[ ]?\n}', ' ', $link_id);
731
+
732
+ if (isset($this->urls[$link_id])) {
733
+ $url = $this->urls[$link_id];
734
+ $url = $this->encodeAttribute($url);
735
+
736
+ $result = "<a href=\"$url\"";
737
+ if ( isset( $this->titles[$link_id] ) ) {
738
+ $title = $this->titles[$link_id];
739
+ $title = $this->encodeAttribute($title);
740
+ $result .= " title=\"$title\"";
741
+ }
742
+
743
+ $link_text = $this->runSpanGamut($link_text);
744
+ $result .= ">$link_text</a>";
745
+ $result = $this->hashPart($result);
746
+ }
747
+ else {
748
+ $result = $whole_match;
749
+ }
750
+ return $result;
751
+ }
752
+ function _doAnchors_inline_callback($matches) {
753
+ $whole_match = $matches[1];
754
+ $link_text = $this->runSpanGamut($matches[2]);
755
+ $url = $matches[3] == '' ? $matches[4] : $matches[3];
756
+ $title =& $matches[7];
757
+
758
+ $url = $this->encodeAttribute($url);
759
+
760
+ $result = "<a href=\"$url\"";
761
+ if (isset($title)) {
762
+ $title = $this->encodeAttribute($title);
763
+ $result .= " title=\"$title\"";
764
+ }
765
+
766
+ $link_text = $this->runSpanGamut($link_text);
767
+ $result .= ">$link_text</a>";
768
+
769
+ return $this->hashPart($result);
770
+ }
771
+
772
+
773
+ function doImages($text) {
774
+ #
775
+ # Turn Markdown image shortcuts into <img> tags.
776
+ #
777
+ #
778
+ # First, handle reference-style labeled images: ![alt text][id]
779
+ #
780
+ $text = preg_replace_callback('{
781
+ ( # wrap whole match in $1
782
+ !\[
783
+ ('.$this->nested_brackets_re.') # alt text = $2
784
+ \]
785
+
786
+ [ ]? # one optional space
787
+ (?:\n[ ]*)? # one optional newline followed by spaces
788
+
789
+ \[
790
+ (.*?) # id = $3
791
+ \]
792
+
793
+ )
794
+ }xs',
795
+ array(&$this, '_doImages_reference_callback'), $text);
796
+
797
+ #
798
+ # Next, handle inline images: ![alt text](url "optional title")
799
+ # Don't forget: encode * and _
800
+ #
801
+ $text = preg_replace_callback('{
802
+ ( # wrap whole match in $1
803
+ !\[
804
+ ('.$this->nested_brackets_re.') # alt text = $2
805
+ \]
806
+ \s? # One optional whitespace character
807
+ \( # literal paren
808
+ [ \n]*
809
+ (?:
810
+ <(\S*)> # src url = $3
811
+ |
812
+ ('.$this->nested_url_parenthesis_re.') # src url = $4
813
+ )
814
+ [ \n]*
815
+ ( # $5
816
+ ([\'"]) # quote char = $6
817
+ (.*?) # title = $7
818
+ \6 # matching quote
819
+ [ \n]*
820
+ )? # title is optional
821
+ \)
822
+ )
823
+ }xs',
824
+ array(&$this, '_doImages_inline_callback'), $text);
825
+
826
+ return $text;
827
+ }
828
+ function _doImages_reference_callback($matches) {
829
+ $whole_match = $matches[1];
830
+ $alt_text = $matches[2];
831
+ $link_id = strtolower($matches[3]);
832
+
833
+ if ($link_id == "") {
834
+ $link_id = strtolower($alt_text); # for shortcut links like ![this][].
835
+ }
836
+
837
+ $alt_text = $this->encodeAttribute($alt_text);
838
+ if (isset($this->urls[$link_id])) {
839
+ $url = $this->encodeAttribute($this->urls[$link_id]);
840
+ $result = "<img src=\"$url\" alt=\"$alt_text\"";
841
+ if (isset($this->titles[$link_id])) {
842
+ $title = $this->titles[$link_id];
843
+ $title = $this->encodeAttribute($title);
844
+ $result .= " title=\"$title\"";
845
+ }
846
+ $result .= $this->empty_element_suffix;
847
+ $result = $this->hashPart($result);
848
+ }
849
+ else {
850
+ # If there's no such link ID, leave intact:
851
+ $result = $whole_match;
852
+ }
853
+
854
+ return $result;
855
+ }
856
+ function _doImages_inline_callback($matches) {
857
+ $whole_match = $matches[1];
858
+ $alt_text = $matches[2];
859
+ $url = $matches[3] == '' ? $matches[4] : $matches[3];
860
+ $title =& $matches[7];
861
+
862
+ $alt_text = $this->encodeAttribute($alt_text);
863
+ $url = $this->encodeAttribute($url);
864
+ $result = "<img src=\"$url\" alt=\"$alt_text\"";
865
+ if (isset($title)) {
866
+ $title = $this->encodeAttribute($title);
867
+ $result .= " title=\"$title\""; # $title already quoted
868
+ }
869
+ $result .= $this->empty_element_suffix;
870
+
871
+ return $this->hashPart($result);
872
+ }
873
+
874
+
875
+ function doHeaders($text) {
876
+ # Setext-style headers:
877
+ # Header 1
878
+ # ========
879
+ #
880
+ # Header 2
881
+ # --------
882
+ #
883
+ $text = preg_replace_callback('{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx',
884
+ array(&$this, '_doHeaders_callback_setext'), $text);
885
+
886
+ # atx-style headers:
887
+ # # Header 1
888
+ # ## Header 2
889
+ # ## Header 2 with closing hashes ##
890
+ # ...
891
+ # ###### Header 6
892
+ #
893
+ $text = preg_replace_callback('{
894
+ ^(\#{1,6}) # $1 = string of #\'s
895
+ [ ]*
896
+ (.+?) # $2 = Header text
897
+ [ ]*
898
+ \#* # optional closing #\'s (not counted)
899
+ \n+
900
+ }xm',
901
+ array(&$this, '_doHeaders_callback_atx'), $text);
902
+
903
+ return $text;
904
+ }
905
+ function _doHeaders_callback_setext($matches) {
906
+ # Terrible hack to check we haven't found an empty list item.
907
+ if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1]))
908
+ return $matches[0];
909
+
910
+ $level = $matches[2]{0} == '=' ? 1 : 2;
911
+ $block = "<h$level>".$this->runSpanGamut($matches[1])."</h$level>";
912
+ return "\n" . $this->hashBlock($block) . "\n\n";
913
+ }
914
+ function _doHeaders_callback_atx($matches) {
915
+ $level = strlen($matches[1]);
916
+ $block = "<h$level>".$this->runSpanGamut($matches[2])."</h$level>";
917
+ return "\n" . $this->hashBlock($block) . "\n\n";
918
+ }
919
+
920
+
921
+ function doLists($text) {
922
+ #
923
+ # Form HTML ordered (numbered) and unordered (bulleted) lists.
924
+ #
925
+ $less_than_tab = $this->tab_width - 1;
926
+
927
+ # Re-usable patterns to match list item bullets and number markers:
928
+ $marker_ul_re = '[*+-]';
929
+ $marker_ol_re = '\d+[.]';
930
+ $marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
931
+
932
+ $markers_relist = array(
933
+ $marker_ul_re => $marker_ol_re,
934
+ $marker_ol_re => $marker_ul_re,
935
+ );
936
+
937
+ foreach ($markers_relist as $marker_re => $other_marker_re) {
938
+ # Re-usable pattern to match any entirel ul or ol list:
939
+ $whole_list_re = '
940
+ ( # $1 = whole list
941
+ ( # $2
942
+ ([ ]{0,'.$less_than_tab.'}) # $3 = number of spaces
943
+ ('.$marker_re.') # $4 = first list item marker
944
+ [ ]+
945
+ )
946
+ (?s:.+?)
947
+ ( # $5
948
+ \z
949
+ |
950
+ \n{2,}
951
+ (?=\S)
952
+ (?! # Negative lookahead for another list item marker
953
+ [ ]*
954
+ '.$marker_re.'[ ]+
955
+ )
956
+ |
957
+ (?= # Lookahead for another kind of list
958
+ \n
959
+ \3 # Must have the same indentation
960
+ '.$other_marker_re.'[ ]+
961
+ )
962
+ )
963
+ )
964
+ '; // mx
965
+
966
+ # We use a different prefix before nested lists than top-level lists.
967
+ # See extended comment in _ProcessListItems().
968
+
969
+ if ($this->list_level) {
970
+ $text = preg_replace_callback('{
971
+ ^
972
+ '.$whole_list_re.'
973
+ }mx',
974
+ array(&$this, '_doLists_callback'), $text);
975
+ }
976
+ else {
977
+ $text = preg_replace_callback('{
978
+ (?:(?<=\n)\n|\A\n?) # Must eat the newline
979
+ '.$whole_list_re.'
980
+ }mx',
981
+ array(&$this, '_doLists_callback'), $text);
982
+ }
983
+ }
984
+
985
+ return $text;
986
+ }
987
+ function _doLists_callback($matches) {
988
+ # Re-usable patterns to match list item bullets and number markers:
989
+ $marker_ul_re = '[*+-]';
990
+ $marker_ol_re = '\d+[.]';
991
+ $marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
992
+
993
+ $list = $matches[1];
994
+ $list_type = preg_match("/$marker_ul_re/", $matches[4]) ? "ul" : "ol";
995
+
996
+ $marker_any_re = ( $list_type == "ul" ? $marker_ul_re : $marker_ol_re );
997
+
998
+ $list .= "\n";
999
+ $result = $this->processListItems($list, $marker_any_re);
1000
+
1001
+ $result = $this->hashBlock("<$list_type>\n" . $result . "</$list_type>");
1002
+ return "\n". $result ."\n\n";
1003
+ }
1004
+
1005
+ var $list_level = 0;
1006
+
1007
+ function processListItems($list_str, $marker_any_re) {
1008
+ #
1009
+ # Process the contents of a single ordered or unordered list, splitting it
1010
+ # into individual list items.
1011
+ #
1012
+ # The $this->list_level global keeps track of when we're inside a list.
1013
+ # Each time we enter a list, we increment it; when we leave a list,
1014
+ # we decrement. If it's zero, we're not in a list anymore.
1015
+ #
1016
+ # We do this because when we're not inside a list, we want to treat
1017
+ # something like this:
1018
+ #
1019
+ # I recommend upgrading to version
1020
+ # 8. Oops, now this line is treated
1021
+ # as a sub-list.
1022
+ #
1023
+ # As a single paragraph, despite the fact that the second line starts
1024
+ # with a digit-period-space sequence.
1025
+ #
1026
+ # Whereas when we're inside a list (or sub-list), that line will be
1027
+ # treated as the start of a sub-list. What a kludge, huh? This is
1028
+ # an aspect of Markdown's syntax that's hard to parse perfectly
1029
+ # without resorting to mind-reading. Perhaps the solution is to
1030
+ # change the syntax rules such that sub-lists must start with a
1031
+ # starting cardinal number; e.g. "1." or "a.".
1032
+
1033
+ $this->list_level++;
1034
+
1035
+ # trim trailing blank lines:
1036
+ $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
1037
+
1038
+ $list_str = preg_replace_callback('{
1039
+ (\n)? # leading line = $1
1040
+ (^[ ]*) # leading whitespace = $2
1041
+ ('.$marker_any_re.' # list marker and space = $3
1042
+ (?:[ ]+|(?=\n)) # space only required if item is not empty
1043
+ )
1044
+ ((?s:.*?)) # list item text = $4
1045
+ (?:(\n+(?=\n))|\n) # tailing blank line = $5
1046
+ (?= \n* (\z | \2 ('.$marker_any_re.') (?:[ ]+|(?=\n))))
1047
+ }xm',
1048
+ array(&$this, '_processListItems_callback'), $list_str);
1049
+
1050
+ $this->list_level--;
1051
+ return $list_str;
1052
+ }
1053
+ function _processListItems_callback($matches) {
1054
+ $item = $matches[4];
1055
+ $leading_line =& $matches[1];
1056
+ $leading_space =& $matches[2];
1057
+ $marker_space = $matches[3];
1058
+ $tailing_blank_line =& $matches[5];
1059
+
1060
+ if ($leading_line || $tailing_blank_line ||
1061
+ preg_match('/\n{2,}/', $item))
1062
+ {
1063
+ # Replace marker with the appropriate whitespace indentation
1064
+ $item = $leading_space . str_repeat(' ', strlen($marker_space)) . $item;
1065
+ $item = $this->runBlockGamut($this->outdent($item)."\n");
1066
+ }
1067
+ else {
1068
+ # Recursion for sub-lists:
1069
+ $item = $this->doLists($this->outdent($item));
1070
+ $item = preg_replace('/\n+$/', '', $item);
1071
+ $item = $this->runSpanGamut($item);
1072
+ }
1073
+
1074
+ return "<li>" . $item . "</li>\n";
1075
+ }
1076
+
1077
+
1078
+ function doCodeBlocks($text) {
1079
+ #
1080
+ # Process Markdown `<pre><code>` blocks.
1081
+ #
1082
+ $text = preg_replace_callback('{
1083
+ (?:\n\n|\A\n?)
1084
+ ( # $1 = the code block -- one or more lines, starting with a space/tab
1085
+ (?>
1086
+ [ ]{'.$this->tab_width.'} # Lines must start with a tab or a tab-width of spaces
1087
+ .*\n+
1088
+ )+
1089
+ )
1090
+ ((?=^[ ]{0,'.$this->tab_width.'}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
1091
+ }xm',
1092
+ array(&$this, '_doCodeBlocks_callback'), $text);
1093
+
1094
+ return $text;
1095
+ }
1096
+ function _doCodeBlocks_callback($matches) {
1097
+ $codeblock = $matches[1];
1098
+
1099
+ $codeblock = $this->outdent($codeblock);
1100
+ $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
1101
+
1102
+ # trim leading newlines and trailing newlines
1103
+ $codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock);
1104
+
1105
+ $codeblock = "<pre><code>$codeblock\n</code></pre>";
1106
+ return "\n\n".$this->hashBlock($codeblock)."\n\n";
1107
+ }
1108
+
1109
+
1110
+ function makeCodeSpan($code) {
1111
+ #
1112
+ # Create a code span markup for $code. Called from handleSpanToken.
1113
+ #
1114
+ $code = htmlspecialchars(trim($code), ENT_NOQUOTES);
1115
+ return $this->hashPart("<code>$code</code>");
1116
+ }
1117
+
1118
+
1119
+ var $em_relist = array(
1120
+ '' => '(?:(?<!\*)\*(?!\*)|(?<!_)_(?!_))(?=\S|$)(?![.,:;]\s)',
1121
+ '*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
1122
+ '_' => '(?<=\S|^)(?<!_)_(?!_)',
1123
+ );
1124
+ var $strong_relist = array(
1125
+ '' => '(?:(?<!\*)\*\*(?!\*)|(?<!_)__(?!_))(?=\S|$)(?![.,:;]\s)',
1126
+ '**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
1127
+ '__' => '(?<=\S|^)(?<!_)__(?!_)',
1128
+ );
1129
+ var $em_strong_relist = array(
1130
+ '' => '(?:(?<!\*)\*\*\*(?!\*)|(?<!_)___(?!_))(?=\S|$)(?![.,:;]\s)',
1131
+ '***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
1132
+ '___' => '(?<=\S|^)(?<!_)___(?!_)',
1133
+ );
1134
+ var $em_strong_prepared_relist;
1135
+
1136
+ function prepareItalicsAndBold() {
1137
+ #
1138
+ # Prepare regular expressions for searching emphasis tokens in any
1139
+ # context.
1140
+ #
1141
+ foreach ($this->em_relist as $em => $em_re) {
1142
+ foreach ($this->strong_relist as $strong => $strong_re) {
1143
+ # Construct list of allowed token expressions.
1144
+ $token_relist = array();
1145
+ if (isset($this->em_strong_relist["$em$strong"])) {
1146
+ $token_relist[] = $this->em_strong_relist["$em$strong"];
1147
+ }
1148
+ $token_relist[] = $em_re;
1149
+ $token_relist[] = $strong_re;
1150
+
1151
+ # Construct master expression from list.
1152
+ $token_re = '{('. implode('|', $token_relist) .')}';
1153
+ $this->em_strong_prepared_relist["$em$strong"] = $token_re;
1154
+ }
1155
+ }
1156
+ }
1157
+
1158
+ function doItalicsAndBold($text) {
1159
+ $token_stack = array('');
1160
+ $text_stack = array('');
1161
+ $em = '';
1162
+ $strong = '';
1163
+ $tree_char_em = false;
1164
+
1165
+ while (1) {
1166
+ #
1167
+ # Get prepared regular expression for seraching emphasis tokens
1168
+ # in current context.
1169
+ #
1170
+ $token_re = $this->em_strong_prepared_relist["$em$strong"];
1171
+
1172
+ #
1173
+ # Each loop iteration search for the next emphasis token.
1174
+ # Each token is then passed to handleSpanToken.
1175
+ #
1176
+ $parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
1177
+ $text_stack[0] .= $parts[0];
1178
+ $token =& $parts[1];
1179
+ $text =& $parts[2];
1180
+
1181
+ if (empty($token)) {
1182
+ # Reached end of text span: empty stack without emitting.
1183
+ # any more emphasis.
1184
+ while ($token_stack[0]) {
1185
+ $text_stack[1] .= array_shift($token_stack);
1186
+ $text_stack[0] .= array_shift($text_stack);
1187
+ }
1188
+ break;
1189
+ }
1190
+
1191
+ $token_len = strlen($token);
1192
+ if ($tree_char_em) {
1193
+ # Reached closing marker while inside a three-char emphasis.
1194
+ if ($token_len == 3) {
1195
+ # Three-char closing marker, close em and strong.
1196
+ array_shift($token_stack);
1197
+ $span = array_shift($text_stack);
1198
+ $span = $this->runSpanGamut($span);
1199
+ $span = "<strong><em>$span</em></strong>";
1200
+ $text_stack[0] .= $this->hashPart($span);
1201
+ $em = '';
1202
+ $strong = '';
1203
+ } else {
1204
+ # Other closing marker: close one em or strong and
1205
+ # change current token state to match the other
1206
+ $token_stack[0] = str_repeat($token{0}, 3-$token_len);
1207
+ $tag = $token_len == 2 ? "strong" : "em";
1208
+ $span = $text_stack[0];
1209
+ $span = $this->runSpanGamut($span);
1210
+ $span = "<$tag>$span</$tag>";
1211
+ $text_stack[0] = $this->hashPart($span);
1212
+ $$tag = ''; # $$tag stands for $em or $strong
1213
+ }
1214
+ $tree_char_em = false;
1215
+ } else if ($token_len == 3) {
1216
+ if ($em) {
1217
+ # Reached closing marker for both em and strong.
1218
+ # Closing strong marker:
1219
+ for ($i = 0; $i < 2; ++$i) {
1220
+ $shifted_token = array_shift($token_stack);
1221
+ $tag = strlen($shifted_token) == 2 ? "strong" : "em";
1222
+ $span = array_shift($text_stack);
1223
+ $span = $this->runSpanGamut($span);
1224
+ $span = "<$tag>$span</$tag>";
1225
+ $text_stack[0] .= $this->hashPart($span);
1226
+ $$tag = ''; # $$tag stands for $em or $strong
1227
+ }
1228
+ } else {
1229
+ # Reached opening three-char emphasis marker. Push on token
1230
+ # stack; will be handled by the special condition above.
1231
+ $em = $token{0};
1232
+ $strong = "$em$em";
1233
+ array_unshift($token_stack, $token);
1234
+ array_unshift($text_stack, '');
1235
+ $tree_char_em = true;
1236
+ }
1237
+ } else if ($token_len == 2) {
1238
+ if ($strong) {
1239
+ # Unwind any dangling emphasis marker:
1240
+ if (strlen($token_stack[0]) == 1) {
1241
+ $text_stack[1] .= array_shift($token_stack);
1242
+ $text_stack[0] .= array_shift($text_stack);
1243
+ }
1244
+ # Closing strong marker:
1245
+ array_shift($token_stack);
1246
+ $span = array_shift($text_stack);
1247
+ $span = $this->runSpanGamut($span);
1248
+ $span = "<strong>$span</strong>";
1249
+ $text_stack[0] .= $this->hashPart($span);
1250
+ $strong = '';
1251
+ } else {
1252
+ array_unshift($token_stack, $token);
1253
+ array_unshift($text_stack, '');
1254
+ $strong = $token;
1255
+ }
1256
+ } else {
1257
+ # Here $token_len == 1
1258
+ if ($em) {
1259
+ if (strlen($token_stack[0]) == 1) {
1260
+ # Closing emphasis marker:
1261
+ array_shift($token_stack);
1262
+ $span = array_shift($text_stack);
1263
+ $span = $this->runSpanGamut($span);
1264
+ $span = "<em>$span</em>";
1265
+ $text_stack[0] .= $this->hashPart($span);
1266
+ $em = '';
1267
+ } else {
1268
+ $text_stack[0] .= $token;
1269
+ }
1270
+ } else {
1271
+ array_unshift($token_stack, $token);
1272
+ array_unshift($text_stack, '');
1273
+ $em = $token;
1274
+ }
1275
+ }
1276
+ }
1277
+ return $text_stack[0];
1278
+ }
1279
+
1280
+
1281
+ function doBlockQuotes($text) {
1282
+ $text = preg_replace_callback('/
1283
+ ( # Wrap whole match in $1
1284
+ (?>
1285
+ ^[ ]*>[ ]? # ">" at the start of a line
1286
+ .+\n # rest of the first line
1287
+ (.+\n)* # subsequent consecutive lines
1288
+ \n* # blanks
1289
+ )+
1290
+ )
1291
+ /xm',
1292
+ array(&$this, '_doBlockQuotes_callback'), $text);
1293
+
1294
+ return $text;
1295
+ }
1296
+ function _doBlockQuotes_callback($matches) {
1297
+ $bq = $matches[1];
1298
+ # trim one level of quoting - trim whitespace-only lines
1299
+ $bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq);
1300
+ $bq = $this->runBlockGamut($bq); # recurse
1301
+
1302
+ $bq = preg_replace('/^/m', " ", $bq);
1303
+ # These leading spaces cause problem with <pre> content,
1304
+ # so we need to fix that:
1305
+ $bq = preg_replace_callback('{(\s*<pre>.+?</pre>)}sx',
1306
+ array(&$this, '_doBlockQuotes_callback2'), $bq);
1307
+
1308
+ return "\n". $this->hashBlock("<blockquote>\n$bq\n</blockquote>")."\n\n";
1309
+ }
1310
+ function _doBlockQuotes_callback2($matches) {
1311
+ $pre = $matches[1];
1312
+ $pre = preg_replace('/^ /m', '', $pre);
1313
+ return $pre;
1314
+ }
1315
+
1316
+
1317
+ function formParagraphs($text) {
1318
+ #
1319
+ # Params:
1320
+ # $text - string to process with html <p> tags
1321
+ #
1322
+ # Strip leading and trailing lines:
1323
+ $text = preg_replace('/\A\n+|\n+\z/', '', $text);
1324
+
1325
+ $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
1326
+
1327
+ #
1328
+ # Wrap <p> tags and unhashify HTML blocks
1329
+ #
1330
+ foreach ($grafs as $key => $value) {
1331
+ if (!preg_match('/^B\x1A[0-9]+B$/', $value)) {
1332
+ # Is a paragraph.
1333
+ $value = $this->runSpanGamut($value);
1334
+ $value = preg_replace('/^([ ]*)/', "<p>", $value);
1335
+ $value .= "</p>";
1336
+ $grafs[$key] = $this->unhash($value);
1337
+ }
1338
+ else {
1339
+ # Is a block.
1340
+ # Modify elements of @grafs in-place...
1341
+ $graf = $value;
1342
+ $block = $this->html_hashes[$graf];
1343
+ $graf = $block;
1344
+ // if (preg_match('{
1345
+ // \A
1346
+ // ( # $1 = <div> tag
1347
+ // <div \s+
1348
+ // [^>]*
1349
+ // \b
1350
+ // markdown\s*=\s* ([\'"]) # $2 = attr quote char
1351
+ // 1
1352
+ // \2
1353
+ // [^>]*
1354
+ // >
1355
+ // )
1356
+ // ( # $3 = contents
1357
+ // .*
1358
+ // )
1359
+ // (</div>) # $4 = closing tag
1360
+ // \z
1361
+ // }xs', $block, $matches))
1362
+ // {
1363
+ // list(, $div_open, , $div_content, $div_close) = $matches;
1364
+ //
1365
+ // # We can't call Markdown(), because that resets the hash;
1366
+ // # that initialization code should be pulled into its own sub, though.
1367
+ // $div_content = $this->hashHTMLBlocks($div_content);
1368
+ //
1369
+ // # Run document gamut methods on the content.
1370
+ // foreach ($this->document_gamut as $method => $priority) {
1371
+ // $div_content = $this->$method($div_content);
1372
+ // }
1373
+ //
1374
+ // $div_open = preg_replace(
1375
+ // '{\smarkdown\s*=\s*([\'"]).+?\1}', '', $div_open);
1376
+ //
1377
+ // $graf = $div_open . "\n" . $div_content . "\n" . $div_close;
1378
+ // }
1379
+ $grafs[$key] = $graf;
1380
+ }
1381
+ }
1382
+
1383
+ return implode("\n\n", $grafs);
1384
+ }
1385
+
1386
+
1387
+ function encodeAttribute($text) {
1388
+ #
1389
+ # Encode text for a double-quoted HTML attribute. This function
1390
+ # is *not* suitable for attributes enclosed in single quotes.
1391
+ #
1392
+ $text = $this->encodeAmpsAndAngles($text);
1393
+ $text = str_replace('"', '&quot;', $text);
1394
+ return $text;
1395
+ }
1396
+
1397
+
1398
+ function encodeAmpsAndAngles($text) {
1399
+ #
1400
+ # Smart processing for ampersands and angle brackets that need to
1401
+ # be encoded. Valid character entities are left alone unless the
1402
+ # no-entities mode is set.
1403
+ #
1404
+ if ($this->no_entities) {
1405
+ $text = str_replace('&', '&amp;', $text);
1406
+ } else {
1407
+ # Ampersand-encoding based entirely on Nat Irons's Amputator
1408
+ # MT plugin: <http://bumppo.net/projects/amputator/>
1409
+ $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
1410
+ '&amp;', $text);;
1411
+ }
1412
+ # Encode remaining <'s
1413
+ $text = str_replace('<', '&lt;', $text);
1414
+
1415
+ return $text;
1416
+ }
1417
+
1418
+
1419
+ function doAutoLinks($text) {
1420
+ $text = preg_replace_callback('{<((https?|ftp|dict):[^\'">\s]+)>}i',
1421
+ array(&$this, '_doAutoLinks_url_callback'), $text);
1422
+
1423
+ # Email addresses: <address@domain.foo>
1424
+ $text = preg_replace_callback('{
1425
+ <
1426
+ (?:mailto:)?
1427
+ (
1428
+ (?:
1429
+ [-!#$%&\'*+/=?^_`.{|}~\w\x80-\xFF]+
1430
+ |
1431
+ ".*?"
1432
+ )
1433
+ \@
1434
+ (?:
1435
+ [-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+
1436
+ |
1437
+ \[[\d.a-fA-F:]+\] # IPv4 & IPv6
1438
+ )
1439
+ )
1440
+ >
1441
+ }xi',
1442
+ array(&$this, '_doAutoLinks_email_callback'), $text);
1443
+
1444
+ return $text;
1445
+ }
1446
+ function _doAutoLinks_url_callback($matches) {
1447
+ $url = $this->encodeAttribute($matches[1]);
1448
+ $link = "<a href=\"$url\">$url</a>";
1449
+ return $this->hashPart($link);
1450
+ }
1451
+ function _doAutoLinks_email_callback($matches) {
1452
+ $address = $matches[1];
1453
+ $link = $this->encodeEmailAddress($address);
1454
+ return $this->hashPart($link);
1455
+ }
1456
+
1457
+
1458
+ function encodeEmailAddress($addr) {
1459
+ #
1460
+ # Input: an email address, e.g. "foo@example.com"
1461
+ #
1462
+ # Output: the email address as a mailto link, with each character
1463
+ # of the address encoded as either a decimal or hex entity, in
1464
+ # the hopes of foiling most address harvesting spam bots. E.g.:
1465
+ #
1466
+ # <p><a href="&#109;&#x61;&#105;&#x6c;&#116;&#x6f;&#58;&#x66;o&#111;
1467
+ # &#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;&#101;&#46;&#x63;&#111;
1468
+ # &#x6d;">&#x66;o&#111;&#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;
1469
+ # &#101;&#46;&#x63;&#111;&#x6d;</a></p>
1470
+ #
1471
+ # Based by a filter by Matthew Wickline, posted to BBEdit-Talk.
1472
+ # With some optimizations by Milian Wolff.
1473
+ #
1474
+ $addr = "mailto:" . $addr;
1475
+ $chars = preg_split('/(?<!^)(?!$)/', $addr);
1476
+ $seed = (int)abs(crc32($addr) / strlen($addr)); # Deterministic seed.
1477
+
1478
+ foreach ($chars as $key => $char) {
1479
+ $ord = ord($char);
1480
+ # Ignore non-ascii chars.
1481
+ if ($ord < 128) {
1482
+ $r = ($seed * (1 + $key)) % 100; # Pseudo-random function.
1483
+ # roughly 10% raw, 45% hex, 45% dec
1484
+ # '@' *must* be encoded. I insist.
1485
+ if ($r > 90 && $char != '@') /* do nothing */;
1486
+ else if ($r < 45) $chars[$key] = '&#x'.dechex($ord).';';
1487
+ else $chars[$key] = '&#'.$ord.';';
1488
+ }
1489
+ }
1490
+
1491
+ $addr = implode('', $chars);
1492
+ $text = implode('', array_slice($chars, 7)); # text without `mailto:`
1493
+ $addr = "<a href=\"$addr\">$text</a>";
1494
+
1495
+ return $addr;
1496
+ }
1497
+
1498
+
1499
+ function parseSpan($str) {
1500
+ #
1501
+ # Take the string $str and parse it into tokens, hashing embeded HTML,
1502
+ # escaped characters and handling code spans.
1503
+ #
1504
+ $output = '';
1505
+
1506
+ $span_re = '{
1507
+ (
1508
+ \\\\'.$this->escape_chars_re.'
1509
+ |
1510
+ (?<![`\\\\])
1511
+ `+ # code span marker
1512
+ '.( $this->no_markup ? '' : '
1513
+ |
1514
+ <!-- .*? --> # comment
1515
+ |
1516
+ <\?.*?\?> | <%.*?%> # processing instruction
1517
+ |
1518
+ <[/!$]?[-a-zA-Z0-9:_]+ # regular tags
1519
+ (?>
1520
+ \s
1521
+ (?>[^"\'>]+|"[^"]*"|\'[^\']*\')*
1522
+ )?
1523
+ >
1524
+ ').'
1525
+ )
1526
+ }xs';
1527
+
1528
+ while (1) {
1529
+ #
1530
+ # Each loop iteration seach for either the next tag, the next
1531
+ # openning code span marker, or the next escaped character.
1532
+ # Each token is then passed to handleSpanToken.
1533
+ #
1534
+ $parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE);
1535
+
1536
+ # Create token from text preceding tag.
1537
+ if ($parts[0] != "") {
1538
+ $output .= $parts[0];
1539
+ }
1540
+
1541
+ # Check if we reach the end.
1542
+ if (isset($parts[1])) {
1543
+ $output .= $this->handleSpanToken($parts[1], $parts[2]);
1544
+ $str = $parts[2];
1545
+ }
1546
+ else {
1547
+ break;
1548
+ }
1549
+ }
1550
+
1551
+ return $output;
1552
+ }
1553
+
1554
+
1555
+ function handleSpanToken($token, &$str) {
1556
+ #
1557
+ # Handle $token provided by parseSpan by determining its nature and
1558
+ # returning the corresponding value that should replace it.
1559
+ #
1560
+ switch ($token{0}) {
1561
+ case "\\":
1562
+ return $this->hashPart("&#". ord($token{1}). ";");
1563
+ case "`":
1564
+ # Search for end marker in remaining text.
1565
+ if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm',
1566
+ $str, $matches))
1567
+ {
1568
+ $str = $matches[2];
1569
+ $codespan = $this->makeCodeSpan($matches[1]);
1570
+ return $this->hashPart($codespan);
1571
+ }
1572
+ return $token; // return as text since no ending marker found.
1573
+ default:
1574
+ return $this->hashPart($token);
1575
+ }
1576
+ }
1577
+
1578
+
1579
+ function outdent($text) {
1580
+ #
1581
+ # Remove one level of line-leading tabs or spaces
1582
+ #
1583
+ return preg_replace('/^(\t|[ ]{1,'.$this->tab_width.'})/m', '', $text);
1584
+ }
1585
+
1586
+
1587
+ # String length function for detab. `_initDetab` will create a function to
1588
+ # hanlde UTF-8 if the default function does not exist.
1589
+ var $utf8_strlen = 'mb_strlen';
1590
+
1591
+ function detab($text) {
1592
+ #
1593
+ # Replace tabs with the appropriate amount of space.
1594
+ #
1595
+ # For each line we separate the line in blocks delemited by
1596
+ # tab characters. Then we reconstruct every line by adding the
1597
+ # appropriate number of space between each blocks.
1598
+
1599
+ $text = preg_replace_callback('/^.*\t.*$/m',
1600
+ array(&$this, '_detab_callback'), $text);
1601
+
1602
+ return $text;
1603
+ }
1604
+ function _detab_callback($matches) {
1605
+ $line = $matches[0];
1606
+ $strlen = $this->utf8_strlen; # strlen function for UTF-8.
1607
+
1608
+ # Split in blocks.
1609
+ $blocks = explode("\t", $line);
1610
+ # Add each blocks to the line.
1611
+ $line = $blocks[0];
1612
+ unset($blocks[0]); # Do not add first block twice.
1613
+ foreach ($blocks as $block) {
1614
+ # Calculate amount of space, insert spaces, insert block.
1615
+ $amount = $this->tab_width -
1616
+ $strlen($line, 'UTF-8') % $this->tab_width;
1617
+ $line .= str_repeat(" ", $amount) . $block;
1618
+ }
1619
+ return $line;
1620
+ }
1621
+ function _initDetab() {
1622
+ #
1623
+ # Check for the availability of the function in the `utf8_strlen` property
1624
+ # (initially `mb_strlen`). If the function is not available, create a
1625
+ # function that will loosely count the number of UTF-8 characters with a
1626
+ # regular expression.
1627
+ #
1628
+ if (function_exists($this->utf8_strlen)) return;
1629
+ $this->utf8_strlen = create_function('$text', 'return preg_match_all(
1630
+ "/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/",
1631
+ $text, $m);');
1632
+ }
1633
+
1634
+
1635
+ function unhash($text) {
1636
+ #
1637
+ # Swap back in all the tags hashed by _HashHTMLBlocks.
1638
+ #
1639
+ return preg_replace_callback('/(.)\x1A[0-9]+\1/',
1640
+ array(&$this, '_unhash_callback'), $text);
1641
+ }
1642
+ function _unhash_callback($matches) {
1643
+ return $this->html_hashes[$matches[0]];
1644
+ }
1645
+
1646
+ }
1647
+
1648
+ /*
1649
+
1650
+ PHP Markdown
1651
+ ============
1652
+
1653
+ Description
1654
+ -----------
1655
+
1656
+ This is a PHP translation of the original Markdown formatter written in
1657
+ Perl by John Gruber.
1658
+
1659
+ Markdown is a text-to-HTML filter; it translates an easy-to-read /
1660
+ easy-to-write structured text format into HTML. Markdown's text format
1661
+ is most similar to that of plain text email, and supports features such
1662
+ as headers, *emphasis*, code blocks, blockquotes, and links.
1663
+
1664
+ Markdown's syntax is designed not as a generic markup language, but
1665
+ specifically to serve as a front-end to (X)HTML. You can use span-level
1666
+ HTML tags anywhere in a Markdown document, and you can use block level
1667
+ HTML tags (like <div> and <table> as well).
1668
+
1669
+ For more information about Markdown's syntax, see:
1670
+
1671
+ <http://daringfireball.net/projects/markdown/>
1672
+
1673
+
1674
+ Bugs
1675
+ ----
1676
+
1677
+ To file bug reports please send email to:
1678
+
1679
+ <michel.fortin@michelf.com>
1680
+
1681
+ Please include with your report: (1) the example input; (2) the output you
1682
+ expected; (3) the output Markdown actually produced.
1683
+
1684
+
1685
+ Version History
1686
+ ---------------
1687
+
1688
+ See the readme file for detailed release notes for this version.
1689
+
1690
+
1691
+ Copyright and License
1692
+ ---------------------
1693
+
1694
+ PHP Markdown
1695
+ Copyright (c) 2004-2009 Michel Fortin
1696
+ <http://michelf.com/>
1697
+ All rights reserved.
1698
+
1699
+ Based on Markdown
1700
+ Copyright (c) 2003-2006 John Gruber
1701
+ <http://daringfireball.net/>
1702
+ All rights reserved.
1703
+
1704
+ Redistribution and use in source and binary forms, with or without
1705
+ modification, are permitted provided that the following conditions are
1706
+ met:
1707
+
1708
+ * Redistributions of source code must retain the above copyright notice,
1709
+ this list of conditions and the following disclaimer.
1710
+
1711
+ * Redistributions in binary form must reproduce the above copyright
1712
+ notice, this list of conditions and the following disclaimer in the
1713
+ documentation and/or other materials provided with the distribution.
1714
+
1715
+ * Neither the name "Markdown" nor the names of its contributors may
1716
+ be used to endorse or promote products derived from this software
1717
+ without specific prior written permission.
1718
+
1719
+ This software is provided by the copyright holders and contributors "as
1720
+ is" and any express or implied warranties, including, but not limited
1721
+ to, the implied warranties of merchantability and fitness for a
1722
+ particular purpose are disclaimed. In no event shall the copyright owner
1723
+ or contributors be liable for any direct, indirect, incidental, special,
1724
+ exemplary, or consequential damages (including, but not limited to,
1725
+ procurement of substitute goods or services; loss of use, data, or
1726
+ profits; or business interruption) however caused and on any theory of
1727
+ liability, whether in contract, strict liability, or tort (including
1728
+ negligence or otherwise) arising in any way out of the use of this
1729
+ software, even if advised of the possibility of such damage.
1730
+
1731
+ */
1732
+ ?>
tabs.js → includes/tabs.js RENAMED
File without changes
modules/404s.php DELETED
@@ -1,180 +0,0 @@
1
- <?php
2
- /**
3
- * 404 Monitor Module
4
- *
5
- * @version 1.0.7
6
- * @since 0.4
7
- */
8
-
9
- if (class_exists('SU_Module')) {
10
-
11
- class SU_404s extends SU_Module {
12
-
13
- var $hitset;
14
-
15
- function __construct() {
16
- //Load 404s from the database
17
- $this->hitset = new SU_HitSet('404s', "status_code=404 AND redirect_url='' AND url NOT LIKE '%/favicon.ico'");
18
-
19
- add_filter('su_save_hit', array(&$this, 'should_log_hit'), 10, 2);
20
- }
21
-
22
- function should_log_hit($should_log, $hit) {
23
- if ($hit['status_code'] == 404)
24
- return true;
25
- else
26
- return $should_log;
27
- }
28
-
29
- function get_menu_title() { return __('404 Monitor', 'seo-ultimate'); }
30
-
31
- function get_menu_count() {
32
- //Find out how many *new* 404s there are
33
- global $wpdb;
34
- $table = SEO_Ultimate::get_table_name('hits');
35
- return $wpdb->query("SELECT id FROM $table WHERE is_new=1 AND status_code=404 AND redirect_url='' AND url NOT LIKE '%/favicon.ico'");
36
- }
37
-
38
- function admin_page_contents() {
39
-
40
- global $wpdb;
41
- $table = SEO_Ultimate::get_table_name('hits');
42
-
43
- if (!$this->get_setting('log_hits', true, 'settings'))
44
-
45
- $this->queue_message('warning', sprintf(
46
- __('Please note that new 404 errors will not be recorded, since visitor logging is disabled in the %s.', 'seo-ultimate'),
47
- $this->get_admin_link('settings', __('Plugin Settings module', 'seo-ultimate'))
48
- ));
49
-
50
- //Are we deleting a 404 entry?
51
- if ($this->is_action('delete')) {
52
-
53
- if ($wpdb->query($wpdb->prepare("DELETE FROM $table WHERE id = %d LIMIT 1", intval($_GET['object']))))
54
- $this->queue_message('success', __('The log entry was successfully deleted.', 'seo-ultimate'));
55
- else
56
- $this->queue_message('error', __('This log entry has already been deleted.', 'seo-ultimate'));
57
-
58
- //The database has changed, so reload our data from it
59
- $this->hitset->query_db();
60
-
61
- //Are we clearing the whole 404 log?
62
- } elseif ($this->is_action('clear')) {
63
-
64
- if ($wpdb->query("DELETE FROM $table WHERE status_code=404")) {
65
- $this->queue_message('success', __('The log was successfully cleared.', 'seo-ultimate'));
66
-
67
- //The database has changed, so reload our data from it
68
- $this->hitset->query_db();
69
- }
70
- }
71
-
72
- if (!$this->hitset->have_hits())
73
- $this->queue_message('success', __("No 404 errors in the log.", 'seo-ultimate'));
74
-
75
- $this->print_messages();
76
-
77
- if ($this->hitset->have_hits()) {
78
-
79
- //Display the 404 table
80
- $this->hitset->admin_table(array(&$this, 'hits_table_action_links'));
81
-
82
- //Create the "Clear Log" button
83
- $clearurl = $this->get_nonce_url('clear');
84
- $confirm = __("Are you sure you want to delete all 404 log entries?", 'seo-ultimate');
85
- echo "<a href=\"$clearurl\" class=\"button-secondary\" onclick=\"javascript:return confirm('$confirm')\">";
86
- _e("Clear Log", 'seo-ultimate');
87
- echo "</a>";
88
- }
89
- }
90
-
91
- //Returns the HTML that should appear when the user hovers over a row of the 404s table
92
- function hits_table_action_links($row) {
93
- $url = $row['url'];
94
-
95
- $deleteurl = $this->get_nonce_url('delete', $row['id']);
96
- $url_encoded = urlencode($url);
97
-
98
- $anchors = array(
99
- __("Open", 'seo-ultimate')
100
- , __("Google Cache", 'seo-ultimate')
101
- , __("Delete Log Entry", 'seo-ultimate')
102
- );
103
-
104
- return <<<STR
105
-
106
- <span class="open"><a href="$url" target="_blank">{$anchors[0]}</a> | </span>
107
- <span class="cache"><a href="http://www.google.com/search?q=cache%3A$url_encoded" target="_blank">{$anchors[1]}</a> | </span>
108
- <span class="delete"><a href="$deleteurl">{$anchors[2]}</a></span>
109
-
110
- STR;
111
- }
112
-
113
- function admin_dropdowns() {
114
- $dropdowns = array();
115
-
116
- //Overview dropdown
117
- $dropdowns['overview'] = __('Overview', 'seo-ultimate');
118
-
119
- //Only show the "Options Help" dropdown if the options in questions are showing
120
- if ($this->hitset->have_hits()) $dropdowns['options'] = __('Options Help', 'seo-ultimate');
121
-
122
- //Troubleshooting dropdown
123
- $dropdowns['troubleshooting'] = __('Troubleshooting', 'seo-ultimate');
124
-
125
- return $dropdowns;
126
- }
127
-
128
- function admin_dropdown_overview() {
129
- $help = __("
130
- <ul>
131
- <li><p><strong>What it does:</strong> The 404 Monitor keeps track of non-existant URLs that generated 404 errors.
132
- 404 errors are when a search engine or visitor comes to a URL on your site but nothing exists at that URL.</p></li>
133
- <li><p><strong>Why it helps:</strong> The 404 Monitor helps you spot 404 errors;
134
- then you can take steps to correct them to reduce linkjuice loss from broken links.</p></li>
135
- <li><p><strong>How to use it:</strong> Check the 404 Monitor occasionally for errors.
136
- (A numeric bubble will appear next to the &#8220;404 Monitor&#8221; item on the menu if there are any newly-logged URLs that you haven&#8217;t seen yet.
137
- These new URLs will also be highlighted green in the table.)
138
- If a 404 error&#8217;s referring URL is located on your site, try locating and fixing the broken URL.
139
- If moved content was previously located at the requested URL, try using a redirection plugin to point the old URL to the new one.</p></li>
140
- </ul>
141
- ", 'seo-ultimate');
142
-
143
- if (!$this->hitset->have_hits()) {
144
-
145
- //Only show this if we don't have 404s in the log
146
- $help .= '<p>'.__('Currently, the 404 Monitor doesn&#8217;t have any 404 errors in its log. This is good, and means there&#8217;s no action required on your part. If the 404 Monitor logs any 404 errors in the future, you&#8217;ll see them on this page.', 'seo-ultimate').'</p>';
147
-
148
- }
149
-
150
- return $help;
151
- }
152
-
153
- function admin_dropdown_options() {
154
- return __("
155
- <p>Hover over a table row to access these options:</p>
156
- <ul>
157
- <li>The &#8220;View&#8221; link will open the URL in a new window. This is useful for testing whether or not a redirect is working.</li>
158
- <li>The &#8220;Google Cache&#8221; link will open Google&#8217;s archived version of the URL in a new window. This is useful for determining what content, if any, used to be located at that URL.</li>
159
- <li>Once you've taken care of a 404 error, you can click the &#8220;Delete Log Entry&#8221; link to remove it from the list. The URL will reappear on the list if it triggers a 404 error in the future.</li>
160
- </ul>
161
- ", 'seo-ultimate');
162
- }
163
-
164
- function admin_dropdown_troubleshooting() {
165
- return sprintf(__("
166
- <p>404 Monitor doesn&#8217;t appear to work? Take these notes into consideration:</p>
167
- <ul>
168
- <li>Visitor logging must be enabled in the %s. (It&#8217;s enabled by default.)</li>
169
- <li>In order for the 404 Monitor to track 404 errors, you must have &#8220;Pretty Permalinks&#8221; enabled in your <a href='options-permalink.php'>permalink options</a>.</li>
170
- <li>Some parts of your website may not be under WordPress&#8217;s control; the 404 Monitor can&#8217;t track 404 errors on non-WordPress website areas.</li>
171
- <li>The 404 Monitor doesn&#8217;t record 404 errors generated by logged-in users.</li>
172
- </ul>
173
- ", 'seo-ultimate'),
174
- $this->get_admin_link('settings', __('Plugin Settings module', 'seo-ultimate'))
175
- );
176
- }
177
- }
178
-
179
- }
180
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
modules/404s/404s.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * 404 Monitor Module
4
+ *
5
+ * @version 1.0.8
6
+ * @since 0.4
7
+ */
8
+
9
+ if (class_exists('SU_Module')) {
10
+
11
+ class SU_404s extends SU_Module {
12
+
13
+ var $hitset;
14
+
15
+ function __construct() {
16
+ //Load 404s from the database
17
+ $this->hitset = new SU_HitSet('404s', "status_code=404 AND redirect_url='' AND url NOT LIKE '%/favicon.ico'");
18
+
19
+ add_filter('su_save_hit', array(&$this, 'should_log_hit'), 10, 2);
20
+ }
21
+
22
+ function should_log_hit($should_log, $hit) {
23
+ if ($hit['status_code'] == 404)
24
+ return true;
25
+ else
26
+ return $should_log;
27
+ }
28
+
29
+ function get_module_title() { return __('404 Monitor', 'seo-ultimate'); }
30
+
31
+ function has_menu_count() { return true; }
32
+
33
+ function get_menu_count() {
34
+ //Find out how many *new* 404s there are
35
+ global $wpdb;
36
+ $table = $this->plugin->get_table_name('hits');
37
+ return $wpdb->query("SELECT id FROM $table WHERE is_new=1 AND status_code=404 AND redirect_url='' AND url NOT LIKE '%/favicon.ico'");
38
+ }
39
+
40
+ function admin_page_contents() {
41
+
42
+ global $wpdb;
43
+ $table = $this->plugin->get_table_name('hits');
44
+
45
+ if (!$this->get_setting('log_hits', true, 'settings'))
46
+
47
+ $this->queue_message('warning', sprintf(
48
+ __('Please note that new 404 errors will not be recorded, since visitor logging is disabled in the %s.', 'seo-ultimate'),
49
+ $this->get_admin_link('settings', __('Plugin Settings module', 'seo-ultimate'))
50
+ ));
51
+
52
+ //Are we deleting a 404 entry?
53
+ if ($this->is_action('delete')) {
54
+
55
+ if ($wpdb->query($wpdb->prepare("DELETE FROM $table WHERE id = %d LIMIT 1", intval($_GET['object']))))
56
+ $this->queue_message('success', __('The log entry was successfully deleted.', 'seo-ultimate'));
57
+ else
58
+ $this->queue_message('error', __('This log entry has already been deleted.', 'seo-ultimate'));
59
+
60
+ //The database has changed, so reload our data from it
61
+ $this->hitset->query_db();
62
+
63
+ //Are we clearing the whole 404 log?
64
+ } elseif ($this->is_action('clear')) {
65
+
66
+ if ($wpdb->query("DELETE FROM $table WHERE status_code=404")) {
67
+ $this->queue_message('success', __('The log was successfully cleared.', 'seo-ultimate'));
68
+
69
+ //The database has changed, so reload our data from it
70
+ $this->hitset->query_db();
71
+ }
72
+ }
73
+
74
+ if (!$this->hitset->have_hits())
75
+ $this->queue_message('success', __("No 404 errors in the log.", 'seo-ultimate'));
76
+
77
+ $this->print_messages();
78
+
79
+ if ($this->hitset->have_hits()) {
80
+
81
+ //Display the 404 table
82
+ $this->hitset->admin_table(array(&$this, 'hits_table_action_links'));
83
+
84
+ //Create the "Clear Log" button
85
+ $clearurl = $this->get_nonce_url('clear');
86
+ $confirm = __("Are you sure you want to delete all 404 log entries?", 'seo-ultimate');
87
+ echo "<a href=\"$clearurl\" class=\"button-secondary\" onclick=\"javascript:return confirm('$confirm')\">";
88
+ _e("Clear Log", 'seo-ultimate');
89
+ echo "</a>";
90
+ }
91
+ }
92
+
93
+ //Returns the HTML that should appear when the user hovers over a row of the 404s table
94
+ function hits_table_action_links($row) {
95
+ $url = $row['url'];
96
+
97
+ $deleteurl = $this->get_nonce_url('delete', $row['id']);
98
+ $url_encoded = urlencode($url);
99
+
100
+ $anchors = array(
101
+ __("Open", 'seo-ultimate')
102
+ , __("Google Cache", 'seo-ultimate')
103
+ , __("Delete Log Entry", 'seo-ultimate')
104
+ );
105
+
106
+ return <<<STR
107
+
108
+ <span class="open"><a href="$url" target="_blank">{$anchors[0]}</a> | </span>
109
+ <span class="cache"><a href="http://www.google.com/search?q=cache%3A$url_encoded" target="_blank">{$anchors[1]}</a> | </span>
110
+ <span class="delete"><a href="$deleteurl">{$anchors[2]}</a></span>
111
+
112
+ STR;
113
+ }
114
+ }
115
+
116
+ }
117
+ ?>
modules/{canonical.php → canonical/canonical.php} RENAMED
@@ -2,7 +2,7 @@
2
  /**
3
  * Canonicalizer Module
4
  *
5
- * @version 1.1.1
6
  * @since 0.3
7
  */
8
 
@@ -10,7 +10,7 @@ if (class_exists('SU_Module')) {
10
 
11
  class SU_Canonical extends SU_Module {
12
 
13
- function get_menu_title() { return __('Canonicalizer', 'seo-ultimate'); }
14
 
15
  function init() {
16
  //If the canonical tags are enabled, then...
@@ -41,7 +41,7 @@ class SU_Canonical extends SU_Module {
41
  function link_rel_canonical_tag() {
42
  //Display the canonical tag if a canonical URL is available
43
  if ($url = $this->get_canonical_url()) {
44
- $url = attribute_escape($url);
45
  echo "\t<link rel=\"canonical\" href=\"$url\" />\n";
46
  }
47
  }
@@ -148,7 +148,7 @@ class SU_Canonical extends SU_Module {
148
 
149
  global $wp_rewrite, $wp_query;
150
 
151
- $url = SEO_Ultimate::get_current_url();
152
 
153
  if (is_singular()) {
154
  $num = absint(get_query_var('page'));
@@ -177,31 +177,6 @@ class SU_Canonical extends SU_Module {
177
  }
178
  }
179
  }
180
-
181
- function admin_dropdowns() {
182
- return array(
183
- 'overview' => __('Overview', 'seo-ultimate')
184
- );
185
- }
186
-
187
- function admin_dropdown_overview() {
188
- return __("
189
- <ul>
190
- <li><p><strong>What it does:</strong> Canonicalizer improves on two WordPress features to minimize possible exact-content duplication penalties.
191
- The <code>&lt;link rel=&quot;canonical&quot; /&gt;</code> tags setting improves on the canonical tags feature of WordPress 2.9 and above by encompassing much more of your site than just your posts and Pages.</p>
192
- <p>The nonexistent pagination redirect feature fills a gap in WordPress&#8217;s built-in canonicalization functionality:
193
- for example, if a URL request is made for page 6 of a category archive, and that category doesn&#8217;t have a page 6,
194
- then by default, depending on the context, WordPress will display a blank page, or it will display the content of the closest page number available,
195
- without issuing a 404 error or a 301 redirect (thus creating two or more identical webpages).
196
- This duplicate-content situation can happen when you, for example, remove many posts from a category, thus reducing the amount of pagination needed in the category&#8217;s archive.
197
- The Canonicalizer&#8217;s feature fixes that behavior by issuing 301 redirects to page 1 of the paginated section in question.</p></li>
198
- <li><p><strong>Why it helps:</strong> These features will point Google to the correct URL for your homepage and each of your posts, Pages, categories, tags, date archives, and author archives.
199
- That way, if Google comes across an alternate URL by which one of those items can be accessed, it will be able to find the correct URL
200
- and won&#8217;t penalize you for having two identical pages on your site.</p></li>
201
- <li><p><strong>How to use it:</strong> Just check both checkboxes and click Save Changes. SEO Ultimate will do the rest.</p></li>
202
- </ul>
203
- ", 'seo-ultimate');
204
- }
205
  }
206
 
207
  }
2
  /**
3
  * Canonicalizer Module
4
  *
5
+ * @version 1.1.2
6
  * @since 0.3
7
  */
8
 
10
 
11
  class SU_Canonical extends SU_Module {
12
 
13
+ function get_module_title() { return __('Canonicalizer', 'seo-ultimate'); }
14
 
15
  function init() {
16
  //If the canonical tags are enabled, then...
41
  function link_rel_canonical_tag() {
42
  //Display the canonical tag if a canonical URL is available
43
  if ($url = $this->get_canonical_url()) {
44
+ $url = su_esc_attr($url);
45
  echo "\t<link rel=\"canonical\" href=\"$url\" />\n";
46
  }
47
  }
148
 
149
  global $wp_rewrite, $wp_query;
150
 
151
+ $url = suurl::current();
152
 
153
  if (is_singular()) {
154
  $num = absint(get_query_var('page'));
177
  }
178
  }
179
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  }
181
 
182
  }
modules/class.su-importmodule.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Import Module
4
+ *
5
+ * @abstract
6
+ * @version 1.0
7
+ * @since 1.5
8
+ */
9
+
10
+ if (class_exists('SU_Module')) {
11
+
12
+ class SU_ImportModule extends SU_Module {
13
+
14
+ var $error = false;
15
+
16
+ function get_menu_parent() { return 'su-import-modules'; }
17
+
18
+ function get_op_title() { return $this->get_module_title(); }
19
+ function get_import_desc() { return ''; }
20
+
21
+ function admin_page() {
22
+ $this->admin_page_start('tools');
23
+
24
+ if ($this->is_action('update')) {
25
+ ob_start();
26
+ $this->admin_page_contents();
27
+ ob_end_clean();
28
+
29
+ $this->import_page_contents();
30
+ } else
31
+ $this->admin_page_contents();
32
+
33
+ $this->admin_page_end();
34
+ }
35
+
36
+ function admin_form_end($button = false, $table = true) {
37
+ if (!$button) $button = __("Import Now", 'seo-ultimate');
38
+ parent::admin_form_end($button, $table);
39
+
40
+ $this->print_message('warning', sprintf(__('The import cannot be undone. It is your responsibility to <a href="%s" target="_blank">backup your database</a> before proceeding!', 'seo-ultimate'), suwp::get_backup_url()));
41
+ }
42
+
43
+ function import_page_contents() {
44
+
45
+ //echo "<table id='import-status'>\n";
46
+ echo "<div id='import-status'>\n";
47
+ $this->do_import();
48
+
49
+ if (!$this->error)
50
+ $this->import_status('success', __("Import complete.", 'seo-ultimate'));
51
+
52
+ echo "</div>\n";
53
+ //echo "</table>\n";
54
+
55
+ if ($this->error) {
56
+ echo '<p><a href="admin.php?page=su-import-aiosp" class="button-secondary">';
57
+ _e('Return to import page', 'seo-ultimate');
58
+ } elseif ($this->plugin->module_exists('settings')) {
59
+ echo '<p><a href="options-general.php?page=seo-ultimate" class="button-secondary">';
60
+ _e('Return to settings page', 'seo-ultimate');
61
+ } else {
62
+ echo '<p><a href="admin.php?page=seo" class="button-secondary">';
63
+ _e('Return to SEO page', 'seo-ultimate');
64
+ }
65
+ echo "</a></p>\n";
66
+ }
67
+
68
+ function import_status($type, $message) {
69
+ //echo "<tr><td class='image'><img src='{$this->import_status_image}' alt='' /></td><td class='message'>$message</td></tr>";
70
+ $type = su_esc_attr($type);
71
+ if (strcmp($type, 'error') == 0) $this->error = true;
72
+ echo "<div class='su-status su-$type'>$message</div>";
73
+ }
74
+
75
+ function import_option($module, $key, $option) {
76
+ if (!isset($this->settings[$module][$key]) || $this->get_setting('overwrite_su')) {
77
+ $this->settings[$module][$key] = get_option($option);
78
+ if ($this->get_setting('delete_import')) delete_option($option);
79
+ }
80
+ }
81
+ }
82
+
83
+ }
84
+ ?>
class.su-module.php → modules/class.su-module.php RENAMED
@@ -9,8 +9,28 @@ class SU_Module {
9
 
10
  /********** VARIABLES **********/
11
 
 
 
 
 
12
  var $module_key;
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  /**
15
  * Stores the module file's URL.
16
  *
@@ -19,6 +39,14 @@ class SU_Module {
19
  */
20
  var $module_url;
21
 
 
 
 
 
 
 
 
 
22
  /**
23
  * Stores the module's plugin page hook (the full hook with seo_page_ prefix).
24
  * A reconstructed value of the get_plugin_page_hook() function, which is only available after admin init.
@@ -36,6 +64,13 @@ class SU_Module {
36
  */
37
  var $messages = array();
38
 
 
 
 
 
 
 
 
39
 
40
  /********** CONSTRUCTOR FUNCTION **********/
41
 
@@ -59,6 +94,24 @@ class SU_Module {
59
  */
60
  function __construct() { }
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  /**
63
  * The title of the admin page, which is displayed in the <title> and <h2> tags.
64
  * Is the same as the menu title by default.
@@ -67,7 +120,7 @@ class SU_Module {
67
  *
68
  * @return string The title shown on this module's admin page.
69
  */
70
- function get_page_title() { return $this->get_menu_title(); }
71
 
72
  /**
73
  * The title that appears on the administration navigation menu.
@@ -76,7 +129,7 @@ class SU_Module {
76
  *
77
  * @return string The title shown on the admin menu.
78
  */
79
- function get_menu_title() { return ''; }
80
 
81
  /**
82
  * Determines where this module's admin page should appear relative to those of other modules.
@@ -88,6 +141,16 @@ class SU_Module {
88
  */
89
  function get_menu_pos() { return 999; }
90
 
 
 
 
 
 
 
 
 
 
 
91
  /**
92
  * The number that should be displayed in a bubble next to the module's menu title.
93
  * A return value of zero means no bubble is shown.
@@ -98,6 +161,15 @@ class SU_Module {
98
  */
99
  function get_menu_count() { return 0; }
100
 
 
 
 
 
 
 
 
 
 
101
  /**
102
  * A descriptive label of the menu count.
103
  *
@@ -127,6 +199,15 @@ class SU_Module {
127
  */
128
  function get_menu_parent_hook() { return $this->get_menu_parent(); }
129
 
 
 
 
 
 
 
 
 
 
130
  /**
131
  * The module key of this module's parent. Defaults to false (no parent).
132
  *
@@ -136,6 +217,49 @@ class SU_Module {
136
  */
137
  function get_parent_module() { return false; }
138
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  /**
140
  * Called at WordPress's init hook.
141
  *
@@ -165,25 +289,45 @@ class SU_Module {
165
  *
166
  * @since 0.1
167
  */
168
- function admin_page_contents() { }
 
 
169
 
170
  /**
171
- * Returns an array of arrays, each of which includes the key, title, and content of a custom module dropdown.
172
  *
173
- * @since 0.9
 
 
 
 
174
  *
175
  * @return array
176
  */
177
- function admin_dropdowns() { return array(); }
178
-
179
- /**
180
- * Returns the module's custom help content that should go in the "Help" dropdown of WordPress 2.7 and above.
181
- *
182
- * @since 0.1
183
- *
184
- * @return string|false The help text, or false if no custom help is available.
185
- */
186
- function admin_help() { return false; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
 
188
  /**
189
  * Adds the module's post meta box field HTML to the array.
@@ -195,7 +339,6 @@ class SU_Module {
195
  */
196
  function postmeta_fields($fields) { return $fields; }
197
 
198
-
199
  /********** INITIALIZATION FUNCTIONALITY **********/
200
 
201
  /**
@@ -233,20 +376,6 @@ class SU_Module {
233
  die(str_rot13('Zbqhyr ybnqrq sebz na rkgreany fbhepr!'));
234
  }
235
 
236
- /**
237
- * Checks to see whether a specified module exists.
238
- *
239
- * @since 0.1
240
- * @uses $seo_ultimate
241
- *
242
- * @param string $key The key of the module to check.
243
- * @return boolean Whether the module is loaded into SEO Ultimate.
244
- */
245
- function module_exists($key) {
246
- global $seo_ultimate;
247
- return isset($seo_ultimate->modules[$key]);
248
- }
249
-
250
  /**
251
  * Returns the absolute URL of the module's admin page.
252
  *
@@ -262,7 +391,7 @@ class SU_Module {
262
 
263
  if ($key === false) {
264
  if ($key = $this->get_parent_module()) {
265
- $anchor = '#'.SEO_Ultimate::key_to_hook($this->get_module_key());
266
  } else {
267
  $key = $this->get_module_key();
268
  $anchor = '';
@@ -270,11 +399,10 @@ class SU_Module {
270
  }
271
 
272
  $basepage = 'admin.php';
273
- global $seo_ultimate;
274
- if (isset($seo_ultimate->modules[$key]) && su_str_endswith($custom_basepage = $seo_ultimate->modules[$key]->get_menu_parent(), '.php'))
275
  $basepage = $custom_basepage;
276
 
277
- return admin_url($basepage.'?page='.SEO_Ultimate::key_to_hook($key).$anchor);
278
  }
279
 
280
  /**
@@ -289,7 +417,7 @@ class SU_Module {
289
  */
290
  function get_admin_link($key, $label) {
291
 
292
- if ($key == false || $this->module_exists($key))
293
  return sprintf('<a href="%s">%s</a>', $this->get_admin_url($key), $label);
294
  else
295
  return $label;
@@ -305,12 +433,144 @@ class SU_Module {
305
  function is_module_admin_page() {
306
  if (is_admin()) {
307
  global $plugin_page;
308
- if (strcmp($plugin_page, SEO_Ultimate::key_to_hook($this->get_module_key())) == 0) return true;
309
  }
310
 
311
  return false;
312
  }
313
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314
 
315
  /********** SETTINGS FUNCTIONS **********/
316
 
@@ -318,20 +578,18 @@ class SU_Module {
318
  * Retrieves the given setting from a module's settings array.
319
  *
320
  * @since 0.1
321
- * @uses get_module_key()
322
  *
323
  * @param string $key The name of the setting to retrieve.
324
  * @param mixed $default What should be returned if the setting does not exist. Optional.
325
- * @param string|null $module The module to which the setting belongs. Defaults to the current module. Optional.
326
  * @return mixed The value of the setting, or the $default variable.
327
  */
328
  function get_setting($key, $default=null, $module=null) {
329
- if (!$module) $module = $this->get_module_key();
330
 
331
- global $seo_ultimate;
332
-
333
- if (isset($seo_ultimate->dbdata['settings'][$module][$key]))
334
- $setting = $seo_ultimate->dbdata['settings'][$module][$key];
335
  else
336
  $setting = $default;
337
 
@@ -345,22 +603,20 @@ class SU_Module {
345
  * Sets a value in the module's settings array.
346
  *
347
  * @since 0.1
348
- * @uses get_module_key()
349
  *
350
  * @param string $key The key of the setting to be changed.
351
  * @param string $value The new value to assign to the setting.
352
- * @param string|null $module The module to which the setting belongs. Defaults to the current module. Optional.
353
  */
354
  function update_setting($key, $value, $module=null) {
355
- if (!$module) $module = $this->get_module_key();
356
 
357
  $use_custom = apply_filters("su_custom_update_setting-$module-$key", false, $value, $key) ||
358
  apply_filters("su_custom_update_setting-$module", false, $value, $key);
359
 
360
- if (!$use_custom) {
361
- global $seo_ultimate;
362
- $seo_ultimate->dbdata['settings'][$module][$key] = $value;
363
- }
364
  }
365
 
366
  /**
@@ -455,7 +711,13 @@ class SU_Module {
455
 
456
  //Output the beginning of the admin screen
457
  echo "<div class=\"wrap\">\n";
458
- echo "<div id=\"su-".attribute_escape($this->get_module_key())."\" class=\"su-module\">\n";
 
 
 
 
 
 
459
  screen_icon($icon);
460
  echo "\n<h2>".$this->get_page_title()."</h2>\n";
461
  }
@@ -495,28 +757,59 @@ class SU_Module {
495
  * Outputs a tab control and loads the current tab.
496
  *
497
  * @since 0.7
498
- * @uses $seo_ultimate
499
  * @uses get_admin_url()
500
  * @uses SEO_Ultimate::plugin_dir_url
501
  *
502
  * @param array $tabs The internationalized tab titles are the array keys, and the references to the functions that display the tab contents are the array values.
 
503
  */
504
- function admin_page_tabs($tabs = array()) {
505
 
506
- global $seo_ultimate;
507
-
508
- echo "\n\n<div id='su-tabset' class='su-tabs'>\n";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
509
 
510
- foreach ($tabs as $title => $function) {
511
- $id = preg_replace('/[^a-z0-9]/', '', strtolower($title));
512
- echo "<fieldset id='$id'>\n<h3>$title</h3>\n";
513
- if (!is_array($function)) $call = array(&$this, $function);
514
- if (is_callable($call)) call_user_func($call);
515
- echo "</fieldset>\n";
516
  }
517
- echo "</div>\n";
518
-
519
- echo '<script type="text/javascript" src="'.$seo_ultimate->plugin_dir_url.'tabs.js?v='.SU_VERSION.'"></script>';
520
  }
521
 
522
  /**
@@ -547,37 +840,27 @@ class SU_Module {
547
  */
548
  function screen_meta_filter($screen_meta) {
549
 
550
- $dropdowns = array_reverse($this->admin_dropdowns());
551
 
552
- $script = "<script type='text/javascript'>jQuery(function($) { $('#contextual-help-link').css('display', 'none'); });</script>";
553
-
554
- if (is_array($dropdowns) && count($dropdowns)) {
555
- foreach ($dropdowns as $key => $label) {
556
-
557
  $label = htmlspecialchars($label);
 
558
 
559
- $function = array(&$this, "admin_dropdown_$key");
560
- if (is_callable($function)) {
561
- $content = "<div class='su-help'>\n";
562
- $content .= '<h5>'.sprintf(_c('%s %s|Dropdown Title', 'seo-ultimate'), $this->get_page_title(), $label)."</h5>\n\n";
563
- $content .= call_user_func($function);
564
- $content .= "\n</div>\n";
565
- $screen_meta[] = compact('key', 'label', 'content');
566
- }
 
 
567
  }
568
 
569
- echo $script;
570
-
571
- } elseif ($this->admin_help() !== false) {
572
-
573
- $content = "<div class='su-help'>\n";
574
- $content .= '<h5>'.sprintf(_c('%s Documentation', 'seo-ultimate'), $this->get_page_title())."</h5>\n\n";
575
- $content .= $this->admin_help();
576
- $content .= "\n</div>\n";
577
-
578
- $screen_meta[] = array('key' => 'documentation', 'label' => __('Documentation', 'seo-ultimate'), 'content' => $content);
579
-
580
- echo $script;
581
  }
582
 
583
  return $screen_meta;
@@ -594,7 +877,7 @@ class SU_Module {
594
  */
595
  function admin_footer() {
596
  printf(__('%1$s | %2$s %3$s by %4$s', 'seo-ultimate'),
597
- $this->get_page_title(),
598
  '<a href="'.SU_PLUGIN_URI.'" target="_blank">'.__(SU_PLUGIN_NAME, 'seo-ultimate').'</a>',
599
  SU_VERSION,
600
  '<a href="'.SU_AUTHOR_URI.'" target="_blank">'.__(SU_AUTHOR, 'seo-ultimate').'</a>'
@@ -623,7 +906,7 @@ class SU_Module {
623
  * @param boolean $table Whether or not to start a form table.
624
  */
625
  function admin_form_start($header = false, $table = true) {
626
- $hook = SEO_Ultimate::key_to_hook($this->get_module_key());
627
  if ($header) $this->admin_subheader($header);
628
 
629
  if (!$this->get_parent_module()) {
@@ -660,6 +943,57 @@ class SU_Module {
660
  }
661
  }
662
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
663
  /**
664
  * Applies the necessary HTML so that certain content is displayed only when the mouse hovers over the including table row.
665
  *
@@ -673,6 +1007,19 @@ class SU_Module {
673
  return "<div>$text</div>\n<div class='row-actions'>$hovertext</div>";
674
  }
675
 
 
 
 
 
 
 
 
 
 
 
 
 
 
676
  /**
677
  * Outputs a group of checkboxes into an admin form, and saves the values into the database after form submission.
678
  *
@@ -700,9 +1047,9 @@ class SU_Module {
700
  }
701
 
702
  if ($grouptext)
703
- echo "<tr valign='top'>\n<th scope='row'>$grouptext</th>\n<td><fieldset><legend class='hidden'>$grouptext</legend>\n";
704
  else
705
- echo "<tr valign='top'>\n<td>\n";
706
 
707
  if (is_array($checkboxes)) {
708
  foreach ($checkboxes as $name => $desc) {
@@ -710,7 +1057,7 @@ class SU_Module {
710
  //$desc = preg_replace_callback('/%d/', array(&$this, "insert_int_var_textboxes"), $desc);
711
 
712
  register_setting($this->get_module_key(), $name, 'intval');
713
- $name = attribute_escape($name);
714
 
715
  if (strpos($desc, '%d') === false) {
716
  $onclick = '';
@@ -733,6 +1080,66 @@ class SU_Module {
733
  echo "</td>\n</tr>\n";
734
  }
735
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
736
  /**
737
  * Outputs a group of textboxes into an admin form, and saves the values into the database after form submission.
738
  * Can also display a "Reset" link next to each textbox that reverts its value to a specified default.
@@ -755,15 +1162,14 @@ class SU_Module {
755
  }
756
  }
757
 
758
- if ($grouptext)
759
- echo "<tr valign='top'>\n<th scope='row'>$grouptext</th>\n<td><fieldset><legend class='hidden'>$grouptext</legend>\n";
760
 
761
  foreach ($textboxes as $id => $title) {
762
  register_setting($this->get_module_key(), $id);
763
- $value = wp_specialchars($this->get_setting($id), ENT_QUOTES, false, true);
764
- $default = wp_specialchars($defaults[$id], ENT_QUOTES, false, true);
765
- $id = attribute_escape($id);
766
- $resetmessage = attribute_escape(__("Are you sure you want to replace the textbox contents with this default value?", 'seo-ultimate'));
767
 
768
  if ($grouptext)
769
  echo "<div class='field'><label for='$id'>$title</label><br />\n";
@@ -790,8 +1196,7 @@ class SU_Module {
790
  echo "</td>\n</tr>\n";
791
  }
792
 
793
- if ($grouptext)
794
- echo "</td>\n</tr>\n";
795
  }
796
 
797
  /**
@@ -810,7 +1215,6 @@ class SU_Module {
810
  $this->textboxes(array($id => $title), $default);
811
  }
812
 
813
-
814
  /**
815
  * Outputs a group of textareas into an admin form, and saves the values into the database after form submission.
816
  *
@@ -834,8 +1238,8 @@ class SU_Module {
834
 
835
  foreach ($textareas as $id => $title) {
836
  register_setting($this->get_module_key(), $id);
837
- $value = wp_specialchars($this->get_setting($id), ENT_QUOTES, false, true);
838
- $id = attribute_escape($id);
839
 
840
  echo "<tr valign='top'>\n<th scope='row'><label for='$id'>$title</label></th>\n";
841
  echo "<td><textarea name='$id' id='$id' type='text' class='regular-text' cols='$cols' rows='$rows'>$value</textarea>";
@@ -874,9 +1278,14 @@ class SU_Module {
874
  */
875
  function is_action($action) {
876
  if (!($object = $_GET['object'])) $object = false;
877
- return (strcasecmp($_GET['page'], SEO_Ultimate::key_to_hook($this->get_module_key())) == 0 //Is $this module being shown?
878
- && ($_GET['action'] == $action || $_POST['action'] == $action) //Is this $action being executed?
879
- && $this->nonce_validates($action, $object)); //Is the nonce valid?
 
 
 
 
 
880
  }
881
 
882
  /**
@@ -910,7 +1319,7 @@ class SU_Module {
910
  $key = $this->get_parent_module();
911
  if (!$key) $key = $this->get_module_key();
912
 
913
- $hook = SEO_Ultimate::key_to_hook($key);
914
 
915
  if (strcmp($action, 'update') == 0) {
916
  //We use the settings_fields() function, which outputs a nonce in this particular format.
@@ -937,7 +1346,7 @@ class SU_Module {
937
  $action = urlencode($action);
938
  if ($object) $objectqs = '&object='.urlencode($object); else $objectqs = '';
939
 
940
- $hook = SEO_Ultimate::key_to_hook($this->get_module_key());
941
 
942
  //We don't need to escape ampersands since wp_nonce_url will do that for us
943
  return wp_nonce_url("?page=$hook&action=$action$objectqs",
@@ -985,7 +1394,7 @@ class SU_Module {
985
  foreach ($this->messages as $type => $messages) {
986
  $messages = implode('<br />', $messages);
987
  if ($messages) {
988
- $type = attribute_escape($type);
989
  echo "<div class='su-message'><p class='su-$type'>$messages</p></div>\n";
990
  }
991
  }
@@ -1006,8 +1415,9 @@ class SU_Module {
1006
  * @return string The meta value requested.
1007
  */
1008
  function get_postmeta($key, $id=false) {
1009
-
1010
  if (!$id) {
 
1011
  if (is_admin()) {
1012
  $id = intval($_REQUEST['post']);
1013
  global $post;
@@ -1031,7 +1441,7 @@ class SU_Module {
1031
 
1032
  return $value;
1033
  }
1034
-
1035
  /**
1036
  * Generates the HTML for multiple post meta textboxes.
1037
  *
@@ -1048,8 +1458,8 @@ class SU_Module {
1048
  foreach ($textboxes as $id => $title) {
1049
 
1050
  register_setting('seo-ultimate', $id);
1051
- $value = wp_specialchars($this->get_postmeta($id), ENT_QUOTES, false, true);
1052
- $id = "_su_".attribute_escape($id);
1053
  $title = str_replace(' ', '&nbsp;', $title);
1054
 
1055
  $html .= "<tr class='textbox'>\n<th scope='row'><label for='$id'>$title</label></th>\n"
@@ -1092,7 +1502,7 @@ class SU_Module {
1092
 
1093
  register_setting('seo-ultimate', $name);
1094
  $checked = ($this->get_postmeta($name) == 1);
1095
- $name = "_su_".attribute_escape($name);
1096
 
1097
  $html .= "<label for='$name'><input name='$name' id='$name' type='checkbox' value='1'";
1098
  if ($checked) $html .= " checked='checked'";
@@ -1147,8 +1557,7 @@ class SU_Module {
1147
  wp_schedule_event($start, $recurrance, $hook);
1148
 
1149
  //Make a record of it
1150
- global $seo_ultimate;
1151
- $seo_ultimate->dbdata['cron'][$mk][$function] = array($hook, $start, $recurrance);
1152
 
1153
  //Run the event now
1154
  call_user_func(array($this, $function));
@@ -1156,24 +1565,5 @@ class SU_Module {
1156
 
1157
  add_action($hook, array(&$this, $function));
1158
  }
1159
-
1160
- /********** RSS FUNCTION **********/
1161
-
1162
- /**
1163
- * Loads an RSS feed and returns it as an object.
1164
- *
1165
- * @since 0.1
1166
- * @uses get_user_agent() Hooks into WordPress's http_header_useragent filter.
1167
- *
1168
- * @param string $url The URL of the RSS feed to load.
1169
- * @return object $rss The RSS object.
1170
- */
1171
- function load_rss($url) {
1172
- add_filter('http_headers_useragent', 'su_get_user_agent');
1173
- require_once (ABSPATH . WPINC . '/rss.php');
1174
- $rss = fetch_rss($url);
1175
- remove_filter('http_headers_useragent', 'su_get_user_agent');
1176
- return $rss;
1177
- }
1178
  }
1179
  ?>
9
 
10
  /********** VARIABLES **********/
11
 
12
+ /**
13
+ * @since 0.1
14
+ * @var string
15
+ */
16
  var $module_key;
17
 
18
+ /**
19
+ * Stores the parent module if applicable.
20
+ *
21
+ * @since 1.5
22
+ * @var SU_Module
23
+ */
24
+ var $parent_module = null;
25
+
26
+ /**
27
+ * Stores any child modules.
28
+ *
29
+ * @since 1.5
30
+ * @var array
31
+ */
32
+ var $modules = array();
33
+
34
  /**
35
  * Stores the module file's URL.
36
  *
39
  */
40
  var $module_url;
41
 
42
+ /**
43
+ * Stores the URL to the directory containing the module file's URL. Has trailing slash.
44
+ *
45
+ * @since 1.5
46
+ * @var string
47
+ */
48
+ var $module_dir_url;
49
+
50
  /**
51
  * Stores the module's plugin page hook (the full hook with seo_page_ prefix).
52
  * A reconstructed value of the get_plugin_page_hook() function, which is only available after admin init.
64
  */
65
  var $messages = array();
66
 
67
+ /**
68
+ * Stores the plugin object by reference.
69
+ *
70
+ * @since 1.5
71
+ */
72
+ var $plugin = null;
73
+
74
 
75
  /********** CONSTRUCTOR FUNCTION **********/
76
 
94
  */
95
  function __construct() { }
96
 
97
+ /**
98
+ * The module's official title.
99
+ *
100
+ * @since 1.5
101
+ *
102
+ * @return string
103
+ */
104
+ function get_module_title() { return ''; }
105
+
106
+ /**
107
+ * The title to be used by parent modules.
108
+ *
109
+ * @since 1.5
110
+ *
111
+ * @return string
112
+ */
113
+ function get_module_subtitle() { return $this->get_module_title(); }
114
+
115
  /**
116
  * The title of the admin page, which is displayed in the <title> and <h2> tags.
117
  * Is the same as the menu title by default.
120
  *
121
  * @return string The title shown on this module's admin page.
122
  */
123
+ function get_page_title() { return $this->get_module_title(); }
124
 
125
  /**
126
  * The title that appears on the administration navigation menu.
129
  *
130
  * @return string The title shown on the admin menu.
131
  */
132
+ function get_menu_title() { return $this->get_module_title(); }
133
 
134
  /**
135
  * Determines where this module's admin page should appear relative to those of other modules.
141
  */
142
  function get_menu_pos() { return 999; }
143
 
144
+ /**
145
+ * Determines where this module's admin contents should appear on the parent page relative to those of other sibling modules.
146
+ * If two modules have the same order index, they are sorted alphabetically.
147
+ *
148
+ * @since 1.5
149
+ *
150
+ * @return int The child order index.
151
+ */
152
+ function get_child_order() { return 999; }
153
+
154
  /**
155
  * The number that should be displayed in a bubble next to the module's menu title.
156
  * A return value of zero means no bubble is shown.
161
  */
162
  function get_menu_count() { return 0; }
163
 
164
+ /**
165
+ * Whether or not the module will ever return a non-zero menu count.
166
+ *
167
+ * @since 1.5
168
+ *
169
+ * @return boolean
170
+ */
171
+ function has_menu_count() { return false; }
172
+
173
  /**
174
  * A descriptive label of the menu count.
175
  *
199
  */
200
  function get_menu_parent_hook() { return $this->get_menu_parent(); }
201
 
202
+ /**
203
+ * The status (enabled/silenced/hidden) of the module when the module is newly added to the plugin.
204
+ *
205
+ * @since 1.5
206
+ *
207
+ * @return int Either SU_MODULE_ENABLED, SU_MODULE_SILENCED, or SU_MODULE_HIDDEN.
208
+ */
209
+ function get_default_status() { return SU_MODULE_ENABLED; }
210
+
211
  /**
212
  * The module key of this module's parent. Defaults to false (no parent).
213
  *
217
  */
218
  function get_parent_module() { return false; }
219
 
220
+ /**
221
+ * Returns an array of admin page tabs; the label is the key and the callback is the value.
222
+ *
223
+ * @since 1.5
224
+ *
225
+ * @return array
226
+ */
227
+ function get_admin_page_tabs() { return array(); }
228
+
229
+ /**
230
+ * Whether or not the module can "exist on its own."
231
+ * Determines whether or not the module appears in the Module Manager.
232
+ *
233
+ * @since 1.5
234
+ *
235
+ * @return bool
236
+ */
237
+ function is_independent_module() {
238
+ return true;
239
+ }
240
+
241
+ /**
242
+ * The array key of the plugin's settings array in which this module's settings are stored.
243
+ *
244
+ * @since 1.5
245
+ *
246
+ * @return string
247
+ */
248
+ function get_settings_key() {
249
+ if (strlen($parent = $this->get_parent_module()) && !$this->is_independent_module())
250
+ return $this->plugin->modules[$parent]->get_settings_key();
251
+ else
252
+ return $this->get_module_key();
253
+ }
254
+
255
+ /**
256
+ * Whether or not this module should be the default screen for the "SEO" menu.
257
+ *
258
+ * @since 1.5
259
+ * @return bool
260
+ */
261
+ function is_menu_default() { return false; }
262
+
263
  /**
264
  * Called at WordPress's init hook.
265
  *
289
  *
290
  * @since 0.1
291
  */
292
+ function admin_page_contents() {
293
+ $this->children_admin_page_tabs_form();
294
+ }
295
 
296
  /**
297
+ * Returns an array of custom contextual help dropdowns; internationalized titles are the array keys and contents are the array values.
298
  *
299
+ * @since 1.5
300
+ * @uses sumd::get_sections()
301
+ * @uses sumd::get_section()
302
+ * @uses SEO_Ultimate::get_translated_readme_path()
303
+ * @uses SEO_Ultimate::get_readme_path()
304
  *
305
  * @return array
306
  */
307
+ function get_admin_dropdowns() {
308
+
309
+ $paths = array($this->plugin->get_translated_readme_path(), $this->plugin->get_readme_path());
310
+
311
+ foreach ($paths as $path) {
312
+ $readme = file_get_contents($path);
313
+ $sections = sumd::get_sections(sumd::get_section($readme, $this->get_module_title()));
314
+ if (count($sections)) {
315
+
316
+ if (sustr::has($path, '/translations/') && preg_match("|\nStable tag: ([a-zA-Z0-9. ]+)|i", $readme, $matches)) {
317
+ $version = $matches[1];
318
+ if (version_compare($version, SU_VERSION, '<'))
319
+ $sections = suarr::aprintf(false, '%s<p><em>'
320
+ . __('(Note: This translated documentation was designed for an older version of SEO Ultimate and may be outdated.)', 'seo-ultimate')
321
+ . '</em></p>'
322
+ , $sections);
323
+ }
324
+
325
+ return $sections;
326
+ }
327
+ }
328
+
329
+ return array();
330
+ }
331
 
332
  /**
333
  * Adds the module's post meta box field HTML to the array.
339
  */
340
  function postmeta_fields($fields) { return $fields; }
341
 
 
342
  /********** INITIALIZATION FUNCTIONALITY **********/
343
 
344
  /**
376
  die(str_rot13('Zbqhyr ybnqrq sebz na rkgreany fbhepr!'));
377
  }
378
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
  /**
380
  * Returns the absolute URL of the module's admin page.
381
  *
391
 
392
  if ($key === false) {
393
  if ($key = $this->get_parent_module()) {
394
+ $anchor = '#'.$this->plugin->key_to_hook($this->get_module_key());
395
  } else {
396
  $key = $this->get_module_key();
397
  $anchor = '';
399
  }
400
 
401
  $basepage = 'admin.php';
402
+ if (isset($this->plugin->modules[$key]) && sustr::endswith($custom_basepage = $this->plugin->modules[$key]->get_menu_parent(), '.php'))
 
403
  $basepage = $custom_basepage;
404
 
405
+ return admin_url($basepage.'?page='.$this->plugin->key_to_hook($key).$anchor);
406
  }
407
 
408
  /**
417
  */
418
  function get_admin_link($key, $label) {
419
 
420
+ if ($key == false || $this->plugin->module_exists($key))
421
  return sprintf('<a href="%s">%s</a>', $this->get_admin_url($key), $label);
422
  else
423
  return $label;
433
  function is_module_admin_page() {
434
  if (is_admin()) {
435
  global $plugin_page;
436
+ if (strcmp($plugin_page, $this->plugin->key_to_hook($this->get_module_key())) == 0) return true;
437
  }
438
 
439
  return false;
440
  }
441
 
442
+ /**
443
+ * Returns the filename of the module's icon URL.
444
+ *
445
+ * @since 1.5
446
+ *
447
+ * @return string
448
+ */
449
+ function get_menu_icon_filename() {
450
+ $filenames = array(
451
+ $this->get_settings_key()
452
+ , $this->get_module_key()
453
+ , $this->get_parent_module_key()
454
+ );
455
+
456
+ foreach ($filenames as $filename) {
457
+ $image = $this->module_dir_url.$filename.'.png';
458
+ if (is_readable($image)) return $image;
459
+ }
460
+
461
+ return '';
462
+ }
463
+
464
+
465
+ /********** CHILD MODULE FUNCTIONS **********/
466
+
467
+ /**
468
+ * Finds child modules of this module and fills $this->modules accordingly.
469
+ *
470
+ * @since 1.5
471
+ */
472
+ function load_child_modules() {
473
+ foreach ($this->plugin->modules as $key => $x_module) {
474
+ if ($key != $this->get_module_key()) {
475
+ $module =& $this->plugin->modules[$key];
476
+ if ($module->get_parent_module() == $this->get_module_key()) {
477
+ $module->parent_module =& $this;
478
+ $this->modules[$key] =& $module;
479
+ }
480
+ }
481
+ }
482
+
483
+ if (count($this->modules) > 0)
484
+ uasort($this->modules, array(&$this, 'module_sort_callback'));
485
+ }
486
+
487
+ /**
488
+ * Returns an array of this module's admin tabs plus those of its children.
489
+ *
490
+ * @since 1.5
491
+ * @return array
492
+ */
493
+ function get_children_admin_page_tabs() {
494
+ $tabs = $this->get_admin_page_tabs();
495
+
496
+ foreach ($this->modules as $key => $x_module) {
497
+ $module =& $this->modules[$key];
498
+ $child_tabs = $module->get_admin_page_tabs();
499
+ if (empty($child_tabs))
500
+ $child_tabs[$module->get_module_subtitle()] = array(&$module, 'admin_page_contents');
501
+ $tabs = array_merge($tabs, $child_tabs);
502
+ }
503
+
504
+ return $tabs;
505
+ }
506
+
507
+ /**
508
+ * Outputs this module's admin tabs plus those of its children.
509
+ *
510
+ * @since 1.5
511
+ * @return array
512
+ */
513
+ function children_admin_page_tabs() {
514
+ if (count($tabs = $this->get_children_admin_page_tabs()))
515
+ $this->admin_page_tabs($tabs);
516
+ }
517
+
518
+ /**
519
+ * Outputs a form containing this module's admin tabs plus those of its children.
520
+ *
521
+ * @since 1.5
522
+ */
523
+ function children_admin_page_tabs_form() {
524
+ if (count($tabs = $this->get_children_admin_page_tabs())) {
525
+ $this->admin_form_start(false, false);
526
+ $this->admin_page_tabs($tabs);
527
+ $this->admin_form_end(false, false);
528
+ }
529
+ }
530
+
531
+ /**
532
+ * Outputs the admin pages of this module's children, one after the other.
533
+ *
534
+ * @since 1.5
535
+ */
536
+ function children_admin_pages() {
537
+ foreach ($this->modules as $key => $x_module) {
538
+ $this->modules[$key]->admin_page_contents();
539
+ }
540
+ }
541
+
542
+ /**
543
+ * Outputs a form containing the admin pages of this module's children, outputted one after the other.
544
+ *
545
+ * @since 1.5
546
+ */
547
+ function children_admin_pages_form() {
548
+ $this->admin_form_start();
549
+ $this->children_admin_pages();
550
+ $this->admin_form_end();
551
+ }
552
+
553
+ /**
554
+ * Compares two modules to determine which of the two should be displayed first on the parent page.
555
+ * Sorts by child order first, and title second.
556
+ * Works as a uasort() callback.
557
+ *
558
+ * @since 1.5
559
+ * @uses SU_Module::get_child_order()
560
+ * @uses SU_Module::get_module_subtitle()
561
+ *
562
+ * @param SU_Module $a The first module to compare.
563
+ * @param SU_Module $b The second module to compare.
564
+ * @return int This will be -1 if $a comes first, or 1 if $b comes first.
565
+ */
566
+ function module_sort_callback($a, $b) {
567
+
568
+ if ($a->get_child_order() == $b->get_child_order()) {
569
+ return strcmp($a->get_module_subtitle(), $b->get_module_subtitle());
570
+ }
571
+
572
+ return ($a->get_child_order() < $b->get_child_order()) ? -1 : 1;
573
+ }
574
 
575
  /********** SETTINGS FUNCTIONS **********/
576
 
578
  * Retrieves the given setting from a module's settings array.
579
  *
580
  * @since 0.1
581
+ * @uses get_settings_key()
582
  *
583
  * @param string $key The name of the setting to retrieve.
584
  * @param mixed $default What should be returned if the setting does not exist. Optional.
585
+ * @param string|null $module The module to which the setting belongs. Defaults to the current module's settings key. Optional.
586
  * @return mixed The value of the setting, or the $default variable.
587
  */
588
  function get_setting($key, $default=null, $module=null) {
589
+ if (!$module) $module = $this->get_settings_key();
590
 
591
+ if (isset($this->plugin->dbdata['settings'][$module][$key]))
592
+ $setting = $this->plugin->dbdata['settings'][$module][$key];
 
 
593
  else
594
  $setting = $default;
595
 
603
  * Sets a value in the module's settings array.
604
  *
605
  * @since 0.1
606
+ * @uses get_settings_key()
607
  *
608
  * @param string $key The key of the setting to be changed.
609
  * @param string $value The new value to assign to the setting.
610
+ * @param string|null $module The module to which the setting belongs. Defaults to the current module's settings key. Optional.
611
  */
612
  function update_setting($key, $value, $module=null) {
613
+ if (!$module) $module = $this->get_settings_key();
614
 
615
  $use_custom = apply_filters("su_custom_update_setting-$module-$key", false, $value, $key) ||
616
  apply_filters("su_custom_update_setting-$module", false, $value, $key);
617
 
618
+ if (!$use_custom)
619
+ $this->plugin->dbdata['settings'][$module][$key] = $value;
 
 
620
  }
621
 
622
  /**
711
 
712
  //Output the beginning of the admin screen
713
  echo "<div class=\"wrap\">\n";
714
+
715
+ if (strcmp($pclass = strtolower(get_parent_class($this)), 'su_module') != 0)
716
+ $class = ' '.str_replace('_', '-', $pclass);
717
+ else
718
+ $class = '';
719
+
720
+ echo "<div id=\"su-".su_esc_attr($this->get_module_key())."\" class=\"su-module$class\">\n";
721
  screen_icon($icon);
722
  echo "\n<h2>".$this->get_page_title()."</h2>\n";
723
  }
757
  * Outputs a tab control and loads the current tab.
758
  *
759
  * @since 0.7
 
760
  * @uses get_admin_url()
761
  * @uses SEO_Ultimate::plugin_dir_url
762
  *
763
  * @param array $tabs The internationalized tab titles are the array keys, and the references to the functions that display the tab contents are the array values.
764
+ * @param bool $table Whether or not the tab contents should be wrapped in a form table.
765
  */
766
+ function admin_page_tabs($tabs = array(), $table=false) {
767
 
768
+ if ($c = count($tabs)) {
769
+
770
+ if ($c > 1)
771
+ echo "\n\n<div id='su-tabset' class='su-tabs'>\n";
772
+
773
+ foreach ($tabs as $title => $function) {
774
+
775
+ if ($c > 1) {
776
+ $id = preg_replace('/[^a-z0-9]/', '', strtolower($title));
777
+ echo "<fieldset id='$id'>\n<h3>$title</h3>\n";
778
+ }
779
+
780
+ if ($table) echo "<table class='form-table'>\n";
781
+
782
+ $call = $args = array();
783
+
784
+ if (is_array($function)) {
785
+
786
+ if (is_array($function[0])) {
787
+ $call = array_shift($function);
788
+ $args = $function;
789
+ } elseif (is_string($function[0])) {
790
+ $call = array_shift($function);
791
+ $call = array(&$this, $call);
792
+ $args = $function;
793
+ } else {
794
+ $call = $function;
795
+ }
796
+ } else {
797
+ $call = array(&$this, $function);
798
+ }
799
+ if (is_callable($call)) call_user_func_array($call, $args);
800
+
801
+ if ($table) echo "</table>";
802
+
803
+ if ($c > 1)
804
+ echo "</fieldset>\n";
805
+ }
806
+
807
+ if ($c > 1) {
808
+ echo "</div>\n";
809
 
810
+ echo '<script type="text/javascript" src="'.$this->plugin->plugin_dir_url.'includes/tabs.js?v='.SU_VERSION.'"></script>';
811
+ }
 
 
 
 
812
  }
 
 
 
813
  }
814
 
815
  /**
840
  */
841
  function screen_meta_filter($screen_meta) {
842
 
843
+ $sections = array_reverse($this->get_admin_dropdowns());
844
 
845
+ if (is_array($sections) && count($sections)) {
846
+ foreach ($sections as $label => $text) {
847
+ $key = preg_replace('|[^a-z]|', '', strtolower($label));
 
 
848
  $label = htmlspecialchars($label);
849
+ $content = "<div class='su-help'>\n";
850
 
851
+ $header = sprintf(_c('%s %s|Dropdown Title', 'seo-ultimate'), $this->get_module_title(), $label);
852
+ $header = sustr::unique_words($header);
853
+
854
+ $text = wptexturize(Markdown($text));
855
+ $text = str_replace('<a ', '<a target="_blank" ', $text);
856
+
857
+ $content .= "<h5>$header</h5>\n\n";
858
+ $content .= $text;
859
+ $content .= "\n</div>\n";
860
+ $screen_meta[] = compact('key', 'label', 'content');
861
  }
862
 
863
+ echo "<script type='text/javascript'>jQuery(function($) { $('#contextual-help-link').css('display', 'none'); });</script>";
 
 
 
 
 
 
 
 
 
 
 
864
  }
865
 
866
  return $screen_meta;
877
  */
878
  function admin_footer() {
879
  printf(__('%1$s | %2$s %3$s by %4$s', 'seo-ultimate'),
880
+ $this->get_module_title(),
881
  '<a href="'.SU_PLUGIN_URI.'" target="_blank">'.__(SU_PLUGIN_NAME, 'seo-ultimate').'</a>',
882
  SU_VERSION,
883
  '<a href="'.SU_AUTHOR_URI.'" target="_blank">'.__(SU_AUTHOR, 'seo-ultimate').'</a>'
906
  * @param boolean $table Whether or not to start a form table.
907
  */
908
  function admin_form_start($header = false, $table = true) {
909
+ $hook = $this->plugin->key_to_hook($this->get_module_key());
910
  if ($header) $this->admin_subheader($header);
911
 
912
  if (!$this->get_parent_module()) {
943
  }
944
  }
945
 
946
+ /**
947
+ * Begins an admin form table.
948
+ *
949
+ * @since 1.5
950
+ */
951
+ function admin_form_table_start() {
952
+ echo "<table class='form-table'>\n";
953
+ }
954
+
955
+ /**
956
+ * Ends an admin form table
957
+ *
958
+ * @since 1.5
959
+ */
960
+ function admin_form_table_end() {
961
+ echo "</table>\n";
962
+ }
963
+
964
+ /**
965
+ * Outputs the HTML that begins an admin form group.
966
+ *
967
+ * @since 1.5
968
+ *
969
+ * @param string $title The title of the group.
970
+ * @param bool $newtable Whether to open a new <table> element.
971
+ */
972
+ function admin_form_group_start($title, $newtable=true) {
973
+ echo "<tr valign='top'>\n<th scope='row'>$title</th>\n<td><fieldset><legend class='hidden'>$title</legend>\n";
974
+ if ($newtable) echo "<table>\n";
975
+ }
976
+
977
+ /**
978
+ * Outputs the HTML that ends an admin form group.
979
+ *
980
+ * @since 1.5
981
+ *
982
+ * @param bool $newtable Whether to close a <table> element.
983
+ */
984
+ function admin_form_group_end($newtable=true) {
985
+ if ($newtable) echo "</table>\n";
986
+ echo "</td>\n</tr>\n";
987
+ }
988
+
989
+ function admin_form_indent_start() {
990
+ echo "<tr valign='top'><td colspan='2'><table class='su-indent'>";
991
+ }
992
+
993
+ function admin_form_indent_end() {
994
+ echo "</table></td></tr>";
995
+ }
996
+
997
  /**
998
  * Applies the necessary HTML so that certain content is displayed only when the mouse hovers over the including table row.
999
  *
1007
  return "<div>$text</div>\n<div class='row-actions'>$hovertext</div>";
1008
  }
1009
 
1010
+ /**
1011
+ * Outputs a text block into an admin form.
1012
+ *
1013
+ * @since 1.5
1014
+ *
1015
+ * @param string $text
1016
+ */
1017
+ function textblock($text) {
1018
+ echo "<tr valign='top' class='su-admin-form-textblock'>\n<td colspan='2'>\n";
1019
+ echo $text;
1020
+ echo "\n</td>\n</tr>\n";
1021
+ }
1022
+
1023
  /**
1024
  * Outputs a group of checkboxes into an admin form, and saves the values into the database after form submission.
1025
  *
1047
  }
1048
 
1049
  if ($grouptext)
1050
+ $this->admin_form_group_start($grouptext, false);
1051
  else
1052
+ echo "<tr valign='top' class='su-admin-form-checkbox'>\n<td colspan='2'>\n";
1053
 
1054
  if (is_array($checkboxes)) {
1055
  foreach ($checkboxes as $name => $desc) {
1057
  //$desc = preg_replace_callback('/%d/', array(&$this, "insert_int_var_textboxes"), $desc);
1058
 
1059
  register_setting($this->get_module_key(), $name, 'intval');
1060
+ $name = su_esc_attr($name);
1061
 
1062
  if (strpos($desc, '%d') === false) {
1063
  $onclick = '';
1080
  echo "</td>\n</tr>\n";
1081
  }
1082
 
1083
+ /**
1084
+ * Outputs a single checkbox into an admin form and saves its value into the database after form submission.
1085
+ *
1086
+ * @since 1.5
1087
+ * @uses checkboxes()
1088
+ *
1089
+ * @param string $id The field/setting ID.
1090
+ * @param string $desc The checkbox's label.
1091
+ * @return string The HTML that would render the checkbox.
1092
+ */
1093
+ function checkbox($id, $desc) {
1094
+ $this->checkboxes(array($id => $desc));
1095
+ }
1096
+
1097
+ /**
1098
+ * Outputs a set of radio buttons into an admin form and saves the set's value into the database after form submission.
1099
+ *
1100
+ * @since 1.5
1101
+ * @uses is_action()
1102
+ * @uses update_setting()
1103
+ * @uses admin_form_group_start()
1104
+ * @uses admin_form_group_end()
1105
+ * @uses su_esc_attr()
1106
+ * @uses get_setting()
1107
+ *
1108
+ * @param string $name The name of the set of radio buttons.
1109
+ * @param array $values The keys of this array are the radio button values, and the array values are the label strings.
1110
+ * @param string|false $grouptext The text to display in a table cell to the left of the one containing the radio buttons. Optional.
1111
+ */
1112
+ function radiobuttons($name, $values, $grouptext=false) {
1113
+
1114
+ //Save radio button setting after form submission
1115
+ if ($this->is_action('update'))
1116
+ $this->update_setting($name, $_POST[$name]);
1117
+
1118
+ if ($grouptext)
1119
+ $this->admin_form_group_start($grouptext, false);
1120
+ else
1121
+ echo "<tr valign='top' class='su-admin-form-radio'>\n<td colspan='2'>\n";
1122
+
1123
+ if (is_array($values)) {
1124
+
1125
+ register_setting($this->get_module_key(), $name, 'intval');
1126
+ $name = su_esc_attr($name);
1127
+
1128
+ foreach ($values as $value => $desc) {
1129
+
1130
+ $value = su_esc_attr($value);
1131
+ $id = "{$name}_{$value}";
1132
+
1133
+ echo "<label for='$id'><input name='$name' id='$id' type='radio' value='$value'";
1134
+ if (strcmp($this->get_setting($name), $value) == 0) echo " checked='checked'";
1135
+ echo " /> $desc</label><br />\n";
1136
+ }
1137
+ }
1138
+
1139
+ if ($grouptext) echo "</fieldset>";
1140
+ echo "</td>\n</tr>\n";
1141
+ }
1142
+
1143
  /**
1144
  * Outputs a group of textboxes into an admin form, and saves the values into the database after form submission.
1145
  * Can also display a "Reset" link next to each textbox that reverts its value to a specified default.
1162
  }
1163
  }
1164
 
1165
+ if ($grouptext) $this->admin_form_group_start($grouptext, false);
 
1166
 
1167
  foreach ($textboxes as $id => $title) {
1168
  register_setting($this->get_module_key(), $id);
1169
+ $value = su_esc_editable_html($this->get_setting($id));
1170
+ $default = su_esc_editable_html($defaults[$id]);
1171
+ $id = su_esc_attr($id);
1172
+ $resetmessage = su_esc_attr(__("Are you sure you want to replace the textbox contents with this default value?", 'seo-ultimate'));
1173
 
1174
  if ($grouptext)
1175
  echo "<div class='field'><label for='$id'>$title</label><br />\n";
1196
  echo "</td>\n</tr>\n";
1197
  }
1198
 
1199
+ if ($grouptext) $this->admin_form_group_end(false);
 
1200
  }
1201
 
1202
  /**
1215
  $this->textboxes(array($id => $title), $default);
1216
  }
1217
 
 
1218
  /**
1219
  * Outputs a group of textareas into an admin form, and saves the values into the database after form submission.
1220
  *
1238
 
1239
  foreach ($textareas as $id => $title) {
1240
  register_setting($this->get_module_key(), $id);
1241
+ $value = su_esc_editable_html($this->get_setting($id));
1242
+ $id = su_esc_attr($id);
1243
 
1244
  echo "<tr valign='top'>\n<th scope='row'><label for='$id'>$title</label></th>\n";
1245
  echo "<td><textarea name='$id' id='$id' type='text' class='regular-text' cols='$cols' rows='$rows'>$value</textarea>";
1278
  */
1279
  function is_action($action) {
1280
  if (!($object = $_GET['object'])) $object = false;
1281
+ return (
1282
+ (
1283
+ ( strcasecmp($_GET['page'], $this->plugin->key_to_hook($this->get_module_key())) == 0 ) //Is $this module being shown?
1284
+ || ( strlen($this->get_parent_module()) && strcasecmp($_GET['page'], $this->plugin->key_to_hook($this->get_parent_module())) == 0)
1285
+ )
1286
+ && ($_GET['action'] == $action || $_POST['action'] == $action) //Is this $action being executed?
1287
+ && $this->nonce_validates($action, $object) //Is the nonce valid?
1288
+ );
1289
  }
1290
 
1291
  /**
1319
  $key = $this->get_parent_module();
1320
  if (!$key) $key = $this->get_module_key();
1321
 
1322
+ $hook = $this->plugin->key_to_hook($key);
1323
 
1324
  if (strcmp($action, 'update') == 0) {
1325
  //We use the settings_fields() function, which outputs a nonce in this particular format.
1346
  $action = urlencode($action);
1347
  if ($object) $objectqs = '&object='.urlencode($object); else $objectqs = '';
1348
 
1349
+ $hook = $this->plugin->key_to_hook($this->get_module_key());
1350
 
1351
  //We don't need to escape ampersands since wp_nonce_url will do that for us
1352
  return wp_nonce_url("?page=$hook&action=$action$objectqs",
1394
  foreach ($this->messages as $type => $messages) {
1395
  $messages = implode('<br />', $messages);
1396
  if ($messages) {
1397
+ $type = su_esc_attr($type);
1398
  echo "<div class='su-message'><p class='su-$type'>$messages</p></div>\n";
1399
  }
1400
  }
1415
  * @return string The meta value requested.
1416
  */
1417
  function get_postmeta($key, $id=false) {
1418
+
1419
  if (!$id) {
1420
+ //This code is different from suwp::get_post_id();
1421
  if (is_admin()) {
1422
  $id = intval($_REQUEST['post']);
1423
  global $post;
1441
 
1442
  return $value;
1443
  }
1444
+
1445
  /**
1446
  * Generates the HTML for multiple post meta textboxes.
1447
  *
1458
  foreach ($textboxes as $id => $title) {
1459
 
1460
  register_setting('seo-ultimate', $id);
1461
+ $value = su_esc_editable_html($this->get_postmeta($id));
1462
+ $id = "_su_".su_esc_attr($id);
1463
  $title = str_replace(' ', '&nbsp;', $title);
1464
 
1465
  $html .= "<tr class='textbox'>\n<th scope='row'><label for='$id'>$title</label></th>\n"
1502
 
1503
  register_setting('seo-ultimate', $name);
1504
  $checked = ($this->get_postmeta($name) == 1);
1505
+ $name = "_su_".su_esc_attr($name);
1506
 
1507
  $html .= "<label for='$name'><input name='$name' id='$name' type='checkbox' value='1'";
1508
  if ($checked) $html .= " checked='checked'";
1557
  wp_schedule_event($start, $recurrance, $hook);
1558
 
1559
  //Make a record of it
1560
+ $this->plugin->dbdata['cron'][$mk][$function] = array($hook, $start, $recurrance);
 
1561
 
1562
  //Run the event now
1563
  call_user_func(array($this, $function));
1565
 
1566
  add_action($hook, array(&$this, $function));
1567
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1568
  }
1569
  ?>
modules/{competition-queries.php → competition-queries/competition-queries.php} RENAMED
@@ -2,7 +2,7 @@
2
  /**
3
  * Competition Researcher Module
4
  *
5
- * @version 1.0.1
6
  * @since 1.2
7
  */
8
 
@@ -10,8 +10,8 @@ if (class_exists('SU_Module')) {
10
 
11
  class SU_CompetitionQueries extends SU_Module {
12
 
 
13
  function get_menu_title() { return __('Comp. Researcher', 'seo-ultimate'); }
14
- function get_page_title() { return __('Competition Researcher', 'seo-ultimate'); }
15
 
16
  function admin_page_contents() {
17
  echo '<p>';
2
  /**
3
  * Competition Researcher Module
4
  *
5
+ * @version 1.0.2
6
  * @since 1.2
7
  */
8
 
10
 
11
  class SU_CompetitionQueries extends SU_Module {
12
 
13
+ function get_module_title() { return __('Competition Researcher', 'seo-ultimate'); }
14
  function get_menu_title() { return __('Comp. Researcher', 'seo-ultimate'); }
 
15
 
16
  function admin_page_contents() {
17
  echo '<p>';
modules/{files.php → files/files.php} RENAMED
@@ -2,8 +2,8 @@
2
  /**
3
  * File Editor Module
4
  *
5
- * @version 1.0.2
6
- * @since 2.0
7
  */
8
 
9
  if (class_exists('SU_Module')) {
@@ -12,7 +12,7 @@ class SU_Files extends SU_Module {
12
 
13
  var $htaccess_recovery = null;
14
 
15
- function get_menu_title() { return __('File Editor', 'seo-ultimate'); }
16
 
17
  function init() {
18
 
@@ -130,7 +130,7 @@ class SU_Files extends SU_Module {
130
  if ($pagenow == 'options-privacy.php') { //Shows on the "Settings > Privacy" page
131
  $this->print_message('info', sprintf(
132
  __('Please note that your privacy settings won&#8217;t have any effect on your robots.txt file, since you&#8217;re using <a href="%s">a custom one</a>.', 'seo-ultimate'),
133
- admin_url('admin.php?page='.SEO_Ultimate::key_to_hook($this->get_module_key()))
134
  ));
135
  }
136
  }
2
  /**
3
  * File Editor Module
4
  *
5
+ * @version 1.0.3
6
+ * @since 0.8
7
  */
8
 
9
  if (class_exists('SU_Module')) {
12
 
13
  var $htaccess_recovery = null;
14
 
15
+ function get_module_title() { return __('File Editor', 'seo-ultimate'); }
16
 
17
  function init() {
18
 
130
  if ($pagenow == 'options-privacy.php') { //Shows on the "Settings > Privacy" page
131
  $this->print_message('info', sprintf(
132
  __('Please note that your privacy settings won&#8217;t have any effect on your robots.txt file, since you&#8217;re using <a href="%s">a custom one</a>.', 'seo-ultimate'),
133
+ admin_url('admin.php?page='.$this->plugin->key_to_hook($this->get_module_key()))
134
  ));
135
  }
136
  }
modules/{linkbox.php → linkbox/linkbox.php} RENAMED
@@ -2,7 +2,7 @@
2
  /**
3
  * Linkbox Inserter Module
4
  *
5
- * @version 1.0.3
6
  * @since 0.6
7
  */
8
 
@@ -10,7 +10,7 @@ if (class_exists('SU_Module')) {
10
 
11
  class SU_Linkbox extends SU_Module {
12
 
13
- function get_menu_title() { return __('Linkbox Inserter', 'seo-ultimate'); }
14
 
15
  function get_default_settings() {
16
  //The default linkbox HTML
@@ -59,7 +59,7 @@ class SU_Linkbox extends SU_Module {
59
  function linkbox_filter($content, $id = false) {
60
 
61
  //If no ID is provided, get the ID of the current post
62
- if (!$id) $id = SEO_Ultimate::get_post_id();
63
 
64
  if ($id) {
65
  //Don't add a linkbox if a "more" link is present (since a linkbox should go at the very bottom of a post)
@@ -70,7 +70,7 @@ class SU_Linkbox extends SU_Module {
70
  $linkbox = $this->get_setting('html');
71
  $linkbox = str_replace(
72
  array('{id}', '{url}', '{title}'),
73
- array(intval($id), attribute_escape(get_permalink($id)), attribute_escape(get_the_title($id))),
74
  $linkbox
75
  );
76
 
@@ -84,49 +84,6 @@ class SU_Linkbox extends SU_Module {
84
  function linkbox_action($id = false) {
85
  echo $this->linkbox_filter('', $id);
86
  }
87
-
88
- function admin_dropdowns() {
89
- return array(
90
- 'overview' => __('Overview', 'seo-ultimate')
91
- , 'settings' => __('Settings Help', 'seo-ultimate')
92
- );
93
- }
94
-
95
- function admin_dropdown_overview() {
96
- return __("
97
- <ul>
98
- <li><p><strong>What it does:</strong> Linkbox Inserter can add linkboxes to your posts/pages.</p></li>
99
- <li><p><strong>Why it helps:</strong> Linkboxes contain HTML code that visitors can use to link to your site. This is a great way to encourage SEO-beneficial linking activity.</p></li>
100
- <li><p><strong>How to use it:</strong> Use the checkboxes to enable the Linkbox Inserter in various areas of your site. Customize the HTML if desired. Click &#8220;Save Changes&#8221; when finished.</p></li>
101
- </ul>
102
- ", 'seo-ultimate');
103
- }
104
-
105
- function admin_dropdown_settings() {
106
- return __("
107
- <p>Here&#8217;s information on the various settings:</p>
108
- <ul>
109
- <li><p><strong>Display linkboxes...</strong></p>
110
- <ul>
111
- <li><p><strong>At the end of posts</strong> &mdash; Adds the linkbox HTML to the end of all posts
112
- (whether they&#8217;re displayed on the blog homepage, in archives, or by themselves).</p></li>
113
- <li><p><strong>At the end of pages</strong> &mdash; Adds the linkbox HTML to the end of all Pages.</p></li>
114
- <li><p><strong>When called by the su_linkbox hook</strong> &mdash; For more fine-tuned control over where linkboxes appear,
115
- enable this option and add <code>&lt;?php&nbsp;do_action('su_linkbox');&nbsp;?&gt;</code> to your theme.
116
- You can also add an ID parameter to display the linkbox of a particular post/page; for example:
117
- <code>&lt;?php&nbsp;do_action('su_linkbox',&nbsp;123);&nbsp;?&gt;</code></p></li>
118
- </ul>
119
- </li>
120
- <li><p><strong>HTML</strong> &mdash; The HTML that will be outputted to display the linkboxes. The HTML field supports these variables:</p>
121
- <ul>
122
- <li>{id} &mdash; The ID of the current post/page, or the ID passed to the action hook call.</li>
123
- <li>{url} &mdash; The permalink URL of the post/page.</li>
124
- <li>{title} &mdash; The title of the post/page.</li>
125
- </ul>
126
- </li>
127
- </ul>
128
- ", 'seo-ultimate');
129
- }
130
  }
131
 
132
  }
2
  /**
3
  * Linkbox Inserter Module
4
  *
5
+ * @version 1.0.4
6
  * @since 0.6
7
  */
8
 
10
 
11
  class SU_Linkbox extends SU_Module {
12
 
13
+ function get_module_title() { return __('Linkbox Inserter', 'seo-ultimate'); }
14
 
15
  function get_default_settings() {
16
  //The default linkbox HTML
59
  function linkbox_filter($content, $id = false) {
60
 
61
  //If no ID is provided, get the ID of the current post
62
+ if (!$id) $id = suwp::get_post_id();
63
 
64
  if ($id) {
65
  //Don't add a linkbox if a "more" link is present (since a linkbox should go at the very bottom of a post)
70
  $linkbox = $this->get_setting('html');
71
  $linkbox = str_replace(
72
  array('{id}', '{url}', '{title}'),
73
+ array(intval($id), su_esc_attr(get_permalink($id)), su_esc_attr(get_the_title($id))),
74
  $linkbox
75
  );
76
 
84
  function linkbox_action($id = false) {
85
  echo $this->linkbox_filter('', $id);
86
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  }
88
 
89
  }
modules/meta.php DELETED
@@ -1,201 +0,0 @@
1
- <?php
2
- /**
3
- * Meta Editor Module
4
- *
5
- * @version 1.0.6
6
- * @since 0.3
7
- */
8
-
9
- if (class_exists('SU_Module')) {
10
-
11
- class SU_Meta extends SU_Module {
12
-
13
- function get_menu_title() { return __('Meta Editor', 'seo-ultimate'); }
14
-
15
- function init() {
16
- add_filter('su_meta_robots', array(&$this, 'meta_robots'));
17
- add_action('su_head', array(&$this, 'head_tag_output'));
18
- add_filter('su_postmeta_help', array(&$this, 'postmeta_help'), 20);
19
- }
20
-
21
- function get_default_settings() {
22
- return array(
23
- 'home_description_tagline_default' => true
24
- );
25
- }
26
-
27
- function admin_page_contents() {
28
- $this->admin_form_start();
29
- $this->textareas(array(
30
- 'home_description' => __("Blog Homepage Meta Description", 'seo-ultimate')
31
- , 'home_keywords' => __("Blog Homepage Meta Keywords", 'seo-ultimate')
32
- ), 3);
33
- $this->checkboxes(array(
34
- 'home_description_tagline_default' => __("Use this blog&#8217s tagline as the default homepage description.", 'seo-ultimate')
35
- ), __("Default Values", 'seo-ultimate'));
36
- $this->checkboxes(array(
37
- 'noodp' => __("Don&#8217t use this site&#8217s Open Directory description in search results.", 'seo-ultimate')
38
- , 'noydir' => __("Don&#8217t use this site&#8217s Yahoo! Directory description in search results.", 'seo-ultimate')
39
- , 'noarchive' => __("Don&#8217t cache or archive this site.", 'seo-ultimate')
40
- ), __("Spider Instructions", 'seo-ultimate'));
41
- $this->textboxes(array(
42
- 'google_verify' => __("Google Webmaster Tools:", 'seo-ultimate')
43
- , 'yahoo_verify' => __("Yahoo! Site Explorer:", 'seo-ultimate')
44
- , 'microsoft_verify' => __("Bing Webmaster Center:", 'seo-ultimate')
45
- ), array(), __("Verification Codes", 'seo-ultimate'));
46
- $this->textarea('custom_html', __("Custom &lt;head&gt; HTML", 'seo-ultimate'));
47
- $this->admin_form_end();
48
- }
49
-
50
- function postmeta_fields($fields) {
51
- $id = "_su_description";
52
- $value = attribute_escape($this->get_postmeta('description'));
53
-
54
- $fields['20|description|keywords'] =
55
- "<tr class='textarea'>\n<th scope='row'><label for='$id'>".__("Description:", 'seo-ultimate')."</label></th>\n"
56
- . "<td><textarea name='$id' id='$id' type='text' class='regular-text' cols='60' rows='3'"
57
- . " onkeyup=\"javascript:document.getElementById('su_meta_description_charcount').innerHTML = document.getElementById('_su_description').value.length\">$value</textarea>"
58
- . "<br />".sprintf(__("You&#8217;ve entered %s characters. Most search engines use up to 160.", 'seo-ultimate'), "<strong id='su_meta_description_charcount'>".strlen($value)."</strong>")
59
- . "</td>\n</tr>\n"
60
- . $this->get_postmeta_textbox('keywords', __('Keywords:<br /><em>(separate with commas)</em>', 'seo-ultimate'))
61
- ;
62
-
63
- return $fields;
64
- }
65
-
66
- //Add the appropriate commands to the meta robots array
67
- function meta_robots($commands) {
68
-
69
- $tags = array('noodp', 'noydir', 'noarchive');
70
-
71
- foreach ($tags as $tag) {
72
- if ($this->get_setting($tag)) $commands[] = $tag;
73
- }
74
-
75
- return $commands;
76
- }
77
-
78
- function head_tag_output() {
79
-
80
- $desc = false;
81
- $kw = false;
82
-
83
- //If we're viewing the homepage, look for homepage meta data.
84
- if (is_home()) {
85
- $desc = $this->get_setting('home_description');
86
- if (!$desc && $this->get_setting('home_description_tagline_default')) $desc = get_bloginfo('description');
87
- $kw = $this->get_setting('home_keywords');
88
-
89
- //If we're viewing a post or page, look for its meta data.
90
- } elseif (is_singular()) {
91
- $desc = $this->get_postmeta('description');
92
- $kw = $this->get_postmeta('keywords');
93
- }
94
-
95
- //Do we have a description? If so, output it.
96
- if ($desc) {
97
- $desc = su_esc_attr($desc);
98
- echo "\t<meta name=\"description\" content=\"$desc\" />\n";
99
- }
100
-
101
- //Do we have keywords? If so, output them.
102
- if ($kw) {
103
- $kw = su_esc_attr($kw);
104
- echo "\t<meta name=\"keywords\" content=\"$kw\" />\n";
105
- }
106
-
107
- //Supported meta tags and their names
108
- $verify = array(
109
- 'google' => 'google-site-verification'
110
- , 'yahoo' => 'y_key'
111
- , 'microsoft' => 'msvalidate.01'
112
- );
113
-
114
- //Do we have verification tags? If so, output them.
115
- foreach ($verify as $site => $name) {
116
- if ($value = $this->get_setting($site.'_verify')) {
117
- $value = su_esc_attr($value);
118
- echo "\t<meta name=\"$name\" content=\"$value\" />\n";
119
- }
120
- }
121
-
122
- //Display custom code if provided
123
- if ($custom = $this->get_setting('custom_html')) {
124
-
125
- //Does the plugin user want us to surround code insertions with comments? If so, mark the custom code as such.
126
- $mark_code = $this->get_setting('mark_code', false, 'settings');
127
- $desc = __('Custom Header Code', 'seo-ultimate');
128
-
129
- echo "\n";
130
- if ($mark_code) echo "\t<!-- $desc -->\n";
131
- echo $custom;
132
- if ($mark_code) echo "\n\t<!-- /$desc -->";
133
- echo "\n\n";
134
- }
135
-
136
- }
137
-
138
- function admin_dropdowns() {
139
- return array(
140
- 'overview' => __('Overview', 'seo-ultimate')
141
- , 'settings' => __('Settings Help', 'seo-ultimate')
142
- );
143
- }
144
-
145
- function admin_dropdown_overview() {
146
- return __("
147
- <ul>
148
- <li><p><strong>What it does:</strong> Meta Editor lets you customize a wide variety of settings known as &#8220;meta data.&#8221;</p></li>
149
- <li><p><strong>Why it helps:</strong> Using meta data, you can convey information to search engines, such as what text you want displayed by your site in search results, what your site is about, whether they can cache your site, etc.</p></li>
150
- <li><p><strong>How to use it:</strong> Adjust the settings as desired, and then click Save Changes. You can refer to the &#8220;Settings Help&#8221; tab for information on the settings available. You can also customize the meta data of an individual post or page by using the textboxes that Meta Editor adds to the post/page editors.</p></li>
151
- </ul>
152
- ", 'seo-ultimate');
153
- }
154
-
155
- function admin_dropdown_settings() {
156
- return __("
157
- <p>Here&#8217;s information on the various settings:</p>
158
- <ul>
159
- <li><p><strong>Blog Homepage Meta Description</strong> &mdash; When your blog homepage appears in search results, it&#8217;ll have a title and a description.
160
- When you insert content into the description field below, the Meta Editor will add code to your blog homepage (the <code>&lt;meta&nbsp;name=&quot;description&quot;&nbsp;/&gt;</code> tag)
161
- that asks search engines to use what you&#8217;ve entered as the homepage&#8217;s search results description.</p></li>
162
- <li><p><strong>Blog Homepage Meta Keywords</strong> &mdash; Here you can enter keywords that describe the overall subject matter of your entire blog. Use commas to separate keywords.
163
- Your keywords will be put in the <code>&lt;meta&nbsp;name=&quot;keywords&quot;&nbsp;/&gt;</code> tag on your blog homepage.</p></li>
164
- <li><p><strong>Default Values</strong></p>
165
- <ul>
166
- <li><p><strong>Use this blog&#8217;s tagline as the default homepage description.</strong> &mdash;
167
- If this box is checked and if the Blog Homepage Meta Description field is empty,
168
- Meta Editor will use your blog&#8217;s <a href='options-general.php' target='_blank'>tagline</a> as the meta description.</p></li>
169
- </ul>
170
- </li>
171
- <li><p><strong>Spider Instructions</strong></p>
172
- <ul>
173
- <li><p><strong>Don&#8217;t use this site&#8217;s Open Directory / Yahoo! Directory description in search results.</strong> &mdash;
174
- If your site is listed in the <a href='http://www.dmoz.org/' target='_blank'>Open Directory (DMOZ)</a> or
175
- the <a href='http://dir.yahoo.com/' target='_blank'>Yahoo! Directory</a>,
176
- some search engines may use your directory listing as the meta description.
177
- These boxes tell search engines not to do that and will give you full control over your meta descriptions.
178
- These settings have no effect if your site isn&#8217;t listed in the Open Directory or Yahoo! Directory respectively.</p></li>
179
- <li><p><strong>Don&#8217;t cache or archive this site.</strong> &mdash;
180
- When you check this box, Meta Editor will ask search engines (Google, Yahoo!, Bing, etc.) and archivers (Archive.org, etc.)
181
- to <em>not</em> make cached or archived &#8220;copies&#8221; of your site.</p></li>
182
- </ul>
183
- </li>
184
- <li><p><strong>Verification Codes</strong> &mdash; This section lets you enter in verification codes for the webmaster portals of the 3 leading search engines.</p></li>
185
- <li><p><strong>Custom &lt;head&gt; HTML</strong> &mdash; Just enter in raw HTML code here, and it&#8217;ll be entered into the &lt;head&gt; tag across your entire site.</p></li>
186
- </ul>
187
- ", 'seo-ultimate');
188
- }
189
-
190
- function postmeta_help($help) {
191
- $help[] = __("<strong>Description:</strong> &mdash; The value of the meta description tag. The description will often appear underneath the title in search engine results. ".
192
- "Writing an accurate, attention-grabbing description for every post is important to ensuring a good search results clickthrough rate.", 'seo-ultimate');
193
- $help[] = __("<strong>Keywords:</strong> &mdash; The value of the meta keywords tag. The keywords list gives search engines a hint as to what this post/page is about. ".
194
- "Be sure to separate keywords with commas, like so: <samp>one,two,three</samp>.", 'seo-ultimate');
195
- return $help;
196
- }
197
-
198
- }
199
-
200
- }
201
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
modules/meta/meta-settings.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Meta Editor Settings Module
4
+ *
5
+ * @version 1.0
6
+ * @since 1.5
7
+ */
8
+
9
+ if (class_exists('SU_Module')) {
10
+
11
+ class SU_MetaSettings extends SU_Module {
12
+
13
+ function get_parent_module() { return 'meta'; }
14
+ function is_independent_module() { return false; }
15
+
16
+ function get_module_title() { return __('Meta Editor Settings', 'seo-ultimate'); }
17
+ function get_module_subtitle() { return __('Settings', 'seo-ultimate'); }
18
+
19
+ function get_default_settings() {
20
+ return array(
21
+ 'home_description_tagline_default' => true
22
+ );
23
+ }
24
+
25
+ function admin_page_contents() {
26
+ $this->admin_form_table_start();
27
+ $this->textareas(array(
28
+ 'home_description' => __("Blog Homepage Meta Description", 'seo-ultimate')
29
+ , 'home_keywords' => __("Blog Homepage Meta Keywords", 'seo-ultimate')
30
+ ), 3);
31
+ $this->checkboxes(array(
32
+ 'home_description_tagline_default' => __("Use this blog&#8217s tagline as the default homepage description.", 'seo-ultimate')
33
+ ), __("Default Values", 'seo-ultimate'));
34
+ $this->checkboxes(array(
35
+ 'noodp' => __("Don&#8217t use this site&#8217s Open Directory description in search results.", 'seo-ultimate')
36
+ , 'noydir' => __("Don&#8217t use this site&#8217s Yahoo! Directory description in search results.", 'seo-ultimate')
37
+ , 'noarchive' => __("Don&#8217t cache or archive this site.", 'seo-ultimate')
38
+ ), __("Spider Instructions", 'seo-ultimate'));
39
+ $this->textboxes(array(
40
+ 'google_verify' => __("Google Webmaster Tools:", 'seo-ultimate')
41
+ , 'yahoo_verify' => __("Yahoo! Site Explorer:", 'seo-ultimate')
42
+ , 'microsoft_verify' => __("Bing Webmaster Center:", 'seo-ultimate')
43
+ ), array(), __("Verification Codes", 'seo-ultimate'));
44
+ $this->textarea('custom_html', __("Custom &lt;head&gt; HTML", 'seo-ultimate'));
45
+ $this->admin_form_table_end();
46
+ }
47
+ }
48
+
49
+ }
50
+ ?>
modules/meta/meta.php ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Meta Editor Module
4
+ *
5
+ * @version 1.0.7
6
+ * @since 0.3
7
+ */
8
+
9
+ if (class_exists('SU_Module')) {
10
+
11
+ class SU_Meta extends SU_Module {
12
+
13
+ function get_module_title() { return __('Meta Editor', 'seo-ultimate'); }
14
+
15
+ function init() {
16
+ $this->admin_page_tabs_init();
17
+
18
+ add_filter('su_meta_robots', array(&$this, 'meta_robots'));
19
+ add_action('su_head', array(&$this, 'head_tag_output'));
20
+ add_filter('su_postmeta_help', array(&$this, 'postmeta_help'), 20);
21
+ }
22
+
23
+ //Add the appropriate commands to the meta robots array
24
+ function meta_robots($commands) {
25
+
26
+ $tags = array('noodp', 'noydir', 'noarchive');
27
+
28
+ foreach ($tags as $tag) {
29
+ if ($this->get_setting($tag)) $commands[] = $tag;
30
+ }
31
+
32
+ return $commands;
33
+ }
34
+
35
+ function head_tag_output() {
36
+
37
+ $desc = false;
38
+ $kw = false;
39
+
40
+ //If we're viewing the homepage, look for homepage meta data.
41
+ if (is_home()) {
42
+ $desc = $this->get_setting('home_description');
43
+ if (!$desc && $this->get_setting('home_description_tagline_default')) $desc = get_bloginfo('description');
44
+ $kw = $this->get_setting('home_keywords');
45
+
46
+ //If we're viewing a post or page, look for its meta data.
47
+ } elseif (is_singular()) {
48
+ $desc = $this->get_postmeta('description');
49
+ $kw = $this->get_postmeta('keywords');
50
+ }
51
+
52
+ //Do we have a description? If so, output it.
53
+ if ($desc) {
54
+ $desc = su_esc_attr($desc);
55
+ echo "\t<meta name=\"description\" content=\"$desc\" />\n";
56
+ }
57
+
58
+ //Do we have keywords? If so, output them.
59
+ if ($kw) {
60
+ $kw = su_esc_attr($kw);
61
+ echo "\t<meta name=\"keywords\" content=\"$kw\" />\n";
62
+ }
63
+
64
+ //Supported meta tags and their names
65
+ $verify = array(
66
+ 'google' => 'google-site-verification'
67
+ , 'yahoo' => 'y_key'
68
+ , 'microsoft' => 'msvalidate.01'
69
+ );
70
+
71
+ //Do we have verification tags? If so, output them.
72
+ foreach ($verify as $site => $name) {
73
+ if ($value = $this->get_setting($site.'_verify')) {
74
+ $value = su_esc_attr($value);
75
+ echo "\t<meta name=\"$name\" content=\"$value\" />\n";
76
+ }
77
+ }
78
+
79
+ //Display custom code if provided
80
+ if ($custom = $this->get_setting('custom_html')) {
81
+
82
+ //Does the plugin user want us to surround code insertions with comments? If so, mark the custom code as such.
83
+ $mark_code = $this->get_setting('mark_code', false, 'settings');
84
+ $desc = __('Custom Header Code', 'seo-ultimate');
85
+
86
+ echo "\n";
87
+ if ($mark_code) echo "\t<!-- $desc -->\n";
88
+ echo $custom;
89
+ if ($mark_code) echo "\n\t<!-- /$desc -->";
90
+ echo "\n\n";
91
+ }
92
+
93
+ }
94
+
95
+ function postmeta_fields($fields) {
96
+ $id = "_su_description";
97
+ $value = attribute_escape($this->get_postmeta('description'));
98
+
99
+ $fields['20|description|keywords'] =
100
+ "<tr class='textarea'>\n<th scope='row'><label for='$id'>".__("Description:", 'seo-ultimate')."</label></th>\n"
101
+ . "<td><textarea name='$id' id='$id' type='text' class='regular-text' cols='60' rows='3'"
102
+ . " onkeyup=\"javascript:document.getElementById('su_meta_description_charcount').innerHTML = document.getElementById('_su_description').value.length\">$value</textarea>"
103
+ . "<br />".sprintf(__("You&#8217;ve entered %s characters. Most search engines use up to 160.", 'seo-ultimate'), "<strong id='su_meta_description_charcount'>".strlen($value)."</strong>")
104
+ . "</td>\n</tr>\n"
105
+ . $this->get_postmeta_textbox('keywords', __('Keywords:<br /><em>(separate with commas)</em>', 'seo-ultimate'))
106
+ ;
107
+
108
+ return $fields;
109
+ }
110
+
111
+ function postmeta_help($help) {
112
+ $help[] = __("<strong>Description:</strong> &mdash; The value of the meta description tag. The description will often appear underneath the title in search engine results. ".
113
+ "Writing an accurate, attention-grabbing description for every post is important to ensuring a good search results clickthrough rate.", 'seo-ultimate');
114
+ $help[] = __("<strong>Keywords:</strong> &mdash; The value of the meta keywords tag. The keywords list gives search engines a hint as to what this post/page is about. ".
115
+ "Be sure to separate keywords with commas, like so: <samp>one,two,three</samp>.", 'seo-ultimate');
116
+ return $help;
117
+ }
118
+
119
+ }
120
+
121
+ }
122
+ ?>
modules.css → modules/modules.css RENAMED
@@ -52,6 +52,25 @@ div.su-module table.report th, div.su-module table.report td {
52
  text-align: left;
53
  }
54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  /* TABS (Heavily based on CSS from the Breadcrumbs NavXT plugin) */
56
 
57
  div.su-module .su-tabs ul.ui-tabs-nav {
52
  text-align: left;
53
  }
54
 
55
+ div.su-module table.su-indent {
56
+ padding-left: 30px;
57
+ }
58
+
59
+ div.su-module table.su-indent th {
60
+ font-size: 1.1em;
61
+ }
62
+
63
+ div.su-module table.su-indent th:after { content: ":"; }
64
+
65
+ div.su-importmodule div.su-status {
66
+ padding-top: 0.5em;
67
+ padding-bottom: 0.5em;
68
+ }
69
+
70
+ div.su-importmodule #import-status {
71
+ padding: 1em 0;
72
+ }
73
+
74
  /* TABS (Heavily based on CSS from the Breadcrumbs NavXT plugin) */
75
 
76
  div.su-module .su-tabs ul.ui-tabs-nav {
modules.js → modules/modules.js RENAMED
File without changes
modules/{modules.php → modules/modules.php} RENAMED
@@ -2,7 +2,7 @@
2
  /**
3
  * Module Manager Module
4
  *
5
- * @version 1.1.1
6
  * @since 0.7
7
  */
8
 
@@ -10,29 +10,28 @@ if (class_exists('SU_Module')) {
10
 
11
  class SU_Modules extends SU_Module {
12
 
 
13
  function get_menu_title() { return __('Modules', 'seo-ultimate'); }
14
- function get_page_title() { return __('Module Manager', 'seo-ultimate'); }
15
  function get_menu_pos() { return 10; }
 
16
 
17
  function init() {
18
- global $seo_ultimate;
19
-
20
  if ($this->is_action('update')) {
21
 
22
  foreach ($_POST as $key => $value) {
23
  if (substr($key, 0, 3) == 'su-') {
24
  $key = str_replace(array('su-', '-module-status'), '', $key);
25
- $seo_ultimate->dbdata['modules'][$key] = intval($value);
 
 
26
  }
27
  }
28
  }
29
  }
30
 
31
  function admin_page_contents() {
32
- global $seo_ultimate;
33
-
34
  echo "<p>";
35
- _e("SEO Ultimate&#8217;s features are located in groups called &#8220;modules.&#8221; By default, most of these modules are listed in the &#8220;SEO&#8221; menu on the left. Whenever you&#8217;re working with a module, you can view documentation by clicking the &#8220;Help&#8221; tab in the upper-right-hand corner of your administration screen.", 'seo-ultimate');
36
  echo "</p><p>";
37
  _e("The Module Manager lets you disable or hide modules you don&#8217;t use. You can also silence modules from displaying bubble alerts on the menu.", 'seo-ultimate');
38
  echo "</p>";
@@ -62,26 +61,58 @@ STR;
62
 
63
  $modules = array();
64
 
65
- foreach ($seo_ultimate->modules as $key => $module) {
 
 
66
  //On some setups, get_parent_class() returns the class name in lowercase
67
- if (strcasecmp(get_parent_class($module), 'SU_Module') == 0 && !in_array($key, array('stats', 'modules')))
68
  $modules[$key] = $module->get_page_title();
69
  }
70
 
71
- $modules = array_merge($modules, $seo_ultimate->disabled_modules);
 
 
 
 
 
 
72
  asort($modules);
73
 
 
 
 
 
 
 
 
 
 
74
  foreach ($modules as $key => $name) {
75
 
76
- $currentstatus = $seo_ultimate->dbdata['modules'][$key];
77
 
78
  echo "\t\t<tr>\n\t\t\t<td class='module-status' id='$key-module-status'>\n";
79
  echo "\t\t\t\t<input type='hidden' name='su-$key-module-status' id='su-$key-module-status' value='$currentstatus' />\n";
80
 
81
  foreach ($statuses as $statuscode => $statuslabel) {
82
- if ($currentstatus == $statuscode) $current = ' current'; else $current = '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  $codeclass = str_replace('-', 'n', strval($statuscode));
84
- echo "\t\t\t\t\t<span class='status-$codeclass'>";
85
  echo "<a href='javascript:void(0)' onclick=\"javascript:set_module_status('$key', $statuscode, this)\" class='$current'>$statuslabel</a></span>\n";
86
  }
87
 
@@ -104,18 +135,6 @@ STR;
104
 
105
  $this->admin_form_end(false, false);
106
  }
107
-
108
- function admin_help() {
109
- return __("
110
- <p>The Module Manager lets you customize the visibility and accessibility of each module; here are the options available:</p>
111
- <ul>
112
- <li><strong>Enabled</strong> &mdash; The default option. The module will be fully enabled and accessible.</li>
113
- <li><strong>Silenced</strong> &mdash; The module will be enabled and accessible, but it won&#8217;t be allowed to display numeric bubble alerts on the menu.</li>
114
- <li><strong>Hidden</strong> &mdash; The module&#8217;s functionality will be enabled, but the module won&#8217;t be visible on the SEO menu. You will still be able to access the module&#8217;s admin page by clicking on its title in the Module Manager table.</li>
115
- <li><strong>Disabled</strong> &mdash; The module will be completely disabled and inaccessible.</li>
116
- </ul>
117
- ", 'seo-ultimate');
118
- }
119
  }
120
 
121
  } elseif ($_GET['css'] == 'admin') {
2
  /**
3
  * Module Manager Module
4
  *
5
+ * @version 1.2
6
  * @since 0.7
7
  */
8
 
10
 
11
  class SU_Modules extends SU_Module {
12
 
13
+ function get_module_title() { return __('Module Manager', 'seo-ultimate'); }
14
  function get_menu_title() { return __('Modules', 'seo-ultimate'); }
 
15
  function get_menu_pos() { return 10; }
16
+ function is_menu_default(){ return true; }
17
 
18
  function init() {
 
 
19
  if ($this->is_action('update')) {
20
 
21
  foreach ($_POST as $key => $value) {
22
  if (substr($key, 0, 3) == 'su-') {
23
  $key = str_replace(array('su-', '-module-status'), '', $key);
24
+ $value = intval($value);
25
+
26
+ $this->plugin->dbdata['modules'][$key] = $value;
27
  }
28
  }
29
  }
30
  }
31
 
32
  function admin_page_contents() {
 
 
33
  echo "<p>";
34
+ _e("SEO Ultimate&#8217;s features are located in groups called &#8220;modules.&#8221; By default, most of these modules are listed in the &#8220;SEO&#8221; menu on the left. Whenever you&#8217;re working with a module, you can view documentation by clicking the tabs in the upper-right-hand corner of your administration screen.", 'seo-ultimate');
35
  echo "</p><p>";
36
  _e("The Module Manager lets you disable or hide modules you don&#8217;t use. You can also silence modules from displaying bubble alerts on the menu.", 'seo-ultimate');
37
  echo "</p>";
61
 
62
  $modules = array();
63
 
64
+ foreach ($this->plugin->modules as $key => $x_module) {
65
+ $module =& $this->plugin->modules[$key];
66
+
67
  //On some setups, get_parent_class() returns the class name in lowercase
68
+ if (strcasecmp(get_parent_class($module), 'SU_Module') == 0 && !in_array($key, array('modules')) && $module->is_independent_module())
69
  $modules[$key] = $module->get_page_title();
70
  }
71
 
72
+ foreach ($this->plugin->disabled_modules as $key => $class) {
73
+
74
+ if (call_user_func(array($class, 'is_independent_module')))
75
+ $modules[$key] = call_user_func(array($class, 'get_module_title'));
76
+
77
+ }
78
+
79
  asort($modules);
80
 
81
+ //Do we have any modules requiring the "Silenced" column? Store that boolean in $any_hmc
82
+ $any_hmc = false;
83
+ foreach ($modules as $key => $name) {
84
+ if ($this->plugin->call_module_func($key, 'has_menu_count', $hmc) && $hmc) {
85
+ $any_hmc = true;
86
+ break;
87
+ }
88
+ }
89
+
90
  foreach ($modules as $key => $name) {
91
 
92
+ $currentstatus = $this->plugin->dbdata['modules'][$key];
93
 
94
  echo "\t\t<tr>\n\t\t\t<td class='module-status' id='$key-module-status'>\n";
95
  echo "\t\t\t\t<input type='hidden' name='su-$key-module-status' id='su-$key-module-status' value='$currentstatus' />\n";
96
 
97
  foreach ($statuses as $statuscode => $statuslabel) {
98
+
99
+ $hmc = ($this->plugin->call_module_func($key, 'has_menu_count', $_hmc) && $_hmc);
100
+
101
+ $is_current = false;
102
+ $style = '';
103
+ switch ($statuscode) {
104
+ case SU_MODULE_ENABLED:
105
+ if ($currentstatus == SU_MODULE_SILENCED && !$hmc) $is_current = true;
106
+ break;
107
+ case SU_MODULE_SILENCED:
108
+ if (!$any_hmc) continue 2;
109
+ if (!$hmc) $style = " style='visibility: hidden;'";
110
+ break;
111
+ }
112
+
113
+ if ($is_current || $currentstatus == $statuscode) $current = ' current'; else $current = '';
114
  $codeclass = str_replace('-', 'n', strval($statuscode));
115
+ echo "\t\t\t\t\t<span class='status-$codeclass'$style>";
116
  echo "<a href='javascript:void(0)' onclick=\"javascript:set_module_status('$key', $statuscode, this)\" class='$current'>$statuslabel</a></span>\n";
117
  }
118
 
135
 
136
  $this->admin_form_end(false, false);
137
  }
 
 
 
 
 
 
 
 
 
 
 
 
138
  }
139
 
140
  } elseif ($_GET['css'] == 'admin') {
modules/{more-links.php → more-links/more-links.php} RENAMED
@@ -2,7 +2,7 @@
2
  /**
3
  * More Link Customizer Module
4
  *
5
- * @version 1.0
6
  * @since 1.3
7
  */
8
 
@@ -10,7 +10,7 @@ if (class_exists('SU_Module')) {
10
 
11
  class SU_MoreLinks extends SU_Module {
12
 
13
- function get_menu_title() { return __('More Link Customizer', 'seo-ultimate'); }
14
 
15
  function get_default_settings() {
16
  return array(
@@ -64,16 +64,6 @@ class SU_MoreLinks extends SU_Module {
64
 
65
  return $value;
66
  }
67
-
68
- function admin_help() {
69
- return __("
70
- <ul>
71
- <li><p><strong>What it does:</strong> More Link Customizer lets you modify the anchor text of your posts&#8217; <a href='http://codex.wordpress.org/Customizing_the_Read_More' target='_blank'>&#8220;more&#8221; links</a>.</p></li>
72
- <li><p><strong>Why it helps:</strong> On the typical WordPress setup, the &#8220;more link&#8221; always has the same anchor text (e.g. &#8220;Read more of this entry &raquo;&#8221;). Since internal anchor text conveys web page topicality to search engines, the &#8220;read more&#8221; phrase isn&#8217;t a desirable anchor phrase. More Link Customizer lets you replace the boilerplate text with a new anchor that, by default, integrates your post titles (which will ideally be keyword-oriented).</p></li>
73
- <li><p><strong>How to use it:</strong> On this page you can set the anchor text you&#8217;d like to use by default. The <code>{post}</code> variable will be replaced with the post&#8217;s title. HTML and encoded entities are supported. If instead you decide that you&#8217;d like to use the default anchor text specified by your currently-active theme, just erase the contents of the textbox. The anchor text can be overriden on a per-post basis via the &#8220;More Link Text&#8221; box in the &#8220;SEO Settings&#8221; section of the WordPress post editor.</p></li>
74
- </ul>
75
- ", 'seo-ultimate');
76
- }
77
  }
78
 
79
  }
2
  /**
3
  * More Link Customizer Module
4
  *
5
+ * @version 1.0.1
6
  * @since 1.3
7
  */
8
 
10
 
11
  class SU_MoreLinks extends SU_Module {
12
 
13
+ function get_module_title() { return __('More Link Customizer', 'seo-ultimate'); }
14
 
15
  function get_default_settings() {
16
  return array(
64
 
65
  return $value;
66
  }
 
 
 
 
 
 
 
 
 
 
67
  }
68
 
69
  }
modules/{noindex.php → noindex/noindex.php} RENAMED
@@ -2,7 +2,7 @@
2
  /**
3
  * Noindex Manager Module
4
  *
5
- * @version 1.1.1
6
  * @since 0.1
7
  */
8
 
@@ -10,7 +10,7 @@ if (class_exists('SU_Module')) {
10
 
11
  class SU_Noindex extends SU_Module {
12
 
13
- function get_menu_title() { return __('Noindex Manager', 'seo-ultimate'); }
14
 
15
  function init() {
16
 
@@ -88,45 +88,6 @@ class SU_Noindex extends SU_Module {
88
  function xhtml_noindex_tag() {
89
  echo "\t<meta name=\"robots\" content=\"noindex\" />\n";
90
  }
91
-
92
- function admin_dropdowns() {
93
- return array(
94
- 'overview' => __('Overview', 'seo-ultimate')
95
- , 'settings' => __('Settings Help', 'seo-ultimate')
96
- );
97
- }
98
-
99
- function admin_dropdown_overview() {
100
- return __("
101
- <ul>
102
- <li><p><strong>What it does:</strong> Noindex Manager lets you prohibit the search engine spiders from indexing certain pages on your blog using the &quot;meta robots noindex&quot; tag.</p></li>
103
- <li><p><strong>Why it helps:</strong> This module lets you &#8220;noindex&#8221; pages that contain unimportant content (e.g. the login page), or pages that mostly contain duplicate content.</p></li>
104
- <li><p><strong>How to use it:</strong> Adjust the settings as desired, and then click Save Changes. You can refer to the &#8220;Settings Help&#8221; tab for information on the settings available.</p></li>
105
- </ul>
106
- ", 'seo-ultimate');
107
- }
108
-
109
- function admin_dropdown_settings() {
110
- return __("
111
- <p>Here&#8217;s information on the various settings:</p>
112
- <ul>
113
- <li><p><strong>Administration back-end pages</strong> &mdash; Tells spiders not to index the administration area (the part you&#8217;re in now),
114
- in the unlikely event a spider somehow gains access to the administration. Recommended.</p></li>
115
- <li><p><strong>Author archives</strong> &mdash; Tells spiders not to index author archives. Useful if your blog only has one author.</p></li>
116
- <li><p><strong>Blog search pages</strong> &mdash; Tells spiders not to index the result pages of WordPress&#8217;s blog search function. Recommended.</p></li>
117
- <li><p><strong>Category archives</strong> &mdash; Tells spiders not to index category archives. Recommended only if you don&#8217;t use categories.</p></li>
118
- <li><p><strong>Comment feeds</strong> &mdash; Tells spiders not to index the RSS feeds that exist for every post&#8217;s comments.
119
- (These comment feeds are totally separate from your normal blog feeds.) Recommended.</p></li>
120
- <li><p><strong>Comment subpages</strong> &mdash; Tells spiders not to index posts' comment subpages.</p></li>
121
- <li><p><strong>Date-based archives</strong> &mdash; Tells spiders not to index day/month/year archives.
122
- Recommended, since these pages have little keyword value.</p></li>
123
- <li><p><strong>Subpages of the homepage</strong> &mdash; Tells spiders not to index the homepage's subpages (page 2, page 3, etc).
124
- Recommended.</p></li>
125
- <li><p><strong>Tag archives</strong> &mdash; Tells spiders not to index tag archives. Recommended only if you don&#8217;t use tags.</p></li>
126
- <li><p><strong>User login/registration pages</strong> &mdash; Tells spiders not to index WordPress&#8217;s user login and registration pages. Recommended.</p></li>
127
- </ul>
128
- ", 'seo-ultimate');
129
- }
130
  }
131
 
132
  }
2
  /**
3
  * Noindex Manager Module
4
  *
5
+ * @version 1.1.2
6
  * @since 0.1
7
  */
8
 
10
 
11
  class SU_Noindex extends SU_Module {
12
 
13
+ function get_module_title() { return __('Noindex Manager', 'seo-ultimate'); }
14
 
15
  function init() {
16
 
88
  function xhtml_noindex_tag() {
89
  echo "\t<meta name=\"robots\" content=\"noindex\" />\n";
90
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  }
92
 
93
  }
modules/{sds-blog.php → sds-blog/sds-blog.php} RENAMED
@@ -2,7 +2,7 @@
2
  /**
3
  * SEO Design Solutions Whitepapers Module
4
  *
5
- * @version 1.0.4
6
  * @since 0.1
7
  */
8
 
@@ -10,8 +10,9 @@ if (class_exists('SU_Module')) {
10
 
11
  class SU_SdsBlog extends SU_Module {
12
 
13
- function get_page_title() { return __('SEO Design Solutions Whitepapers', 'seo-ultimate'); }
14
- function get_menu_title() { return __('Whitepapers', 'seo-ultimate'); }
 
15
  function get_menu_count() { return $this->get_unread_count(); }
16
 
17
  function __construct() {
@@ -33,7 +34,7 @@ class SU_SdsBlog extends SU_Module {
33
  }
34
 
35
  function load_blog_rss() {
36
- $rss = $this->load_rss('http://feeds.seodesignsolutions.com/SeoDesignSolutionsBlog');
37
  if ($rss) $this->update_setting('rssitems', $rss->items);
38
  }
39
 
2
  /**
3
  * SEO Design Solutions Whitepapers Module
4
  *
5
+ * @version 1.0.5
6
  * @since 0.1
7
  */
8
 
10
 
11
  class SU_SdsBlog extends SU_Module {
12
 
13
+ function get_module_title() { return __('Whitepapers', 'seo-ultimate'); }
14
+ function get_page_title() { return __('SEO Design Solutions Whitepapers', 'seo-ultimate'); }
15
+ function has_menu_count() { return true; }
16
  function get_menu_count() { return $this->get_unread_count(); }
17
 
18
  function __construct() {
34
  }
35
 
36
  function load_blog_rss() {
37
+ $rss = suwp::load_rss('http://feeds.seodesignsolutions.com/SeoDesignSolutionsBlog');
38
  if ($rss) $this->update_setting('rssitems', $rss->items);
39
  }
40
 
modules/{settings.php → settings/settings.php} RENAMED
@@ -2,7 +2,7 @@
2
  /**
3
  * SEO Ultimate Plugin Settings Module
4
  *
5
- * @version 2.2.3
6
  * @since 0.2
7
  */
8
 
@@ -12,6 +12,7 @@ class SU_Settings extends SU_Module {
12
 
13
  var $wp_meta_called = false;
14
 
 
15
  function get_page_title() { return __('SEO Ultimate Plugin Settings', 'seo-ultimate'); }
16
  function get_menu_title() { return __('SEO Ultimate', 'seo-ultimate'); }
17
  function get_menu_parent(){ return 'options-general.php'; }
@@ -31,16 +32,15 @@ class SU_Settings extends SU_Module {
31
  }
32
 
33
  function init() {
34
- global $seo_ultimate;
35
 
36
- if ($this->is_action('export')) {
37
  header('Content-Type: application/octet-stream');
38
  header('Content-Disposition: attachment; filename="SEO Ultimate Settings ('.date('Y-m-d').').dat"');
39
 
40
  $options = $this->portable_options();
41
  $export = array();
42
  foreach ($options as $option) {
43
- $data = $seo_ultimate->dbdata[$option];
44
  $data = apply_filters("su_{$option}_export_array", $data);
45
  $export[$option] = $data;
46
  }
@@ -49,7 +49,7 @@ class SU_Settings extends SU_Module {
49
  echo $export;
50
  die();
51
 
52
- } elseif ($this->is_action('import')) {
53
 
54
  if (strlen($_FILES['settingsfile']['name'])) {
55
 
@@ -61,7 +61,7 @@ class SU_Settings extends SU_Module {
61
 
62
  $options = $this->portable_options();
63
  foreach ($options as $option) {
64
- $seo_ultimate->dbdata[$option] = array_merge($seo_ultimate->dbdata[$option], $import[$option]);
65
  }
66
 
67
  $this->queue_message('success', __("Settings successfully imported.", 'seo-ultimate'));
@@ -73,10 +73,10 @@ class SU_Settings extends SU_Module {
73
  } else
74
  $this->queue_message('warning', __("Settings could not be imported because no settings file was selected. Please click the &#8220;Browse&#8221; button and select a file to import.", 'seo-ultimate'));
75
 
76
- } elseif ($this->is_action('reset')) {
77
 
78
- $seo_ultimate->dbdata['settings'] = array();
79
- unset($seo_ultimate->dbdata['modules']);
80
  $this->load_default_settings();
81
 
82
  $this->queue_message('success', __("All settings have been erased and defaults have been restored.", 'seo-ultimate'));
@@ -123,7 +123,7 @@ class SU_Settings extends SU_Module {
123
  echo "<tr><th scope='row'>";
124
  _e("Export:", 'seo-ultimate');
125
  echo "</th><td>";
126
- $url = $this->get_nonce_url('export');
127
  echo "<a href='$url' class='button-secondary'>".__("Download Settings File", 'seo-ultimate')."</a>";
128
  echo "</td></tr>";
129
 
@@ -131,12 +131,12 @@ class SU_Settings extends SU_Module {
131
  echo "<tr><th scope='row'>";
132
  _e("Import:", 'seo-ultimate');
133
  echo "</th><td>";
134
- $hook = SEO_Ultimate::key_to_hook($this->get_module_key());
135
  echo "<form enctype='multipart/form-data' method='post' action='?page=$hook&amp;action=import'>\n";
136
  echo "\t<input name='settingsfile' type='file' /> ";
137
  $confirm = __("Are you sure you want to import this settings file? This will overwrite your current settings and cannot be undone.", 'seo-ultimate');
138
  echo "<input type='submit' class='button-secondary' value='".__("Import This Settings File", 'seo-ultimate')."' onclick=\"javascript:return confirm('$confirm')\" />\n";
139
- wp_nonce_field($this->get_nonce_handle('import'));
140
  echo "</form>\n";
141
  echo "</td></tr>";
142
 
@@ -144,13 +144,42 @@ class SU_Settings extends SU_Module {
144
  echo "<tr><th scope='row'>";
145
  _e("Reset:", 'seo-ultimate');
146
  echo "</th><td>";
147
- $url = $this->get_nonce_url('reset');
148
  $confirm = __("Are you sure you want to erase all module settings? This cannot be undone.", 'seo-ultimate');
149
  echo "<a href='$url' class='button-secondary' onclick=\"javascript:return confirm('$confirm')\">".__("Restore Default Settings", 'seo-ultimate')."</a>";
150
  echo "</td></tr>";
151
 
152
  //End table
153
  echo "</table>";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  }
155
 
156
  function meta_link() {
@@ -168,24 +197,6 @@ class SU_Settings extends SU_Module {
168
  echo "\n<p id='suattr'$pstyle>Search engine optimization by <a href='http://www.seodesignsolutions.com/'$astyle>SEO Design Solutions</a></a></p>\n";
169
  }
170
  }
171
-
172
- function admin_help() {
173
- return __("
174
- <p>The Settings module lets you manage settings related to the SEO Ultimate plugin as a whole.</p>
175
- <p>Here&#8217;s information on some of the settings:</p>
176
- <ul>
177
- <li><p><strong>Enable attribution link</strong> &mdash; If enabled, the plugin will display an attribution link on your site.
178
- We ask that you please leave this enabled.</p></li>
179
- <li><p><strong>Insert comments around HTML code insertions</strong> &mdash; If enabled, SEO Ultimate will use HTML comments to identify all code it inserts into your &lt;head&gt; tag.
180
- This is useful if you&#8217;re trying to figure out whether or not SEO Ultimate is inserting a certain piece of header code.</p></li>
181
- <li><p><strong>Allow modules to save visitor information to the database</strong> &mdash; This allows enabled modules to record information about the people or robots that visit your website.
182
- This information is stored in your WordPress database. This setting must be enabled in order for modules like the 404 Monitor to function.</p></li>
183
- <li><p><strong>Delete logged visitor information after ___ days</strong> &mdash; If enabled, SEO Ultimate will delete visitor information once it has been stored for more than a specified number of days.
184
- (The default value is 30.) Enable this setting if the visitor-logging functionality is making your database size unmanageable.
185
- Please note that as soon as you enable this and click the Save button, your old visitor information will be irreversably purged accordingly.</p></li>
186
- </ul>
187
- ", 'seo-ultimate');
188
- }
189
 
190
  }
191
 
2
  /**
3
  * SEO Ultimate Plugin Settings Module
4
  *
5
+ * @version 2.3
6
  * @since 0.2
7
  */
8
 
12
 
13
  var $wp_meta_called = false;
14
 
15
+ function get_module_title() { return __('Plugin Settings', 'seo-ultimate'); }
16
  function get_page_title() { return __('SEO Ultimate Plugin Settings', 'seo-ultimate'); }
17
  function get_menu_title() { return __('SEO Ultimate', 'seo-ultimate'); }
18
  function get_menu_parent(){ return 'options-general.php'; }
32
  }
33
 
34
  function init() {
 
35
 
36
+ if ($this->is_action('su-export')) {
37
  header('Content-Type: application/octet-stream');
38
  header('Content-Disposition: attachment; filename="SEO Ultimate Settings ('.date('Y-m-d').').dat"');
39
 
40
  $options = $this->portable_options();
41
  $export = array();
42
  foreach ($options as $option) {
43
+ $data = $this->plugin->dbdata[$option];
44
  $data = apply_filters("su_{$option}_export_array", $data);
45
  $export[$option] = $data;
46
  }
49
  echo $export;
50
  die();
51
 
52
+ } elseif ($this->is_action('su-import')) {
53
 
54
  if (strlen($_FILES['settingsfile']['name'])) {
55
 
61
 
62
  $options = $this->portable_options();
63
  foreach ($options as $option) {
64
+ $this->plugin->dbdata[$option] = array_merge($this->plugin->dbdata[$option], $import[$option]);
65
  }
66
 
67
  $this->queue_message('success', __("Settings successfully imported.", 'seo-ultimate'));
73
  } else
74
  $this->queue_message('warning', __("Settings could not be imported because no settings file was selected. Please click the &#8220;Browse&#8221; button and select a file to import.", 'seo-ultimate'));
75
 
76
+ } elseif ($this->is_action('su-reset')) {
77
 
78
+ $this->plugin->dbdata['settings'] = array();
79
+ unset($this->plugin->dbdata['modules']);
80
  $this->load_default_settings();
81
 
82
  $this->queue_message('success', __("All settings have been erased and defaults have been restored.", 'seo-ultimate'));
123
  echo "<tr><th scope='row'>";
124
  _e("Export:", 'seo-ultimate');
125
  echo "</th><td>";
126
+ $url = $this->get_nonce_url('su-export');
127
  echo "<a href='$url' class='button-secondary'>".__("Download Settings File", 'seo-ultimate')."</a>";
128
  echo "</td></tr>";
129
 
131
  echo "<tr><th scope='row'>";
132
  _e("Import:", 'seo-ultimate');
133
  echo "</th><td>";
134
+ $hook = $this->plugin->key_to_hook($this->get_module_key());
135
  echo "<form enctype='multipart/form-data' method='post' action='?page=$hook&amp;action=import'>\n";
136
  echo "\t<input name='settingsfile' type='file' /> ";
137
  $confirm = __("Are you sure you want to import this settings file? This will overwrite your current settings and cannot be undone.", 'seo-ultimate');
138
  echo "<input type='submit' class='button-secondary' value='".__("Import This Settings File", 'seo-ultimate')."' onclick=\"javascript:return confirm('$confirm')\" />\n";
139
+ wp_nonce_field($this->get_nonce_handle('su-import'));
140
  echo "</form>\n";
141
  echo "</td></tr>";
142
 
144
  echo "<tr><th scope='row'>";
145
  _e("Reset:", 'seo-ultimate');
146
  echo "</th><td>";
147
+ $url = $this->get_nonce_url('su-reset');
148
  $confirm = __("Are you sure you want to erase all module settings? This cannot be undone.", 'seo-ultimate');
149
  echo "<a href='$url' class='button-secondary' onclick=\"javascript:return confirm('$confirm')\">".__("Restore Default Settings", 'seo-ultimate')."</a>";
150
  echo "</td></tr>";
151
 
152
  //End table
153
  echo "</table>";
154
+
155
+ //Import from other plugins
156
+ $importmodules = array();
157
+ foreach ($this->plugin->modules as $key => $x_module) {
158
+ $module =& $this->plugin->modules[$key];
159
+ if (is_a($module, 'SU_ImportModule')) {
160
+ $importmodules[$key] =& $module;
161
+ }
162
+ }
163
+
164
+ if (count($importmodules)) {
165
+ $this->admin_subheader(__("Import from Other Plugins", 'seo-ultimate'));
166
+ echo "\n<p>";
167
+ _e("You can import settings and data from these plugins. Clicking a plugin&#8217;s name will take you to the importer page, where you can customize parameters and start the import.", 'seo-ultimate');
168
+ echo "</p>\n";
169
+ echo "<table class='widefat'>\n";
170
+
171
+ $class = '';
172
+ foreach ($importmodules as $key => $x_module) {
173
+ $module =& $importmodules[$key];
174
+ $title = $module->get_op_title();
175
+ $desc = $module->get_import_desc();
176
+ $url = $module->get_admin_url();
177
+ $class = ($class) ? '' : 'alternate';
178
+ echo "\t<tr class='$class'><td><a href='$url'>$title</a></td><td>$desc</td></tr>\n";
179
+ }
180
+
181
+ echo "</table>\n";
182
+ }
183
  }
184
 
185
  function meta_link() {
197
  echo "\n<p id='suattr'$pstyle>Search engine optimization by <a href='http://www.seodesignsolutions.com/'$astyle>SEO Design Solutions</a></a></p>\n";
198
  }
199
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
 
201
  }
202
 
modules/{site-keyword-queries.php → site-keyword-queries/site-keyword-queries.php} RENAMED
@@ -2,16 +2,16 @@
2
  /**
3
  * Internal Relevance Researcher Module
4
  *
5
- * @version 1.0
6
  * @since 1.4
7
  */
8
 
9
  if (class_exists('SU_Module')) {
10
 
11
  class SU_SiteKeywordQueries extends SU_Module {
12
-
 
13
  function get_menu_title() { return __('Int. Rel. Researcher', 'seo-ultimate'); }
14
- function get_page_title() { return __('Internal Relevance Researcher', 'seo-ultimate'); }
15
 
16
  function admin_page_contents() {
17
  ?>
2
  /**
3
  * Internal Relevance Researcher Module
4
  *
5
+ * @version 1.0.1
6
  * @since 1.4
7
  */
8
 
9
  if (class_exists('SU_Module')) {
10
 
11
  class SU_SiteKeywordQueries extends SU_Module {
12
+
13
+ function get_module_title() { return __('Internal Relevance Researcher', 'seo-ultimate'); }
14
  function get_menu_title() { return __('Int. Rel. Researcher', 'seo-ultimate'); }
 
15
 
16
  function admin_page_contents() {
17
  ?>
modules/{slugs.php → slugs/slugs.php} RENAMED
@@ -2,7 +2,7 @@
2
  /**
3
  * Slug Optimizer Module
4
  *
5
- * @version 1.0.2
6
  * @since 0.9
7
  */
8
 
@@ -10,7 +10,7 @@ if (class_exists('SU_Module')) {
10
 
11
  class SU_Slugs extends SU_Module {
12
 
13
- function get_menu_title() { return __('Slug Optimizer', 'seo-ultimate'); }
14
 
15
  function admin_page_contents() {
16
  $this->admin_form_start();
@@ -56,51 +56,6 @@ class SU_Slugs extends SU_Module {
56
  return $newslug;
57
  }
58
 
59
- function admin_dropdowns() {
60
- return array(
61
- 'overview' => __('Overview', 'seo-ultimate')
62
- , 'faq' => __('FAQ', 'seo-ultimate')
63
- );
64
- }
65
-
66
- function admin_dropdown_overview() {
67
- return __("
68
- <ul>
69
- <li><p><strong>What it does:</strong> Slug Optimizer removes common words from the portion of a post&#8217;s or Page&#8217;s URL that is based on its title. (This portion is also known as the &#8220;slug.&#8221;)</p></li>
70
- <li><p><strong>Why it helps:</strong> Slug Optimizer increases keyword potency because there are fewer words in your URLs competing for relevance.</p></li>
71
- <li><p><strong>How to use it:</strong> Slug Optimizer goes to work when you&#8217;re editing a post or Page, with no action required on your part.
72
- If needed, you can use the textbox below to customize which words are removed.</p></li>
73
- </ul>
74
- ", 'seo-ultimate');
75
- }
76
-
77
- function admin_dropdown_faq() {
78
- return __("
79
- <h6>What's a slug?</h6>
80
- <p>The slug of a post or page is the portion of its URL that is based on its title.</p>
81
- <p>When you edit a post or Page in WordPress, the slug is the yellow-highlighted portion of the Permalink beneath the Title textbox.</p>
82
-
83
- <h6>Does the Slug Optimizer change my existing URLs?</h6>
84
- <p>No. Slug Optimizer will not relocate your content by changing existing URLs. Slug Optimizer only takes effect on new posts and pages.</p>
85
-
86
- <h6>How do I see Slug Optimizer in action?</h6>
87
- <ol>
88
- <li>Create a new post/Page in WordPress.</li>
89
- <li>Type in a title containing some common words.</li>
90
- <li>Click outside the Title box. WordPress will insert a URL labeled &#8220;Permalink&#8221; below the Title textbox. The Slug Optimizer will have removed the common words from the URL.</li>
91
- </ol>
92
-
93
- <h6>Why didn't the Slug Optimizer remove common words from my slug?</h6>
94
- <p>It's possible that every word in your post title is in the list of words to remove. In this case, Slug Optimizer doesn't remove the words, because if it did, you'd end up with a blank slug.</p>
95
-
96
- <h6>What if I want to include a common word in my slug?</h6>
97
- <p>When editing the post or page in question, just click the Edit button next to the permalink and change the slug as desired.</p>
98
-
99
- <h6>How do I revert back to the optimized slug after making changes?</h6>
100
- <p>When editing the post or page in question, just click the Edit button next to the permalink; a Save button will appear in its place. Next erase the contents of the textbox, and then click the aforementioned Save button.</p>
101
- ", 'seo-ultimate');
102
- }
103
-
104
  function get_default_settings() {
105
 
106
  //Special thanks to the "SEO Slugs" plugin for the stopwords array.
2
  /**
3
  * Slug Optimizer Module
4
  *
5
+ * @version 1.0.3
6
  * @since 0.9
7
  */
8
 
10
 
11
  class SU_Slugs extends SU_Module {
12
 
13
+ function get_module_title() { return __('Slug Optimizer', 'seo-ultimate'); }
14
 
15
  function admin_page_contents() {
16
  $this->admin_form_start();
56
  return $newslug;
57
  }
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  function get_default_settings() {
60
 
61
  //Special thanks to the "SEO Slugs" plugin for the stopwords array.
modules/titles/titles-formats.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class SU_TitlesFormats extends SU_Module {
3
+
4
+ function get_parent_module() { return 'titles'; }
5
+ function get_child_order() { return 10; }
6
+ function is_independent_module() { return false; }
7
+
8
+ function get_module_title() { return __('Title Rewriter Formats', 'seo-ultimate'); }
9
+ function get_module_subtitle() { return __('Default Formats', 'seo-ultimate'); }
10
+
11
+ function admin_page_contents() {
12
+ echo "<table class='form-table'>\n";
13
+ $this->textboxes($this->parent_module->get_supported_settings(), $this->parent_module->get_default_settings());
14
+ echo "</table>";
15
+ }
16
+ }
17
+ ?>
modules/titles/titles-posts.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Post Title Editor Module
4
+ *
5
+ * @version 1.0
6
+ * @since 1.5
7
+ */
8
+
9
+ if (class_exists('SU_Module')) {
10
+
11
+ class SU_TitlesPosts extends SU_Module {
12
+
13
+ function get_parent_module() { return 'titles'; }
14
+ function get_child_order() { return 20; }
15
+ function is_independent_module() { return false; }
16
+
17
+ function get_module_title() { return __('Post Title Editor', 'seo-ultimate'); }
18
+
19
+ function get_admin_page_tabs() {
20
+
21
+ $type_keys = array('post', 'page');
22
+
23
+ $type_labels = array(
24
+ 'post' => __('Posts')
25
+ , 'page' => __('Pages')
26
+ , 'attachment' => __('Attachments')
27
+ );
28
+
29
+ return $this->parent_module->get_object_subtype_tabs('post', $type_keys, $type_labels, array(&$this, 'admin_page_tab'));
30
+ }
31
+
32
+ function admin_page_tab($post_type) {
33
+ $this->parent_module->title_editing_table($post_type, 'get_posts', 'post_type='.$post_type.'&numberposts=%1$d&offset=%2$d');
34
+ }
35
+
36
+ }
37
+
38
+ }
39
+
40
+ ?>
modules/{titles.php → titles/titles.php} RENAMED
@@ -2,15 +2,15 @@
2
  /**
3
  * Title Rewriter Module
4
  *
5
- * @version 2.0.1
6
  * @since 0.1
7
  */
8
 
9
  if (class_exists('SU_Module')) {
10
 
11
  class SU_Titles extends SU_Module {
12
-
13
- function get_menu_title() { return __('Title Rewriter', 'seo-ultimate'); }
14
 
15
  function init() {
16
  add_action('template_redirect', array(&$this, 'before_header'), 0);
@@ -55,16 +55,6 @@ class SU_Titles extends SU_Module {
55
  );
56
  }
57
 
58
- function admin_page_contents() {
59
- $this->admin_form_start(false, false);
60
- $this->admin_page_tabs(array(
61
- __('Default Formats', 'seo-ultimate') => 'admin_page_formats_tab'
62
- , __('Posts', 'seo-ultimate') => 'admin_page_posts_tab'
63
- , __('Pages', 'seo-ultimate') => 'admin_page_pages_tab'
64
- ));
65
- $this->admin_form_end(false, false);
66
- }
67
-
68
  function admin_page_formats_tab() {
69
  echo "<table class='form-table'>\n";
70
  $this->textboxes($this->get_supported_settings(), $this->get_default_settings());
@@ -134,6 +124,10 @@ class SU_Titles extends SU_Module {
134
  if ($post_title = $this->get_postmeta('title'))
135
  return htmlspecialchars($this->get_title_paged($post_title));
136
 
 
 
 
 
137
  //Load post/page titles
138
  $post_id = 0;
139
  $post_title = '';
@@ -221,6 +215,7 @@ class SU_Titles extends SU_Module {
221
  , '{author_nickname}' => $author['nickname']
222
  , '{query}' => attribute_escape(get_search_query())
223
  , '{ucquery}' => attribute_escape(ucwords(get_search_query()))
 
224
  );
225
 
226
  $title = str_replace(array_keys($variables), array_values($variables), htmlspecialchars($format));
@@ -255,6 +250,27 @@ class SU_Titles extends SU_Module {
255
  return $title;
256
  }
257
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
  function admin_page_posts_tab() {
259
  $this->title_editing_table('post', __('Post'), 'get_posts');
260
  }
@@ -287,17 +303,53 @@ class SU_Titles extends SU_Module {
287
  return false;
288
  }
289
 
290
- function title_editing_table($object_type, $object_type_label, $function,
291
- $get_value_callback = 'get_singular_title', $save_value_callback = 'save_singular_title',
292
- $num_varname = 'numberposts', $offset_varname = 'offset', $id_varname = 'ID', $title_varname = 'post_title', $edit_link_function = 'get_edit_post_link') {
293
 
294
- $mk = $this->get_module_key();
 
 
295
 
296
- add_filter("su_get_setting-$mk", array(&$this, $get_value_callback), 10, 2);
297
- add_filter("su_custom_update_setting-$mk", array(&$this, $save_value_callback), 10, 3);
 
 
 
 
 
 
 
 
 
 
 
298
 
299
- $headers = array( __('ID'), $object_type_label, __('Title Tag', 'seo-ultimate') );
 
 
 
 
 
 
 
 
 
 
 
 
 
300
 
 
 
 
 
 
 
 
 
 
 
301
  echo <<<STR
302
  <table class="widefat fullwidth" cellspacing="0">
303
  <thead><tr>
@@ -313,94 +365,76 @@ STR;
313
  $args = "$num_varname=20&$offset_varname=0";
314
  else
315
  $args = '';*/
316
- $args = "$num_varname=1000";
 
 
 
 
 
317
 
318
- $objects = $function($args);
319
- $pagination_total = ceil(count($function()) / 2);
320
 
321
  foreach ($objects as $object) {
322
  $id = $object->$id_varname;
323
- $editlink = $edit_link_function($id);
324
  $title = $object->$title_varname;
325
 
326
- $this->textbox("{$object_type}_{$id}_title", "<a href='$editlink'>$title</a>");
 
327
  }
328
 
329
  echo "\t</tbody>\n</table>\n";
330
 
331
  }
332
 
333
- function admin_dropdowns() {
334
- return array(
335
- 'overview' => __('Overview', 'seo-ultimate')
336
- , 'settings' => __('Settings & Variables', 'seo-ultimate')
337
- );
338
- }
339
-
340
- function admin_dropdown_overview() {
341
- return __("
342
- <ul>
343
- <li><p><strong>What it does:</strong> Title Rewriter helps you customize the contents of your website&#8217;s <code>&lt;title&gt;</code> tags.
344
- The tag contents are displayed in web browser title bars and in search engine result pages.</p></li>
345
- <li><p><strong>Why it helps:</strong> Proper title rewriting ensures that the keywords in your post/Page titles have greater prominence for search engine spiders and users.
346
- This is an important foundation for WordPress SEO.</p></li>
347
- <li><p><strong>How to use it:</strong> Title Rewriter enables recommended settings automatically, so you shouldn&#8217;t need to change anything.
348
- If you do wish to edit the rewriting formats, you can do so using the textboxes below (the &#8220;Settings Help&#8221; tab includes additional information on this).
349
- You also have the option of overriding the <code>&lt;title&gt;</code> tag of an individual post or page by using the textboxes under the &#8220;Post&#8221; and &#8220;Page&#8221; tabs below, or by using the &#8220;Title Tag&#8221; textbox that Title Rewriter adds to the post/page editors.</p></li>
350
- </ul>
351
- ", 'seo-ultimate');
352
- }
353
-
354
- function admin_dropdown_settings() {
355
- return __("
356
- <p>Various variables, surrounded in {curly brackets}, are provided for use in the title formats.
357
- All settings support the {blog} variable, which is replaced with the name of the blog,
358
- and the {tagline} variable, which is replaced with the blog tagline as set under <a href='options-general.php' target='_blank'>General&nbsp;Settings</a>.</p>
359
- <p>Here&#8217;s information on each of the settings and its supported variables:</p>
360
- <ul>
361
- <li><p><strong>Blog Homepage Title</strong> &mdash; Displays on the main blog posts page.</p></li>
362
- <li><p><strong>Post Title Format</strong> &mdash; Displays on single-post pages. Supports these variables:</p>
363
- <ul>
364
- <li>{post} &mdash; The post&#8217;s title.</li>
365
- <li>{category} &mdash; The title of the post category with the lowest ID number.</li>
366
- <li>{categories} &mdash; A natural-language list of the post&#8217;s categories (e.g. &#8220;Category A, Category B, and Category C&#8221;).</li>
367
- <li>{tags} &mdash; A natural-language list of the post&#8217;s tags (e.g. &#8220;Tag A, Tag B, and Tag C&#8221;).</li>
368
- <li>{author} &mdash; The Display Name of the post&#8217;s author.</li>
369
- <li>{author_username}, {author_firstname}, {author_lastname}, {author_nickname} &mdash; The username, first name, last name, and nickname of the post&#8217;s author, respectively, as set in his or her profile.</li>
370
- </ul>
371
- <li><p><strong>Page Title Format</strong> &mdash; Displays on WordPress Pages. The {page} variable is replaced with the Page&#8217;s title. Also supports the same author variables as the Post Title Format.</p></li>
372
- <li><p><strong>Category Title Format</strong> &mdash; Displays on category archives. The {category} variable is replaced with the name of the category, and {category_description} is replaced with its description.</p></li>
373
- <li><p><strong>Tag Title Format</strong> &mdash; Displays on tag archives. The {tag} variable is replaced with the name of the tag, and {tag_description} is replaced with its description.</p></li>
374
- <li><p><strong>Day Archive Title Format</strong> &mdash; Displays on day archives. Supports these variables:</p>
375
- <ul>
376
- <li>{day} &mdash; The day number, with ordinal suffix, e.g. 23rd</li>
377
- <li>{daynum} &mdash; The two-digit day number, e.g. 23</li>
378
- <li>{month} &mdash; The name of the month, e.g. April</li>
379
- <li>{monthnum} &mdash; The two-digit number of the month, e.g. 04</li>
380
- <li>{year} &mdash; The year, e.g. 2009</li>
381
- </ul></li>
382
- <li><p><strong>Month Archive Title Format</strong> &mdash; Displays on month archives. Supports {month}, {monthnum}, and {year}.</p></li>
383
- <li><p><strong>Year Archive Title Format</strong> &mdash; Displays on year archives. Supports the {year} variable.</p></li>
384
- <li><p><strong>Author Archive Title Format</strong> &mdash; Displays on author archives. Supports the same author variables as the Post Title Format box,
385
- i.e. {author}, {author_username}, {author_firstname}, {author_lastname}, and {author_nickname}.</p></li>
386
- <li><p><strong>Search Title Format</strong> &mdash; Displays on the result pages for WordPress&#8217;s blog search function.
387
- The {query} variable is replaced with the search query as-is. The {ucwords} variable returns the search query with the first letter of each word capitalized.</p></li>
388
- <li><p><strong>404 Title Format</strong> &mdash; Displays whenever a URL doesn&#8217;t go anywhere.</p></li>
389
- <li><p><strong>Pagination Title Format</strong> &mdash; Displays whenever the visitor is on a subpage (page 2, page 3, etc). Supports these variables:</p>
390
- <ul>
391
- <li>{title} &mdash; The title that would normally be displayed on page 1.</li>
392
- <li>{num} &mdash; The current page number (2, 3, etc).</li>
393
- <li>{max} &mdash; The total number of subpages available. Would usually be used like this: Page {num} of {max}</li>
394
- </ul></li>
395
- </ul>
396
- ", 'seo-ultimate');
397
  }
398
 
399
  function postmeta_help($help) {
400
  $help[] = __("<strong>Title Tag</strong> &mdash; The exact contents of the &lt;title&gt; tag. The title appears in visitors' title bars and in search engine result titles. ".
401
- "If this box is left blank, then the <a href='admin.php?page=titles' target='_blank'>default post/page titles</a> are used.", 'seo-ultimate');
402
  return $help;
403
  }
 
 
 
 
 
 
 
 
 
 
404
 
405
  }
406
 
2
  /**
3
  * Title Rewriter Module
4
  *
5
+ * @version 2.0.2
6
  * @since 0.1
7
  */
8
 
9
  if (class_exists('SU_Module')) {
10
 
11
  class SU_Titles extends SU_Module {
12
+
13
+ function get_module_title() { return __('Title Rewriter', 'seo-ultimate'); }
14
 
15
  function init() {
16
  add_action('template_redirect', array(&$this, 'before_header'), 0);
55
  );
56
  }
57
 
 
 
 
 
 
 
 
 
 
 
58
  function admin_page_formats_tab() {
59
  echo "<table class='form-table'>\n";
60
  $this->textboxes($this->get_supported_settings(), $this->get_default_settings());
124
  if ($post_title = $this->get_postmeta('title'))
125
  return htmlspecialchars($this->get_title_paged($post_title));
126
 
127
+ //Custom taxonomy title?
128
+ if ((is_category() || is_tag() || is_tax()) && $tax_title = $this->get_taxonomy_title('', $wp_query->get_queried_object_id()))
129
+ return htmlspecialchars($tax_title);
130
+
131
  //Load post/page titles
132
  $post_id = 0;
133
  $post_title = '';
215
  , '{author_nickname}' => $author['nickname']
216
  , '{query}' => attribute_escape(get_search_query())
217
  , '{ucquery}' => attribute_escape(ucwords(get_search_query()))
218
+ , '{url_words}' => $this->get_url_words($_SERVER['REQUEST_URI'])
219
  );
220
 
221
  $title = str_replace(array_keys($variables), array_values($variables), htmlspecialchars($format));
250
  return $title;
251
  }
252
 
253
+ function get_url_words($url) {
254
+
255
+ //Remove any extensions (.html, .php, etc)
256
+ $url = preg_replace('|\\.[a-zA-Z]{1,4}$|', ' ', $url);
257
+
258
+ //Turn slashes to >>
259
+ $url = str_replace('/', ' &raquo; ', $url);
260
+
261
+ //Remove word separators
262
+ $url = str_replace(array('.', '/', '-'), ' ', $url);
263
+
264
+ //Capitalize the first letter of every word
265
+ $url = explode(' ', $url);
266
+ $url = array_map('trim', $url);
267
+ $url = array_map('ucwords', $url);
268
+ $url = implode(' ', $url);
269
+ $url = trim($url);
270
+
271
+ return $url;
272
+ }
273
+
274
  function admin_page_posts_tab() {
275
  $this->title_editing_table('post', __('Post'), 'get_posts');
276
  }
303
  return false;
304
  }
305
 
306
+ function get_taxonomy_title($value, $key) {
307
+ return $this->get_title_from_settings('taxonomy', $value, $key);
308
+ }
309
 
310
+ function save_taxonomy_title($unused, $value, $key) {
311
+ return $this->save_title_to_settings('taxonomy', $value, $key);
312
+ }
313
 
314
+ function get_title_from_settings($type, $value, $key) {
315
+ if (is_int($key))
316
+ $id = $key;
317
+ else
318
+ $id = $this->get_id_from_settings_key($key);
319
+
320
+ if ($id) {
321
+ $titles = $this->get_setting($type.'_titles', array());
322
+ return $titles[$id];
323
+ }
324
+
325
+ return $value;
326
+ }
327
 
328
+ function save_title_to_settings($type, $value, $key) {
329
+ if (is_int($key))
330
+ $id = $key;
331
+ else
332
+ $id = $this->get_id_from_settings_key($key);
333
+
334
+ if ($id) {
335
+ $titles = $this->get_setting($type.'_titles', array());
336
+ $titles[$id] = $value;
337
+ $this->update_setting($type.'_titles', $titles);
338
+ }
339
+
340
+ return false;
341
+ }
342
 
343
+ function title_editing_table($object_type, $function, $args, $func_set = 'singular',
344
+ $id_varname = 'ID', $title_varname = 'post_title', $edit_link_function = 'get_edit_post_link') {
345
+
346
+ $mk = $this->get_module_key();
347
+
348
+ add_filter("su_get_setting-$mk", array(&$this, "get_{$func_set}_title"), 10, 2);
349
+ add_filter("su_custom_update_setting-$mk", array(&$this, "save_{$func_set}_title"), 10, 3);
350
+
351
+ $headers = array( __('ID'), __('Name'), __('Title Tag', 'seo-ultimate') );
352
+
353
  echo <<<STR
354
  <table class="widefat fullwidth" cellspacing="0">
355
  <thead><tr>
365
  $args = "$num_varname=20&$offset_varname=0";
366
  else
367
  $args = '';*/
368
+ //$args = "$num_varname=1000";
369
+ $args = (array)$args;
370
+ foreach ($args as $arg_key => $arg) {
371
+ if (is_string($arg))
372
+ $args[$arg_key] = sprintf($arg, 1000, 0);
373
+ }
374
 
375
+ $objects = call_user_func_array($function, $args);
376
+ //$pagination_total = ceil(count($function()) / 2);
377
 
378
  foreach ($objects as $object) {
379
  $id = $object->$id_varname;
380
+ $editlink = call_user_func($edit_link_function, $id, $object_type);
381
  $title = $object->$title_varname;
382
 
383
+ if ($editlink) $label = "<a href='$editlink' target='_blank'>$title</a>"; else $label = $title;
384
+ $this->textbox("{$object_type}_{$id}_title", $label);
385
  }
386
 
387
  echo "\t</tbody>\n</table>\n";
388
 
389
  }
390
 
391
+ function get_object_subtype_tabs($type, $keys, $labels, $callback) {
392
+
393
+ $labels = apply_filters("su_{$type}_tabs", $labels);
394
+
395
+ $types = array();
396
+ foreach ($keys as $key) {
397
+
398
+ $label = $labels[$key];
399
+
400
+ if (!$label) {
401
+ //Rudimentary English pluralization; would turn "post" to "Posts"
402
+ //Can be internationalized later on
403
+ $label = ucwords($key);
404
+ if (sustr::endswith($label, 's'))
405
+ $label .= 'es';
406
+ else
407
+ $label .= 's';
408
+
409
+ $label = __($label, 'seo-ultimate');
410
+ }
411
+
412
+ $types[$key] = $label;
413
+ }
414
+
415
+ $tabs = array();
416
+ foreach ($types as $key => $label) {
417
+ $tabs[$label] = array($callback, $key);
418
+ }
419
+
420
+ return $tabs;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
  }
422
 
423
  function postmeta_help($help) {
424
  $help[] = __("<strong>Title Tag</strong> &mdash; The exact contents of the &lt;title&gt; tag. The title appears in visitors' title bars and in search engine result titles. ".
425
+ "If this box is left blank, then the <a href='admin.php?page=su-titles' target='_blank'>default post/page titles</a> are used.", 'seo-ultimate');
426
  return $help;
427
  }
428
+
429
+ //Imports title tag data from other plugins
430
+ function import_op_titles($value) {
431
+ if (!strlen($value))
432
+ return $this->import_postmeta(array(
433
+ SU_AIOSP_PATH => array('_aioseop_title', 'title')
434
+ ));
435
+
436
+ return $value;
437
+ }
438
 
439
  }
440
 
class.seo-ultimate.php → plugin/class.seo-ultimate.php RENAMED
@@ -28,6 +28,14 @@ class SEO_Ultimate {
28
  */
29
  var $disabled_modules = array();
30
 
 
 
 
 
 
 
 
 
31
  /**
32
  * Stores all database data.
33
  *
@@ -88,7 +96,6 @@ class SEO_Ultimate {
88
  */
89
  var $hit_redirect_trigger = '';
90
 
91
-
92
  /********** CLASS CONSTRUCTORS **********/
93
 
94
  /**
@@ -117,7 +124,7 @@ class SEO_Ultimate {
117
  * @uses log_redirect() Hooked into WordPress's "wp_redirect" filter.
118
  * @uses log_hit() Hooked into WordPress's "status_header" filter.
119
  */
120
- function __construct() {
121
 
122
  /********** LOAD/SAVE DATABASE DATA **********/
123
 
@@ -132,7 +139,7 @@ class SEO_Ultimate {
132
  /********** CLASS CONSTRUCTION **********/
133
 
134
  //Load data about the plugin file itself into the class
135
- $this->load_plugin_data();
136
 
137
 
138
  /********** VERSION CHECKING **********/
@@ -223,9 +230,9 @@ class SEO_Ultimate {
223
  * @since 0.1
224
  * @uses __construct()
225
  */
226
- function SEO_Ultimate() {
227
 
228
- $this->__construct();
229
  }
230
 
231
 
@@ -347,14 +354,16 @@ class SEO_Ultimate {
347
  * @uses $plugin_file_url
348
  * @uses $plugin_dir_path
349
  * @uses $plugin_dir_url
 
 
350
  */
351
- function load_plugin_data() {
352
 
353
  //Load plugin path/URL information
354
  $filename = 'seo-ultimate.php';
355
- $this->plugin_dir_path = trailingslashit(dirname(trailingslashit(WP_PLUGIN_DIR).plugin_basename(__FILE__)));
356
  $this->plugin_file_path = $this->plugin_dir_path.$filename;
357
- $this->plugin_dir_url = trailingslashit(plugins_url(dirname(plugin_basename(__FILE__))));
358
  $this->plugin_file_url = $this->plugin_dir_url.$filename;
359
  }
360
 
@@ -375,12 +384,9 @@ class SEO_Ultimate {
375
  * @uses remove_cron_jobs()
376
  */
377
  function load_modules() {
378
-
379
  //The plugin_dir_path variable must be set before calling this function!
380
  if (!$this->plugin_dir_path) return false;
381
-
382
- //The modules are in the "modules" subdirectory of the plugin folder.
383
- $dir = opendir($this->plugin_dir_path.'modules');
384
 
385
  //If no modules list is found, then create a new, empty list.
386
  if (!isset($this->dbdata['modules']))
@@ -389,50 +395,73 @@ class SEO_Ultimate {
389
  //Get the modules list from last time the plugin was loaded.
390
  $oldmodules = $this->dbdata['modules'];
391
 
392
- //This loop will be repeated as long as there are more files to inspect
393
- while ($file = readdir($dir)) {
 
 
 
 
394
 
395
- //Modules are non-directory files with the .php extension
396
- //We need to exclude index.php or else we'll get 403s galore
397
- if ($file != '.' && $file != '..' && $file != 'index.php' && !is_dir($file) &&
398
- substr($file, -4) == '.php') {
399
-
400
- //Figure out the module's array key and class name
401
- $module = strval(strtolower(substr($file, 0, -4)));
402
- $class = 'SU_'.str_replace(' ', '', ucwords(str_replace('-', ' ', $module)));
403
-
404
- //If this module is disabled...
405
- if ($oldmodules[$module] == SU_MODULE_DISABLED) {
406
-
407
- $name = file($this->plugin_dir_path."modules/$file");
408
- if ($name) $name = str_replace(' Module', '', ltrim($name[2], ' *'));
409
- else $name = ucwords(str_replace('-', ' ', $module));
410
-
411
- $this->disabled_modules[$module] = __($name, 'seo-ultimate');
412
-
413
- } else {
414
 
415
- //Load the module's code
416
- require_once("modules/$file");
 
417
 
418
- //If this is actually a module...
419
- if (class_exists($class)) {
420
 
421
- //Create an instance of the module's class and store it in the array
422
- $this->modules[$module] = new $class;
423
-
424
- //We must tell the module what its key is so that it can save settings
425
- $this->modules[$module]->module_key = $module;
426
 
427
- //Tell the module what its URL is
428
- $this->modules[$module]->module_url = $this->plugin_dir_url."modules/$file";
429
 
430
- //Tell the module what its plugin page hook is
431
- $this->modules[$module]->plugin_page_hook =
432
- $this->modules[$module]->get_menu_parent_hook().'_page_'.SEO_Ultimate::key_to_hook($module);
 
 
 
433
 
434
- } //If this isn't a module, then the file will simply be included as-is
435
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
436
  }
437
  }
438
 
@@ -450,8 +479,11 @@ class SEO_Ultimate {
450
  $newmodules[$key] = $oldmodules[$key];
451
  } else {
452
  $this->modules[$key]->activate();
453
- $newmodules[$key] = SU_MODULE_ENABLED;
454
  }
 
 
 
455
  }
456
 
457
  //Register disabled modules as such
@@ -464,6 +496,20 @@ class SEO_Ultimate {
464
 
465
  //Remove the cron jobs of deleted modules
466
  $this->remove_cron_jobs();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
467
  }
468
 
469
  /**
@@ -484,6 +530,11 @@ class SEO_Ultimate {
484
  foreach ($this->modules as $key => $module) {
485
  //Accessing $module directly causes problems when the modules use the &$this reference
486
  $this->modules[$key]->load_default_settings();
 
 
 
 
 
487
  $this->modules[$key]->init();
488
  }
489
  }
@@ -613,7 +664,7 @@ class SEO_Ultimate {
613
  global $wpdb;
614
 
615
  //Get the current URL
616
- $url = $this->get_current_url();
617
 
618
  //Have we seen this URL before?
619
  $table = $this->get_table_name('hits');
@@ -692,11 +743,14 @@ class SEO_Ultimate {
692
  * @uses key_to_hook()
693
  */
694
  function add_menus() {
695
-
696
  //If subitems have numeric bubbles, then add them up and show the total by the main menu item
697
  $count = 0;
698
  foreach ($this->modules as $key => $module) {
699
- if ($this->dbdata['modules'][$key] > SU_MODULE_SILENCED && $module->get_menu_count() > 0 && $module->get_menu_parent() == 'seo')
 
 
 
700
  $count += $module->get_menu_count();
701
  }
702
  $count_code = $this->get_menu_count_code($count);
@@ -709,24 +763,25 @@ class SEO_Ultimate {
709
  $admin_page_hooks['seo'] = 'seo';
710
 
711
  //Add all the subitems
712
- foreach ($this->modules as $file => $module) {
713
-
 
714
  //Show a module on the menu only if it provides a menu title and it doesn't have a parent module
715
  if ($module->get_menu_title() && !$module->get_parent_module()) {
716
 
717
  //If the module is hidden, put the module under a non-existant menu parent
718
  //(this will let the module's admin page be loaded, but it won't show up on the menu)
719
- if ($this->dbdata['modules'][$file] > SU_MODULE_HIDDEN)
720
  $parent = $module->get_menu_parent();
721
  else
722
  $parent = 'su-hidden-modules';
723
 
724
- if ($this->dbdata['modules'][$file] > SU_MODULE_SILENCED)
725
  $count_code = $this->get_menu_count_code($module->get_menu_count());
726
  else
727
  $count_code = '';
728
 
729
- $hook = $this->key_to_hook($file);
730
 
731
  add_submenu_page($parent, $module->get_page_title(), $module->get_menu_title().$count_code,
732
  'manage_options', $hook, array($module, 'admin_page'));
@@ -787,7 +842,7 @@ class SEO_Ultimate {
787
  */
788
  function key_to_hook($key) {
789
  switch ($key) {
790
- case 'modules': return 'seo'; break;
791
  case 'settings': return 'seo-ultimate'; break;
792
  default: return "su-$key"; break;
793
  }
@@ -804,7 +859,7 @@ class SEO_Ultimate {
804
  */
805
  function hook_to_key($hook) {
806
  switch ($hook) {
807
- case 'seo': return 'modules'; break;
808
  case 'seo-ultimate': return 'settings'; break;
809
  default: return substr($hook, 3); break;
810
  }
@@ -821,10 +876,12 @@ class SEO_Ultimate {
821
  */
822
  function get_admin_menu_icon_url($hook) {
823
  $key = $this->hook_to_key($hook);
824
- if (isset($this->modules[$key]) && is_readable($this->plugin_dir_path."images/$key.png"))
825
- return $this->plugin_dir_url."images/$key.png";
826
- else
827
- return $hook;
 
 
828
  }
829
 
830
 
@@ -864,7 +921,7 @@ class SEO_Ultimate {
864
  function admin_includes() {
865
 
866
  //Global CSS
867
- echo "\n<link rel='stylesheet' type='text/css' href='".$this->plugin_dir_url."global.css?v=".SU_VERSION."' />\n";
868
 
869
  //Figure out what plugin admin page we're on
870
  global $plugin_page;
@@ -876,8 +933,8 @@ class SEO_Ultimate {
876
  if (strcmp($key, $pp) == 0) {
877
 
878
  //We're viewing a module page, so print links to the CSS/JavaScript files loaded for all modules
879
- echo "\n<link rel='stylesheet' type='text/css' href='".$this->plugin_dir_url."modules.css?v=".SU_VERSION."' />\n";
880
- echo "\n<script type='text/javascript' src='".$this->plugin_dir_url."modules.js?v=".SU_VERSION."'></script>\n";
881
 
882
  //Print links to the module's CSS and JavaScript.
883
  echo "\n<link rel='stylesheet' type='text/css' href='".$module->module_url."?css=admin&amp;v=".SU_VERSION."' />\n";
@@ -990,9 +1047,10 @@ class SEO_Ultimate {
990
  */
991
  function plugin_update_info($plugin_data, $r) {
992
  if ($r && $r->new_version && !is_plugin_active('changelogger/changelogger.php')) {
993
- $info = $this->load_webpage("http://www.seodesignsolutions.com/apis/su/update-info/?ov=".urlencode(SU_VERSION)."&nv=".urlencode($r->new_version));
994
  if ($info) {
995
  $info = strip_tags($info, "<br><a><b><i><span>");
 
996
  echo "<span class='su-plugin-update-info'><br />$info</span>";
997
  }
998
  }
@@ -1011,6 +1069,54 @@ class SEO_Ultimate {
1011
  }
1012
  }
1013
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1014
  /********** ADMIN POST META BOX FUNCTIONS **********/
1015
 
1016
  /**
@@ -1149,14 +1255,13 @@ class SEO_Ultimate {
1149
 
1150
  $metakey = "_su_$field";
1151
 
1152
- //Delete the old value
1153
- delete_post_meta($post_id, $metakey);
1154
-
1155
- //Add the new value, if there is one
1156
  $value = $_POST[$metakey];
1157
- if (!empty($value)) {
1158
- add_post_meta($post_id, $metakey, $value);
1159
- }
 
 
 
1160
  }
1161
  }
1162
 
@@ -1217,68 +1322,36 @@ class SEO_Ultimate {
1217
  if ($markcode) echo "<!-- /".SU_PLUGIN_NAME." -->\n\n";
1218
  }
1219
 
1220
- /********** PSEUDO-STATIC FUNCTIONS **********/
1221
 
1222
- /**
1223
- * Approximately determines the URL in the visitor's address bar. (Includes query strings, but not #anchors.)
1224
- *
1225
- * @since 0.1
1226
- *
1227
- * @return string The current URL.
1228
- */
1229
- function get_current_url() {
1230
- $url = 'http';
1231
- if ($_SERVER["HTTPS"] == "on") $url .= "s";
1232
- $url .= "://";
1233
-
1234
- if ($_SERVER["SERVER_PORT"] != "80")
1235
- return $url.$_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
1236
- else
1237
- return $url.$_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
1238
- }
1239
 
1240
  /**
1241
- * Determines the ID of the current post.
1242
- * Works in the admin as well as the front-end.
1243
- *
1244
- * @since 0.2
1245
  *
1246
- * @return int|false The ID of the current post, or false on failure.
 
1247
  */
1248
- function get_post_id() {
1249
- if (is_admin())
1250
- return intval($_REQUEST['post']);
1251
- elseif (in_the_loop())
1252
- return intval(get_the_ID());
1253
- elseif (is_singular()) {
1254
- global $wp_query;
1255
- return $wp_query->get_queried_object_id();
1256
- }
1257
-
1258
- return false;
1259
  }
1260
 
1261
  /**
1262
- * Loads a webpage and returns its HTML as a string.
1263
- *
1264
- * @since 0.3
1265
  *
1266
- * @param string $url The URL of the webpage to load.
1267
- * @return string The HTML of the URL.
1268
  */
1269
- function load_webpage($url) {
1270
-
1271
- $options = array();
1272
- $options['headers'] = array(
1273
- 'User-Agent' => su_get_user_agent()
1274
- );
1275
-
1276
- $response = wp_remote_request($url, $options);
1277
-
1278
- if ( is_wp_error( $response ) ) return false;
1279
- if ( 200 != $response['response']['code'] ) return false;
1280
 
1281
- return trim( $response['body'] );
1282
  }
1283
  }
1284
  ?>
28
  */
29
  var $disabled_modules = array();
30
 
31
+ /**
32
+ * The key of the module whose admin page appears when the "SEO" menu item is clicked.
33
+ *
34
+ * @since 1.5
35
+ * @var string
36
+ */
37
+ var $default_menu_module = 'modules';
38
+
39
  /**
40
  * Stores all database data.
41
  *
96
  */
97
  var $hit_redirect_trigger = '';
98
 
 
99
  /********** CLASS CONSTRUCTORS **********/
100
 
101
  /**
124
  * @uses log_redirect() Hooked into WordPress's "wp_redirect" filter.
125
  * @uses log_hit() Hooked into WordPress's "status_header" filter.
126
  */
127
+ function __construct($plugin_file) {
128
 
129
  /********** LOAD/SAVE DATABASE DATA **********/
130
 
139
  /********** CLASS CONSTRUCTION **********/
140
 
141
  //Load data about the plugin file itself into the class
142
+ $this->load_plugin_data($plugin_file);
143
 
144
 
145
  /********** VERSION CHECKING **********/
230
  * @since 0.1
231
  * @uses __construct()
232
  */
233
+ function SEO_Ultimate($plugin_file) {
234
 
235
+ $this->__construct($plugin_file);
236
  }
237
 
238
 
354
  * @uses $plugin_file_url
355
  * @uses $plugin_dir_path
356
  * @uses $plugin_dir_url
357
+ *
358
+ * @param string $plugin_path The path to the "official" plugin file.
359
  */
360
+ function load_plugin_data($plugin_path) {
361
 
362
  //Load plugin path/URL information
363
  $filename = 'seo-ultimate.php';
364
+ $this->plugin_dir_path = trailingslashit(dirname(trailingslashit(WP_PLUGIN_DIR).plugin_basename($plugin_path)));
365
  $this->plugin_file_path = $this->plugin_dir_path.$filename;
366
+ $this->plugin_dir_url = trailingslashit(plugins_url(dirname(plugin_basename($plugin_path))));
367
  $this->plugin_file_url = $this->plugin_dir_url.$filename;
368
  }
369
 
384
  * @uses remove_cron_jobs()
385
  */
386
  function load_modules() {
387
+
388
  //The plugin_dir_path variable must be set before calling this function!
389
  if (!$this->plugin_dir_path) return false;
 
 
 
390
 
391
  //If no modules list is found, then create a new, empty list.
392
  if (!isset($this->dbdata['modules']))
395
  //Get the modules list from last time the plugin was loaded.
396
  $oldmodules = $this->dbdata['modules'];
397
 
398
+ //The modules are in the "modules" subdirectory of the plugin folder.
399
+ $dirpath = $this->plugin_dir_path.'modules';
400
+ $dir = opendir($dirpath);
401
+
402
+ //This loop will be repeated as long as there are more folders to inspect
403
+ while ($folder = readdir($dir)) {
404
 
405
+ //If the item is a folder...
406
+ if (suio::is_dir($folder, $dirpath)) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
407
 
408
+ //Open the subfolder
409
+ $subdirpath = $dirpath.'/'.$folder;
410
+ $subdir = opendir($subdirpath);
411
 
412
+ //Scan the files in the subfolder (seo-ultimate/modules/???/*)
413
+ while ($file = readdir($subdir)) {
414
 
415
+ //Modules are non-directory files with the .php extension
416
+ //We need to exclude index.php or else we'll get 403s galore
417
+ if (suio::is_file($file, $subdirpath, 'php') && $file != 'index.php') {
 
 
418
 
419
+ $filepath = $subdirpath.'/'.$file;
 
420
 
421
+ //Figure out the module's array key and class name
422
+ $module = strval(strtolower(substr($file, 0, -4)));
423
+ $class = 'SU_'.str_replace(' ', '', ucwords(str_replace('-', ' ', $module)));
424
+
425
+ //Load the module's code
426
+ include_once $filepath;
427
 
428
+ //If this is actually a module...
429
+ if (class_exists($class)) {
430
+
431
+ if ($module_parent = call_user_func(array($class, 'get_parent_module')))
432
+ $module_disabled = ($oldmodules[$module_parent] == SU_MODULE_DISABLED);
433
+ else
434
+ $module_disabled = ($oldmodules[$module] == SU_MODULE_DISABLED);
435
+
436
+ //If this module is disabled...
437
+ if ($module_disabled) {
438
+
439
+ $this->disabled_modules[$module] = $class;
440
+
441
+ } else {
442
+
443
+ //Create an instance of the module's class and store it in the array
444
+ $this->modules[$module] = new $class;
445
+
446
+ //We must tell the module what its key is so that it can save settings
447
+ $this->modules[$module]->module_key = $module;
448
+
449
+ //Tell the module what its URL is
450
+ $this->modules[$module]->module_dir_url = $mdirurl = $this->plugin_dir_url."modules/$folder/";
451
+ $this->modules[$module]->module_url = $mdirurl . $file;
452
+
453
+ /*
454
+ //Is this module the default menu module?
455
+ if ($this->modules[$module]->get_menu_parent() === 'seo' && $this->modules[$module]->is_menu_default())
456
+ $this->default_menu_module = $module;
457
+ */
458
+
459
+ //Give the module this plugin's object by reference
460
+ $this->modules[$module]->plugin =& $this;
461
+ }
462
+ } //If this isn't a module, then the file will simply be included as-is
463
+ }
464
+ }
465
  }
466
  }
467
 
479
  $newmodules[$key] = $oldmodules[$key];
480
  } else {
481
  $this->modules[$key]->activate();
482
+ $newmodules[$key] = $this->modules[$key]->get_default_status();
483
  }
484
+
485
+ if ($module_parent = $this->modules[$key]->get_parent_module() && !$this->modules[$key]->is_independent_module())
486
+ $newmodules[$key] = $newmodules[$module_parent];
487
  }
488
 
489
  //Register disabled modules as such
496
 
497
  //Remove the cron jobs of deleted modules
498
  $this->remove_cron_jobs();
499
+
500
+ //Tell the modules what their plugin page hooks are
501
+ foreach ($this->modules as $key => $module)
502
+ $this->modules[$key]->plugin_page_hook =
503
+ $this->modules[$key]->get_menu_parent_hook().'_page_'.$this->key_to_hook($key);
504
+
505
+ if (!$this->module_exists($this->default_menu_module)) {
506
+ foreach ($this->modules as $key => $module) {
507
+ if ($this->modules[$key]->get_menu_parent() === 'seo' && $this->modules[$key]->get_parent_module() == false) {
508
+ $this->default_menu_module = $key;
509
+ break;
510
+ }
511
+ }
512
+ }
513
  }
514
 
515
  /**
530
  foreach ($this->modules as $key => $module) {
531
  //Accessing $module directly causes problems when the modules use the &$this reference
532
  $this->modules[$key]->load_default_settings();
533
+ $this->modules[$key]->load_child_modules();
534
+ }
535
+
536
+ //Only run init tasks after all other init functions are completed for all modules
537
+ foreach ($this->modules as $key => $module) {
538
  $this->modules[$key]->init();
539
  }
540
  }
664
  global $wpdb;
665
 
666
  //Get the current URL
667
+ $url = suurl::current();
668
 
669
  //Have we seen this URL before?
670
  $table = $this->get_table_name('hits');
743
  * @uses key_to_hook()
744
  */
745
  function add_menus() {
746
+
747
  //If subitems have numeric bubbles, then add them up and show the total by the main menu item
748
  $count = 0;
749
  foreach ($this->modules as $key => $module) {
750
+ if ( ($this->dbdata['modules'][$key] > SU_MODULE_SILENCED || !count($this->dbdata['modules']))
751
+ && $module->get_menu_count() > 0
752
+ && $module->get_menu_parent() == 'seo'
753
+ )
754
  $count += $module->get_menu_count();
755
  }
756
  $count_code = $this->get_menu_count_code($count);
763
  $admin_page_hooks['seo'] = 'seo';
764
 
765
  //Add all the subitems
766
+ foreach ($this->modules as $key => $x_module) {
767
+ $module =& $this->modules[$key];
768
+
769
  //Show a module on the menu only if it provides a menu title and it doesn't have a parent module
770
  if ($module->get_menu_title() && !$module->get_parent_module()) {
771
 
772
  //If the module is hidden, put the module under a non-existant menu parent
773
  //(this will let the module's admin page be loaded, but it won't show up on the menu)
774
+ if ($this->dbdata['modules'][$key] > SU_MODULE_HIDDEN || !count($this->dbdata['modules']))
775
  $parent = $module->get_menu_parent();
776
  else
777
  $parent = 'su-hidden-modules';
778
 
779
+ if ($this->dbdata['modules'][$key] > SU_MODULE_SILENCED || !count($this->dbdata['modules']))
780
  $count_code = $this->get_menu_count_code($module->get_menu_count());
781
  else
782
  $count_code = '';
783
 
784
+ $hook = $this->key_to_hook($key);
785
 
786
  add_submenu_page($parent, $module->get_page_title(), $module->get_menu_title().$count_code,
787
  'manage_options', $hook, array($module, 'admin_page'));
842
  */
843
  function key_to_hook($key) {
844
  switch ($key) {
845
+ case $this->default_menu_module: return 'seo'; break;
846
  case 'settings': return 'seo-ultimate'; break;
847
  default: return "su-$key"; break;
848
  }
859
  */
860
  function hook_to_key($hook) {
861
  switch ($hook) {
862
+ case 'seo': return $this->default_menu_module; break;
863
  case 'seo-ultimate': return 'settings'; break;
864
  default: return substr($hook, 3); break;
865
  }
876
  */
877
  function get_admin_menu_icon_url($hook) {
878
  $key = $this->hook_to_key($hook);
879
+ if (isset($this->modules[$key])) {
880
+ if (strlen($image = $this->modules[$key]->get_menu_icon_filename()))
881
+ return $this->modules[$key]->module_dir_url.$image;
882
+ }
883
+
884
+ return $hook;
885
  }
886
 
887
 
921
  function admin_includes() {
922
 
923
  //Global CSS
924
+ echo "\n<link rel='stylesheet' type='text/css' href='".$this->plugin_dir_url."plugin/global.css?v=".SU_VERSION."' />\n";
925
 
926
  //Figure out what plugin admin page we're on
927
  global $plugin_page;
933
  if (strcmp($key, $pp) == 0) {
934
 
935
  //We're viewing a module page, so print links to the CSS/JavaScript files loaded for all modules
936
+ echo "\n<link rel='stylesheet' type='text/css' href='".$this->plugin_dir_url."modules/modules.css?v=".SU_VERSION."' />\n";
937
+ echo "\n<script type='text/javascript' src='".$this->plugin_dir_url."modules/modules.js?v=".SU_VERSION."'></script>\n";
938
 
939
  //Print links to the module's CSS and JavaScript.
940
  echo "\n<link rel='stylesheet' type='text/css' href='".$module->module_url."?css=admin&amp;v=".SU_VERSION."' />\n";
1047
  */
1048
  function plugin_update_info($plugin_data, $r) {
1049
  if ($r && $r->new_version && !is_plugin_active('changelogger/changelogger.php')) {
1050
+ $info = suwp::load_webpage("http://www.seodesignsolutions.com/apis/su/update-info/?ov=".urlencode(SU_VERSION)."&nv=".urlencode($r->new_version));
1051
  if ($info) {
1052
  $info = strip_tags($info, "<br><a><b><i><span>");
1053
+ $info = str_replace('backup your database', '<a href="'.suwp::get_backup_url().'">backup your database</a>', $info);
1054
  echo "<span class='su-plugin-update-info'><br />$info</span>";
1055
  }
1056
  }
1069
  }
1070
  }
1071
 
1072
+
1073
+ /********** MODULE FUNCTIONS ***********/
1074
+
1075
+ /**
1076
+ * Checks to see whether a specified module exists.
1077
+ *
1078
+ * @since 1.5
1079
+ *
1080
+ * @param string $key The key of the module to check.
1081
+ * @return boolean Whether the module is loaded into SEO Ultimate.
1082
+ */
1083
+ function module_exists($key) {
1084
+ return isset($this->modules[$key]);
1085
+ }
1086
+
1087
+ /**
1088
+ * Calls the function of a module.
1089
+ *
1090
+ * @since 1.5
1091
+ *
1092
+ * @param string $key The key of the module to which the function belongs.
1093
+ * @param string $function The name of the function to call.
1094
+ * @param mixed $result Passed by reference. Set to the result of the function.
1095
+ * @return boolean Whether or not the function existed.
1096
+ */
1097
+ function call_module_func($key, $function, &$result) {
1098
+
1099
+ //Wipe passed-by-reference variable clean
1100
+ $result = null;
1101
+
1102
+ $args = func_get_args();
1103
+ $args = array_slice($args, 3);
1104
+
1105
+ if (isset($this->modules[$key]))
1106
+ $obj =& $this->modules[$key];
1107
+ elseif (isset($this->disabled_modules[$key]))
1108
+ $obj = $key;
1109
+ else
1110
+ return false;
1111
+
1112
+ if (is_callable($call = array($obj, $function))) {
1113
+ $result = call_user_func_array($call, $args);
1114
+ return true;
1115
+ }
1116
+
1117
+ return false;
1118
+ }
1119
+
1120
  /********** ADMIN POST META BOX FUNCTIONS **********/
1121
 
1122
  /**
1255
 
1256
  $metakey = "_su_$field";
1257
 
 
 
 
 
1258
  $value = $_POST[$metakey];
1259
+ if (empty($value))
1260
+ //Delete the old value
1261
+ delete_post_meta($post_id, $metakey);
1262
+ else
1263
+ //Add the new value
1264
+ update_post_meta($post_id, $metakey, $value);
1265
  }
1266
  }
1267
 
1322
  if ($markcode) echo "<!-- /".SU_PLUGIN_NAME." -->\n\n";
1323
  }
1324
 
 
1325
 
1326
+ /********** README FUNCTIONS **********/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1327
 
1328
  /**
1329
+ * Returns the full server path to the main readme.txt file.
 
 
 
1330
  *
1331
+ * @since 1.5
1332
+ * @return string
1333
  */
1334
+ function get_readme_path() {
1335
+ return $this->plugin_dir_path.'readme.txt';
 
 
 
 
 
 
 
 
 
1336
  }
1337
 
1338
  /**
1339
+ * Returns the full server path to the main readme.txt file, or a translated readme.txt file if it exists for the current WPLANG.
 
 
1340
  *
1341
+ * @since 1.5
1342
+ * @return string
1343
  */
1344
+ function get_translated_readme_path() {
1345
+ if (defined('WPLANG') && strlen(WPLANG)) {
1346
+ $wplang = sustr::preg_filter('a-zA-Z0-9_', WPLANG);
1347
+ $langvars = array($wplang, array_shift(explode('_', $wplang)));
1348
+ foreach ($langvars as $langvar) {
1349
+ $path = $this->plugin_dir_path."translations/readme-$langvar.txt";
1350
+ if (is_readable($path)) return $path;
1351
+ }
1352
+ }
 
 
1353
 
1354
+ return $this->plugin_dir_path.'readme.txt';
1355
  }
1356
  }
1357
  ?>
class.su-hitset.php → plugin/class.su-hitset.php RENAMED
@@ -2,7 +2,7 @@
2
  /**
3
  * A class that stores the results of a query to to the hits table.
4
  *
5
- * @version 1.1.1
6
  */
7
  class SU_HitSet {
8
 
@@ -82,8 +82,8 @@ class SU_HitSet {
82
  $cell = sprintf(__('%1$s<br />%2$s', 'seo-ultimate'), $date, $time);
83
  break;
84
  case 'user_agent':
85
- $text = su_str_truncate($cell, 50);
86
- $ua = attribute_escape($cell);
87
  $cell = "<abbr title='$ua'>$text</abbr>";
88
  break;
89
  case 'url':
2
  /**
3
  * A class that stores the results of a query to to the hits table.
4
  *
5
+ * @version 1.1.2
6
  */
7
  class SU_HitSet {
8
 
82
  $cell = sprintf(__('%1$s<br />%2$s', 'seo-ultimate'), $date, $time);
83
  break;
84
  case 'user_agent':
85
+ $text = sustr::truncate($cell, 50);
86
+ $ua = su_esc_attr($cell);
87
  $cell = "<abbr title='$ua'>$text</abbr>";
88
  break;
89
  case 'url':
global.css → plugin/global.css RENAMED
@@ -44,11 +44,21 @@ These styles are sometimes or always referenced outside of SEO Ultimate's admin
44
  color: #0000FF;
45
  }
46
 
47
- #wpcontent .su-message p {
 
48
  background-position: 10px center;
49
- padding: 10px 10px 10px 36px;
 
 
 
 
50
  margin: 1em 0;
51
  color: black;
 
 
 
 
 
52
  border-width: 1px;
53
  border-style: solid;
54
  }
44
  color: #0000FF;
45
  }
46
 
47
+ #wpcontent div.su-status,
48
+ #wpcontent span.su-status {
49
  background-position: 10px center;
50
+ padding-left: 31px;
51
+ }
52
+
53
+ #wpcontent .su-message p,
54
+ #wpcontent p.su-status {
55
  margin: 1em 0;
56
  color: black;
57
+ background-position: 10px center;
58
+ padding: 10px 10px 10px 36px;
59
+ }
60
+
61
+ #wpcontent .su-message p {
62
  border-width: 1px;
63
  border-style: solid;
64
  }
{images → plugin/images}/error.png RENAMED
File without changes
{images → plugin/images}/icon.png RENAMED
File without changes
{images → plugin/images}/index.php RENAMED
File without changes
{images → plugin/images}/info.png RENAMED
File without changes
{images → plugin/images}/sds-logo.png RENAMED
File without changes
{images → plugin/images}/seo.png RENAMED
File without changes
{images → plugin/images}/success.png RENAMED
File without changes
{images → plugin/images}/warning.png RENAMED
File without changes
plugin/su-constants.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ define('SU_MODULE_ENABLED', 10);
4
+ define('SU_MODULE_SILENCED', 5);
5
+ define('SU_MODULE_HIDDEN', 0);
6
+ define('SU_MODULE_DISABLED', -10);
7
+
8
+ define('SU_RESULT_OK', 1);
9
+ define('SU_RESULT_WARNING', 0);
10
+ define('SU_RESULT_ERROR', -1);
11
+
12
+ define('SU_AIOSP_PATH', 'all-in-one-seo-pack/all_in_one_seo_pack.php');
13
+
14
+ ?>
plugin/su-functions.php ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Non-class functions.
4
+ */
5
+
6
+ /********** INDEPENDENTLY-OPERABLE FUNCTIONS **********/
7
+
8
+ /**
9
+ * Returns the plugin's User-Agent value.
10
+ * Can be used as a WordPress filter.
11
+ *
12
+ * @since 0.1
13
+ * @uses SU_USER_AGENT
14
+ *
15
+ * @return string The user agent.
16
+ */
17
+ function su_get_user_agent() {
18
+ return SU_USER_AGENT;
19
+ }
20
+
21
+ /**
22
+ * Records an event in the debug log file.
23
+ * Usage: su_debug_log(__FILE__, __CLASS__, __FUNCTION__, __LINE__, "Message");
24
+ *
25
+ * @since 0.1
26
+ * @uses SU_VERSION
27
+ *
28
+ * @param string $file The value of __FILE__
29
+ * @param string $class The value of __CLASS__
30
+ * @param string $function The value of __FUNCTION__
31
+ * @param string $line The value of __LINE__
32
+ * @param string $message The message to log.
33
+ */
34
+ function su_debug_log($file, $class, $function, $line, $message) {
35
+ global $seo_ultimate;
36
+ if (isset($seo_ultimate->modules['settings']) && $seo_ultimate->modules['settings']->get_setting('debug_mode') === true) {
37
+
38
+ $date = date("Y-m-d H:i:s");
39
+ $version = SU_VERSION;
40
+ $message = str_replace("\r\n", "\n", $message);
41
+ $message = str_replace("\n", "\r\n", $message);
42
+
43
+ $log = "Date: $date\r\nVersion: $version\r\nFile: $file\r\nClass: $class\r\nFunction: $function\r\nLine: $line\r\nMessage: $message\r\n\r\n";
44
+ $logfile = trailingslashit(dirname(__FILE__))."seo-ultimate.log";
45
+
46
+ @error_log($log, 3, $logfile);
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Joins strings into a natural-language list.
52
+ * Can be internationalized with gettext or the su_lang_implode filter.
53
+ *
54
+ * @since 1.1
55
+ *
56
+ * @param array $items The strings (or objects with $var child strings) to join.
57
+ * @param string|false $var The name of the items' object variables whose values should be imploded into a list.
58
+ If false, the items themselves will be used.
59
+ * @param bool $ucwords Whether or not to capitalize the first letter of every word in the list.
60
+ * @return string|array The items in a natural-language list.
61
+ */
62
+ function su_lang_implode($items, $var=false, $ucwords=false) {
63
+
64
+ if (is_array($items) ) {
65
+
66
+ if (strlen($var)) {
67
+ $_items = array();
68
+ foreach ($items as $item) $_items[] = $item->$var;
69
+ $items = $_items;
70
+ }
71
+
72
+ if ($ucwords) $items = array_map('ucwords', $items);
73
+
74
+ switch (count($items)) {
75
+ case 0: $list = ''; break;
76
+ case 1: $list = $items[0]; break;
77
+ case 2: $list = sprintf(__('%s and %s', 'seo-ultimate'), $items[0], $items[1]); break;
78
+ default:
79
+ $last = array_pop($items);
80
+ $list = implode(__(', ', 'seo-ultimate'), $items);
81
+ $list = sprintf(__('%s, and %s', 'seo-ultimate'), $list, $last);
82
+ break;
83
+ }
84
+
85
+ return apply_filters('su_lang_implode', $list, $items);
86
+ }
87
+
88
+ return $items;
89
+ }
90
+
91
+ /**
92
+ * Escapes an attribute value and removes unwanted characters.
93
+ *
94
+ * @since 0.8
95
+ *
96
+ * @param string $str The attribute value.
97
+ * @return string The filtered attribute value.
98
+ */
99
+ function su_esc_attr($str) {
100
+ $str = str_replace(array("\t", "\r\n", "\n"), ' ', $str);
101
+ $str = attribute_escape($str);
102
+ return $str;
103
+ }
104
+
105
+ /**
106
+ * Escapes HTML. Double-encodes existing entities (ideal for editable HTML).
107
+ *
108
+ * @sincec 1.5
109
+ *
110
+ * @param string $str The string that potentially contains HTML.
111
+ * @return string The filtered string.
112
+ */
113
+ function su_esc_editable_html($str) {
114
+ return wp_specialchars($str, ENT_QUOTES, false, true);
115
+ }
116
+
117
+
118
+ /********** CLASS FUNCTION ALIASES **********/
119
+
120
+ /**
121
+ * Launches the uninstallation process.
122
+ * WordPress will call this when the plugin is uninstalled, as instructed by the register_uninstall_hook() call in {@link SEO_Ultimate::__construct()}.
123
+ *
124
+ * @since 0.1
125
+ * @uses $seo_ultimate
126
+ * @uses SEO_Ultimate::uninstall()
127
+ */
128
+ function su_uninstall() {
129
+ global $seo_ultimate;
130
+ $seo_ultimate->uninstall();
131
+ }
132
+
133
+ ?>
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
  === SEO Ultimate ===
2
  Contributors: SEO Design Solutions
3
  Tags: seo, google, yahoo, bing, search engines, admin, post, page, modules, title, meta, noindex, canonical, 404, robots.txt, htaccess, slugs, url, anchor, more, link, excerpt, permalink
4
- Requires at least: 2.7
5
- Tested up to: 2.9.1
6
- Stable tag: 1.4.1
7
 
8
  This all-in-one SEO plugin gives you control over titles, noindex, meta data, slugs, canonical tags, "more" links, 404 error tracking, and more.
9
 
@@ -11,9 +11,9 @@ This all-in-one SEO plugin gives you control over titles, noindex, meta data, sl
11
 
12
  = Recent Releases =
13
 
 
14
  * Version 1.4 adds the Internal Relevance Researcher module
15
  * Version 1.3 adds the More Link Customizer module
16
- * Version 1.2 adds the Competition Researcher module
17
 
18
  = Features =
19
 
@@ -76,10 +76,10 @@ SEO Ultimate is an all-in-one [SEO](http://www.seodesignsolutions.com/) plugin w
76
  * Reset all settings back to "factory defaults" if something goes wrong.
77
 
78
  * **Additional features**
79
- * Supports WordPress plugin translation. POT file is included in the zip file.
80
  * SEO Ultimate documentation is seamlessly integrated into the contextual help system of WordPress 2.7+ and is accessible via the dropdowns in the upper-right-hand corner of the admin screen. In-depth info, explanations, and FAQ are just a click away.
81
  * Unlike certain other SEO plugins, SEO Ultimate sports a clean, simple, aesthetically-pleasing interface, with no ads or donation nags.
82
- * SEO Ultimate cleanly integrates itself into WordPress without using plastering its name all over the interface.
83
  * If you choose to delete SEO Ultimate from within the WordPress plugin manager, SEO Ultimate will remove all its settings from your database.
84
  * Includes icon integration with the WordPress 2.7+ menu and the Ozh Admin Drop Down Menu plugin.
85
  * Uses WordPress plugin security features like nonces, etc.
@@ -90,7 +90,7 @@ SEO Ultimate is an all-in-one [SEO](http://www.seodesignsolutions.com/) plugin w
90
  * Automated internal linking.
91
  * ...And much, much more! Install SEO Ultimate today and use WordPress's automatic plugin updater to get new features as they're released.
92
 
93
- **[Download](http://downloads.wordpress.org/plugin/seo-ultimate.zip) your free copy of SEO Ultimate today.**
94
 
95
  == Installation ==
96
 
@@ -464,11 +464,13 @@ Here's information on each of the settings and its supported variables:
464
 
465
  * **Year Archive Title Format** -- Displays on year archives. Supports the {year} variable.
466
 
467
- * **Author Archive Title Format** -- Displays on author archives. Supports the same author variables as the Post Title Format box, i.e. {author}, {author_username}, {author_firstname}, {author_lastname}, and {author_nickname}.
468
 
469
  * **Search Title Format** -- Displays on the result pages for WordPress's blog search function. The {query} variable is replaced with the search query as-is. The {ucwords} variable returns the search query with the first letter of each word capitalized.
470
 
471
- * **404 Title Format** -- Displays whenever a URL doesn't go anywhere.
 
 
472
 
473
  * **Pagination Title Format** -- Displays whenever the visitor is on a subpage (page 2, page 3, etc). Supports these variables:
474
 
@@ -490,6 +492,30 @@ Here's information on each of the settings and its supported variables:
490
  Try disabling other SEO plugins, as they may be conflicting with SEO Ultimate. Also, check to make sure your theme is [plugin-friendly](http://wordpress.jdwebdev.com/blog/theme-plugin-hooks/).
491
 
492
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
493
 
494
  == Frequently Asked Questions ==
495
 
@@ -513,18 +539,9 @@ Here's information on each of the settings and its supported variables:
513
  * **How do I remove the attribution link?**
514
  Because of the tremendous effort put into this plugin, we ask that you please leave the link enabled. If you must disable it, you can do so under `Settings > SEO Ultimate`.
515
 
516
-
517
- = Plugin Settings Page =
518
-
519
  * **Where is the Plugin Settings page?**
520
  The plugin settings page is located under `Settings > SEO Ultimate`.
521
 
522
- * **Why doesn't the settings exporter include all my data in an export?**
523
- The settings export/import system is designed to facilitate moving settings between sites. It is NOT a replacement for keeping your database backed up. The settings exporter doesn't include data that is specific to your site. For example, logged 404 errors are not included because those 404 errors only apply to your site, not another site. Also, post/page titles/meta are not included because the site into which you import the file could have totally different posts/pages located under the same ID numbers.
524
-
525
- If you're moving a site to a different server or restoring a crashed site, you should do so with database backup/restore.
526
-
527
-
528
  = "SEO Settings" box =
529
 
530
  * **Where is the SEO Settings box located?**
@@ -556,6 +573,16 @@ Frequently asked questions, documentation, and troubleshooting tips for SEO Ulti
556
 
557
  == Changelog ==
558
 
 
 
 
 
 
 
 
 
 
 
559
  = Version 1.4.1 (January 11, 2010) =
560
  * Compatibility: Meta Editor now supports the new Google Webmaster Tools verification code
561
 
1
  === SEO Ultimate ===
2
  Contributors: SEO Design Solutions
3
  Tags: seo, google, yahoo, bing, search engines, admin, post, page, modules, title, meta, noindex, canonical, 404, robots.txt, htaccess, slugs, url, anchor, more, link, excerpt, permalink
4
+ Requires at least: 2.8
5
+ Tested up to: 2.9
6
+ Stable tag: 1.5
7
 
8
  This all-in-one SEO plugin gives you control over titles, noindex, meta data, slugs, canonical tags, "more" links, 404 error tracking, and more.
9
 
11
 
12
  = Recent Releases =
13
 
14
+ * Version 1.5 adds under-the-hood improvements and additional documentation
15
  * Version 1.4 adds the Internal Relevance Researcher module
16
  * Version 1.3 adds the More Link Customizer module
 
17
 
18
  = Features =
19
 
76
  * Reset all settings back to "factory defaults" if something goes wrong.
77
 
78
  * **Additional features**
79
+ * Supports [WordPress plugin translation](http://urbangiraffe.com/articles/translating-wordpress-themes-and-plugins/). POT file is included in the zip file.
80
  * SEO Ultimate documentation is seamlessly integrated into the contextual help system of WordPress 2.7+ and is accessible via the dropdowns in the upper-right-hand corner of the admin screen. In-depth info, explanations, and FAQ are just a click away.
81
  * Unlike certain other SEO plugins, SEO Ultimate sports a clean, simple, aesthetically-pleasing interface, with no ads or donation nags.
82
+ * SEO Ultimate cleanly integrates itself into WordPress without plastering its name all over the interface.
83
  * If you choose to delete SEO Ultimate from within the WordPress plugin manager, SEO Ultimate will remove all its settings from your database.
84
  * Includes icon integration with the WordPress 2.7+ menu and the Ozh Admin Drop Down Menu plugin.
85
  * Uses WordPress plugin security features like nonces, etc.
90
  * Automated internal linking.
91
  * ...And much, much more! Install SEO Ultimate today and use WordPress's automatic plugin updater to get new features as they're released.
92
 
93
+ [**Download**](http://downloads.wordpress.org/plugin/seo-ultimate.zip) **your free copy of SEO Ultimate today.**
94
 
95
  == Installation ==
96
 
464
 
465
  * **Year Archive Title Format** -- Displays on year archives. Supports the {year} variable.
466
 
467
+ * **Author Archive Title Format** -- Displays on author archives. Supports the same author variables as the Post Title Format box, i.e. {author}, {author\_username}, {author\_firstname}, {author\_lastname}, and {author\_nickname}.
468
 
469
  * **Search Title Format** -- Displays on the result pages for WordPress's blog search function. The {query} variable is replaced with the search query as-is. The {ucwords} variable returns the search query with the first letter of each word capitalized.
470
 
471
+ * **404 Title Format** -- Displays whenever a URL doesn't go anywhere. Supports this variable:
472
+
473
+ * {url_words} -- The words used in the error-generating URL. The first letter of each word will be capitalized.
474
 
475
  * **Pagination Title Format** -- Displays whenever the visitor is on a subpage (page 2, page 3, etc). Supports these variables:
476
 
492
  Try disabling other SEO plugins, as they may be conflicting with SEO Ultimate. Also, check to make sure your theme is [plugin-friendly](http://wordpress.jdwebdev.com/blog/theme-plugin-hooks/).
493
 
494
 
495
+ == Plugin Settings ==
496
+
497
+ = Overview =
498
+
499
+ The Settings module lets you manage settings related to the SEO Ultimate plugin as a whole.
500
+
501
+ = Settings =
502
+
503
+ Here's information on some of the settings:
504
+
505
+ * **Enable attribution link** -- If enabled, the plugin will display an attribution link on your site. We ask that you please leave this enabled.
506
+
507
+ * **Insert comments around HTML code insertions** -- If enabled, SEO Ultimate will use HTML comments to identify all code it inserts into your `<head>` tag. This is useful if you&#8217;re trying to figure out whether or not SEO Ultimate is inserting a certain piece of header code.
508
+
509
+ * **Allow modules to save visitor information to the database** -- This allows enabled modules to record information about the people or robots that visit your website. This information is stored in your WordPress database. This setting must be enabled in order for modules like the 404 Monitor to function.
510
+
511
+ * **Delete logged visitor information after ___ days** -- If enabled, SEO Ultimate will delete visitor information once it has been stored for more than a specified number of days. (The default value is 30.) Enable this setting if the visitor-logging functionality is making your database size unmanageable. Please note that as soon as you enable this and click the Save button, your old visitor information will be irreversably purged accordingly.
512
+
513
+ = FAQ =
514
+
515
+ * **Why doesn't the settings exporter include all my data in an export?** -- The settings export/import system is designed to facilitate moving settings between sites. It is NOT a replacement for keeping your database backed up. The settings exporter doesn't include data that is specific to your site. For example, logged 404 errors are not included because those 404 errors only apply to your site, not another site. Also, post/page titles/meta are not included because the site into which you import the file could have totally different posts/pages located under the same ID numbers.
516
+
517
+ If you're moving a site to a different server or restoring a crashed site, you should do so with database backup/restore.
518
+
519
 
520
  == Frequently Asked Questions ==
521
 
539
  * **How do I remove the attribution link?**
540
  Because of the tremendous effort put into this plugin, we ask that you please leave the link enabled. If you must disable it, you can do so under `Settings > SEO Ultimate`.
541
 
 
 
 
542
  * **Where is the Plugin Settings page?**
543
  The plugin settings page is located under `Settings > SEO Ultimate`.
544
 
 
 
 
 
 
 
545
  = "SEO Settings" box =
546
 
547
  * **Where is the SEO Settings box located?**
573
 
574
  == Changelog ==
575
 
576
+ = Version 1.5 (January 23, 2010) =
577
+ * Major under-the-hood changes and improvements
578
+ * Feature: Added new {url_words} title format variable to Title Rewriter
579
+ * Bugfix: Fixed broken link in the "SEO Settings" contextual help dropdown
580
+ * Improvement: Module documentation now loaded directly from the readme file (eliminates duplication)
581
+ * Improvement: Much more documentation now available from within the plugin
582
+ * Improvement: Module Manager now only shows the "Silenced" option for applicable modules
583
+ * Improvement: Cleaned root folder (now includes only the readme, screenshots, plugin file, POT file, and blank index.php)
584
+ * Improvement: Reduced database usage when saving post meta
585
+
586
  = Version 1.4.1 (January 11, 2010) =
587
  * Compatibility: Meta Editor now supports the new Google Webmaster Tools verification code
588
 
seo-ultimate.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: SEO Ultimate
4
  Plugin URI: http://www.seodesignsolutions.com/wordpress-seo/
5
  Description: This all-in-one SEO plugin gives you control over titles, noindex, meta data, slugs, canonical tags, "more" links, 404 error tracking, and more.
6
- Version: 1.4.1
7
  Author: SEO Design Solutions
8
  Author URI: http://www.seodesignsolutions.com/
9
  Text Domain: seo-ultimate
@@ -12,12 +12,12 @@ Text Domain: seo-ultimate
12
  /**
13
  * The main SEO Ultimate plugin file.
14
  * @package SeoUltimate
15
- * @version 1.4.1
16
  * @link http://www.seodesignsolutions.com/wordpress-seo/ SEO Ultimate Homepage
17
  */
18
 
19
  /*
20
- Copyright 2009 John Lamansky
21
 
22
  This program is free software; you can redistribute it and/or modify
23
  it under the terms of the GNU General Public License as published by
@@ -38,26 +38,28 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
38
  //Reading plugin info from constants is faster than trying to parse it from the header above.
39
  define("SU_PLUGIN_NAME", "SEO Ultimate");
40
  define("SU_PLUGIN_URI", "http://www.seodesignsolutions.com/wordpress-seo/");
41
- define("SU_VERSION", "1.4.1");
42
  define("SU_AUTHOR", "SEO Design Solutions");
43
  define("SU_AUTHOR_URI", "http://www.seodesignsolutions.com/");
44
- define("SU_USER_AGENT", "SeoUltimate/1.4.1");
45
 
46
- define('SU_MODULE_ENABLED', 10);
47
- define('SU_MODULE_SILENCED', 5);
48
- define('SU_MODULE_HIDDEN', 0);
49
- define('SU_MODULE_DISABLED', -10);
50
 
51
- define('SU_RESULT_OK', 1);
52
- define('SU_RESULT_WARNING', 0);
53
- define('SU_RESULT_ERROR', -1);
 
 
54
 
55
- /********** INCLUDES **********/
 
 
 
 
56
 
57
- include 'functions.php';
58
- include 'class.seo-ultimate.php';
59
- include 'class.su-module.php';
60
- include 'class.su-hitset.php';
61
 
62
 
63
  /********** PLUGIN FILE LOAD HANDLER **********/
@@ -67,7 +69,7 @@ include 'class.su-hitset.php';
67
 
68
  global $seo_ultimate;
69
  if (defined('ABSPATH'))
70
- $seo_ultimate =& new SEO_Ultimate();
71
  else {
72
  header('Status: 403 Forbidden');
73
  header('HTTP/1.1 403 Forbidden');
3
  Plugin Name: SEO Ultimate
4
  Plugin URI: http://www.seodesignsolutions.com/wordpress-seo/
5
  Description: This all-in-one SEO plugin gives you control over titles, noindex, meta data, slugs, canonical tags, "more" links, 404 error tracking, and more.
6
+ Version: 1.5
7
  Author: SEO Design Solutions
8
  Author URI: http://www.seodesignsolutions.com/
9
  Text Domain: seo-ultimate
12
  /**
13
  * The main SEO Ultimate plugin file.
14
  * @package SeoUltimate
15
+ * @version 1.5
16
  * @link http://www.seodesignsolutions.com/wordpress-seo/ SEO Ultimate Homepage
17
  */
18
 
19
  /*
20
+ Copyright (c) 2009 John Lamansky
21
 
22
  This program is free software; you can redistribute it and/or modify
23
  it under the terms of the GNU General Public License as published by
38
  //Reading plugin info from constants is faster than trying to parse it from the header above.
39
  define("SU_PLUGIN_NAME", "SEO Ultimate");
40
  define("SU_PLUGIN_URI", "http://www.seodesignsolutions.com/wordpress-seo/");
41
+ define("SU_VERSION", "1.5");
42
  define("SU_AUTHOR", "SEO Design Solutions");
43
  define("SU_AUTHOR_URI", "http://www.seodesignsolutions.com/");
44
+ define("SU_USER_AGENT", "SeoUltimate/1.5");
45
 
46
+ /********** INCLUDES **********/
 
 
 
47
 
48
+ //Libraries
49
+ include 'includes/jlfunctions/jlfunctions.php';
50
+ include 'includes/jlwp/jlwp.php';
51
+ if (!class_exists('Markdown'))
52
+ include_once 'includes/markdown/markdown.php';
53
 
54
+ //Plugin files
55
+ include 'plugin/su-constants.php';
56
+ include 'plugin/su-functions.php';
57
+ include 'plugin/class.seo-ultimate.php';
58
+ include 'plugin/class.su-hitset.php';
59
 
60
+ //Module files
61
+ include 'modules/class.su-module.php';
62
+ include 'modules/class.su-importmodule.php';
 
63
 
64
 
65
  /********** PLUGIN FILE LOAD HANDLER **********/
69
 
70
  global $seo_ultimate;
71
  if (defined('ABSPATH'))
72
+ $seo_ultimate =& new SEO_Ultimate(__FILE__);
73
  else {
74
  header('Status: 403 Forbidden');
75
  header('HTTP/1.1 403 Forbidden');
seo-ultimate.pot CHANGED
@@ -1,511 +1,363 @@
1
- # SEO Ultimate
2
- # Copyright (C) 2009 John Lamansky
3
  # This file is distributed under the same license as the SEO Ultimate package.
 
4
  #
5
  #, fuzzy
6
  msgid ""
7
  msgstr ""
8
- "Project-Id-Version: SEO Ultimate 1.3\n"
9
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/seo-ultimate\n"
10
- "POT-Creation-Date: 2009-07-23 22:19+0000\n"
 
 
 
11
  "MIME-Version: 1.0\n"
12
  "Content-Type: text/plain; charset=utf-8\n"
13
  "Content-Transfer-Encoding: 8bit\n"
14
 
15
- #. #-#-#-#-# seo-ultimate.pot (SEO Ultimate 1.3) #-#-#-#-#
16
- #. Plugin Name of an extension
17
- #: class.seo-ultimate.php:705 modules/settings.php:16
18
- msgid "SEO Ultimate"
19
- msgstr ""
20
-
21
- #: class.seo-ultimate.php:705
22
- msgid "SEO"
23
- msgstr ""
24
-
25
- #: class.seo-ultimate.php:918
26
- msgid "SEO Settings Help"
27
- msgstr ""
28
-
29
- #: class.seo-ultimate.php:920
30
- msgid "The SEO Settings box lets you customize these settings:"
31
- msgstr ""
32
-
33
- #: class.seo-ultimate.php:922
34
- msgid "(The SEO Settings box is part of the SEO Ultimate plugin.)"
35
- msgstr ""
36
-
37
- #: class.seo-ultimate.php:977
38
- #, php-format
39
- msgid ""
40
- "SEO Ultimate includes the functionality of %1$s. You may want to deactivate %"
41
- "1$s to avoid plugin conflicts."
42
- msgstr ""
43
-
44
- #: class.seo-ultimate.php:1070
45
- msgid "SEO Settings"
46
- msgstr ""
47
-
48
- #: class.su-hitset.php:44
49
- msgid "Date"
50
- msgstr ""
51
-
52
- #: class.su-hitset.php:45
53
- msgid "IP Address"
54
- msgstr ""
55
-
56
- #: class.su-hitset.php:46
57
- msgid "User Agent"
58
- msgstr ""
59
-
60
- #: class.su-hitset.php:47
61
- msgid "URL Requested"
62
- msgstr ""
63
-
64
- #: class.su-hitset.php:48
65
- msgid "Redirected To"
66
- msgstr ""
67
-
68
- #: class.su-hitset.php:49
69
- msgid "Status Code"
70
- msgstr ""
71
-
72
- #: class.su-hitset.php:50
73
- msgid "Referring URL"
74
- msgstr ""
75
-
76
- #: class.su-hitset.php:82
77
- #, php-format
78
- msgid "%1$s<br />%2$s"
79
- msgstr ""
80
-
81
- #: class.su-module.php:562
82
- #, php-format
83
- msgid "%s %s|Dropdown Title"
84
- msgstr ""
85
-
86
- #: class.su-module.php:574
87
- #, php-format
88
- msgid "%s Documentation"
89
- msgstr ""
90
-
91
- #: class.su-module.php:578
92
- msgid "Documentation"
93
- msgstr ""
94
-
95
- #: class.su-module.php:596
96
- #, php-format
97
- msgid "%1$s | %2$s %3$s by %4$s"
98
- msgstr ""
99
-
100
- #: class.su-module.php:630
101
- msgid "Settings updated."
102
- msgstr ""
103
-
104
- #: class.su-module.php:650
105
- msgid "Save Changes"
106
- msgstr ""
107
-
108
- #: class.su-module.php:766
109
- msgid ""
110
- "Are you sure you want to replace the textbox contents with this default "
111
- "value?"
112
- msgstr ""
113
-
114
- #: class.su-module.php:781
115
- msgid "Reset"
116
- msgstr ""
117
-
118
- #: functions.php:133
119
  #, php-format
120
  msgid "%s and %s"
121
  msgstr ""
122
 
123
- #: functions.php:136
124
  msgid ", "
125
  msgstr ""
126
 
127
- #: functions.php:137
128
  #, php-format
129
  msgid "%s, and %s"
130
  msgstr ""
131
 
132
- #: modules/404s.php:29
133
  msgid "404 Monitor"
134
  msgstr ""
135
 
136
- #: modules/404s.php:46
137
  #, php-format
138
  msgid ""
139
  "Please note that new 404 errors will not be recorded, since visitor logging "
140
  "is disabled in the %s."
141
  msgstr ""
142
 
143
- #: modules/404s.php:47 modules/404s.php:174
144
  msgid "Plugin Settings module"
145
  msgstr ""
146
 
147
- #: modules/404s.php:54
148
  msgid "The log entry was successfully deleted."
149
  msgstr ""
150
 
151
- #: modules/404s.php:56
152
  msgid "This log entry has already been deleted."
153
  msgstr ""
154
 
155
- #: modules/404s.php:65
156
  msgid "The log was successfully cleared."
157
  msgstr ""
158
 
159
- #: modules/404s.php:73
160
  msgid "No 404 errors in the log."
161
  msgstr ""
162
 
163
- #: modules/404s.php:84
164
  msgid "Are you sure you want to delete all 404 log entries?"
165
  msgstr ""
166
 
167
- #: modules/404s.php:86
168
  msgid "Clear Log"
169
  msgstr ""
170
 
171
- #: modules/404s.php:99
172
  msgid "Open"
173
  msgstr ""
174
 
175
- #: modules/404s.php:100
176
  msgid "Google Cache"
177
  msgstr ""
178
 
179
- #: modules/404s.php:101
180
  msgid "Delete Log Entry"
181
  msgstr ""
182
 
183
- #: modules/404s.php:117 modules/canonical.php:183 modules/files.php:140
184
- #: modules/linkbox.php:90 modules/meta.php:140 modules/noindex.php:94
185
- #: modules/slugs.php:61 modules/titles.php:335
186
- msgid "Overview"
187
  msgstr ""
188
 
189
- #: modules/404s.php:120
190
- msgid "Options Help"
191
  msgstr ""
192
 
193
- #: modules/404s.php:123
194
- msgid "Troubleshooting"
195
  msgstr ""
196
 
197
- #: modules/404s.php:129
198
- msgid ""
199
- "\r\n"
200
- "<ul>\r\n"
201
- "\t<li><p><strong>What it does:</strong> The 404 Monitor keeps track of non-"
202
- "existant URLs that generated 404 errors.\r\n"
203
- "\t\t404 errors are when a search engine or visitor comes to a URL on your "
204
- "site but nothing exists at that URL.</p></li>\r\n"
205
- "\t<li><p><strong>Why it helps:</strong> The 404 Monitor helps you spot 404 "
206
- "errors; \r\n"
207
- "\t\tthen you can take steps to correct them to reduce linkjuice loss from "
208
- "broken links.</p></li>\r\n"
209
- "\t<li><p><strong>How to use it:</strong> Check the 404 Monitor occasionally "
210
- "for errors.\r\n"
211
- "\t\t(A numeric bubble will appear next to the &#8220;404 Monitor&#8221; item "
212
- "on the menu if there are any newly-logged URLs that you haven&#8217;t seen "
213
- "yet. \r\n"
214
- "\t\tThese new URLs will also be highlighted green in the table.)\r\n"
215
- "\t\tIf a 404 error&#8217;s referring URL is located on your site, try "
216
- "locating and fixing the broken URL.\r\n"
217
- "\t\tIf moved content was previously located at the requested URL, try using "
218
- "a redirection plugin to point the old URL to the new one.</p></li>\r\n"
219
- "</ul>\r\n"
220
- msgstr ""
221
-
222
- #: modules/404s.php:146
223
  msgid ""
224
- "Currently, the 404 Monitor doesn&#8217;t have any 404 errors in its log. "
225
- "This is good, and means there&#8217;s no action required on your part. If "
226
- "the 404 Monitor logs any 404 errors in the future, you&#8217;ll see them on "
227
- "this page."
 
 
228
  msgstr ""
229
 
230
- #: modules/404s.php:154
 
 
 
 
 
 
 
 
 
 
 
 
231
  msgid ""
232
- "\r\n"
233
- "<p>Hover over a table row to access these options:</p>\r\n"
234
- "<ul>\r\n"
235
- "\t\t<li>The &#8220;View&#8221; link will open the URL in a new window. This "
236
- "is useful for testing whether or not a redirect is working.</li>\r\n"
237
- "\t\t<li>The &#8220;Google Cache&#8221; link will open Google&#8217;s "
238
- "archived version of the URL in a new window. This is useful for determining "
239
- "what content, if any, used to be located at that URL.</li>\r\n"
240
- "\t\t<li>Once you've taken care of a 404 error, you can click the &#8220;"
241
- "Delete Log Entry&#8221; link to remove it from the list. The URL will "
242
- "reappear on the list if it triggers a 404 error in the future.</li>\r\n"
243
- "</ul>\r\n"
244
- msgstr ""
245
-
246
- #: modules/404s.php:165
247
  #, php-format
248
- msgid ""
249
- "\r\n"
250
- "<p>404 Monitor doesn&#8217;t appear to work? Take these notes into "
251
- "consideration:</p>\r\n"
252
- "<ul>\r\n"
253
- "\t<li>Visitor logging must be enabled in the %s. (It&#8217;s enabled by "
254
- "default.)</li>\r\n"
255
- "\t<li>In order for the 404 Monitor to track 404 errors, you must have &#8220;"
256
- "Pretty Permalinks&#8221; enabled in your <a href='options-permalink."
257
- "php'>permalink options</a>.</li>\r\n"
258
- "\t<li>Some parts of your website may not be under WordPress&#8217;s control; "
259
- "the 404 Monitor can&#8217;t track 404 errors on non-WordPress website areas."
260
- "</li>\r\n"
261
- "\t<li>The 404 Monitor doesn&#8217;t record 404 errors generated by logged-in "
262
- "users.</li>\r\n"
263
- "</ul>\r\n"
264
- msgstr ""
265
-
266
- #: modules/canonical.php:13
267
- msgid "Canonicalizer"
268
  msgstr ""
269
 
270
- #: modules/canonical.php:34
271
- msgid "Generate <code>&lt;link rel=&quot;canonical&quot; /&gt;</code> tags."
 
272
  msgstr ""
273
 
274
- #: modules/canonical.php:35
275
- msgid "Redirect requests for nonexistent pagination."
276
  msgstr ""
277
 
278
- #: modules/canonical.php:188
 
 
 
 
279
  msgid ""
280
- "\r\n"
281
- "<ul>\r\n"
282
- "\t<li><p><strong>What it does:</strong> Canonicalizer improves on two "
283
- "WordPress features to minimize possible exact-content duplication penalties."
284
- "\r\n"
285
- "\t\tThe <code>&lt;link rel=&quot;canonical&quot; /&gt;</code> tags setting "
286
- "improves on the canonical tags feature of WordPress 2.9 and above by "
287
- "encompassing much more of your site than just your posts and Pages.</p>\r\n"
288
- "\t\t<p>The nonexistent pagination redirect feature fills a gap in "
289
- "WordPress&#8217;s built-in canonicalization functionality: \r\n"
290
- "\t\tfor example, if a URL request is made for page 6 of a category archive, "
291
- "and that category doesn&#8217;t have a page 6,\r\n"
292
- "\t\tthen by default, depending on the context, WordPress will display a "
293
- "blank page, or it will display the content of the closest page number "
294
- "available, \r\n"
295
- "\t\twithout issuing a 404 error or a 301 redirect (thus creating two or more "
296
- "identical webpages). \r\n"
297
- "\t\tThis duplicate-content situation can happen when you, for example, "
298
- "remove many posts from a category, thus reducing the amount of pagination "
299
- "needed in the category&#8217;s archive. \r\n"
300
- "\t\tThe Canonicalizer&#8217;s feature fixes that behavior by issuing 301 "
301
- "redirects to page 1 of the paginated section in question.</p></li>\r\n"
302
- "\t<li><p><strong>Why it helps:</strong> These features will point Google to "
303
- "the correct URL for your homepage and each of your posts, Pages, categories, "
304
- "tags, date archives, and author archives. \r\n"
305
- "That way, if Google comes across an alternate URL by which one of those "
306
- "items can be accessed, it will be able to find the correct URL \r\n"
307
- "and won&#8217;t penalize you for having two identical pages on your site.</"
308
- "p></li>\r\n"
309
- "\t<li><p><strong>How to use it:</strong> Just check both checkboxes and "
310
- "click Save Changes. SEO Ultimate will do the rest.</p></li>\r\n"
311
- "</ul>\r\n"
312
- msgstr ""
313
-
314
- #: modules/competition-queries.php:13
315
- msgid "Comp. Researcher"
316
  msgstr ""
317
 
318
- #: modules/competition-queries.php:14
 
 
 
 
319
  msgid "Competition Researcher"
320
  msgstr ""
321
 
322
- #: modules/competition-queries.php:18
 
 
 
 
323
  msgid ""
324
  "The Competition Researcher provides you with easy access to various search "
325
  "engine tools which you can use to research multiple search queries or URLs."
326
  msgstr ""
327
 
328
- #: modules/competition-queries.php:22
329
  msgid "Step 1: Choose Your Research Tool"
330
  msgstr ""
331
 
332
- #: modules/competition-queries.php:26
333
  msgid "Keywords"
334
  msgstr ""
335
 
336
- #: modules/competition-queries.php:26
337
  msgid "Normal Search"
338
  msgstr ""
339
 
340
- #: modules/competition-queries.php:26
341
  msgid "Find out how many pages contain the words in each query"
342
  msgstr ""
343
 
344
- #: modules/competition-queries.php:27
345
  msgid "Phrase Match"
346
  msgstr ""
347
 
348
- #: modules/competition-queries.php:27
349
  msgid ""
350
  "Find out how many &#8220;actual&#8221; pages are competing for each query"
351
  msgstr ""
352
 
353
- #: modules/competition-queries.php:28
354
  msgid "Allinanchor"
355
  msgstr ""
356
 
357
- #: modules/competition-queries.php:28
358
  msgid "Find out which sites have the most links for each query"
359
  msgstr ""
360
 
361
- #: modules/competition-queries.php:29
362
  msgid "Allintitle"
363
  msgstr ""
364
 
365
- #: modules/competition-queries.php:29
366
  msgid ""
367
  "Find out which sites have the highest relevance in the title for each query"
368
  msgstr ""
369
 
370
- #: modules/competition-queries.php:30
371
  msgid "Allintext"
372
  msgstr ""
373
 
374
- #: modules/competition-queries.php:30
375
  msgid "Find out which sites have the most relevant content/text on their pages"
376
  msgstr ""
377
 
378
- #: modules/competition-queries.php:31
379
  msgid "Allinurl"
380
  msgstr ""
381
 
382
- #: modules/competition-queries.php:31
383
  msgid ""
384
  "Find out which sites have the most relevant naming conventions for each "
385
  "keyword"
386
  msgstr ""
387
 
388
- #: modules/competition-queries.php:33
389
  msgid "URLs"
390
  msgstr ""
391
 
392
- #: modules/competition-queries.php:33
393
  msgid "Site"
394
  msgstr ""
395
 
396
- #: modules/competition-queries.php:33
397
  msgid "Find out how many pages are indexed for each domain"
398
  msgstr ""
399
 
400
- #: modules/competition-queries.php:34 modules/competition-queries.php:39
 
401
  msgid "Inbound Links"
402
  msgstr ""
403
 
404
- #: modules/competition-queries.php:34
405
  msgid "Find out how many sites link to the domains"
406
  msgstr ""
407
 
408
- #: modules/competition-queries.php:35 modules/competition-queries.php:39
 
409
  msgid "Outbound Links"
410
  msgstr ""
411
 
412
- #: modules/competition-queries.php:35
413
  msgid "Find out how many sites the domains link to"
414
  msgstr ""
415
 
416
- #: modules/competition-queries.php:57
417
  msgid "Step 2: Enter the <span id='methodtype'>Keywords</span> To Research"
418
  msgstr ""
419
 
420
- #: modules/competition-queries.php:59
421
  msgid "(Type in one per line)"
422
  msgstr ""
423
 
424
- #: modules/competition-queries.php:61
425
  msgid "Step 3: Set Options and Submit"
426
  msgstr ""
427
 
428
- #: modules/competition-queries.php:63
 
429
  msgid "Show 100 results per page"
430
  msgstr ""
431
 
432
- #: modules/competition-queries.php:65
 
433
  msgid "Use Google's minimal mode"
434
  msgstr ""
435
 
436
- #: modules/competition-queries.php:71
 
437
  msgid "Submit"
438
  msgstr ""
439
 
440
- #: modules/files.php:15
441
  msgid "File Editor"
442
  msgstr ""
443
 
444
- #: modules/files.php:53
445
  msgid ""
446
  "A .htaccess file exists, but it&#8217;s not writable. You can edit it here "
447
  "once the file permissions are corrected."
448
  msgstr ""
449
 
450
- #: modules/files.php:59
451
  msgid ""
452
  "WordPress won&#8217;t be able to display your robots.txt file because the "
453
  "default <a href=\"options-permalink.php\" target=\"_blank\">permalink "
454
  "structure</a> is in use."
455
  msgstr ""
456
 
457
- #: modules/files.php:66
458
  #, php-format
459
  msgid "robots.txt [<a href=\"%s\" target=\"_blank\">Open</a>]"
460
  msgstr ""
461
 
462
- #: modules/files.php:70
463
  msgid "Enable this custom robots.txt file and disable the default file"
464
  msgstr ""
465
 
466
- #: modules/files.php:71
467
  msgid "Let other plugins add rules to my custom robots.txt file"
468
  msgstr ""
469
 
470
- #: modules/files.php:72
471
  msgid "robots.txt Settings"
472
  msgstr ""
473
 
474
- #: modules/files.php:75
475
  msgid ""
476
  "Please realize that incorrectly editing your robots.txt file could block "
477
  "search engines from your site."
478
  msgstr ""
479
 
480
- #: modules/files.php:79
481
  msgid ".htaccess"
482
  msgstr ""
483
 
484
- #: modules/files.php:82
485
  msgid ""
486
  "Also, incorrectly editing your .htaccess file could disable your entire "
487
  "website. Edit with caution!"
488
  msgstr ""
489
 
490
- #: modules/files.php:132
491
  #, php-format
492
  msgid ""
493
  "Please note that your privacy settings won&#8217;t have any effect on your "
494
  "robots.txt file, since you&#8217;re using <a href=\"%s\">a custom one</a>."
495
  msgstr ""
496
 
497
- #: modules/files.php:141 modules/slugs.php:62
 
 
 
 
498
  msgid "FAQ"
499
  msgstr ""
500
 
501
- #: modules/files.php:146
502
  msgid ""
503
  "The File Editor module lets you edit system files that are of SEO value. "
504
  "Edit the files as desired, then click Save Changes. If you create a custom "
505
  "robots.txt file, be sure to enable it with the checkbox."
506
  msgstr ""
507
 
508
- #: modules/files.php:150
509
  msgid ""
510
  "\r\n"
511
  "<h6>Why do I get a &#8220;500 Server Error&#8221; after using the File "
@@ -538,949 +390,656 @@ msgid ""
538
  "you can try recovering your edits from there.</p>\r\n"
539
  msgstr ""
540
 
541
- #: modules/linkbox.php:13
542
  msgid "Linkbox Inserter"
543
  msgstr ""
544
 
545
- #: modules/linkbox.php:19
546
  msgid "Link to this post!"
547
  msgstr ""
548
 
549
- #: modules/linkbox.php:46
550
  msgid "At the end of posts"
551
  msgstr ""
552
 
553
- #: modules/linkbox.php:47
554
  msgid "At the end of pages"
555
  msgstr ""
556
 
557
- #: modules/linkbox.php:48
558
  msgid "When called by the su_linkbox hook"
559
  msgstr ""
560
 
561
- #: modules/linkbox.php:49
562
  msgid "Display linkboxes..."
563
  msgstr ""
564
 
565
- #: modules/linkbox.php:50
566
  msgid "Linkbox HTML"
567
  msgstr ""
568
 
569
- #: modules/linkbox.php:91 modules/meta.php:141 modules/noindex.php:95
570
- msgid "Settings Help"
571
  msgstr ""
572
 
573
- #: modules/linkbox.php:96
574
- msgid ""
575
- "\r\n"
576
- "<ul>\r\n"
577
- "\t<li><p><strong>What it does:</strong> Linkbox Inserter can add linkboxes "
578
- "to your posts/pages.</p></li>\r\n"
579
- "\t<li><p><strong>Why it helps:</strong> Linkboxes contain HTML code that "
580
- "visitors can use to link to your site. This is a great way to encourage SEO-"
581
- "beneficial linking activity.</p></li>\r\n"
582
- "\t<li><p><strong>How to use it:</strong> Use the checkboxes to enable the "
583
- "Linkbox Inserter in various areas of your site. Customize the HTML if "
584
- "desired. Click &#8220;Save Changes&#8221; when finished.</p></li>\r\n"
585
- "</ul>\r\n"
586
- msgstr ""
587
-
588
- #: modules/linkbox.php:106
589
- msgid ""
590
- "\r\n"
591
- "<p>Here&#8217;s information on the various settings:</p>\r\n"
592
- "<ul>\r\n"
593
- "\t<li><p><strong>Display linkboxes...</strong></p>\r\n"
594
- "\t\t<ul>\r\n"
595
- "\t\t\t<li><p><strong>At the end of posts</strong> &mdash; Adds the linkbox "
596
- "HTML to the end of all posts \r\n"
597
- "\t\t\t\t(whether they&#8217;re displayed on the blog homepage, in archives, "
598
- "or by themselves).</p></li>\r\n"
599
- "\t\t\t<li><p><strong>At the end of pages</strong> &mdash; Adds the linkbox "
600
- "HTML to the end of all Pages.</p></li>\r\n"
601
- "\t\t\t<li><p><strong>When called by the su_linkbox hook</strong> &mdash; For "
602
- "more fine-tuned control over where linkboxes appear, \r\n"
603
- "\t\t\t\tenable this option and add <code>&lt;?php&nbsp;do_action"
604
- "('su_linkbox');&nbsp;?&gt;</code> to your theme. \r\n"
605
- "\t\t\t\tYou can also add an ID parameter to display the linkbox of a "
606
- "particular post/page; for example: \r\n"
607
- "\t\t\t\t<code>&lt;?php&nbsp;do_action('su_linkbox',&nbsp;123);&nbsp;?&gt;</"
608
- "code></p></li>\r\n"
609
- "\t\t</ul>\r\n"
610
- "\t</li>\r\n"
611
- "\t<li><p><strong>HTML</strong> &mdash; The HTML that will be outputted to "
612
- "display the linkboxes. The HTML field supports these variables:</p>\r\n"
613
- "\t\t<ul>\r\n"
614
- "\t\t\t<li>{id} &mdash; The ID of the current post/page, or the ID passed to "
615
- "the action hook call.</li>\r\n"
616
- "\t\t\t<li>{url} &mdash; The permalink URL of the post/page.</li>\r\n"
617
- "\t\t\t<li>{title} &mdash; The title of the post/page.</li>\r\n"
618
- "\t\t</ul>\r\n"
619
- "\t</li>\r\n"
620
- "</ul>\r\n"
621
- msgstr ""
622
-
623
- #: modules/meta.php:13
624
- msgid "Meta Editor"
625
  msgstr ""
626
 
627
- #: modules/meta.php:30
628
  msgid "Blog Homepage Meta Description"
629
  msgstr ""
630
 
631
- #: modules/meta.php:31
632
  msgid "Blog Homepage Meta Keywords"
633
  msgstr ""
634
 
635
- #: modules/meta.php:34
636
  msgid "Use this blog&#8217s tagline as the default homepage description."
637
  msgstr ""
638
 
639
- #: modules/meta.php:35
640
  msgid "Default Values"
641
  msgstr ""
642
 
643
- #: modules/meta.php:37
644
  msgid ""
645
  "Don&#8217t use this site&#8217s Open Directory description in search results."
646
  msgstr ""
647
 
648
- #: modules/meta.php:38
649
  msgid ""
650
  "Don&#8217t use this site&#8217s Yahoo! Directory description in search "
651
  "results."
652
  msgstr ""
653
 
654
- #: modules/meta.php:39
655
  msgid "Don&#8217t cache or archive this site."
656
  msgstr ""
657
 
658
- #: modules/meta.php:40
659
  msgid "Spider Instructions"
660
  msgstr ""
661
 
662
- #: modules/meta.php:42
663
  msgid "Google Webmaster Tools:"
664
  msgstr ""
665
 
666
- #: modules/meta.php:43
667
  msgid "Yahoo! Site Explorer:"
668
  msgstr ""
669
 
670
- #: modules/meta.php:44
671
  msgid "Bing Webmaster Center:"
672
  msgstr ""
673
 
674
- #: modules/meta.php:45
675
  msgid "Verification Codes"
676
  msgstr ""
677
 
678
- #: modules/meta.php:46
679
  msgid "Custom &lt;head&gt; HTML"
680
  msgstr ""
681
 
682
- #: modules/meta.php:55
 
 
 
 
 
 
 
 
683
  msgid "Description:"
684
  msgstr ""
685
 
686
- #: modules/meta.php:58
687
  #, php-format
688
  msgid "You&#8217;ve entered %s characters. Most search engines use up to 160."
689
  msgstr ""
690
 
691
- #: modules/meta.php:60
692
  msgid "Keywords:<br /><em>(separate with commas)</em>"
693
  msgstr ""
694
 
695
- #: modules/meta.php:127
696
- msgid "Custom Header Code"
697
- msgstr ""
698
-
699
- #: modules/meta.php:146
700
- msgid ""
701
- "\r\n"
702
- "<ul>\r\n"
703
- "\t<li><p><strong>What it does:</strong> Meta Editor lets you customize a "
704
- "wide variety of settings known as &#8220;meta data.&#8221;</p></li>\r\n"
705
- "\t<li><p><strong>Why it helps:</strong> Using meta data, you can convey "
706
- "information to search engines, such as what text you want displayed by your "
707
- "site in search results, what your site is about, whether they can cache your "
708
- "site, etc.</p></li>\r\n"
709
- "\t<li><p><strong>How to use it:</strong> Adjust the settings as desired, and "
710
- "then click Save Changes. You can refer to the &#8220;Settings Help&#8221; "
711
- "tab for information on the settings available. You can also customize the "
712
- "meta data of an individual post or page by using the textboxes that Meta "
713
- "Editor adds to the post/page editors.</p></li>\r\n"
714
- "</ul>\r\n"
715
- msgstr ""
716
-
717
- #: modules/meta.php:156
718
- msgid ""
719
- "\r\n"
720
- "<p>Here&#8217;s information on the various settings:</p>\r\n"
721
- "<ul>\r\n"
722
- "\t<li><p><strong>Blog Homepage Meta Description</strong> &mdash; When your "
723
- "blog homepage appears in search results, it&#8217;ll have a title and a "
724
- "description. \r\n"
725
- "\t\tWhen you insert content into the description field below, the Meta "
726
- "Editor will add code to your blog homepage (the <code>&lt;meta&nbsp;"
727
- "name=&quot;description&quot;&nbsp;/&gt;</code> tag)\r\n"
728
- "\t\tthat asks search engines to use what you&#8217;ve entered as the "
729
- "homepage&#8217;s search results description.</p></li>\r\n"
730
- "\t<li><p><strong>Blog Homepage Meta Keywords</strong> &mdash; Here you can "
731
- "enter keywords that describe the overall subject matter of your entire blog. "
732
- "Use commas to separate keywords. \r\n"
733
- "\t\tYour keywords will be put in the <code>&lt;meta&nbsp;name=&quot;"
734
- "keywords&quot;&nbsp;/&gt;</code> tag on your blog homepage.</p></li>\r\n"
735
- "\t<li><p><strong>Default Values</strong></p>\r\n"
736
- "\t\t<ul>\r\n"
737
- "\t\t\t<li><p><strong>Use this blog&#8217;s tagline as the default homepage "
738
- "description.</strong> &mdash; \r\n"
739
- "\t\t\t\tIf this box is checked and if the Blog Homepage Meta Description "
740
- "field is empty, \r\n"
741
- "\t\t\t\tMeta Editor will use your blog&#8217;s <a href='options-general.php' "
742
- "target='_blank'>tagline</a> as the meta description.</p></li>\r\n"
743
- "\t\t</ul>\r\n"
744
- "\t</li>\r\n"
745
- "\t<li><p><strong>Spider Instructions</strong></p>\r\n"
746
- "\t\t<ul>\r\n"
747
- "\t\t\t<li><p><strong>Don&#8217;t use this site&#8217;s Open Directory / "
748
- "Yahoo! Directory description in search results.</strong> &mdash; \r\n"
749
- "\t\t\t\tIf your site is listed in the <a href='http://www.dmoz.org/' "
750
- "target='_blank'>Open Directory (DMOZ)</a> or \r\n"
751
- "\t\t\t\tthe <a href='http://dir.yahoo.com/' target='_blank'>Yahoo! "
752
- "Directory</a>, \r\n"
753
- "\t\t\t\tsome search engines may use your directory listing as the meta "
754
- "description. \r\n"
755
- "\t\t\t\tThese boxes tell search engines not to do that and will give you "
756
- "full control over your meta descriptions. \r\n"
757
- "\t\t\t\tThese settings have no effect if your site isn&#8217;t listed in the "
758
- "Open Directory or Yahoo! Directory respectively.</p></li>\r\n"
759
- "\t\t\t<li><p><strong>Don&#8217;t cache or archive this site.</strong> "
760
- "&mdash; \r\n"
761
- "\t\t\t\tWhen you check this box, Meta Editor will ask search engines "
762
- "(Google, Yahoo!, Bing, etc.) and archivers (Archive.org, etc.) \r\n"
763
- "\t\t\t\tto <em>not</em> make cached or archived &#8220;copies&#8221; of your "
764
- "site.</p></li>\r\n"
765
- "\t\t</ul>\r\n"
766
- "\t</li>\r\n"
767
- "\t<li><p><strong>Verification Codes</strong> &mdash; This section lets you "
768
- "enter in verification codes for the webmaster portals of the 3 leading "
769
- "search engines.</p></li>\r\n"
770
- "\t<li><p><strong>Custom &lt;head&gt; HTML</strong> &mdash; Just enter in raw "
771
- "HTML code here, and it&#8217;ll be entered into the &lt;head&gt; tag across "
772
- "your entire site.</p></li>\r\n"
773
- "</ul>\r\n"
774
- msgstr ""
775
-
776
- #: modules/meta.php:191
777
  msgid ""
778
  "<strong>Description:</strong> &mdash; The value of the meta description tag. "
779
  "The description will often appear underneath the title in search engine "
780
  "results. "
781
  msgstr ""
782
 
783
- #: modules/meta.php:193
784
  msgid ""
785
  "<strong>Keywords:</strong> &mdash; The value of the meta keywords tag. The "
786
  "keywords list gives search engines a hint as to what this post/page is "
787
  "about. "
788
  msgstr ""
789
 
790
- #: modules/modules.php:13
791
- msgid "Modules"
792
  msgstr ""
793
 
794
- #: modules/modules.php:14
795
- msgid "Module Manager"
796
  msgstr ""
797
 
798
- #: modules/modules.php:35
799
  msgid ""
800
  "SEO Ultimate&#8217;s features are located in groups called &#8220;modules."
801
  "&#8221; By default, most of these modules are listed in the &#8220;"
802
  "SEO&#8221; menu on the left. Whenever you&#8217;re working with a module, "
803
- "you can view documentation by clicking the &#8220;Help&#8221; tab in the "
804
- "upper-right-hand corner of your administration screen."
805
  msgstr ""
806
 
807
- #: modules/modules.php:37
808
  msgid ""
809
  "The Module Manager lets you disable or hide modules you don&#8217;t use. "
810
  "You can also silence modules from displaying bubble alerts on the menu."
811
  msgstr ""
812
 
813
- #: modules/modules.php:43
814
  msgid "Status"
815
  msgstr ""
816
 
817
- #: modules/modules.php:44
818
  msgid "Module"
819
  msgstr ""
820
 
821
- #: modules/modules.php:57
822
  msgid "Enabled"
823
  msgstr ""
824
 
825
- #: modules/modules.php:58
826
  msgid "Silenced"
827
  msgstr ""
828
 
829
- #: modules/modules.php:59
830
  msgid "Hidden"
831
  msgstr ""
832
 
833
- #: modules/modules.php:60
834
  msgid "Disabled"
835
  msgstr ""
836
 
837
- #: modules/modules.php:109
838
- msgid ""
839
- "\r\n"
840
- "<p>The Module Manager lets you customize the visibility and accessibility of "
841
- "each module; here are the options available:</p>\r\n"
842
- "<ul>\r\n"
843
- "\t<li><strong>Enabled</strong> &mdash; The default option. The module will "
844
- "be fully enabled and accessible.</li>\r\n"
845
- "\t<li><strong>Silenced</strong> &mdash; The module will be enabled and "
846
- "accessible, but it won&#8217;t be allowed to display numeric bubble alerts "
847
- "on the menu.</li>\r\n"
848
- "\t<li><strong>Hidden</strong> &mdash; The module&#8217;s functionality will "
849
- "be enabled, but the module won&#8217;t be visible on the SEO menu. You will "
850
- "still be able to access the module&#8217;s admin page by clicking on its "
851
- "title in the Module Manager table.</li>\r\n"
852
- "\t<li><strong>Disabled</strong> &mdash; The module will be completely "
853
- "disabled and inaccessible.</li>\r\n"
854
- "</ul>\r\n"
855
- msgstr ""
856
-
857
- #: modules/more-links.php:13
858
  msgid "More Link Customizer"
859
  msgstr ""
860
 
861
- #: modules/more-links.php:28
862
  msgid "Default More Link Text"
863
  msgstr ""
864
 
865
- #: modules/more-links.php:46
866
  msgid "More Link Text:"
867
  msgstr ""
868
 
869
- #: modules/more-links.php:69
870
- msgid ""
871
- "\r\n"
872
- "<ul>\r\n"
873
- "\t<li><p><strong>What it does:</strong> More Link Customizer lets you modify "
874
- "the anchor text of your posts&#8217; <a href='http://codex.wordpress.org/"
875
- "Customizing_the_Read_More' target='_blank'>&#8220;more&#8221; links</a>.</"
876
- "p></li>\r\n"
877
- "\t<li><p><strong>Why it helps:</strong> On the typical WordPress setup, the "
878
- "&#8220;more link&#8221; always has the same anchor text (e.g. &#8220;Read "
879
- "more of this entry &raquo;&#8221;). Since internal anchor text conveys web "
880
- "page topicality to search engines, the &#8220;read more&#8221; phrase "
881
- "isn&#8217;t a desirable anchor phrase. More Link Customizer lets you replace "
882
- "the boilerplate text with a new anchor that, by default, integrates your "
883
- "post titles (which will ideally be keyword-oriented).</p></li>\r\n"
884
- "\t<li><p><strong>How to use it:</strong> On this page you can set the anchor "
885
- "text you&#8217;d like to use by default. The <code>{post}</code> variable "
886
- "will be replaced with the post&#8217;s title. HTML and encoded entities are "
887
- "supported. If instead you decide that you&#8217;d like to use the default "
888
- "anchor text specified by your currently-active theme, just erase the "
889
- "contents of the textbox. The anchor text can be overriden on a per-post "
890
- "basis via the &#8220;More Link Text&#8221; box in the &#8220;SEO "
891
- "Settings&#8221; section of the WordPress post editor.</p></li>\r\n"
892
- "</ul>\r\n"
893
- msgstr ""
894
-
895
- #: modules/noindex.php:13
896
  msgid "Noindex Manager"
897
  msgstr ""
898
 
899
- #: modules/noindex.php:40
900
  msgid ""
901
  "Note: The current <a href='options-privacy.php'>privacy settings</a> will "
902
  "block indexing of the entire site, regardless of which options are set below."
903
  msgstr ""
904
 
905
- #: modules/noindex.php:43
906
  msgid "Prevent indexing of..."
907
  msgstr ""
908
 
909
- #: modules/noindex.php:44
910
  msgid "Administration back-end pages"
911
  msgstr ""
912
 
913
- #: modules/noindex.php:45
914
  msgid "Author archives"
915
  msgstr ""
916
 
917
- #: modules/noindex.php:46
918
  msgid "Blog search pages"
919
  msgstr ""
920
 
921
- #: modules/noindex.php:47
922
  msgid "Category archives"
923
  msgstr ""
924
 
925
- #: modules/noindex.php:48
926
  msgid "Comment feeds"
927
  msgstr ""
928
 
929
- #: modules/noindex.php:49
930
  msgid "Comment subpages"
931
  msgstr ""
932
 
933
- #: modules/noindex.php:50
934
  msgid "Date-based archives"
935
  msgstr ""
936
 
937
- #: modules/noindex.php:51
938
  msgid "Subpages of the homepage"
939
  msgstr ""
940
 
941
- #: modules/noindex.php:52
942
  msgid "Tag archives"
943
  msgstr ""
944
 
945
- #: modules/noindex.php:53
946
  msgid "User login/registration pages"
947
  msgstr ""
948
 
949
- #: modules/noindex.php:100
950
- msgid ""
951
- "\r\n"
952
- "<ul>\r\n"
953
- "\t<li><p><strong>What it does:</strong> Noindex Manager lets you prohibit "
954
- "the search engine spiders from indexing certain pages on your blog using the "
955
- "&quot;meta robots noindex&quot; tag.</p></li>\r\n"
956
- "\t<li><p><strong>Why it helps:</strong> This module lets you &#8220;"
957
- "noindex&#8221; pages that contain unimportant content (e.g. the login page), "
958
- "or pages that mostly contain duplicate content.</p></li>\r\n"
959
- "\t<li><p><strong>How to use it:</strong> Adjust the settings as desired, and "
960
- "then click Save Changes. You can refer to the &#8220;Settings Help&#8221; "
961
- "tab for information on the settings available.</p></li>\r\n"
962
- "</ul>\r\n"
963
- msgstr ""
964
-
965
- #: modules/noindex.php:110
966
- msgid ""
967
- "\r\n"
968
- "<p>Here&#8217;s information on the various settings:</p>\r\n"
969
- "<ul>\r\n"
970
- "\t<li><p><strong>Administration back-end pages</strong> &mdash; Tells "
971
- "spiders not to index the administration area (the part you&#8217;re in now),"
972
- "\r\n"
973
- "\t\tin the unlikely event a spider somehow gains access to the "
974
- "administration. Recommended.</p></li>\r\n"
975
- "\t<li><p><strong>Author archives</strong> &mdash; Tells spiders not to index "
976
- "author archives. Useful if your blog only has one author.</p></li>\r\n"
977
- "\t<li><p><strong>Blog search pages</strong> &mdash; Tells spiders not to "
978
- "index the result pages of WordPress&#8217;s blog search function. "
979
- "Recommended.</p></li>\r\n"
980
- "\t<li><p><strong>Category archives</strong> &mdash; Tells spiders not to "
981
- "index category archives. Recommended only if you don&#8217;t use categories."
982
- "</p></li>\r\n"
983
- "\t<li><p><strong>Comment feeds</strong> &mdash; Tells spiders not to index "
984
- "the RSS feeds that exist for every post&#8217;s comments.\r\n"
985
- "\t\t(These comment feeds are totally separate from your normal blog feeds.) "
986
- "Recommended.</p></li>\r\n"
987
- "\t<li><p><strong>Comment subpages</strong> &mdash; Tells spiders not to "
988
- "index posts' comment subpages.</p></li>\r\n"
989
- "\t<li><p><strong>Date-based archives</strong> &mdash; Tells spiders not to "
990
- "index day/month/year archives.\r\n"
991
- "\t\tRecommended, since these pages have little keyword value.</p></li>\r\n"
992
- "\t<li><p><strong>Subpages of the homepage</strong> &mdash; Tells spiders not "
993
- "to index the homepage's subpages (page 2, page 3, etc).\r\n"
994
- "\t\tRecommended.</p></li>\r\n"
995
- "\t<li><p><strong>Tag archives</strong> &mdash; Tells spiders not to index "
996
- "tag archives. Recommended only if you don&#8217;t use tags.</p></li>\r\n"
997
- "\t<li><p><strong>User login/registration pages</strong> &mdash; Tells "
998
- "spiders not to index WordPress&#8217;s user login and registration pages. "
999
- "Recommended.</p></li>\r\n"
1000
- "</ul>\r\n"
1001
- msgstr ""
1002
-
1003
- #: modules/sds-blog.php:13
1004
- msgid "SEO Design Solutions Whitepapers"
1005
  msgstr ""
1006
 
1007
- #: modules/sds-blog.php:14
1008
- msgid "Whitepapers"
1009
  msgstr ""
1010
 
1011
- #. #-#-#-#-# plugin.pot (PACKAGE VERSION) #-#-#-#-#
1012
  #. Author of an extension
1013
- #: modules/sds-blog.php:42
1014
  msgid "SEO Design Solutions"
1015
  msgstr ""
1016
 
1017
- #: modules/sds-blog.php:43
1018
  msgid ""
1019
  "Search engine optimization articles from the company behind the SEO Ultimate "
1020
  "plugin."
1021
  msgstr ""
1022
 
1023
- #: modules/sds-blog.php:94
1024
  msgid ""
1025
  "The articles below are loaded from the SEO Design Solutions website. Click "
1026
  "on an article&#8217s title to read it."
1027
  msgstr ""
1028
 
1029
- #: modules/settings.php:15
 
 
 
 
1030
  msgid "SEO Ultimate Plugin Settings"
1031
  msgstr ""
1032
 
1033
- #: modules/settings.php:67
 
 
 
 
 
 
1034
  msgid "Settings successfully imported."
1035
  msgstr ""
1036
 
1037
- #: modules/settings.php:69
1038
  msgid ""
1039
  "The uploaded file is not in the proper format. Settings could not be "
1040
  "imported."
1041
  msgstr ""
1042
 
1043
- #: modules/settings.php:71
1044
  msgid "The settings file could not be uploaded successfully."
1045
  msgstr ""
1046
 
1047
- #: modules/settings.php:74
1048
  msgid ""
1049
  "Settings could not be imported because no settings file was selected. Please "
1050
  "click the &#8220;Browse&#8221; button and select a file to import."
1051
  msgstr ""
1052
 
1053
- #: modules/settings.php:82
1054
  msgid "All settings have been erased and defaults have been restored."
1055
  msgstr ""
1056
 
1057
- #: modules/settings.php:96
1058
- msgid "Plugin Settings"
1059
- msgstr ""
1060
-
1061
- #: modules/settings.php:98
1062
  msgid "Enable attribution link"
1063
  msgstr ""
1064
 
1065
- #: modules/settings.php:99
1066
  msgid "Enable attribution link CSS styling"
1067
  msgstr ""
1068
 
1069
- #: modules/settings.php:100
1070
  msgid "Notify me about unnecessary active plugins"
1071
  msgstr ""
1072
 
1073
- #: modules/settings.php:102
1074
  msgid "Insert comments around HTML code insertions"
1075
  msgstr ""
1076
 
1077
- #: modules/settings.php:103
1078
  msgid "Allow modules to save visitor information to the database"
1079
  msgstr ""
1080
 
1081
- #: modules/settings.php:104
1082
  #, php-format
1083
  msgid "Delete logged visitor information after %d days"
1084
  msgstr ""
1085
 
1086
- #: modules/settings.php:109
1087
  msgid "Manage Settings Data"
1088
  msgstr ""
1089
 
1090
- #: modules/settings.php:113
1091
  msgid ""
1092
  "This section allows you to export, import, and reset the settings of the "
1093
  "plugin and all its modules."
1094
  msgstr ""
1095
 
1096
- #: modules/settings.php:115
1097
  msgid ""
1098
  "A settings file includes the data of every checkbox and textbox of every "
1099
  "installed module, as well as the &#8220;Plugin Settings&#8221; section "
1100
  "above. "
1101
  msgstr ""
1102
 
1103
- #: modules/settings.php:124
1104
  msgid "Export:"
1105
  msgstr ""
1106
 
1107
- #: modules/settings.php:127
1108
  msgid "Download Settings File"
1109
  msgstr ""
1110
 
1111
- #: modules/settings.php:132
1112
  msgid "Import:"
1113
  msgstr ""
1114
 
1115
- #: modules/settings.php:137
1116
  msgid ""
1117
  "Are you sure you want to import this settings file? This will overwrite your "
1118
  "current settings and cannot be undone."
1119
  msgstr ""
1120
 
1121
- #: modules/settings.php:138
1122
  msgid "Import This Settings File"
1123
  msgstr ""
1124
 
1125
- #: modules/settings.php:145
1126
  msgid "Reset:"
1127
  msgstr ""
1128
 
1129
- #: modules/settings.php:148
1130
  msgid ""
1131
  "Are you sure you want to erase all module settings? This cannot be undone."
1132
  msgstr ""
1133
 
1134
- #: modules/settings.php:149
1135
  msgid "Restore Default Settings"
1136
  msgstr ""
1137
 
1138
- #: modules/settings.php:173
 
 
 
 
1139
  msgid ""
1140
- "\r\n"
1141
- "<p>The Settings module lets you manage settings related to the SEO Ultimate "
1142
- "plugin as a whole.</p>\r\n"
1143
- "<p>Here&#8217;s information on some of the settings:</p>\r\n"
1144
- "<ul>\r\n"
1145
- "\t<li><p><strong>Enable attribution link</strong> &mdash; If enabled, the "
1146
- "plugin will display an attribution link on your site.\r\n"
1147
- "\t\tWe ask that you please leave this enabled.</p></li>\r\n"
1148
- "\t<li><p><strong>Insert comments around HTML code insertions</strong> "
1149
- "&mdash; If enabled, SEO Ultimate will use HTML comments to identify all code "
1150
- "it inserts into your &lt;head&gt; tag.\r\n"
1151
- "\t\tThis is useful if you&#8217;re trying to figure out whether or not SEO "
1152
- "Ultimate is inserting a certain piece of header code.</p></li>\r\n"
1153
- "\t<li><p><strong>Allow modules to save visitor information to the database</"
1154
- "strong> &mdash; This allows enabled modules to record information about the "
1155
- "people or robots that visit your website.\r\n"
1156
- "\t\tThis information is stored in your WordPress database. This setting must "
1157
- "be enabled in order for modules like the 404 Monitor to function.</p></li>"
1158
- "\r\n"
1159
- "\t<li><p><strong>Delete logged visitor information after ___ days</strong> "
1160
- "&mdash; If enabled, SEO Ultimate will delete visitor information once it has "
1161
- "been stored for more than a specified number of days.\r\n"
1162
- "\t\t(The default value is 30.) Enable this setting if the visitor-logging "
1163
- "functionality is making your database size unmanageable.\r\n"
1164
- "\t\tPlease note that as soon as you enable this and click the Save button, "
1165
- "your old visitor information will be irreversably purged accordingly.</p></"
1166
- "li>\r\n"
1167
- "</ul>\r\n"
1168
- msgstr ""
1169
-
1170
- #: modules/slugs.php:13
1171
  msgid "Slug Optimizer"
1172
  msgstr ""
1173
 
1174
- #: modules/slugs.php:17
1175
  msgid "Words to Remove"
1176
  msgstr ""
1177
 
1178
- #: modules/slugs.php:67
1179
- msgid ""
1180
- "\r\n"
1181
- "<ul>\r\n"
1182
- "\t<li><p><strong>What it does:</strong> Slug Optimizer removes common words "
1183
- "from the portion of a post&#8217;s or Page&#8217;s URL that is based on its "
1184
- "title. (This portion is also known as the &#8220;slug.&#8221;)</p></li>\r\n"
1185
- "\t<li><p><strong>Why it helps:</strong> Slug Optimizer increases keyword "
1186
- "potency because there are fewer words in your URLs competing for relevance.</"
1187
- "p></li>\r\n"
1188
- "\t<li><p><strong>How to use it:</strong> Slug Optimizer goes to work when "
1189
- "you&#8217;re editing a post or Page, with no action required on your part."
1190
- "\r\n"
1191
- "\t\tIf needed, you can use the textbox below to customize which words are "
1192
- "removed.</p></li>\r\n"
1193
- "</ul>\r\n"
1194
  msgstr ""
1195
 
1196
- #: modules/slugs.php:78
1197
- msgid ""
1198
- "\r\n"
1199
- "<h6>What's a slug?</h6>\r\n"
1200
- "<p>The slug of a post or page is the portion of its URL that is based on its "
1201
- "title.</p>\r\n"
1202
- "<p>When you edit a post or Page in WordPress, the slug is the yellow-"
1203
- "highlighted portion of the Permalink beneath the Title textbox.</p>\r\n"
1204
- "\r\n"
1205
- "<h6>Does the Slug Optimizer change my existing URLs?</h6>\r\n"
1206
- "<p>No. Slug Optimizer will not relocate your content by changing existing "
1207
- "URLs. Slug Optimizer only takes effect on new posts and pages.</p>\r\n"
1208
- "\r\n"
1209
- "<h6>How do I see Slug Optimizer in action?</h6>\r\n"
1210
- "<ol>\r\n"
1211
- "\t<li>Create a new post/Page in WordPress.</li>\r\n"
1212
- "\t<li>Type in a title containing some common words.</li>\r\n"
1213
- "\t<li>Click outside the Title box. WordPress will insert a URL labeled "
1214
- "&#8220;Permalink&#8221; below the Title textbox. The Slug Optimizer will "
1215
- "have removed the common words from the URL.</li>\r\n"
1216
- "</ol>\r\n"
1217
- "\r\n"
1218
- "<h6>Why didn't the Slug Optimizer remove common words from my slug?</h6>\r\n"
1219
- "<p>It's possible that every word in your post title is in the list of words "
1220
- "to remove. In this case, Slug Optimizer doesn't remove the words, because if "
1221
- "it did, you'd end up with a blank slug.</p>\r\n"
1222
- "\r\n"
1223
- "<h6>What if I want to include a common word in my slug?</h6>\r\n"
1224
- "<p>When editing the post or page in question, just click the Edit button "
1225
- "next to the permalink and change the slug as desired.</p>\r\n"
1226
- "\r\n"
1227
- "<h6>How do I revert back to the optimized slug after making changes?</h6>\r\n"
1228
- "<p>When editing the post or page in question, just click the Edit button "
1229
- "next to the permalink; a Save button will appear in its place. Next erase "
1230
- "the contents of the textbox, and then click the aforementioned Save button.</"
1231
- "p>\r\n"
1232
  msgstr ""
1233
 
1234
- #: modules/titles.php:13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1235
  msgid "Title Rewriter"
1236
  msgstr ""
1237
 
1238
- #: modules/titles.php:26
1239
  msgid "{blog}"
1240
  msgstr ""
1241
 
1242
- #: modules/titles.php:27
1243
  msgid "{post} | {blog}"
1244
  msgstr ""
1245
 
1246
- #: modules/titles.php:28
1247
  msgid "{page} | {blog}"
1248
  msgstr ""
1249
 
1250
- #: modules/titles.php:29
1251
  msgid "{category} | {blog}"
1252
  msgstr ""
1253
 
1254
- #: modules/titles.php:30
1255
  msgid "{tag} | {blog}"
1256
  msgstr ""
1257
 
1258
- #: modules/titles.php:31
1259
  msgid "Archives for {month} {day}, {year} | {blog}"
1260
  msgstr ""
1261
 
1262
- #: modules/titles.php:32
1263
  msgid "Archives for {month} {year} | {blog}"
1264
  msgstr ""
1265
 
1266
- #: modules/titles.php:33
1267
  msgid "Archives for {year} | {blog}"
1268
  msgstr ""
1269
 
1270
- #: modules/titles.php:34
1271
  msgid "Posts by {author} | {blog}"
1272
  msgstr ""
1273
 
1274
- #: modules/titles.php:35
1275
  msgid "Search Results for {query} | {blog}"
1276
  msgstr ""
1277
 
1278
- #: modules/titles.php:36
1279
  msgid "404 Not Found | {blog}"
1280
  msgstr ""
1281
 
1282
- #: modules/titles.php:37
1283
  msgid "{title} - Page {num}"
1284
  msgstr ""
1285
 
1286
- #: modules/titles.php:43
1287
  msgid "Blog Homepage Title"
1288
  msgstr ""
1289
 
1290
- #: modules/titles.php:44
1291
  msgid "Post Title Format"
1292
  msgstr ""
1293
 
1294
- #: modules/titles.php:45
1295
  msgid "Page Title Format"
1296
  msgstr ""
1297
 
1298
- #: modules/titles.php:46
1299
  msgid "Category Title Format"
1300
  msgstr ""
1301
 
1302
- #: modules/titles.php:47
1303
  msgid "Tag Title Format"
1304
  msgstr ""
1305
 
1306
- #: modules/titles.php:48
1307
  msgid "Day Archive Title Format"
1308
  msgstr ""
1309
 
1310
- #: modules/titles.php:49
1311
  msgid "Month Archive Title Format"
1312
  msgstr ""
1313
 
1314
- #: modules/titles.php:50
1315
  msgid "Year Archive Title Format"
1316
  msgstr ""
1317
 
1318
- #: modules/titles.php:51
1319
  msgid "Author Archive Title Format"
1320
  msgstr ""
1321
 
1322
- #: modules/titles.php:52
1323
  msgid "Search Title Format"
1324
  msgstr ""
1325
 
1326
- #: modules/titles.php:53
1327
  msgid "404 Title Format"
1328
  msgstr ""
1329
 
1330
- #: modules/titles.php:54
1331
  msgid "Pagination Title Format"
1332
  msgstr ""
1333
 
1334
- #: modules/titles.php:61
1335
- msgid "Default Formats"
1336
- msgstr ""
1337
-
1338
- #: modules/titles.php:62
1339
- msgid "Posts"
1340
- msgstr ""
1341
-
1342
- #: modules/titles.php:63
1343
- msgid "Pages"
1344
- msgstr ""
1345
-
1346
- #: modules/titles.php:75
1347
  msgid "Title Tag:"
1348
  msgstr ""
1349
 
1350
- #: modules/titles.php:259
1351
  msgid "Post"
1352
  msgstr ""
1353
 
1354
- #: modules/titles.php:263
1355
  msgid "Page"
1356
  msgstr ""
1357
 
1358
- #: modules/titles.php:299
1359
  msgid "ID"
1360
  msgstr ""
1361
 
1362
- #: modules/titles.php:299
1363
- msgid "Title Tag"
1364
  msgstr ""
1365
 
1366
- #: modules/titles.php:336
1367
- msgid "Settings & Variables"
1368
  msgstr ""
1369
 
1370
- #: modules/titles.php:341
1371
- msgid ""
1372
- "\r\n"
1373
- "<ul>\r\n"
1374
- "\t<li><p><strong>What it does:</strong> Title Rewriter helps you customize "
1375
- "the contents of your website&#8217;s <code>&lt;title&gt;</code> tags.\r\n"
1376
- "\t\tThe tag contents are displayed in web browser title bars and in search "
1377
- "engine result pages.</p></li>\r\n"
1378
- "\t<li><p><strong>Why it helps:</strong> Proper title rewriting ensures that "
1379
- "the keywords in your post/Page titles have greater prominence for search "
1380
- "engine spiders and users.\r\n"
1381
- "\t\tThis is an important foundation for WordPress SEO.</p></li>\r\n"
1382
- "\t<li><p><strong>How to use it:</strong> Title Rewriter enables recommended "
1383
- "settings automatically, so you shouldn&#8217;t need to change anything.\r\n"
1384
- "\t\tIf you do wish to edit the rewriting formats, you can do so using the "
1385
- "textboxes below (the &#8220;Settings Help&#8221; tab includes additional "
1386
- "information on this).\r\n"
1387
- "\t\tYou also have the option of overriding the <code>&lt;title&gt;</code> "
1388
- "tag of an individual post or page by using the textboxes under the &#8220;"
1389
- "Post&#8221; and &#8220;Page&#8221; tabs below, or by using the &#8220;Title "
1390
- "Tag&#8221; textbox that Title Rewriter adds to the post/page editors.</p></"
1391
- "li>\r\n"
1392
- "</ul>\r\n"
1393
- msgstr ""
1394
-
1395
- #: modules/titles.php:355
1396
- msgid ""
1397
- "\r\n"
1398
- "<p>Various variables, surrounded in {curly brackets}, are provided for use "
1399
- "in the title formats.\r\n"
1400
- "All settings support the {blog} variable, which is replaced with the name of "
1401
- "the blog, \r\n"
1402
- "and the {tagline} variable, which is replaced with the blog tagline as set "
1403
- "under <a href='options-general.php' target='_blank'>General&nbsp;Settings</"
1404
- "a>.</p>\r\n"
1405
- "<p>Here&#8217;s information on each of the settings and its supported "
1406
- "variables:</p>\r\n"
1407
- "<ul>\r\n"
1408
- "\t<li><p><strong>Blog Homepage Title</strong> &mdash; Displays on the main "
1409
- "blog posts page.</p></li>\r\n"
1410
- "\t<li><p><strong>Post Title Format</strong> &mdash; Displays on single-post "
1411
- "pages. Supports these variables:</p>\r\n"
1412
- "\t\t<ul>\r\n"
1413
- "\t\t\t<li>{post} &mdash; The post&#8217;s title.</li>\r\n"
1414
- "\t\t\t<li>{category} &mdash; The title of the post category with the lowest "
1415
- "ID number.</li>\r\n"
1416
- "\t\t\t<li>{categories} &mdash; A natural-language list of the post&#8217;s "
1417
- "categories (e.g. &#8220;Category A, Category B, and Category C&#8221;).</li>"
1418
- "\r\n"
1419
- "\t\t\t<li>{tags} &mdash; A natural-language list of the post&#8217;s tags (e."
1420
- "g. &#8220;Tag A, Tag B, and Tag C&#8221;).</li>\r\n"
1421
- "\t\t\t<li>{author} &mdash; The Display Name of the post&#8217;s author.</li>"
1422
- "\r\n"
1423
- "\t\t\t<li>{author_username}, {author_firstname}, {author_lastname}, "
1424
- "{author_nickname} &mdash; The username, first name, last name, and nickname "
1425
- "of the post&#8217;s author, respectively, as set in his or her profile.</li>"
1426
- "\r\n"
1427
- "\t\t</ul>\r\n"
1428
- "\t<li><p><strong>Page Title Format</strong> &mdash; Displays on WordPress "
1429
- "Pages. The {page} variable is replaced with the Page&#8217;s title. Also "
1430
- "supports the same author variables as the Post Title Format.</p></li>\r\n"
1431
- "\t<li><p><strong>Category Title Format</strong> &mdash; Displays on category "
1432
- "archives. The {category} variable is replaced with the name of the category, "
1433
- "and {category_description} is replaced with its description.</p></li>\r\n"
1434
- "\t<li><p><strong>Tag Title Format</strong> &mdash; Displays on tag archives. "
1435
- "The {tag} variable is replaced with the name of the tag, and "
1436
- "{tag_description} is replaced with its description.</p></li>\r\n"
1437
- "\t<li><p><strong>Day Archive Title Format</strong> &mdash; Displays on day "
1438
- "archives. Supports these variables:</p>\r\n"
1439
- "\t\t<ul>\r\n"
1440
- "\t\t\t<li>{day} &mdash; The day number, with ordinal suffix, e.g. 23rd</li>"
1441
- "\r\n"
1442
- "\t\t\t<li>{daynum} &mdash; The two-digit day number, e.g. 23</li>\r\n"
1443
- "\t\t\t<li>{month} &mdash; The name of the month, e.g. April</li>\r\n"
1444
- "\t\t\t<li>{monthnum} &mdash; The two-digit number of the month, e.g. 04</li>"
1445
- "\r\n"
1446
- "\t\t\t<li>{year} &mdash; The year, e.g. 2009</li>\r\n"
1447
- "\t\t</ul></li>\r\n"
1448
- "\t<li><p><strong>Month Archive Title Format</strong> &mdash; Displays on "
1449
- "month archives. Supports {month}, {monthnum}, and {year}.</p></li>\r\n"
1450
- "\t<li><p><strong>Year Archive Title Format</strong> &mdash; Displays on year "
1451
- "archives. Supports the {year} variable.</p></li>\r\n"
1452
- "\t<li><p><strong>Author Archive Title Format</strong> &mdash; Displays on "
1453
- "author archives. Supports the same author variables as the Post Title Format "
1454
- "box, \r\n"
1455
- "\t\ti.e. {author}, {author_username}, {author_firstname}, {author_lastname}, "
1456
- "and {author_nickname}.</p></li>\r\n"
1457
- "\t<li><p><strong>Search Title Format</strong> &mdash; Displays on the result "
1458
- "pages for WordPress&#8217;s blog search function.\r\n"
1459
- "\t\tThe {query} variable is replaced with the search query as-is. The "
1460
- "{ucwords} variable returns the search query with the first letter of each "
1461
- "word capitalized.</p></li>\r\n"
1462
- "\t<li><p><strong>404 Title Format</strong> &mdash; Displays whenever a URL "
1463
- "doesn&#8217;t go anywhere.</p></li>\r\n"
1464
- "\t<li><p><strong>Pagination Title Format</strong> &mdash; Displays whenever "
1465
- "the visitor is on a subpage (page 2, page 3, etc). Supports these variables:"
1466
- "</p>\r\n"
1467
- "\t\t<ul>\r\n"
1468
- "\t\t\t<li>{title} &mdash; The title that would normally be displayed on page "
1469
- "1.</li>\r\n"
1470
- "\t\t\t<li>{num} &mdash; The current page number (2, 3, etc).</li>\r\n"
1471
- "\t\t\t<li>{max} &mdash; The total number of subpages available. Would "
1472
- "usually be used like this: Page {num} of {max}</li>\r\n"
1473
- "\t\t</ul></li>\r\n"
1474
- "</ul>\r\n"
1475
- msgstr ""
1476
-
1477
- #: modules/titles.php:400
1478
  msgid ""
1479
  "<strong>Title Tag</strong> &mdash; The exact contents of the &lt;title&gt; "
1480
  "tag. The title appears in visitors' title bars and in search engine result "
1481
  "titles. "
1482
  msgstr ""
1483
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1484
  #. Plugin URI of an extension
1485
  msgid "http://www.seodesignsolutions.com/wordpress-seo/"
1486
  msgstr ""
1
+ # Translation of the WordPress plugin SEO Ultimate 1.5 by SEO Design Solutions.
2
+ # Copyright (C) 2010 SEO Design Solutions
3
  # This file is distributed under the same license as the SEO Ultimate package.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
5
  #
6
  #, fuzzy
7
  msgid ""
8
  msgstr ""
9
+ "Project-Id-Version: SEO Ultimate 1.5\n"
10
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/seo-ultimate\n"
11
+ "POT-Creation-Date: 2010-01-23 20:08+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
 
19
+ #: includes/jlfunctions/str.php:76 plugin/su-functions.php:77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  #, php-format
21
  msgid "%s and %s"
22
  msgstr ""
23
 
24
+ #: includes/jlfunctions/str.php:79 plugin/su-functions.php:80
25
  msgid ", "
26
  msgstr ""
27
 
28
+ #: includes/jlfunctions/str.php:80 plugin/su-functions.php:81
29
  #, php-format
30
  msgid "%s, and %s"
31
  msgstr ""
32
 
33
+ #: modules/404s/404s.php:29
34
  msgid "404 Monitor"
35
  msgstr ""
36
 
37
+ #: modules/404s/404s.php:48
38
  #, php-format
39
  msgid ""
40
  "Please note that new 404 errors will not be recorded, since visitor logging "
41
  "is disabled in the %s."
42
  msgstr ""
43
 
44
+ #: modules/404s/404s.php:49
45
  msgid "Plugin Settings module"
46
  msgstr ""
47
 
48
+ #: modules/404s/404s.php:56
49
  msgid "The log entry was successfully deleted."
50
  msgstr ""
51
 
52
+ #: modules/404s/404s.php:58
53
  msgid "This log entry has already been deleted."
54
  msgstr ""
55
 
56
+ #: modules/404s/404s.php:67
57
  msgid "The log was successfully cleared."
58
  msgstr ""
59
 
60
+ #: modules/404s/404s.php:75
61
  msgid "No 404 errors in the log."
62
  msgstr ""
63
 
64
+ #: modules/404s/404s.php:86
65
  msgid "Are you sure you want to delete all 404 log entries?"
66
  msgstr ""
67
 
68
+ #: modules/404s/404s.php:88
69
  msgid "Clear Log"
70
  msgstr ""
71
 
72
+ #: modules/404s/404s.php:101
73
  msgid "Open"
74
  msgstr ""
75
 
76
+ #: modules/404s/404s.php:102
77
  msgid "Google Cache"
78
  msgstr ""
79
 
80
+ #: modules/404s/404s.php:103
81
  msgid "Delete Log Entry"
82
  msgstr ""
83
 
84
+ #: modules/canonical/canonical.php:13
85
+ msgid "Canonicalizer"
 
 
86
  msgstr ""
87
 
88
+ #: modules/canonical/canonical.php:34
89
+ msgid "Generate <code>&lt;link rel=&quot;canonical&quot; /&gt;</code> tags."
90
  msgstr ""
91
 
92
+ #: modules/canonical/canonical.php:35
93
+ msgid "Redirect requests for nonexistent pagination."
94
  msgstr ""
95
 
96
+ #: modules/class.su-importmodule.php:37
97
+ msgid "Import Now"
98
+ msgstr ""
99
+
100
+ #: modules/class.su-importmodule.php:40
101
+ #, php-format
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  msgid ""
103
+ "The import cannot be undone. It is your responsibility to <a href=\"%s\" "
104
+ "target=\"_blank\">backup your database</a> before proceeding!"
105
+ msgstr ""
106
+
107
+ #: modules/class.su-importmodule.php:50
108
+ msgid "Import complete."
109
  msgstr ""
110
 
111
+ #: modules/class.su-importmodule.php:57
112
+ msgid "Return to import page"
113
+ msgstr ""
114
+
115
+ #: modules/class.su-importmodule.php:60
116
+ msgid "Return to settings page"
117
+ msgstr ""
118
+
119
+ #: modules/class.su-importmodule.php:63
120
+ msgid "Return to SEO page"
121
+ msgstr ""
122
+
123
+ #: modules/class.su-module.php:320
124
  msgid ""
125
+ "(Note: This translated documentation was designed for an older version of "
126
+ "SEO Ultimate and may be outdated.)"
127
+ msgstr ""
128
+
129
+ #: modules/class.su-module.php:851
 
 
 
 
 
 
 
 
 
 
130
  #, php-format
131
+ msgid "%s %s|Dropdown Title"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  msgstr ""
133
 
134
+ #: modules/class.su-module.php:879
135
+ #, php-format
136
+ msgid "%1$s | %2$s %3$s by %4$s"
137
  msgstr ""
138
 
139
+ #: modules/class.su-module.php:913
140
+ msgid "Settings updated."
141
  msgstr ""
142
 
143
+ #: modules/class.su-module.php:933
144
+ msgid "Save Changes"
145
+ msgstr ""
146
+
147
+ #: modules/class.su-module.php:1172
148
  msgid ""
149
+ "Are you sure you want to replace the textbox contents with this default "
150
+ "value?"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  msgstr ""
152
 
153
+ #: modules/class.su-module.php:1187
154
+ msgid "Reset"
155
+ msgstr ""
156
+
157
+ #: modules/competition-queries/competition-queries.php:13
158
  msgid "Competition Researcher"
159
  msgstr ""
160
 
161
+ #: modules/competition-queries/competition-queries.php:14
162
+ msgid "Comp. Researcher"
163
+ msgstr ""
164
+
165
+ #: modules/competition-queries/competition-queries.php:18
166
  msgid ""
167
  "The Competition Researcher provides you with easy access to various search "
168
  "engine tools which you can use to research multiple search queries or URLs."
169
  msgstr ""
170
 
171
+ #: modules/competition-queries/competition-queries.php:22
172
  msgid "Step 1: Choose Your Research Tool"
173
  msgstr ""
174
 
175
+ #: modules/competition-queries/competition-queries.php:26
176
  msgid "Keywords"
177
  msgstr ""
178
 
179
+ #: modules/competition-queries/competition-queries.php:26
180
  msgid "Normal Search"
181
  msgstr ""
182
 
183
+ #: modules/competition-queries/competition-queries.php:26
184
  msgid "Find out how many pages contain the words in each query"
185
  msgstr ""
186
 
187
+ #: modules/competition-queries/competition-queries.php:27
188
  msgid "Phrase Match"
189
  msgstr ""
190
 
191
+ #: modules/competition-queries/competition-queries.php:27
192
  msgid ""
193
  "Find out how many &#8220;actual&#8221; pages are competing for each query"
194
  msgstr ""
195
 
196
+ #: modules/competition-queries/competition-queries.php:28
197
  msgid "Allinanchor"
198
  msgstr ""
199
 
200
+ #: modules/competition-queries/competition-queries.php:28
201
  msgid "Find out which sites have the most links for each query"
202
  msgstr ""
203
 
204
+ #: modules/competition-queries/competition-queries.php:29
205
  msgid "Allintitle"
206
  msgstr ""
207
 
208
+ #: modules/competition-queries/competition-queries.php:29
209
  msgid ""
210
  "Find out which sites have the highest relevance in the title for each query"
211
  msgstr ""
212
 
213
+ #: modules/competition-queries/competition-queries.php:30
214
  msgid "Allintext"
215
  msgstr ""
216
 
217
+ #: modules/competition-queries/competition-queries.php:30
218
  msgid "Find out which sites have the most relevant content/text on their pages"
219
  msgstr ""
220
 
221
+ #: modules/competition-queries/competition-queries.php:31
222
  msgid "Allinurl"
223
  msgstr ""
224
 
225
+ #: modules/competition-queries/competition-queries.php:31
226
  msgid ""
227
  "Find out which sites have the most relevant naming conventions for each "
228
  "keyword"
229
  msgstr ""
230
 
231
+ #: modules/competition-queries/competition-queries.php:33
232
  msgid "URLs"
233
  msgstr ""
234
 
235
+ #: modules/competition-queries/competition-queries.php:33
236
  msgid "Site"
237
  msgstr ""
238
 
239
+ #: modules/competition-queries/competition-queries.php:33
240
  msgid "Find out how many pages are indexed for each domain"
241
  msgstr ""
242
 
243
+ #: modules/competition-queries/competition-queries.php:34
244
+ #: modules/competition-queries/competition-queries.php:39
245
  msgid "Inbound Links"
246
  msgstr ""
247
 
248
+ #: modules/competition-queries/competition-queries.php:34
249
  msgid "Find out how many sites link to the domains"
250
  msgstr ""
251
 
252
+ #: modules/competition-queries/competition-queries.php:35
253
+ #: modules/competition-queries/competition-queries.php:39
254
  msgid "Outbound Links"
255
  msgstr ""
256
 
257
+ #: modules/competition-queries/competition-queries.php:35
258
  msgid "Find out how many sites the domains link to"
259
  msgstr ""
260
 
261
+ #: modules/competition-queries/competition-queries.php:57
262
  msgid "Step 2: Enter the <span id='methodtype'>Keywords</span> To Research"
263
  msgstr ""
264
 
265
+ #: modules/competition-queries/competition-queries.php:59
266
  msgid "(Type in one per line)"
267
  msgstr ""
268
 
269
+ #: modules/competition-queries/competition-queries.php:61
270
  msgid "Step 3: Set Options and Submit"
271
  msgstr ""
272
 
273
+ #: modules/competition-queries/competition-queries.php:63
274
+ #: modules/site-keyword-queries/site-keyword-queries.php:29
275
  msgid "Show 100 results per page"
276
  msgstr ""
277
 
278
+ #: modules/competition-queries/competition-queries.php:65
279
+ #: modules/site-keyword-queries/site-keyword-queries.php:31
280
  msgid "Use Google's minimal mode"
281
  msgstr ""
282
 
283
+ #: modules/competition-queries/competition-queries.php:71
284
+ #: modules/site-keyword-queries/site-keyword-queries.php:34
285
  msgid "Submit"
286
  msgstr ""
287
 
288
+ #: modules/files/files.php:15
289
  msgid "File Editor"
290
  msgstr ""
291
 
292
+ #: modules/files/files.php:53
293
  msgid ""
294
  "A .htaccess file exists, but it&#8217;s not writable. You can edit it here "
295
  "once the file permissions are corrected."
296
  msgstr ""
297
 
298
+ #: modules/files/files.php:59
299
  msgid ""
300
  "WordPress won&#8217;t be able to display your robots.txt file because the "
301
  "default <a href=\"options-permalink.php\" target=\"_blank\">permalink "
302
  "structure</a> is in use."
303
  msgstr ""
304
 
305
+ #: modules/files/files.php:66
306
  #, php-format
307
  msgid "robots.txt [<a href=\"%s\" target=\"_blank\">Open</a>]"
308
  msgstr ""
309
 
310
+ #: modules/files/files.php:70
311
  msgid "Enable this custom robots.txt file and disable the default file"
312
  msgstr ""
313
 
314
+ #: modules/files/files.php:71
315
  msgid "Let other plugins add rules to my custom robots.txt file"
316
  msgstr ""
317
 
318
+ #: modules/files/files.php:72
319
  msgid "robots.txt Settings"
320
  msgstr ""
321
 
322
+ #: modules/files/files.php:75
323
  msgid ""
324
  "Please realize that incorrectly editing your robots.txt file could block "
325
  "search engines from your site."
326
  msgstr ""
327
 
328
+ #: modules/files/files.php:79
329
  msgid ".htaccess"
330
  msgstr ""
331
 
332
+ #: modules/files/files.php:82
333
  msgid ""
334
  "Also, incorrectly editing your .htaccess file could disable your entire "
335
  "website. Edit with caution!"
336
  msgstr ""
337
 
338
+ #: modules/files/files.php:132
339
  #, php-format
340
  msgid ""
341
  "Please note that your privacy settings won&#8217;t have any effect on your "
342
  "robots.txt file, since you&#8217;re using <a href=\"%s\">a custom one</a>."
343
  msgstr ""
344
 
345
+ #: modules/files/files.php:140
346
+ msgid "Overview"
347
+ msgstr ""
348
+
349
+ #: modules/files/files.php:141
350
  msgid "FAQ"
351
  msgstr ""
352
 
353
+ #: modules/files/files.php:146
354
  msgid ""
355
  "The File Editor module lets you edit system files that are of SEO value. "
356
  "Edit the files as desired, then click Save Changes. If you create a custom "
357
  "robots.txt file, be sure to enable it with the checkbox."
358
  msgstr ""
359
 
360
+ #: modules/files/files.php:150
361
  msgid ""
362
  "\r\n"
363
  "<h6>Why do I get a &#8220;500 Server Error&#8221; after using the File "
390
  "you can try recovering your edits from there.</p>\r\n"
391
  msgstr ""
392
 
393
+ #: modules/linkbox/linkbox.php:13
394
  msgid "Linkbox Inserter"
395
  msgstr ""
396
 
397
+ #: modules/linkbox/linkbox.php:19
398
  msgid "Link to this post!"
399
  msgstr ""
400
 
401
+ #: modules/linkbox/linkbox.php:46
402
  msgid "At the end of posts"
403
  msgstr ""
404
 
405
+ #: modules/linkbox/linkbox.php:47
406
  msgid "At the end of pages"
407
  msgstr ""
408
 
409
+ #: modules/linkbox/linkbox.php:48
410
  msgid "When called by the su_linkbox hook"
411
  msgstr ""
412
 
413
+ #: modules/linkbox/linkbox.php:49
414
  msgid "Display linkboxes..."
415
  msgstr ""
416
 
417
+ #: modules/linkbox/linkbox.php:50
418
  msgid "Linkbox HTML"
419
  msgstr ""
420
 
421
+ #: modules/meta/meta-settings.php:16
422
+ msgid "Meta Editor Settings"
423
  msgstr ""
424
 
425
+ #: modules/meta/meta-settings.php:17
426
+ msgid "Settings"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
427
  msgstr ""
428
 
429
+ #: modules/meta/meta-settings.php:28
430
  msgid "Blog Homepage Meta Description"
431
  msgstr ""
432
 
433
+ #: modules/meta/meta-settings.php:29
434
  msgid "Blog Homepage Meta Keywords"
435
  msgstr ""
436
 
437
+ #: modules/meta/meta-settings.php:32
438
  msgid "Use this blog&#8217s tagline as the default homepage description."
439
  msgstr ""
440
 
441
+ #: modules/meta/meta-settings.php:33
442
  msgid "Default Values"
443
  msgstr ""
444
 
445
+ #: modules/meta/meta-settings.php:35
446
  msgid ""
447
  "Don&#8217t use this site&#8217s Open Directory description in search results."
448
  msgstr ""
449
 
450
+ #: modules/meta/meta-settings.php:36
451
  msgid ""
452
  "Don&#8217t use this site&#8217s Yahoo! Directory description in search "
453
  "results."
454
  msgstr ""
455
 
456
+ #: modules/meta/meta-settings.php:37
457
  msgid "Don&#8217t cache or archive this site."
458
  msgstr ""
459
 
460
+ #: modules/meta/meta-settings.php:38
461
  msgid "Spider Instructions"
462
  msgstr ""
463
 
464
+ #: modules/meta/meta-settings.php:40
465
  msgid "Google Webmaster Tools:"
466
  msgstr ""
467
 
468
+ #: modules/meta/meta-settings.php:41
469
  msgid "Yahoo! Site Explorer:"
470
  msgstr ""
471
 
472
+ #: modules/meta/meta-settings.php:42
473
  msgid "Bing Webmaster Center:"
474
  msgstr ""
475
 
476
+ #: modules/meta/meta-settings.php:43
477
  msgid "Verification Codes"
478
  msgstr ""
479
 
480
+ #: modules/meta/meta-settings.php:44
481
  msgid "Custom &lt;head&gt; HTML"
482
  msgstr ""
483
 
484
+ #: modules/meta/meta.php:13
485
+ msgid "Meta Editor"
486
+ msgstr ""
487
+
488
+ #: modules/meta/meta.php:84
489
+ msgid "Custom Header Code"
490
+ msgstr ""
491
+
492
+ #: modules/meta/meta.php:100
493
  msgid "Description:"
494
  msgstr ""
495
 
496
+ #: modules/meta/meta.php:103
497
  #, php-format
498
  msgid "You&#8217;ve entered %s characters. Most search engines use up to 160."
499
  msgstr ""
500
 
501
+ #: modules/meta/meta.php:105
502
  msgid "Keywords:<br /><em>(separate with commas)</em>"
503
  msgstr ""
504
 
505
+ #: modules/meta/meta.php:112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
506
  msgid ""
507
  "<strong>Description:</strong> &mdash; The value of the meta description tag. "
508
  "The description will often appear underneath the title in search engine "
509
  "results. "
510
  msgstr ""
511
 
512
+ #: modules/meta/meta.php:114
513
  msgid ""
514
  "<strong>Keywords:</strong> &mdash; The value of the meta keywords tag. The "
515
  "keywords list gives search engines a hint as to what this post/page is "
516
  "about. "
517
  msgstr ""
518
 
519
+ #: modules/modules/modules.php:13
520
+ msgid "Module Manager"
521
  msgstr ""
522
 
523
+ #: modules/modules/modules.php:14
524
+ msgid "Modules"
525
  msgstr ""
526
 
527
+ #: modules/modules/modules.php:34
528
  msgid ""
529
  "SEO Ultimate&#8217;s features are located in groups called &#8220;modules."
530
  "&#8221; By default, most of these modules are listed in the &#8220;"
531
  "SEO&#8221; menu on the left. Whenever you&#8217;re working with a module, "
532
+ "you can view documentation by clicking the tabs in the upper-right-hand "
533
+ "corner of your administration screen."
534
  msgstr ""
535
 
536
+ #: modules/modules/modules.php:36
537
  msgid ""
538
  "The Module Manager lets you disable or hide modules you don&#8217;t use. "
539
  "You can also silence modules from displaying bubble alerts on the menu."
540
  msgstr ""
541
 
542
+ #: modules/modules/modules.php:42
543
  msgid "Status"
544
  msgstr ""
545
 
546
+ #: modules/modules/modules.php:43
547
  msgid "Module"
548
  msgstr ""
549
 
550
+ #: modules/modules/modules.php:56
551
  msgid "Enabled"
552
  msgstr ""
553
 
554
+ #: modules/modules/modules.php:57
555
  msgid "Silenced"
556
  msgstr ""
557
 
558
+ #: modules/modules/modules.php:58
559
  msgid "Hidden"
560
  msgstr ""
561
 
562
+ #: modules/modules/modules.php:59
563
  msgid "Disabled"
564
  msgstr ""
565
 
566
+ #: modules/more-links/more-links.php:13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
567
  msgid "More Link Customizer"
568
  msgstr ""
569
 
570
+ #: modules/more-links/more-links.php:28
571
  msgid "Default More Link Text"
572
  msgstr ""
573
 
574
+ #: modules/more-links/more-links.php:46
575
  msgid "More Link Text:"
576
  msgstr ""
577
 
578
+ #: modules/noindex/noindex.php:13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
579
  msgid "Noindex Manager"
580
  msgstr ""
581
 
582
+ #: modules/noindex/noindex.php:40
583
  msgid ""
584
  "Note: The current <a href='options-privacy.php'>privacy settings</a> will "
585
  "block indexing of the entire site, regardless of which options are set below."
586
  msgstr ""
587
 
588
+ #: modules/noindex/noindex.php:43
589
  msgid "Prevent indexing of..."
590
  msgstr ""
591
 
592
+ #: modules/noindex/noindex.php:44
593
  msgid "Administration back-end pages"
594
  msgstr ""
595
 
596
+ #: modules/noindex/noindex.php:45
597
  msgid "Author archives"
598
  msgstr ""
599
 
600
+ #: modules/noindex/noindex.php:46
601
  msgid "Blog search pages"
602
  msgstr ""
603
 
604
+ #: modules/noindex/noindex.php:47
605
  msgid "Category archives"
606
  msgstr ""
607
 
608
+ #: modules/noindex/noindex.php:48
609
  msgid "Comment feeds"
610
  msgstr ""
611
 
612
+ #: modules/noindex/noindex.php:49
613
  msgid "Comment subpages"
614
  msgstr ""
615
 
616
+ #: modules/noindex/noindex.php:50
617
  msgid "Date-based archives"
618
  msgstr ""
619
 
620
+ #: modules/noindex/noindex.php:51
621
  msgid "Subpages of the homepage"
622
  msgstr ""
623
 
624
+ #: modules/noindex/noindex.php:52
625
  msgid "Tag archives"
626
  msgstr ""
627
 
628
+ #: modules/noindex/noindex.php:53
629
  msgid "User login/registration pages"
630
  msgstr ""
631
 
632
+ #: modules/sds-blog/sds-blog.php:13
633
+ msgid "Whitepapers"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
634
  msgstr ""
635
 
636
+ #: modules/sds-blog/sds-blog.php:14
637
+ msgid "SEO Design Solutions Whitepapers"
638
  msgstr ""
639
 
640
+ #. #-#-#-#-# plugin.pot (SEO Ultimate 1.5) #-#-#-#-#
641
  #. Author of an extension
642
+ #: modules/sds-blog/sds-blog.php:43
643
  msgid "SEO Design Solutions"
644
  msgstr ""
645
 
646
+ #: modules/sds-blog/sds-blog.php:44
647
  msgid ""
648
  "Search engine optimization articles from the company behind the SEO Ultimate "
649
  "plugin."
650
  msgstr ""
651
 
652
+ #: modules/sds-blog/sds-blog.php:95
653
  msgid ""
654
  "The articles below are loaded from the SEO Design Solutions website. Click "
655
  "on an article&#8217s title to read it."
656
  msgstr ""
657
 
658
+ #: modules/settings/settings.php:15 modules/settings/settings.php:96
659
+ msgid "Plugin Settings"
660
+ msgstr ""
661
+
662
+ #: modules/settings/settings.php:16
663
  msgid "SEO Ultimate Plugin Settings"
664
  msgstr ""
665
 
666
+ #. #-#-#-#-# plugin.pot (SEO Ultimate 1.5) #-#-#-#-#
667
+ #. Plugin Name of an extension
668
+ #: modules/settings/settings.php:17 plugin/class.seo-ultimate.php:759
669
+ msgid "SEO Ultimate"
670
+ msgstr ""
671
+
672
+ #: modules/settings/settings.php:67
673
  msgid "Settings successfully imported."
674
  msgstr ""
675
 
676
+ #: modules/settings/settings.php:69
677
  msgid ""
678
  "The uploaded file is not in the proper format. Settings could not be "
679
  "imported."
680
  msgstr ""
681
 
682
+ #: modules/settings/settings.php:71
683
  msgid "The settings file could not be uploaded successfully."
684
  msgstr ""
685
 
686
+ #: modules/settings/settings.php:74
687
  msgid ""
688
  "Settings could not be imported because no settings file was selected. Please "
689
  "click the &#8220;Browse&#8221; button and select a file to import."
690
  msgstr ""
691
 
692
+ #: modules/settings/settings.php:82
693
  msgid "All settings have been erased and defaults have been restored."
694
  msgstr ""
695
 
696
+ #: modules/settings/settings.php:98
 
 
 
 
697
  msgid "Enable attribution link"
698
  msgstr ""
699
 
700
+ #: modules/settings/settings.php:99
701
  msgid "Enable attribution link CSS styling"
702
  msgstr ""
703
 
704
+ #: modules/settings/settings.php:100
705
  msgid "Notify me about unnecessary active plugins"
706
  msgstr ""
707
 
708
+ #: modules/settings/settings.php:102
709
  msgid "Insert comments around HTML code insertions"
710
  msgstr ""
711
 
712
+ #: modules/settings/settings.php:103
713
  msgid "Allow modules to save visitor information to the database"
714
  msgstr ""
715
 
716
+ #: modules/settings/settings.php:104
717
  #, php-format
718
  msgid "Delete logged visitor information after %d days"
719
  msgstr ""
720
 
721
+ #: modules/settings/settings.php:109
722
  msgid "Manage Settings Data"
723
  msgstr ""
724
 
725
+ #: modules/settings/settings.php:113
726
  msgid ""
727
  "This section allows you to export, import, and reset the settings of the "
728
  "plugin and all its modules."
729
  msgstr ""
730
 
731
+ #: modules/settings/settings.php:115
732
  msgid ""
733
  "A settings file includes the data of every checkbox and textbox of every "
734
  "installed module, as well as the &#8220;Plugin Settings&#8221; section "
735
  "above. "
736
  msgstr ""
737
 
738
+ #: modules/settings/settings.php:124
739
  msgid "Export:"
740
  msgstr ""
741
 
742
+ #: modules/settings/settings.php:127
743
  msgid "Download Settings File"
744
  msgstr ""
745
 
746
+ #: modules/settings/settings.php:132
747
  msgid "Import:"
748
  msgstr ""
749
 
750
+ #: modules/settings/settings.php:137
751
  msgid ""
752
  "Are you sure you want to import this settings file? This will overwrite your "
753
  "current settings and cannot be undone."
754
  msgstr ""
755
 
756
+ #: modules/settings/settings.php:138
757
  msgid "Import This Settings File"
758
  msgstr ""
759
 
760
+ #: modules/settings/settings.php:145
761
  msgid "Reset:"
762
  msgstr ""
763
 
764
+ #: modules/settings/settings.php:148
765
  msgid ""
766
  "Are you sure you want to erase all module settings? This cannot be undone."
767
  msgstr ""
768
 
769
+ #: modules/settings/settings.php:149
770
  msgid "Restore Default Settings"
771
  msgstr ""
772
 
773
+ #: modules/settings/settings.php:165
774
+ msgid "Import from Other Plugins"
775
+ msgstr ""
776
+
777
+ #: modules/settings/settings.php:167
778
  msgid ""
779
+ "You can import settings and data from these plugins. Clicking a plugin&#8217;"
780
+ "s name will take you to the importer page, where you can customize "
781
+ "parameters and start the import."
782
+ msgstr ""
783
+
784
+ #: modules/site-keyword-queries/site-keyword-queries.php:13
785
+ msgid "Internal Relevance Researcher"
786
+ msgstr ""
787
+
788
+ #: modules/site-keyword-queries/site-keyword-queries.php:14
789
+ msgid "Int. Rel. Researcher"
790
+ msgstr ""
791
+
792
+ #: modules/site-keyword-queries/site-keyword-queries.php:22
793
+ msgid "Step 1: Enter Keywords"
794
+ msgstr ""
795
+
796
+ #: modules/site-keyword-queries/site-keyword-queries.php:24
797
+ msgid "(Type one keyword per line)"
798
+ msgstr ""
799
+
800
+ #: modules/site-keyword-queries/site-keyword-queries.php:26
801
+ msgid "Step 2: Set Options and Submit"
802
+ msgstr ""
803
+
804
+ #: modules/site-keyword-queries/site-keyword-queries.php:28
805
+ msgid "Put keywords in quotes"
806
+ msgstr ""
807
+
808
+ #: modules/slugs/slugs.php:13
 
809
  msgid "Slug Optimizer"
810
  msgstr ""
811
 
812
+ #: modules/slugs/slugs.php:17
813
  msgid "Words to Remove"
814
  msgstr ""
815
 
816
+ #: modules/titles/titles-formats.php:8
817
+ msgid "Title Rewriter Formats"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
818
  msgstr ""
819
 
820
+ #: modules/titles/titles-formats.php:9
821
+ msgid "Default Formats"
822
+ msgstr ""
823
+
824
+ #: modules/titles/titles-posts.php:17
825
+ msgid "Post Title Editor"
826
+ msgstr ""
827
+
828
+ #: modules/titles/titles-posts.php:24
829
+ msgid "Posts"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
830
  msgstr ""
831
 
832
+ #: modules/titles/titles-posts.php:25
833
+ msgid "Pages"
834
+ msgstr ""
835
+
836
+ #: modules/titles/titles-posts.php:26
837
+ msgid "Attachments"
838
+ msgstr ""
839
+
840
+ #: modules/titles/titles-taxonomies.php:17
841
+ msgid "Taxonomy Title Editor"
842
+ msgstr ""
843
+
844
+ #: modules/titles/titles-taxonomies.php:24
845
+ msgid "Categories"
846
+ msgstr ""
847
+
848
+ #: modules/titles/titles-taxonomies.php:25
849
+ msgid "Post Tags"
850
+ msgstr ""
851
+
852
+ #: modules/titles/titles.php:13
853
  msgid "Title Rewriter"
854
  msgstr ""
855
 
856
+ #: modules/titles/titles.php:26
857
  msgid "{blog}"
858
  msgstr ""
859
 
860
+ #: modules/titles/titles.php:27
861
  msgid "{post} | {blog}"
862
  msgstr ""
863
 
864
+ #: modules/titles/titles.php:28
865
  msgid "{page} | {blog}"
866
  msgstr ""
867
 
868
+ #: modules/titles/titles.php:29
869
  msgid "{category} | {blog}"
870
  msgstr ""
871
 
872
+ #: modules/titles/titles.php:30
873
  msgid "{tag} | {blog}"
874
  msgstr ""
875
 
876
+ #: modules/titles/titles.php:31
877
  msgid "Archives for {month} {day}, {year} | {blog}"
878
  msgstr ""
879
 
880
+ #: modules/titles/titles.php:32
881
  msgid "Archives for {month} {year} | {blog}"
882
  msgstr ""
883
 
884
+ #: modules/titles/titles.php:33
885
  msgid "Archives for {year} | {blog}"
886
  msgstr ""
887
 
888
+ #: modules/titles/titles.php:34
889
  msgid "Posts by {author} | {blog}"
890
  msgstr ""
891
 
892
+ #: modules/titles/titles.php:35
893
  msgid "Search Results for {query} | {blog}"
894
  msgstr ""
895
 
896
+ #: modules/titles/titles.php:36
897
  msgid "404 Not Found | {blog}"
898
  msgstr ""
899
 
900
+ #: modules/titles/titles.php:37
901
  msgid "{title} - Page {num}"
902
  msgstr ""
903
 
904
+ #: modules/titles/titles.php:43
905
  msgid "Blog Homepage Title"
906
  msgstr ""
907
 
908
+ #: modules/titles/titles.php:44
909
  msgid "Post Title Format"
910
  msgstr ""
911
 
912
+ #: modules/titles/titles.php:45
913
  msgid "Page Title Format"
914
  msgstr ""
915
 
916
+ #: modules/titles/titles.php:46
917
  msgid "Category Title Format"
918
  msgstr ""
919
 
920
+ #: modules/titles/titles.php:47
921
  msgid "Tag Title Format"
922
  msgstr ""
923
 
924
+ #: modules/titles/titles.php:48
925
  msgid "Day Archive Title Format"
926
  msgstr ""
927
 
928
+ #: modules/titles/titles.php:49
929
  msgid "Month Archive Title Format"
930
  msgstr ""
931
 
932
+ #: modules/titles/titles.php:50
933
  msgid "Year Archive Title Format"
934
  msgstr ""
935
 
936
+ #: modules/titles/titles.php:51
937
  msgid "Author Archive Title Format"
938
  msgstr ""
939
 
940
+ #: modules/titles/titles.php:52
941
  msgid "Search Title Format"
942
  msgstr ""
943
 
944
+ #: modules/titles/titles.php:53
945
  msgid "404 Title Format"
946
  msgstr ""
947
 
948
+ #: modules/titles/titles.php:54
949
  msgid "Pagination Title Format"
950
  msgstr ""
951
 
952
+ #: modules/titles/titles.php:65
 
 
 
 
 
 
 
 
 
 
 
 
953
  msgid "Title Tag:"
954
  msgstr ""
955
 
956
+ #: modules/titles/titles.php:275
957
  msgid "Post"
958
  msgstr ""
959
 
960
+ #: modules/titles/titles.php:279
961
  msgid "Page"
962
  msgstr ""
963
 
964
+ #: modules/titles/titles.php:351
965
  msgid "ID"
966
  msgstr ""
967
 
968
+ #: modules/titles/titles.php:351
969
+ msgid "Name"
970
  msgstr ""
971
 
972
+ #: modules/titles/titles.php:351
973
+ msgid "Title Tag"
974
  msgstr ""
975
 
976
+ #: modules/titles/titles.php:424
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
977
  msgid ""
978
  "<strong>Title Tag</strong> &mdash; The exact contents of the &lt;title&gt; "
979
  "tag. The title appears in visitors' title bars and in search engine result "
980
  "titles. "
981
  msgstr ""
982
 
983
+ #: plugin/class.seo-ultimate.php:759
984
+ msgid "SEO"
985
+ msgstr ""
986
+
987
+ #: plugin/class.seo-ultimate.php:975
988
+ msgid "SEO Settings Help"
989
+ msgstr ""
990
+
991
+ #: plugin/class.seo-ultimate.php:977
992
+ msgid "The SEO Settings box lets you customize these settings:"
993
+ msgstr ""
994
+
995
+ #: plugin/class.seo-ultimate.php:979
996
+ msgid "(The SEO Settings box is part of the SEO Ultimate plugin.)"
997
+ msgstr ""
998
+
999
+ #: plugin/class.seo-ultimate.php:1034
1000
+ #, php-format
1001
+ msgid ""
1002
+ "SEO Ultimate includes the functionality of %1$s. You may want to deactivate %"
1003
+ "1$s to avoid plugin conflicts."
1004
+ msgstr ""
1005
+
1006
+ #: plugin/class.seo-ultimate.php:1176
1007
+ msgid "SEO Settings"
1008
+ msgstr ""
1009
+
1010
+ #: plugin/class.su-hitset.php:44
1011
+ msgid "Date"
1012
+ msgstr ""
1013
+
1014
+ #: plugin/class.su-hitset.php:45
1015
+ msgid "IP Address"
1016
+ msgstr ""
1017
+
1018
+ #: plugin/class.su-hitset.php:46
1019
+ msgid "User Agent"
1020
+ msgstr ""
1021
+
1022
+ #: plugin/class.su-hitset.php:47
1023
+ msgid "URL Requested"
1024
+ msgstr ""
1025
+
1026
+ #: plugin/class.su-hitset.php:48
1027
+ msgid "Redirected To"
1028
+ msgstr ""
1029
+
1030
+ #: plugin/class.su-hitset.php:49
1031
+ msgid "Status Code"
1032
+ msgstr ""
1033
+
1034
+ #: plugin/class.su-hitset.php:50
1035
+ msgid "Referring URL"
1036
+ msgstr ""
1037
+
1038
+ #: plugin/class.su-hitset.php:82
1039
+ #, php-format
1040
+ msgid "%1$s<br />%2$s"
1041
+ msgstr ""
1042
+
1043
  #. Plugin URI of an extension
1044
  msgid "http://www.seodesignsolutions.com/wordpress-seo/"
1045
  msgstr ""